@amaui/ui-react
Version:
UI for React
388 lines (387 loc) • 16.1 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
const _excluded = ["value", "dateProperty", "menuOpen", "menuOpenDefault", "timeMenuOpen", "timeMenuOpenDefault", "onChange", "onRemove", "closeOnChange", "startBottom", "endBottom", "noRemove", "children", "className"];
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
import React from 'react';
import { hash, is } from '@amaui/utils';
import { classNames, style, useAmauiTheme } from '@amaui/style-react';
import { AmauiDate, add, diff, format, is as isDate } from '@amaui/date';
import IconMaterialScheduleRounded from '@amaui/icons-material-rounded-react/IconMaterialScheduleW100';
import IconMaterialWbSunnyRounded from '@amaui/icons-material-rounded-react/IconMaterialWbSunnyW100';
import IconMaterialWbTwilightRounded from '@amaui/icons-material-rounded-react/IconMaterialWbTwilightW100';
import IconMaterialCounter7Rounded from '@amaui/icons-material-rounded-react/IconMaterialCounter7W100';
import IconMaterialCalendarMonthRounded from '@amaui/icons-material-rounded-react/IconMaterialCalendarMonthW100';
import IconMaterialDeleteRounded from '@amaui/icons-material-rounded-react/IconMaterialDeleteW100';
import MenuElement from '../Menu';
import CalendarElement from '../Calendar';
import LineElement from '../Line';
import TooltipElement from '../Tooltip';
import IconButtonElement from '../IconButton';
import ButtonElement from '../Button';
import ListItemElement from '../ListItem';
import PaginationItemElement from '../PaginationItem';
import TimePickerElement from '../TimePicker';
import TypeElement from '../Type';
import { formats, staticClassName } from '../utils';
const useStyle = style(theme => ({
root: {},
weekday: {
cursor: 'pointer'
},
dayValue: {
'&:hover': {
boxShadow: 'inset 0px 0px 0px 1px currentColor'
}
},
dayValueRepeating: {
background: theme.palette.background.secondary.quaternary
},
calendar: {
boxShadow: '0px 4px 32px 0px rgba(0, 0, 0, 0.04)',
'& .amaui-Calendar-header': {
paddingTop: '0px'
},
'& .amaui-Calendar-calendars': {
paddingBottom: '4px'
}
},
calendarShortcuts: {
padding: '14px 16px 2px'
},
end: {
padding: '0 12px 12px',
'& .amaui-ListItem-root': {
minHeight: '24px !important',
padding: '0 8px',
borderRadius: theme.methods.shape.radius.value(0.5, 'px')
}
},
minorMenu: {
'& .amaui-List-root': {
width: '100%'
}
},
repeatEndMenu: {
'& .amaui-List-root': {
width: '100%'
}
},
menuMore: {
width: '100%',
padding: '12px',
borderRadius: theme.methods.shape.radius.value(0.5, 'px'),
'& .amaui-TextField-input-wrapper': {
paddingBlock: '12px',
height: '40px'
},
'& .amaui-TextField-icon-end': {
paddingBlock: '8px'
}
},
item: {
'& .amaui-ListItem-root': {
minHeight: '30px !important'
},
'&.amaui-Surface-root': {
background: 'transparent'
}
},
iconInactive: {
opacity: '0',
pointerEvents: 'none'
},
menuFooter: {
marginTop: '8px'
}
}), {
name: 'amaui-CalendarMenu'
});
const CalendarMenu = /*#__PURE__*/React.forwardRef((props_, ref) => {
const theme = useAmauiTheme();
const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.amauiCalendarAvailability?.props?.default), props_), [props_]);
const Line = React.useMemo(() => theme?.elements?.Line || LineElement, [theme]);
const Menu = React.useMemo(() => theme?.elements?.Menu || MenuElement, [theme]);
const Calendar = React.useMemo(() => theme?.elements?.Calendar || CalendarElement, [theme]);
const Tooltip = React.useMemo(() => theme?.elements?.Tooltip || TooltipElement, [theme]);
const IconButton = React.useMemo(() => theme?.elements?.IconButton || IconButtonElement, [theme]);
const Button = React.useMemo(() => theme?.elements?.Button || ButtonElement, [theme]);
const ListItem = React.useMemo(() => theme?.elements?.ListItem || ListItemElement, [theme]);
const PaginationItem = React.useMemo(() => theme?.elements?.PaginationItem || PaginationItemElement, [theme]);
const TimePicker = React.useMemo(() => theme?.elements?.TimePicker || TimePickerElement, [theme]);
const Type = React.useMemo(() => theme?.elements?.Type || TypeElement, [theme]);
const {
value,
dateProperty = 'ends_at',
menuOpen: menuOpen_,
menuOpenDefault,
timeMenuOpen: timeMenuOpen_,
timeMenuOpenDefault,
onChange: onChange_,
onRemove: onRemove_,
closeOnChange = true,
startBottom,
endBottom,
noRemove,
children,
className
} = props,
other = _objectWithoutProperties(props, _excluded);
const {
classes
} = useStyle();
const [menuOpen, setMenuOpen] = React.useState(menuOpenDefault !== undefined ? menuOpenDefault : menuOpen_ !== undefined ? menuOpen_ : false);
const [timeMenuOpen, setTimeMenuOpen] = React.useState(timeMenuOpenDefault !== undefined ? timeMenuOpenDefault : timeMenuOpen_ !== undefined ? timeMenuOpen_ : false);
const refs = {
value: React.useRef(value),
dateProperty: React.useRef(dateProperty),
time: React.useRef(undefined),
repeat: React.useRef(undefined),
repeatEnd: React.useRef(undefined),
onChange: React.useRef(onChange_),
repeatCount: React.useRef({})
};
refs.dateProperty.current = dateProperty;
refs.value.current = value;
refs.onChange.current = onChange_;
const onChange = React.useCallback(async function () {
if (is('function', onChange_)) onChange_(...arguments);
}, [onChange_]);
React.useEffect(() => {
if (menuOpen !== menuOpen_ && menuOpen_ !== undefined) setMenuOpen(menuOpen_);
}, [menuOpen_]);
React.useEffect(() => {
if (timeMenuOpen !== timeMenuOpen_ && timeMenuOpen_ !== undefined) setTimeMenuOpen(timeMenuOpen_);
}, [timeMenuOpen_]);
const onMenuOpen = React.useCallback(() => {
setMenuOpen(true);
}, []);
const onMenuClose = React.useCallback(() => {
setMenuOpen(false);
}, []);
const onTimeMenuOpen = React.useCallback(() => {
setTimeMenuOpen(true);
}, []);
const onTimeMenuClose = React.useCallback(() => {
setTimeMenuOpen(false);
}, []);
const onChangeDate = React.useCallback(valueNew => {
if (closeOnChange) onMenuClose();
onChange(refs.dateProperty.current, valueNew?.milliseconds);
}, [closeOnChange, onChange]);
const onChangeTime = React.useCallback(valueNew => {
onTimeMenuClose();
onChange(refs.dateProperty.current, valueNew?.milliseconds);
}, [onTimeMenuClose, closeOnChange, onChange]);
const onRemove = React.useCallback(() => {
if (is('function', onRemove_)) onRemove_(value);
}, [value, onRemove_]);
React.useEffect(() => {
// reset
refs.repeatCount.current = {};
}, [hash(value)]);
const iconProps = {
size: 'regular'
};
const shortcuts = [{
name: 'Today',
onClick: () => onChangeDate(new AmauiDate()),
icon: /*#__PURE__*/React.createElement(IconMaterialWbSunnyRounded, iconProps)
}, {
name: 'Tomorrow',
onClick: () => onChangeDate(add(1, 'day')),
icon: /*#__PURE__*/React.createElement(IconMaterialWbTwilightRounded, iconProps)
}, {
name: '7 days',
onClick: () => onChangeDate(add(7, 'day')),
icon: /*#__PURE__*/React.createElement(IconMaterialCounter7Rounded, iconProps)
}, {
name: '1 month',
onClick: () => onChangeDate(add(1, 'month')),
icon: /*#__PURE__*/React.createElement(IconMaterialCalendarMonthRounded, iconProps)
}];
const onClear = React.useCallback(event => {
onChange(refs.dateProperty.current, null);
}, [onChange]);
const date = React.useMemo(() => new AmauiDate(value?.[dateProperty] || undefined), [value, dateProperty]);
const repeats = day => {
if (!value?.repeat?.active) return;
let unit = value?.repeat?.unit;
let valueRepeat = value?.repeat?.value;
if (unit === 'day') unit = 'days';
if (unit === 'week') {
unit = 'days';
valueRepeat *= 7;
}
if (unit === 'month') unit = 'months';
let difference = diff(day, date, unit);
let repeating = false;
if (['day', 'week'].includes(value?.repeat?.unit)) {
if (value?.repeat.unit === 'week' && !!value?.repeat?.weekdays?.length) {
difference = diff(day, date.dayWeek === 0 ? add(-1, 'week', date) : date, 'weeks');
if (day.dayWeek === 0) difference -= 1;
const modulus = difference % value?.repeat?.value;
repeating = isDate(day, 'after or same', date) && !modulus && value?.repeat.weekdays?.includes(day.dayWeek);
} else {
const modulus = difference % valueRepeat;
repeating = isDate(day, 'after or same', date) && !modulus;
}
}
if (['month'].includes(value?.repeat?.unit)) {
const modulus = difference % valueRepeat;
const monthDate = add(difference, 'month', date);
repeating = monthDate.year === day.year && monthDate.dayYear === day.dayYear && !modulus;
}
if (['year'].includes(value?.repeat?.unit)) {
const modulus = difference % valueRepeat;
const yearDate = add(difference, 'year', date);
repeating = isDate(day, 'after', date) && yearDate.year === day.year && yearDate.dayYear === day.dayYear && !modulus;
}
if (value?.repeat?.skip_weekends && [0, 6].includes(day.dayWeek)) repeating = false;
if (repeating) {
const formated = format(day, formats.date);
if (value?.repeat?.ends?.active) {
// date
if (value?.repeat.ends.version === 'date') {
const endsDate = new AmauiDate(value?.repeat.ends.value);
repeating = repeating && (day.year < endsDate.year || day.year === endsDate.year && (day.month < endsDate.month || day.month === endsDate.month && day.dayYear <= endsDate.dayYear));
}
}
if (repeating) {
if (!refs.repeatCount.current[value?.id]) refs.repeatCount.current[value?.id] = [];
if (!refs.repeatCount.current[value?.id].includes(formated)) refs.repeatCount.current[value?.id].push(formated);
}
if (value?.repeat?.ends?.active) {
const indexRepeated = refs.repeatCount.current[value?.id]?.indexOf(formated);
// count
if (value?.repeat.ends.version === 'count') repeating = repeating && value?.repeat.ends.value >= (indexRepeated === -1 ? 0 : indexRepeated) + 1;
}
repeating = !value?.repeat.ends?.active || repeating;
}
return repeating;
};
const onContextMenu = React.useCallback(event => {
event.stopPropagation();
}, []);
const palette = theme.palette.color.primary;
return /*#__PURE__*/React.createElement(Menu, _extends({
open: menuOpen,
onOpen: onMenuOpen,
onClose: onMenuClose,
onContextMenu: onContextMenu,
name: /*#__PURE__*/React.createElement(Calendar, {
tonal: true,
color: "themed",
calendarDefault: date,
start: /*#__PURE__*/React.createElement(Line, {
gap: 1,
direction: "row",
align: "center",
justify: "center",
className: classes.calendarShortcuts
}, shortcuts.map((item, index) => /*#__PURE__*/React.createElement(Tooltip, {
key: index,
name: item.name
}, /*#__PURE__*/React.createElement(IconButton, {
onClick: () => {
item.onClick();
onMenuClose();
},
size: "small"
}, item.icon)))),
value: value?.[dateProperty] ? date : null,
onChange: onChangeDate,
onContextMenu: onContextMenu,
size: "small",
end: /*#__PURE__*/React.createElement(Line, {
gap: 0.5,
fullWidth: true,
className: classes.end
}, startBottom, value?.[dateProperty] && /*#__PURE__*/React.createElement(Menu, {
open: timeMenuOpen,
onOpen: onTimeMenuOpen,
onClose: onTimeMenuClose,
name: () => /*#__PURE__*/React.createElement(Line, {
gap: 1,
align: "center",
fullWidth: true
}, /*#__PURE__*/React.createElement(TimePicker, {
value: date,
onChange: onChangeTime,
clear: false,
MainProps: {
elevation: theme.palette.light ? 8 : 0
},
static: true
})),
className: classNames([classes.timeMenu, 'amaui-time']),
style: {
width: refs.time.current?.clientWidth
}
}, /*#__PURE__*/React.createElement(ListItem, {
ref: refs.time,
start: /*#__PURE__*/React.createElement(IconMaterialScheduleRounded, iconProps),
primary: /*#__PURE__*/React.createElement(Type, {
version: "b2",
color: "inherit"
}, format(date, 'HH:mm')),
startAlign: "center",
size: "small",
button: true,
Component: "div",
className: classes.item
})), endBottom, /*#__PURE__*/React.createElement(Line, {
gap: 0.4,
direction: "row",
align: "center",
justify: "space-between",
fullWidth: true,
className: classes.menuFooter
}, /*#__PURE__*/React.createElement(Button, {
onClick: onClear,
version: "text",
size: "small",
disabled: !value?.[dateProperty]
}, "Clear"), !noRemove && /*#__PURE__*/React.createElement(Tooltip, {
name: "Remove"
}, /*#__PURE__*/React.createElement(IconButton, {
size: "small",
onClick: onRemove
}, /*#__PURE__*/React.createElement(IconMaterialDeleteRounded, iconProps))))),
CalendarMonthProps: {
renderDay: (dayAmauiDate, propsDay, day, outside) => {
const repeating = repeats(dayAmauiDate);
return /*#__PURE__*/React.createElement(PaginationItem, _extends({
tonal: true,
color: "inherit",
size: "small",
InteractionProps: {
background: false
},
TypeProps: {
version: 'b3',
priority: !day.selected ? !day.weekend ? 'primary' : 'secondary' : undefined
},
"aria-label": format(dayAmauiDate, 'DD-MM-YYYY'),
className: classNames([classes.dayValue, repeating && classes.dayValueRepeating]),
style: _objectSpread(_objectSpread({}, day.today ? {
boxShadow: `inset 0px 0px 0px 1px ${palette[40]}`
} : undefined), day.selected ? {
color: theme.methods.palette.color.value(undefined, 90, true, palette),
backgroundColor: theme.methods.palette.color.value(undefined, 40, true, palette)
} : undefined)
}, propsDay), day.value);
},
noTransition: true
},
className: classNames(['amaui-ObjectCalendar-root', classes.calendar])
}),
ClickListenerProps: {
contextMenu: false
},
className: classNames([staticClassName('CalendarMenu', theme) && ['amaui-CalendarMenu-root'], className, classes.root])
}, other), children);
});
CalendarMenu.displayName = 'amaui-CalendarMenu';
export default CalendarMenu;