import * as React from 'react';
import ContentAdd from '@mui/icons-material/Add';
import { Fab, Theme, useMediaQuery } from '@mui/material';
import { styled } from '@mui/material/styles';
import clsx from 'clsx';
import isEqual from 'lodash/isEqual';
import merge from 'lodash/merge';
import PropTypes from 'prop-types';
import { useCreatePath, useResourceContext, useTranslate } from 'ra-core';
import { Link, To } from 'react-router-dom';
import { Button, ButtonProps, LocationDescriptor } from './Button';
/**
* Opens the Create view of a given resource
*
* Renders as a regular button on desktop, and a Floating Action Button
* on mobile.
*
* @example // basic usage
* import { CreateButton } from 'react-admin';
*
* const CommentCreateButton = () => (
*
* );
*/
function CreateBtn(props: CreateButtonProps) {
const {
className,
icon = defaultIcon,
label = 'ra.action.create',
resource: resourceProp,
scrollToTop = true,
variant,
to: locationDescriptor,
state: initialState = {},
disableFloatingButton = false,
...rest
} = props;
const resource = useResourceContext(props);
const createPath = useCreatePath();
const translate = useTranslate();
const isSmall = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
const state = merge({}, scrollStates.get(String(scrollToTop)), initialState);
// Duplicated behaviour of Button component (legacy use) which will be removed in v5.
const linkParams = getLinkParams(locationDescriptor);
return !disableFloatingButton && isSmall ? (
{icon}
) : (
{icon}
);
}
const defaultIcon = ;
// avoids using useMemo to get a constant value for the link state
const scrollStates = new Map([
['true', { _scrollToTop: true }],
['false', {}]
]);
interface Props {
resource?: string;
icon?: React.ReactElement;
scrollToTop?: boolean;
to?: LocationDescriptor | To;
state?: any;
}
interface DisableFloatingButtonProps {
disableFloatingButton?: boolean;
}
type CreateButtonProps = DisableFloatingButtonProps & Props & Omit;
CreateBtn.propTypes = {
resource: PropTypes.string,
className: PropTypes.string,
icon: PropTypes.element,
label: PropTypes.string
};
const PREFIX = 'RaCreateButton';
const CreateButtonClasses = {
root: `${PREFIX}-root`,
floating: `${PREFIX}-floating`
};
const StyledFab = styled(Fab, {
name: PREFIX,
overridesResolver: (_props, styles) => styles.root
})(({ theme }) => ({
[`&.${CreateButtonClasses.floating}`]: {
color: theme.palette.getContrastText(theme.palette.primary.main),
margin: 0,
top: 'auto',
right: 20,
bottom: 60,
left: 'auto',
position: 'fixed',
zIndex: 1000
}
})) as unknown as typeof Fab;
const StyledButton = styled(Button, {
name: PREFIX,
overridesResolver: (_props, styles) => styles.root
})({});
function arePropsEqual(prevProps: CreateButtonProps, nextProps: CreateButtonProps) {
return (
prevProps.resource === nextProps.resource &&
prevProps.label === nextProps.label &&
prevProps.translate === nextProps.translate &&
prevProps.disabled === nextProps.disabled &&
isEqual(prevProps.to, nextProps.to) &&
isEqual(prevProps.state, nextProps.state)
);
}
const CreateButton = React.memo(CreateBtn, arePropsEqual);
function getLinkParams(locationDescriptor?: LocationDescriptor | string) {
// eslint-disable-next-line eqeqeq
if (locationDescriptor == undefined) {
return undefined;
}
if (typeof locationDescriptor === 'string') {
return { to: locationDescriptor };
}
const { redirect, replace, state, ...to } = locationDescriptor;
return {
to,
redirect,
replace,
state
};
}
export { CreateButton, CreateButtonClasses };
export type { CreateButtonProps };