UNPKG

@onesy/ui-react

Version:
383 lines 13.9 kB
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["tonal", "color", "label", "onSelect", "emojis", "categories", "selected", "size", "search", "tabs", "className"]; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React from 'react'; import { is, debounce, clamp, capitalize } from '@onesy/utils'; import { classNames, style as styleMethod, useOnesyTheme } from '@onesy/style-react'; import IconMaterialMood from '@onesy/icons-material-rounded-react/IconMaterialMoodW100'; import IconMaterialEmojiNature from '@onesy/icons-material-rounded-react/IconMaterialEmojiNatureW100'; import IconMaterialEmojiFoodBeverage from '@onesy/icons-material-rounded-react/IconMaterialEmojiFoodBeverageW100'; import IconMaterialHiking from '@onesy/icons-material-rounded-react/IconMaterialHikingW100'; import IconMaterialEmojiTransportation from '@onesy/icons-material-rounded-react/IconMaterialEmojiTransportationW100'; import IconMaterialEmojiObjects from '@onesy/icons-material-rounded-react/IconMaterialEmojiObjectsW100'; import IconMaterialEmojiSymbols from '@onesy/icons-material-rounded-react/IconMaterialEmojiSymbolsW100'; import IconMaterialEmojiFlags from '@onesy/icons-material-rounded-react/IconMaterialEmojiFlagsW100'; import MenuElement from '../Menu/Menu'; import LineElement from '../Line'; import SpyScrollElement from '../SpyScroll'; import ListElement from '../List'; import ListSubheaderElement from '../ListSubheader'; import TabsElement from '../Tabs'; import TextFieldElement from '../TextField'; import TabElement from '../Tab'; import TypeElement from '../Type'; import SurfaceElement from '../Surface'; import emojis_list from './emojis_list'; import { staticClassName } from '../utils'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const useStyle = styleMethod(theme => ({ root: {}, wrapper: { height: '70vh', width: '70vw', borderRadius: theme.methods.shape.radius.value(2, 'px'), boxShadow: 'rgba(0, 0, 0, 0.07) 0px 4px 32px 0px', overflow: 'hidden' }, size_small: { maxWidth: 276, maxHeight: 276 }, size_regular: { maxWidth: 340, maxHeight: 340 }, size_large: { maxWidth: 404, maxHeight: 404 }, main: { position: 'relative', height: 0, overflow: 'hidden auto' }, header: { padding: `${theme.methods.space.value(1.5, 'px')} ${theme.methods.space.value(1.5, 'px')} 0` }, categories: { height: '100%', userSelect: 'none' }, category: { paddingInlineStart: theme.methods.space.value(1.5, 'px') }, emoji: { position: 'relative', textAlign: 'center', cursor: 'pointer', transition: theme.methods.transitions.make('transform'), '&$emoji_selected': { '&::before': { content: '""', position: 'absolute', width: 'calc(100% + 4px)', height: 'auto', aspectRatio: '1/1', background: theme.palette.background.default.tertiary, inset: '0', borderRadius: theme.methods.shape.radius.value(40, 'px'), zIndex: '0', left: '50%', transform: 'translate(-50%)', top: '-1px' } }, '&:active': { transform: 'scale(0.94)' } }, emoji_size_small: { fontSize: '1.5rem', width: 24 }, emoji_size_regular: { fontSize: '2rem', width: 32 }, emoji_size_large: { fontSize: '2.5rem', width: 40 }, unicode: { position: 'relative', zIndex: 1 }, subheader: { backdropFilter: 'blur(2px)', background: 'transparent', '&.onesy-ListSubheader-root': { zIndex: 14 } }, tabs: { '&.onesy-Tabs-root': { background: 'transparent' }, '& .onesy-Tabs-tabs': { minWidth: '100%' } }, tab: { '&.onesy-Tab-root': { minWidth: 'unset' } }, tab_size_small: { '&.onesy-Tab-root': { padding: `${theme.methods.space.value(1, 'px')} ${theme.methods.space.value(0.75, 'px')}` } }, tab_size_regular: { '&.onesy-Tab-root': { padding: `${theme.methods.space.value(1, 'px')} ${theme.methods.space.value(1.25, 'px')}` } }, tab_size_large: { '&.onesy-Tab-root': { padding: `${theme.methods.space.value(1, 'px')} ${theme.methods.space.value(1.25, 'px')}` } } }), { name: 'onesy-Emojis' }); const Emojis = props_ => { const theme = useOnesyTheme(); const l = theme.l; const props = _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.onesyEmojis?.props?.default), props_); const Line = theme?.elements?.Line || LineElement; const Menu = theme?.elements?.Menu || MenuElement; const List = theme?.elements?.List || ListElement; const ListSubheader = theme?.elements?.ListSubheader || ListSubheaderElement; const SpyScroll = theme?.elements?.SpyScroll || SpyScrollElement; const Tabs = theme?.elements?.Tabs || TabsElement; const TextField = theme?.elements?.TextField || TextFieldElement; const Tab = theme?.elements?.Tab || TabElement; const Type = theme?.elements?.Type || TypeElement; const Surface = theme?.elements?.Surface || SurfaceElement; const EMOJI_CATEGORIES = React.useMemo(() => { return [{ "name": l("Smileys and People"), "groups": ["Smiley", "Gesture", "Person", "Clothing"], "icon": /*#__PURE__*/_jsx(IconMaterialMood, {}) }, { "name": l("Animals and Nature"), "groups": ["Animal", "Nature"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiNature, {}) }, { "name": l("Food and Drink"), "groups": ["Food"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiFoodBeverage, {}) }, { "name": l("Activity"), "groups": ["Activity"], "icon": /*#__PURE__*/_jsx(IconMaterialHiking, {}) }, { "name": l("Travel and Places"), "groups": ["Travel"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiTransportation, {}) }, { "name": l("Objects"), "groups": ["Object"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiObjects, {}) }, { "name": l("Symbols"), "groups": ["Symbol"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiSymbols, {}) }, { "name": l("Flags and Countries"), "groups": ["Flag", "Country"], "icon": /*#__PURE__*/_jsx(IconMaterialEmojiFlags, {}) }]; }, []); const { tonal = true, color = 'themed', label: label_, onSelect: onSelect_, emojis = emojis_list, categories = EMOJI_CATEGORIES, selected, size = 'regular', search: search_ = true, tabs: tabs_ = true, className } = props, other = _objectWithoutProperties(props, _excluded); const { classes } = useStyle(); const [open, setOpen] = React.useState(false); const [openElement, setOpenElement] = React.useState(); const [search, setSearch] = React.useState(); const [tab, setTab] = React.useState(categories[0].name); const refs = { main: React.useRef(undefined) }; const onOpen = () => { setOpen(true); setTimeout(() => { setOpenElement(refs.main.current || null); }, 140); }; const onClose = () => { setOpen(false); setTimeout(() => { setOpenElement(null); setSearch(''); }, 140); }; const onSelect = valueNew => { if (is('function', onSelect_)) onSelect_(valueNew); }; const emojisPerCategory = React.useMemo(() => { const value = {}; if (is('array', categories)) { categories.forEach(item => { const groups = {}; emojis.forEach(emoji => { const alias = (is('array', emoji.alias) ? emoji.alias : [emoji.alias]).join('').toLowerCase(); if (item.groups.includes(emoji.category) && (!search || alias.includes(search.toLowerCase()))) { if (!groups[emoji.category]) groups[emoji.category] = []; groups[emoji.category].unshift(emoji); } }); value[item.name] = []; item.groups.forEach(group => { if (!!groups[group]?.length) value[item.name].push(...groups[group]); }); }); Object.keys(value).forEach(item_0 => { if (!value[item_0].length) delete value[item_0]; }); } return value; }, [search, emojis, categories]); const onChangeSearch = debounce(valueNew_0 => { setSearch(valueNew_0); }, 140); const onChangeTabs = valueNew_1 => { setTab(valueNew_1); }; const onActiveTab = valueNew_2 => { setTab(valueNew_2.replace(/-/g, ' ')); }; const onTabClick = valueNew_3 => { const elements = Array.from(refs.main.current?.children || []); if (!!elements.length) { const element = elements.find(item_1 => item_1.dataset.onesyCategory === valueNew_3); if (element) { const top = element.offsetTop; const offset = -1; refs.main.current.scroll({ left: 0, top: clamp(top - offset, 0), behavior: 'smooth' }); } } }; const categoriesUsed = Object.keys(emojisPerCategory); const categoryToID = valueNew_4 => valueNew_4.replace(/ /g, '-'); const categoriesUsedIDs = categoriesUsed.map(item_2 => categoryToID(item_2)); const tabs = categories.filter(item_3 => categoriesUsed.some(item_ => item_3.name === item_)).map(item_4 => ({ name: item_4.icon, value: item_4.name })); const label = /*#__PURE__*/_jsx(Line, { tonal: tonal, color: color, Component: Surface, className: classNames([classes.wrapper, classes[`size_${size}`]]), children: /*#__PURE__*/_jsx(SpyScroll, { ids: categoriesUsedIDs, parent: openElement, onActive: onActiveTab, children: /*#__PURE__*/_jsxs(Line, { gap: 0, align: "unset", justify: "unset", fullWidth: true, className: classes.categories, children: [(search_ || tabs_) && /*#__PURE__*/_jsxs(Line, { gap: 1, fullWidth: true, className: classes.header, children: [search_ && /*#__PURE__*/_jsx(TextField, { name: l('Search'), version: "outlined", value: search || '', onChange: onChangeSearch, size: ['small', 'regular'].includes(size) ? 'small' : 'regular', fullWidth: true, clear: true }), tabs_ && !!categoriesUsed.length && /*#__PURE__*/_jsx(Tabs, { valueDefault: tab, value: tab, onChange: onChangeTabs, size: "small", initialLineUpdateTimeout: 440, noDivider: true, className: classes.tabs, children: tabs.map((item_5, index) => /*#__PURE__*/_jsx(Tab, { value: item_5.value, onClick: () => onTabClick(item_5.value), "data-onesy-spy-scroll": categoryToID(item_5.value), className: classNames([classes.tab, classes[`tab_size_${size}`]]), children: /*#__PURE__*/React.cloneElement(item_5.name, { size: ['small', 'regular'].includes(size) ? 'small' : 'regular' }) }, index)) })] }), /*#__PURE__*/_jsx(Line, { ref: refs.main, gap: 0, flex: true, fullWidth: true, className: classes.main, children: categoriesUsed.map((item_6, index_0) => /*#__PURE__*/_jsxs(List, { gap: 1, fullWidth: true, SurfaceProps: { id: categoryToID(item_6), 'data-onesy-category': item_6 }, children: [/*#__PURE__*/_jsx(ListSubheader, { className: classes.subheader, children: /*#__PURE__*/_jsx(Type, { version: size === 'large' ? 'b1' : size === 'regular' ? 'b2' : 'b3', children: item_6 }) }), /*#__PURE__*/_jsx(Line, { gap: 1, direction: "row", align: "center", wrap: "wrap", Component: "li", className: classes.category, children: emojisPerCategory[item_6].map((emoji_0, index_) => /*#__PURE__*/_jsx("span", { onClick: () => onSelect(emoji_0), title: capitalize((is('array', emoji_0.alias) ? emoji_0.alias.join(', ') : emoji_0.alias).replace(/_/g, ' ')), className: classNames([classes.emoji, classes[`emoji_size_${size}`], selected?.includes(emoji_0.unicode) && classes.emoji_selected]), children: /*#__PURE__*/_jsx("span", { className: classes.unicode, children: emoji_0.unicode }) }, index_)) })] }, index_0)) })] }) }) }); return /*#__PURE__*/_jsx(Menu, _objectSpread({ open: open, onOpen: onOpen, onClose: onClose, label: label, className: classNames([staticClassName('Emojis', theme) && ['onesy-Emojis-root', `onesy-Emojis-size-${size}`], className, classes.root]) }, other)); }; Emojis.displayName = 'onesy-Emojis'; export default Emojis;