emoji-picker-react 4.22.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -49
- package/dist/DomUtils/categoryNameFromDom.d.ts +1 -1
- package/dist/DomUtils/classNames.d.ts +24 -23
- package/dist/DomUtils/detectEmojyPartiallyBelowFold.d.ts +2 -2
- package/dist/DomUtils/elementPositionInRow.d.ts +5 -5
- package/dist/DomUtils/eventBelongsToPicker.d.ts +2 -0
- package/dist/DomUtils/focusElement.d.ts +5 -5
- package/dist/DomUtils/getActiveElement.d.ts +2 -2
- package/dist/DomUtils/isJsdom.d.ts +1 -0
- package/dist/DomUtils/isRtl.d.ts +1 -0
- package/dist/DomUtils/keyboardNavigation.d.ts +7 -8
- package/dist/DomUtils/scrollTo.d.ts +4 -5
- package/dist/DomUtils/selectors.d.ts +31 -35
- package/dist/EmojiPickerReact.d.ts +5 -5
- package/dist/Stylesheet/DedupedStyle.d.ts +13 -0
- package/dist/Stylesheet/stylesheet.d.ts +40 -37
- package/dist/components/ErrorBoundary.d.ts +15 -15
- package/dist/components/Layout/Absolute.d.ts +8 -8
- package/dist/components/Layout/Flex.d.ts +13 -13
- package/dist/components/Layout/Relative.d.ts +8 -8
- package/dist/components/Layout/Space.d.ts +7 -7
- package/dist/components/Reactions/BtnPlus.d.ts +2 -2
- package/dist/components/Reactions/DEFAULT_REACTIONS.d.ts +1 -1
- package/dist/components/Reactions/Reactions.d.ts +3 -2
- package/dist/components/atoms/Button.d.ts +11 -6
- package/dist/components/body/EmojiCategory.d.ts +13 -12
- package/dist/components/body/EmojiList.d.ts +7 -4
- package/dist/components/body/EmojiVariationPicker.d.ts +2 -2
- package/dist/components/body/MeasureEmoji.d.ts +2 -2
- package/dist/components/body/listComponents.d.ts +47 -0
- package/dist/components/context/ElementRefContext.d.ts +18 -16
- package/dist/components/context/PickerConfigContext.d.ts +14 -9
- package/dist/components/context/PickerContext.d.ts +57 -25
- package/dist/components/context/PickerDataContext.d.ts +23 -17
- package/dist/components/emoji/BaseEmojiProps.d.ts +14 -13
- package/dist/components/emoji/ClickableEmojiButton.d.ts +23 -15
- package/dist/components/emoji/Emoji.d.ts +18 -15
- package/dist/components/emoji/EmojiImg.d.ts +11 -11
- package/dist/components/emoji/ExportedEmoji.d.ts +11 -11
- package/dist/components/emoji/NativeEmoji.d.ts +6 -6
- package/dist/components/emoji/ViewOnlyEmoji.d.ts +3 -3
- package/dist/components/emoji/emojiStyles.d.ts +6 -1
- package/dist/components/footer/Preview.d.ts +7 -7
- package/dist/components/header/Header.d.ts +2 -2
- package/dist/components/header/Search/BtnClearSearch.d.ts +2 -2
- package/dist/components/header/Search/IcnSearch.d.ts +2 -2
- package/dist/components/header/Search/Search.d.ts +11 -3
- package/dist/components/header/SkinTonePicker/BtnSkinToneVariation.d.ts +12 -12
- package/dist/components/header/SkinTonePicker/SkinTonePicker.d.ts +11 -11
- package/dist/components/icons/svgIcons.d.ts +4 -0
- package/dist/components/main/PickerMainBehaviors.d.ts +4 -0
- package/dist/components/main/defaultAppearance.d.ts +12 -0
- package/dist/components/main/labelHeight.d.ts +1 -0
- package/dist/components/navigation/CategoryButton.d.ts +12 -12
- package/dist/components/navigation/CategoryNavIcon.d.ts +4 -4
- package/dist/components/navigation/CategoryNavigation.d.ts +19 -2
- package/dist/config/categoryConfig.d.ts +34 -34
- package/dist/config/cdnUrls.d.ts +2 -2
- package/dist/config/compareConfig.d.ts +10 -2
- package/dist/config/config.d.ts +166 -64
- package/dist/config/customEmojiConfig.d.ts +14 -14
- package/dist/config/defaultPickerConfiguration.d.ts +10 -0
- package/dist/config/mutableConfig.d.ts +32 -10
- package/dist/config/useConfig.d.ts +48 -36
- package/dist/data/defaultEmojiData.d.ts +9 -0
- package/dist/data/defaultEmojiData.js +40 -0
- package/dist/data/emojis-bn.d.mts +39 -0
- package/dist/data/emojis-bn.d.ts +38 -2
- package/dist/data/emojis-bn.js +25 -2
- package/dist/data/emojis-bn.mjs +2 -0
- package/dist/data/emojis-da.d.mts +39 -0
- package/dist/data/emojis-da.d.ts +38 -2
- package/dist/data/emojis-da.js +25 -2
- package/dist/data/emojis-da.mjs +2 -0
- package/dist/data/emojis-de.d.mts +39 -0
- package/dist/data/emojis-de.d.ts +38 -2
- package/dist/data/emojis-de.js +25 -2
- package/dist/data/emojis-de.mjs +2 -0
- package/dist/data/emojis-en-gb.d.mts +39 -0
- package/dist/data/emojis-en-gb.d.ts +38 -2
- package/dist/data/emojis-en-gb.js +25 -2
- package/dist/data/emojis-en-gb.mjs +2 -0
- package/dist/data/emojis-en.d.mts +39 -0
- package/dist/data/emojis-en.d.ts +38 -2
- package/dist/data/emojis-en.js +25 -2
- package/dist/data/emojis-en.mjs +2 -0
- package/dist/data/emojis-es-mx.d.mts +39 -0
- package/dist/data/emojis-es-mx.d.ts +38 -2
- package/dist/data/emojis-es-mx.js +25 -2
- package/dist/data/emojis-es-mx.mjs +2 -0
- package/dist/data/emojis-es.d.mts +39 -0
- package/dist/data/emojis-es.d.ts +38 -2
- package/dist/data/emojis-es.js +25 -2
- package/dist/data/emojis-es.mjs +2 -0
- package/dist/data/emojis-et.d.mts +39 -0
- package/dist/data/emojis-et.d.ts +38 -2
- package/dist/data/emojis-et.js +25 -2
- package/dist/data/emojis-et.mjs +2 -0
- package/dist/data/emojis-fi.d.mts +39 -0
- package/dist/data/emojis-fi.d.ts +38 -2
- package/dist/data/emojis-fi.js +25 -2
- package/dist/data/emojis-fi.mjs +2 -0
- package/dist/data/emojis-fr.d.mts +39 -0
- package/dist/data/emojis-fr.d.ts +38 -2
- package/dist/data/emojis-fr.js +25 -2
- package/dist/data/emojis-fr.mjs +2 -0
- package/dist/data/emojis-hi.d.mts +39 -0
- package/dist/data/emojis-hi.d.ts +38 -2
- package/dist/data/emojis-hi.js +25 -2
- package/dist/data/emojis-hi.mjs +2 -0
- package/dist/data/emojis-hu.d.mts +39 -0
- package/dist/data/emojis-hu.d.ts +38 -2
- package/dist/data/emojis-hu.js +25 -2
- package/dist/data/emojis-hu.mjs +2 -0
- package/dist/data/emojis-it.d.mts +39 -0
- package/dist/data/emojis-it.d.ts +38 -2
- package/dist/data/emojis-it.js +25 -2
- package/dist/data/emojis-it.mjs +2 -0
- package/dist/data/emojis-ja.d.mts +39 -0
- package/dist/data/emojis-ja.d.ts +38 -2
- package/dist/data/emojis-ja.js +25 -2
- package/dist/data/emojis-ja.mjs +2 -0
- package/dist/data/emojis-ko.d.mts +39 -0
- package/dist/data/emojis-ko.d.ts +38 -2
- package/dist/data/emojis-ko.js +25 -2
- package/dist/data/emojis-ko.mjs +2 -0
- package/dist/data/emojis-lt.d.mts +39 -0
- package/dist/data/emojis-lt.d.ts +38 -2
- package/dist/data/emojis-lt.js +25 -2
- package/dist/data/emojis-lt.mjs +2 -0
- package/dist/data/emojis-ms.d.mts +39 -0
- package/dist/data/emojis-ms.d.ts +38 -2
- package/dist/data/emojis-ms.js +25 -2
- package/dist/data/emojis-ms.mjs +2 -0
- package/dist/data/emojis-nb.d.mts +39 -0
- package/dist/data/emojis-nb.d.ts +38 -2
- package/dist/data/emojis-nb.js +25 -2
- package/dist/data/emojis-nb.mjs +2 -0
- package/dist/data/emojis-nl.d.mts +39 -0
- package/dist/data/emojis-nl.d.ts +38 -2
- package/dist/data/emojis-nl.js +25 -2
- package/dist/data/emojis-nl.mjs +2 -0
- package/dist/data/emojis-pl.d.mts +39 -0
- package/dist/data/emojis-pl.d.ts +38 -2
- package/dist/data/emojis-pl.js +25 -2
- package/dist/data/emojis-pl.mjs +2 -0
- package/dist/data/emojis-pt.d.mts +39 -0
- package/dist/data/emojis-pt.d.ts +38 -2
- package/dist/data/emojis-pt.js +25 -2
- package/dist/data/emojis-pt.mjs +2 -0
- package/dist/data/emojis-ru.d.mts +39 -0
- package/dist/data/emojis-ru.d.ts +38 -2
- package/dist/data/emojis-ru.js +25 -2
- package/dist/data/emojis-ru.mjs +2 -0
- package/dist/data/emojis-sv.d.mts +39 -0
- package/dist/data/emojis-sv.d.ts +38 -2
- package/dist/data/emojis-sv.js +25 -2
- package/dist/data/emojis-sv.mjs +2 -0
- package/dist/data/emojis-th.d.mts +39 -0
- package/dist/data/emojis-th.d.ts +38 -2
- package/dist/data/emojis-th.js +25 -2
- package/dist/data/emojis-th.mjs +2 -0
- package/dist/data/emojis-uk.d.mts +39 -0
- package/dist/data/emojis-uk.d.ts +38 -2
- package/dist/data/emojis-uk.js +25 -2
- package/dist/data/emojis-uk.mjs +2 -0
- package/dist/data/emojis-vi.d.mts +39 -0
- package/dist/data/emojis-vi.d.ts +38 -2
- package/dist/data/emojis-vi.js +25 -2
- package/dist/data/emojis-vi.mjs +2 -0
- package/dist/data/emojis-zh-hant.d.mts +39 -0
- package/dist/data/emojis-zh-hant.d.ts +38 -2
- package/dist/data/emojis-zh-hant.js +25 -2
- package/dist/data/emojis-zh-hant.mjs +2 -0
- package/dist/data/emojis-zh.d.mts +39 -0
- package/dist/data/emojis-zh.d.ts +38 -2
- package/dist/data/emojis-zh.js +25 -2
- package/dist/data/emojis-zh.mjs +2 -0
- package/dist/data/index.js +1 -0
- package/dist/data/registerDefaultEmojiData.d.ts +1 -0
- package/dist/data/registerDefaultEmojiData.js +3 -0
- package/dist/data-core/pickerData.d.ts +12 -0
- package/dist/data-core/prepare.d.ts +23 -0
- package/dist/data-core/search.d.ts +13 -0
- package/dist/data-core/types.d.ts +23 -0
- package/dist/data.d.mts +72 -0
- package/dist/data.d.ts +72 -0
- package/dist/dataUtils/DataTypes.d.ts +23 -19
- package/dist/dataUtils/emojiSelectors.d.ts +15 -16
- package/dist/dataUtils/emojiUtils.d.ts +1 -12
- package/dist/dataUtils/nativeEmojiSequenceSupport.d.ts +10 -0
- package/dist/dataUtils/nativeEmojiSupport.d.ts +40 -0
- package/dist/dataUtils/parseNativeEmoji.d.ts +1 -1
- package/dist/dataUtils/suggested.d.ts +11 -11
- package/dist/dataUtils/suggestedEmojis.d.ts +7 -0
- package/dist/esm/chunks/chunk-46BUDQLE.mjs +228 -0
- package/dist/esm/chunks/chunk-7ZGTUZFB.mjs +16 -0
- package/dist/esm/chunks/chunk-FQIJ4HBW.mjs +25 -0
- package/dist/esm/chunks/chunk-KQPOIRSC.mjs +9305 -0
- package/dist/esm/chunks/chunk-LO4TPPLH.mjs +43 -0
- package/dist/esm/chunks/emojis-6L3GRBAP.mjs +9 -0
- package/dist/esm/data.mjs +18 -0
- package/dist/esm/index.mjs +389 -0
- package/dist/esm/primitives/index.mjs +67 -0
- package/dist/hooks/preloadEmoji.d.ts +9 -9
- package/dist/hooks/useActiveCategoryScrollDetection.d.ts +11 -11
- package/dist/hooks/useCategoryHeight.d.ts +6 -5
- package/dist/hooks/useCloseAllOpenToggles.d.ts +2 -2
- package/dist/hooks/useDataIdentityStabilityWarning.d.ts +13 -0
- package/dist/hooks/useDebouncedState.d.ts +1 -1
- package/dist/hooks/useDisallowMouseMove.d.ts +4 -4
- package/dist/hooks/useDisallowedEmojis.d.ts +2 -3
- package/dist/hooks/useEmojiPreviewEvents.d.ts +3 -3
- package/dist/hooks/useEmojiVirtualization.d.ts +21 -17
- package/dist/hooks/useFilter.d.ts +10 -16
- package/dist/hooks/useFocus.d.ts +3 -3
- package/dist/hooks/useInitialLoad.d.ts +2 -2
- package/dist/hooks/useIsEmojiHidden.d.ts +8 -8
- package/dist/hooks/useIsMounted.d.ts +1 -1
- package/dist/hooks/useIsSearchMode.d.ts +1 -1
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -2
- package/dist/hooks/useKeyboardNavigation.d.ts +3 -1
- package/dist/hooks/useMouseDownHandlers.d.ts +8 -4
- package/dist/hooks/useOnFocus.d.ts +1 -1
- package/dist/hooks/useOnScroll.d.ts +2 -2
- package/dist/hooks/useReactionsFocus.d.ts +1 -0
- package/dist/hooks/useRegisterRegion.d.ts +24 -0
- package/dist/hooks/useResolvedEmojiData.d.ts +37 -0
- package/dist/hooks/useScrollCategoryIntoView.d.ts +1 -1
- package/dist/hooks/useSearchController.d.ts +17 -0
- package/dist/hooks/useSearchResults.d.ts +8 -0
- package/dist/hooks/useSetVariationPicker.d.ts +2 -2
- package/dist/hooks/useShouldHideCustomEmojis.d.ts +1 -1
- package/dist/hooks/useShouldShowSkinTonePicker.d.ts +4 -4
- package/dist/index.d.mts +376 -0
- package/dist/index.d.ts +376 -9
- package/dist/index.js +2 -8
- package/dist/primitives/CategoryNav.d.ts +4 -0
- package/dist/primitives/Empty.d.ts +6 -0
- package/dist/primitives/List.d.ts +4 -0
- package/dist/primitives/LoadError.d.ts +8 -0
- package/dist/primitives/Loading.d.ts +4 -0
- package/dist/primitives/Panel.d.ts +3 -0
- package/dist/primitives/Preview.d.ts +3 -0
- package/dist/primitives/Reactions.d.ts +2 -0
- package/dist/primitives/Root.d.ts +26 -0
- package/dist/primitives/Search.d.ts +5 -0
- package/dist/primitives/SearchInput.d.ts +3 -0
- package/dist/primitives/SkinTone.d.ts +4 -0
- package/dist/primitives/Viewport.d.ts +19 -0
- package/dist/primitives/appearance.d.ts +3 -0
- package/dist/primitives/components.d.ts +27 -0
- package/dist/primitives/hooks.d.ts +48 -0
- package/dist/primitives/index.d.mts +561 -0
- package/dist/primitives/index.d.ts +561 -0
- package/dist/primitives/index.js +2 -0
- package/dist/primitives/nativeProps.d.ts +15 -0
- package/dist/primitives/scope.d.ts +13 -0
- package/dist/primitives/structuralStyles.d.ts +16 -0
- package/dist/primitives/tokens.d.ts +18 -0
- package/dist/primitives/types.d.ts +85 -0
- package/dist/state/activeEmojiStore.d.ts +7 -0
- package/dist/state/navigationRegistry.d.ts +61 -0
- package/dist/state/regionTraversal.d.ts +20 -0
- package/dist/typeRefinements/typeRefinements.d.ts +6 -6
- package/dist/types/exposedTypes.d.ts +16 -6
- package/dist/types/exposedTypes.js +5 -0
- package/dist/virtualization/virtualizationHelpers.d.ts +20 -18
- package/llms-full.txt +3680 -0
- package/llms.txt +66 -476
- package/package.json +204 -66
- package/src/DomUtils/categoryNameFromDom.ts +1 -1
- package/src/DomUtils/classNames.ts +1 -0
- package/src/DomUtils/elementPositionInRow.ts +26 -4
- package/src/DomUtils/eventBelongsToPicker.ts +17 -0
- package/src/DomUtils/getActiveElement.ts +7 -1
- package/src/DomUtils/isJsdom.ts +12 -0
- package/src/DomUtils/isRtl.ts +5 -0
- package/src/DomUtils/keyboardNavigation.ts +105 -149
- package/src/DomUtils/scrollTo.ts +18 -16
- package/src/DomUtils/selectors.ts +20 -111
- package/src/EmojiPickerReact.tsx +155 -48
- package/src/Stylesheet/DedupedStyle.tsx +80 -0
- package/src/Stylesheet/stylesheet.tsx +128 -59
- package/src/components/Layout/Flex.tsx +12 -11
- package/src/components/Reactions/BtnPlus.tsx +61 -51
- package/src/components/Reactions/Reactions.tsx +113 -55
- package/src/components/atoms/Button.tsx +18 -15
- package/src/components/body/EmojiCategory.tsx +77 -40
- package/src/components/body/EmojiList.tsx +55 -23
- package/src/components/body/EmojiVariationPicker.tsx +113 -66
- package/src/components/body/MeasureEmoji.tsx +9 -2
- package/src/components/body/listComponents.tsx +79 -0
- package/src/components/context/ElementRefContext.tsx +46 -35
- package/src/components/context/PickerConfigContext.tsx +55 -40
- package/src/components/context/PickerContext.tsx +567 -92
- package/src/components/context/PickerDataContext.tsx +110 -99
- package/src/components/emoji/BaseEmojiProps.ts +5 -4
- package/src/components/emoji/ClickableEmojiButton.tsx +148 -63
- package/src/components/emoji/Emoji.tsx +24 -2
- package/src/components/emoji/EmojiImg.tsx +13 -12
- package/src/components/emoji/ExportedEmoji.tsx +5 -4
- package/src/components/emoji/NativeEmoji.tsx +19 -16
- package/src/components/emoji/ViewOnlyEmoji.tsx +55 -30
- package/src/components/emoji/emojiStyles.ts +12 -11
- package/src/components/footer/Preview.tsx +86 -91
- package/src/components/header/Header.tsx +21 -6
- package/src/components/header/Search/BtnClearSearch.tsx +69 -55
- package/src/components/header/Search/IcnSearch.tsx +21 -21
- package/src/components/header/Search/Search.tsx +77 -137
- package/src/components/header/SkinTonePicker/BtnSkinToneVariation.tsx +99 -62
- package/src/components/header/SkinTonePicker/SkinTonePicker.tsx +84 -46
- package/src/components/icons/svgIcons.ts +17 -0
- package/src/components/main/PickerMainBehaviors.tsx +163 -0
- package/src/components/main/defaultAppearance.tsx +188 -0
- package/src/components/main/labelHeight.ts +5 -0
- package/src/components/navigation/CategoryButton.tsx +83 -57
- package/src/components/navigation/CategoryNavIcon.tsx +73 -194
- package/src/components/navigation/CategoryNavigation.tsx +118 -46
- package/src/config/categoryConfig.ts +7 -3
- package/src/config/cdnUrls.ts +11 -21
- package/src/config/compareConfig.ts +128 -30
- package/src/config/config.ts +228 -24
- package/src/config/defaultPickerConfiguration.ts +7 -0
- package/src/config/mutableConfig.ts +44 -20
- package/src/config/useConfig.ts +130 -37
- package/src/data/defaultEmojiData.ts +49 -0
- package/src/data/registerDefaultEmojiData.ts +8 -0
- package/src/data-core/pickerData.ts +173 -0
- package/src/data-core/prepare.ts +178 -0
- package/src/data-core/search.ts +122 -0
- package/src/data-core/types.ts +36 -0
- package/src/data.ts +10 -0
- package/src/dataUtils/DataTypes.ts +4 -0
- package/src/dataUtils/emojiSelectors.ts +58 -63
- package/src/dataUtils/emojiUtils.ts +17 -74
- package/src/dataUtils/nativeEmojiSequenceSupport.ts +116 -0
- package/src/dataUtils/nativeEmojiSupport.ts +160 -0
- package/src/dataUtils/suggested.ts +8 -4
- package/src/dataUtils/suggestedEmojis.ts +92 -0
- package/src/env.d.ts +4 -0
- package/src/hooks/preloadEmoji.ts +3 -3
- package/src/hooks/useActiveCategoryScrollDetection.ts +10 -1
- package/src/hooks/useCategoryHeight.ts +82 -8
- package/src/hooks/useDataIdentityStabilityWarning.ts +86 -0
- package/src/hooks/useDebouncedState.ts +13 -1
- package/src/hooks/useDisallowedEmojis.ts +26 -42
- package/src/hooks/useEmojiPreviewEvents.ts +43 -10
- package/src/hooks/useEmojiVirtualization.tsx +38 -4
- package/src/hooks/useFilter.ts +85 -127
- package/src/hooks/useFocus.ts +14 -24
- package/src/hooks/useIsEmojiHidden.ts +10 -6
- package/src/hooks/useKeyboardNavigation.ts +322 -429
- package/src/hooks/useMouseDownHandlers.ts +91 -16
- package/src/hooks/useOnFocus.ts +12 -3
- package/src/hooks/useOnScroll.ts +18 -2
- package/src/hooks/useReactionsFocus.ts +118 -0
- package/src/hooks/useRegisterRegion.ts +92 -0
- package/src/hooks/useResolvedEmojiData.ts +200 -0
- package/src/hooks/useScrollCategoryIntoView.ts +74 -12
- package/src/hooks/useSearchController.ts +369 -0
- package/src/hooks/useSearchResults.ts +51 -0
- package/src/hooks/useSetVariationPicker.ts +4 -1
- package/src/index.tsx +67 -5
- package/src/primitives/CategoryNav.tsx +40 -0
- package/src/primitives/Empty.tsx +68 -0
- package/src/primitives/List.tsx +61 -0
- package/src/primitives/LoadError.tsx +38 -0
- package/src/primitives/Loading.tsx +60 -0
- package/src/primitives/Panel.tsx +47 -0
- package/src/primitives/Preview.tsx +38 -0
- package/src/primitives/Reactions.tsx +2 -0
- package/src/primitives/Root.tsx +398 -0
- package/src/primitives/Search.tsx +41 -0
- package/src/primitives/SearchInput.tsx +110 -0
- package/src/primitives/SkinTone.tsx +76 -0
- package/src/primitives/Viewport.tsx +204 -0
- package/src/primitives/appearance.tsx +7 -0
- package/src/primitives/components.tsx +30 -0
- package/src/primitives/hooks.ts +165 -0
- package/src/primitives/index.ts +94 -0
- package/src/primitives/nativeProps.ts +90 -0
- package/src/primitives/scope.tsx +109 -0
- package/src/primitives/structuralStyles.tsx +133 -0
- package/src/primitives/tokens.ts +149 -0
- package/src/primitives/types.ts +192 -0
- package/src/state/activeEmojiStore.ts +39 -0
- package/src/state/navigationRegistry.ts +209 -0
- package/src/state/regionTraversal.ts +116 -0
- package/src/svg.d.ts +2 -2
- package/src/types/exposedTypes.ts +28 -1
- package/src/virtualization/virtualizationHelpers.ts +20 -6
- package/dist/components/body/Body.d.ts +0 -2
- package/dist/components/main/PickerMain.d.ts +0 -7
- package/dist/dataUtils/alphaNumericEmojiIndex.d.ts +0 -5
- package/dist/emoji-picker-react.cjs.development.js +0 -31413
- package/dist/emoji-picker-react.cjs.development.js.map +0 -1
- package/dist/emoji-picker-react.cjs.production.min.js +0 -2
- package/dist/emoji-picker-react.cjs.production.min.js.map +0 -1
- package/dist/emoji-picker-react.esm.js +0 -31411
- package/dist/emoji-picker-react.esm.js.map +0 -1
- package/dist/hooks/useHideEmojisByUniocode.d.ts +0 -1
- package/src/components/body/Body.tsx +0 -43
- package/src/components/main/PickerMain.tsx +0 -249
- package/src/dataUtils/alphaNumericEmojiIndex.ts +0 -21
package/src/config/useConfig.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
usePickerConfig,
|
|
5
|
+
useSearchSliceConfig,
|
|
6
|
+
} from '../components/context/PickerConfigContext';
|
|
4
7
|
import { useReactionsModeState } from '../components/context/PickerContext';
|
|
5
8
|
import {
|
|
6
9
|
EmojiClickData,
|
|
7
|
-
|
|
10
|
+
EmojiStyleValue,
|
|
8
11
|
SkinTonePickerLocation,
|
|
9
12
|
SkinTones,
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
SuggestionModeValue,
|
|
14
|
+
ThemeValue,
|
|
12
15
|
} from '../types/exposedTypes';
|
|
13
16
|
|
|
14
17
|
import { CategoriesConfig } from './categoryConfig';
|
|
15
18
|
import {
|
|
19
|
+
DEFAULT_LABELS,
|
|
16
20
|
DEFAULT_SEARCH_PLACEHOLDER,
|
|
17
|
-
DEFAULT_SEARCH_CLEAR_BUTTON_LABEL,
|
|
18
|
-
SEARCH_RESULTS_NO_RESULTS_FOUND,
|
|
19
|
-
SEARCH_RESULTS_ONE_RESULT_FOUND,
|
|
20
|
-
SEARCH_RESULTS_MULTIPLE_RESULTS_FOUND,
|
|
21
21
|
PickerDimensions,
|
|
22
|
+
PickerLabels,
|
|
22
23
|
PreviewConfig,
|
|
23
24
|
} from './config';
|
|
24
25
|
import { CustomEmoji } from './customEmojiConfig';
|
|
@@ -29,23 +30,68 @@ export enum MOUSE_EVENT_SOURCE {
|
|
|
29
30
|
PICKER = 'picker',
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Resolved user-facing strings: English defaults, then the legacy
|
|
35
|
+
* individual props, then `labels` (highest precedence).
|
|
36
|
+
*/
|
|
37
|
+
export function useLabels(): PickerLabels {
|
|
38
|
+
const {
|
|
39
|
+
labels,
|
|
40
|
+
searchPlaceHolder,
|
|
41
|
+
searchPlaceholder,
|
|
42
|
+
searchLabel,
|
|
43
|
+
searchClearButtonLabel,
|
|
44
|
+
} = usePickerConfig();
|
|
45
|
+
return React.useMemo(() => {
|
|
46
|
+
const legacyPlaceholder = [searchPlaceHolder, searchPlaceholder].find(
|
|
47
|
+
(p) => p !== undefined && p !== DEFAULT_SEARCH_PLACEHOLDER,
|
|
48
|
+
);
|
|
49
|
+
const resolved: PickerLabels = { ...DEFAULT_LABELS };
|
|
50
|
+
if (legacyPlaceholder !== undefined) {
|
|
51
|
+
resolved.searchPlaceholder = legacyPlaceholder;
|
|
52
|
+
}
|
|
53
|
+
if (searchLabel !== undefined) {
|
|
54
|
+
resolved.searchLabel = searchLabel;
|
|
55
|
+
}
|
|
56
|
+
if (searchClearButtonLabel !== undefined) {
|
|
57
|
+
resolved.searchClear = searchClearButtonLabel;
|
|
58
|
+
}
|
|
59
|
+
if (labels) {
|
|
60
|
+
for (const key of Object.keys(labels) as Array<keyof PickerLabels>) {
|
|
61
|
+
const value = labels[key];
|
|
62
|
+
if (value !== undefined) {
|
|
63
|
+
resolved[key] = value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return resolved;
|
|
68
|
+
}, [
|
|
69
|
+
labels,
|
|
70
|
+
searchPlaceHolder,
|
|
71
|
+
searchPlaceholder,
|
|
72
|
+
searchLabel,
|
|
73
|
+
searchClearButtonLabel,
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
|
|
32
77
|
export function useSearchPlaceHolderConfig(): string {
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
[searchPlaceHolder, searchPlaceholder].find(
|
|
36
|
-
(p) => p !== DEFAULT_SEARCH_PLACEHOLDER,
|
|
37
|
-
) ?? DEFAULT_SEARCH_PLACEHOLDER
|
|
38
|
-
);
|
|
78
|
+
return useLabels().searchPlaceholder;
|
|
39
79
|
}
|
|
40
80
|
|
|
41
81
|
export function useSearchClearButtonLabelConfig(): string {
|
|
42
|
-
|
|
43
|
-
return searchClearButtonLabel ?? DEFAULT_SEARCH_CLEAR_BUTTON_LABEL;
|
|
82
|
+
return useLabels().searchClear;
|
|
44
83
|
}
|
|
45
84
|
|
|
85
|
+
// Literal values are the enum members' own strings, so the public
|
|
86
|
+
// SkinTonesValue narrows to the enum the engine compares against.
|
|
46
87
|
export function useDefaultSkinToneConfig(): SkinTones {
|
|
47
88
|
const { defaultSkinTone } = usePickerConfig();
|
|
48
|
-
return defaultSkinTone;
|
|
89
|
+
return defaultSkinTone as SkinTones;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function useSkinToneConfig(): SkinTones | undefined {
|
|
93
|
+
const { skinTone } = usePickerConfig();
|
|
94
|
+
return skinTone as SkinTones | undefined;
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
export function useAllowExpandReactions(): boolean {
|
|
@@ -58,7 +104,7 @@ export function useSkinTonesDisabledConfig(): boolean {
|
|
|
58
104
|
return skinTonesDisabled;
|
|
59
105
|
}
|
|
60
106
|
|
|
61
|
-
export function useEmojiStyleConfig():
|
|
107
|
+
export function useEmojiStyleConfig(): EmojiStyleValue {
|
|
62
108
|
const { emojiStyle } = usePickerConfig();
|
|
63
109
|
return emojiStyle;
|
|
64
110
|
}
|
|
@@ -91,23 +137,36 @@ export function useOpenConfig(): boolean {
|
|
|
91
137
|
export function useOnEmojiClickConfig(
|
|
92
138
|
mouseEventSource: MOUSE_EVENT_SOURCE,
|
|
93
139
|
): (emoji: EmojiClickData, event: MouseEvent) => void {
|
|
140
|
+
// The ref object is stable; callbacks are read at call time so a
|
|
141
|
+
// subscribed listener always invokes the latest parent callback even
|
|
142
|
+
// when the memoized tree skips rerendering on callback-only updates.
|
|
143
|
+
// Reading them during render would freeze the first-render callback
|
|
144
|
+
// into every listener closure.
|
|
94
145
|
const { current } = useMutableConfig();
|
|
95
146
|
const [, setReactionsOpen] = useReactionsModeState();
|
|
96
147
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
148
|
+
if (mouseEventSource === MOUSE_EVENT_SOURCE.REACTIONS) {
|
|
149
|
+
return (...args) => {
|
|
150
|
+
const onReactionClick = current.onReactionClick;
|
|
151
|
+
if (onReactionClick) {
|
|
152
|
+
return onReactionClick(...args, {
|
|
153
|
+
collapseToReactions: () => {
|
|
154
|
+
setReactionsOpen(true);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const onEmojiClick = current.onEmojiClick || noop;
|
|
159
|
+
return onEmojiClick(...args, {
|
|
103
160
|
collapseToReactions: () => {
|
|
104
|
-
setReactionsOpen(
|
|
161
|
+
setReactionsOpen(true);
|
|
105
162
|
},
|
|
106
163
|
});
|
|
164
|
+
};
|
|
107
165
|
}
|
|
108
166
|
|
|
109
167
|
return (...args) => {
|
|
110
|
-
|
|
168
|
+
const onEmojiClick = current.onEmojiClick || noop;
|
|
169
|
+
return onEmojiClick(...args, {
|
|
111
170
|
collapseToReactions: () => {
|
|
112
171
|
setReactionsOpen(true);
|
|
113
172
|
},
|
|
@@ -118,7 +177,9 @@ export function useOnEmojiClickConfig(
|
|
|
118
177
|
export function useOnSkinToneChangeConfig(): (skinTone: SkinTones) => void {
|
|
119
178
|
const { current } = useMutableConfig();
|
|
120
179
|
|
|
121
|
-
return
|
|
180
|
+
return (skinTone: SkinTones) => {
|
|
181
|
+
current.onSkinToneChange?.(skinTone);
|
|
182
|
+
};
|
|
122
183
|
}
|
|
123
184
|
|
|
124
185
|
export function usePreviewConfig(): PreviewConfig {
|
|
@@ -126,13 +187,13 @@ export function usePreviewConfig(): PreviewConfig {
|
|
|
126
187
|
return previewConfig;
|
|
127
188
|
}
|
|
128
189
|
|
|
129
|
-
export function useThemeConfig():
|
|
190
|
+
export function useThemeConfig(): ThemeValue {
|
|
130
191
|
const { theme } = usePickerConfig();
|
|
131
192
|
|
|
132
193
|
return theme;
|
|
133
194
|
}
|
|
134
195
|
|
|
135
|
-
export function useSuggestedEmojisModeConfig():
|
|
196
|
+
export function useSuggestedEmojisModeConfig(): SuggestionModeValue {
|
|
136
197
|
const { suggestedEmojisMode } = usePickerConfig();
|
|
137
198
|
return suggestedEmojisMode;
|
|
138
199
|
}
|
|
@@ -157,6 +218,17 @@ export function useReactionsOpenConfig(): boolean {
|
|
|
157
218
|
return reactionsDefaultOpen;
|
|
158
219
|
}
|
|
159
220
|
|
|
221
|
+
export function useColumnsConfig(): number | undefined {
|
|
222
|
+
const { columns } = usePickerConfig();
|
|
223
|
+
return validColumns(columns);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function validColumns(columns: unknown): number | undefined {
|
|
227
|
+
return Number.isInteger(columns) && (columns as number) > 0
|
|
228
|
+
? (columns as number)
|
|
229
|
+
: undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
160
232
|
export function useEmojiVersionConfig(): string | null {
|
|
161
233
|
const { emojiVersion } = usePickerConfig();
|
|
162
234
|
return emojiVersion;
|
|
@@ -184,30 +256,51 @@ export function useReactionsConfig(): string[] {
|
|
|
184
256
|
|
|
185
257
|
export function useGetEmojiUrlConfig(): (
|
|
186
258
|
unified: string,
|
|
187
|
-
style:
|
|
259
|
+
style: EmojiStyleValue,
|
|
188
260
|
) => string {
|
|
189
261
|
const { getEmojiUrl } = usePickerConfig();
|
|
190
262
|
return getEmojiUrl;
|
|
191
263
|
}
|
|
192
264
|
|
|
265
|
+
export function useSearchValueConfig(): string | undefined {
|
|
266
|
+
const { searchValue } = useSearchSliceConfig();
|
|
267
|
+
return searchValue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function useDefaultSearchValueConfig(): string | undefined {
|
|
271
|
+
const { defaultSearchValue } = useSearchSliceConfig();
|
|
272
|
+
return defaultSearchValue;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function useSearchLabelConfig(): string {
|
|
276
|
+
return useLabels().searchLabel;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function useSuggestedEmojisConfig(): string[] | undefined {
|
|
280
|
+
const { suggestedEmojis } = usePickerConfig();
|
|
281
|
+
return suggestedEmojis;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function noop() {}
|
|
285
|
+
|
|
193
286
|
function getDimension(dimensionConfig: PickerDimensions): PickerDimensions {
|
|
194
287
|
return typeof dimensionConfig === 'number'
|
|
195
288
|
? `${dimensionConfig}px`
|
|
196
289
|
: dimensionConfig;
|
|
197
290
|
}
|
|
198
291
|
|
|
199
|
-
export function
|
|
292
|
+
export function formatSearchResultsLabel(
|
|
293
|
+
labels: PickerLabels,
|
|
294
|
+
searchResultsCount: number,
|
|
295
|
+
): string {
|
|
200
296
|
const hasResults = searchResultsCount > 0;
|
|
201
297
|
const isPlural = searchResultsCount > 1;
|
|
202
298
|
|
|
203
299
|
if (hasResults) {
|
|
204
300
|
return isPlural
|
|
205
|
-
?
|
|
206
|
-
|
|
207
|
-
searchResultsCount.toString(),
|
|
208
|
-
)
|
|
209
|
-
: SEARCH_RESULTS_ONE_RESULT_FOUND;
|
|
301
|
+
? labels.searchResultsMany.replace('%n', searchResultsCount.toString())
|
|
302
|
+
: labels.searchResultsOne;
|
|
210
303
|
}
|
|
211
304
|
|
|
212
|
-
return
|
|
305
|
+
return labels.searchResultsNone;
|
|
213
306
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { EmojiData } from '../types/exposedTypes';
|
|
2
|
+
|
|
3
|
+
// The bundled English dataset is no longer a static dependency of the
|
|
4
|
+
// picker core. Entry points that promise synchronous data (the default
|
|
5
|
+
// `emoji-picker-react` entry and `emoji-picker-react/data`) register it on
|
|
6
|
+
// import; `emoji-picker-react/primitives` does not, so a lean composition
|
|
7
|
+
// ships without it and loads it on demand (a separate chunk in ESM builds)
|
|
8
|
+
// unless `emojiData` is supplied.
|
|
9
|
+
|
|
10
|
+
let registered: EmojiData | null = null;
|
|
11
|
+
|
|
12
|
+
export function registerDefaultEmojiData(data: EmojiData): void {
|
|
13
|
+
registered = data;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getRegisteredDefaultEmojiData(): EmojiData | null {
|
|
17
|
+
return registered;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Stable empty dataset used while data is loading. */
|
|
21
|
+
export const EMPTY_EMOJI_DATA: EmojiData = Object.freeze({
|
|
22
|
+
categories: {},
|
|
23
|
+
emojis: {},
|
|
24
|
+
}) as EmojiData;
|
|
25
|
+
|
|
26
|
+
/** The registered dataset, or the empty placeholder before registration. */
|
|
27
|
+
export function defaultEmojiDataOrEmpty(): EmojiData {
|
|
28
|
+
return registered ?? EMPTY_EMOJI_DATA;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let pending: Promise<EmojiData> | null = null;
|
|
32
|
+
|
|
33
|
+
/** Load (once) and register the bundled English dataset. */
|
|
34
|
+
export function loadDefaultEmojiData(): Promise<EmojiData> {
|
|
35
|
+
if (registered) {
|
|
36
|
+
return Promise.resolve(registered);
|
|
37
|
+
}
|
|
38
|
+
if (!pending) {
|
|
39
|
+
pending = import('./emojis').then((module) => {
|
|
40
|
+
const data = (module.default ?? module) as unknown as EmojiData;
|
|
41
|
+
registered = registered ?? data;
|
|
42
|
+
return registered;
|
|
43
|
+
}).catch((error) => {
|
|
44
|
+
pending = null;
|
|
45
|
+
throw error;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return pending;
|
|
49
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Side-effect module: makes the bundled English dataset available
|
|
2
|
+
// synchronously. Imported by entries that guarantee sync data.
|
|
3
|
+
import type { EmojiData } from '../types/exposedTypes';
|
|
4
|
+
|
|
5
|
+
import { registerDefaultEmojiData } from './defaultEmojiData';
|
|
6
|
+
import emojis from './emojis';
|
|
7
|
+
|
|
8
|
+
registerDefaultEmojiData(emojis as unknown as EmojiData);
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Shared picker-data derivation.
|
|
2
|
+
//
|
|
3
|
+
// Requirements:
|
|
4
|
+
// - prepare/search-index immutable emoji data outside transient UI state;
|
|
5
|
+
// - cache prepared base data by `emojiData` object identity (WeakMap);
|
|
6
|
+
// - default packaged data shares one prepared base core across Roots;
|
|
7
|
+
// - custom-emoji derivation cached separately by `customEmojis` identity;
|
|
8
|
+
// - `emojiVersion` and `hiddenEmojis` stay per-Root filtering layers and MUST NOT
|
|
9
|
+
// force rebuilding the base index;
|
|
10
|
+
// - caller-provided `emojiData` and `customEmojis` are never mutated;
|
|
11
|
+
// - do not JSON stringify/parse the complete dataset on each Root mount;
|
|
12
|
+
// - no React / ShipStyles imports in this module graph.
|
|
13
|
+
|
|
14
|
+
import type { CustomEmoji } from '../config/customEmojiConfig';
|
|
15
|
+
import { defaultEmojiDataOrEmpty } from '../data/defaultEmojiData';
|
|
16
|
+
import {
|
|
17
|
+
DataEmoji,
|
|
18
|
+
DataEmojis,
|
|
19
|
+
EmojiProperties,
|
|
20
|
+
EmojiProperties as Keys,
|
|
21
|
+
} from '../dataUtils/DataTypes';
|
|
22
|
+
import { Categories, type EmojiData } from '../types/exposedTypes';
|
|
23
|
+
|
|
24
|
+
import { getPreparedCore } from './prepare';
|
|
25
|
+
|
|
26
|
+
export interface PickerDataSnapshot {
|
|
27
|
+
emojiData: EmojiData;
|
|
28
|
+
allEmojis: DataEmojis;
|
|
29
|
+
allEmojisByUnified: Record<string, DataEmoji>;
|
|
30
|
+
customGroups: Record<string, DataEmojis>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface CustomLayer {
|
|
34
|
+
/** Ungrouped customs: becomes `emojis[CUSTOM]` when customs are present. */
|
|
35
|
+
ungrouped: DataEmojis;
|
|
36
|
+
groups: Record<string, DataEmojis>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const customLayerCache = new WeakMap<object, CustomLayer>();
|
|
40
|
+
const EMPTY_CUSTOM_LAYER: CustomLayer = {
|
|
41
|
+
ungrouped: [],
|
|
42
|
+
groups: Object.create(null),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Outer key: dataset source object. Inner key: customEmojis array identity,
|
|
46
|
+
// or NO_CUSTOM sentinel when no customs are supplied.
|
|
47
|
+
const snapshotCache = new WeakMap<object, WeakMap<object, PickerDataSnapshot>>();
|
|
48
|
+
const NO_CUSTOM: object = {};
|
|
49
|
+
|
|
50
|
+
function customToRegularEmoji(emoji: CustomEmoji): DataEmoji {
|
|
51
|
+
return {
|
|
52
|
+
[EmojiProperties.name]: emoji.names.map((name: string) =>
|
|
53
|
+
name.toLowerCase(),
|
|
54
|
+
),
|
|
55
|
+
[EmojiProperties.unified]: emoji.id.toLowerCase(),
|
|
56
|
+
[EmojiProperties.added_in]: '0',
|
|
57
|
+
[EmojiProperties.imgUrl]: emoji.imgUrl,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getCustomLayer(customEmojis?: CustomEmoji[]): CustomLayer {
|
|
62
|
+
if (!customEmojis || customEmojis.length === 0) {
|
|
63
|
+
return EMPTY_CUSTOM_LAYER;
|
|
64
|
+
}
|
|
65
|
+
const cached = customLayerCache.get(customEmojis);
|
|
66
|
+
if (cached) {
|
|
67
|
+
return cached;
|
|
68
|
+
}
|
|
69
|
+
// Never mutate caller data: derive fresh objects/arrays only.
|
|
70
|
+
const groups: Record<string, DataEmojis> = Object.create(null);
|
|
71
|
+
const ungrouped: DataEmojis = [];
|
|
72
|
+
for (const emoji of customEmojis) {
|
|
73
|
+
const derived = customToRegularEmoji(emoji);
|
|
74
|
+
if (emoji.group) {
|
|
75
|
+
groups[emoji.group] = groups[emoji.group] ?? [];
|
|
76
|
+
groups[emoji.group].push(derived);
|
|
77
|
+
} else {
|
|
78
|
+
ungrouped.push(derived);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const layer: CustomLayer = { ungrouped, groups };
|
|
82
|
+
customLayerCache.set(customEmojis, layer);
|
|
83
|
+
return layer;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function getPickerDataSnapshot(
|
|
87
|
+
genericEmojiData?: EmojiData,
|
|
88
|
+
customEmojis?: CustomEmoji[],
|
|
89
|
+
): PickerDataSnapshot {
|
|
90
|
+
const source = (genericEmojiData ??
|
|
91
|
+
defaultEmojiDataOrEmpty()) as EmojiData;
|
|
92
|
+
|
|
93
|
+
// Warm the shared prepared core the picker actually searches through
|
|
94
|
+
// (queryFilterDict in PickerDataContext). One construction per dataset
|
|
95
|
+
// identity backs the "one base index for 10 same-dataset Roots"
|
|
96
|
+
// invariant; there is no second per-snapshot index.
|
|
97
|
+
getPreparedCore(source);
|
|
98
|
+
|
|
99
|
+
const hasCustoms = !!customEmojis && customEmojis.length > 0;
|
|
100
|
+
const customKey: object = hasCustoms
|
|
101
|
+
? (customEmojis as object)
|
|
102
|
+
: NO_CUSTOM;
|
|
103
|
+
|
|
104
|
+
let inner = snapshotCache.get(source);
|
|
105
|
+
if (inner) {
|
|
106
|
+
const hit = inner.get(customKey);
|
|
107
|
+
if (hit) {
|
|
108
|
+
return hit;
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
inner = new WeakMap<object, PickerDataSnapshot>();
|
|
112
|
+
snapshotCache.set(source, inner);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const customLayer = getCustomLayer(customEmojis);
|
|
116
|
+
|
|
117
|
+
// Shallow structural copy only: every non-custom category array keeps its
|
|
118
|
+
// shared source reference. No JSON clone of the full dataset, no mutation
|
|
119
|
+
// (and no freezing) of caller-provided data.
|
|
120
|
+
const sourceEmojis = source.emojis ?? {};
|
|
121
|
+
const nextEmojis: Record<string, DataEmoji[]> = { ...sourceEmojis };
|
|
122
|
+
if (hasCustoms) {
|
|
123
|
+
nextEmojis[Categories.CUSTOM] = customLayer.ungrouped as DataEmoji[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const emojiData = {
|
|
127
|
+
...source,
|
|
128
|
+
emojis: nextEmojis,
|
|
129
|
+
} as EmojiData;
|
|
130
|
+
|
|
131
|
+
const customGroups = customLayer.groups;
|
|
132
|
+
|
|
133
|
+
const allEmojis: DataEmojis = Object.values(nextEmojis)
|
|
134
|
+
.concat(Object.values(customGroups))
|
|
135
|
+
.flat();
|
|
136
|
+
|
|
137
|
+
const allEmojisByUnified: Record<string, DataEmoji> = Object.create(null);
|
|
138
|
+
|
|
139
|
+
allEmojis.forEach((emoji) => {
|
|
140
|
+
const unified = emoji[Keys.unified];
|
|
141
|
+
allEmojisByUnified[unified] = emoji;
|
|
142
|
+
|
|
143
|
+
if (emoji[Keys.variations]) {
|
|
144
|
+
emoji[Keys.variations]?.forEach((variation) => {
|
|
145
|
+
allEmojisByUnified[variation] = emoji;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const snapshot: PickerDataSnapshot = {
|
|
151
|
+
emojiData,
|
|
152
|
+
allEmojis,
|
|
153
|
+
allEmojisByUnified,
|
|
154
|
+
customGroups,
|
|
155
|
+
};
|
|
156
|
+
inner.set(customKey, snapshot);
|
|
157
|
+
return snapshot;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Test-only: expose cache state without breaking WeakMap encapsulation. */
|
|
161
|
+
export function __isSnapshotCached(
|
|
162
|
+
genericEmojiData?: EmojiData,
|
|
163
|
+
customEmojis?: CustomEmoji[],
|
|
164
|
+
): boolean {
|
|
165
|
+
const source = (genericEmojiData ??
|
|
166
|
+
defaultEmojiDataOrEmpty()) as EmojiData;
|
|
167
|
+
const inner = snapshotCache.get(source);
|
|
168
|
+
if (!inner) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const hasCustoms = !!customEmojis && customEmojis.length > 0;
|
|
172
|
+
return inner.has(hasCustoms ? (customEmojis as object) : NO_CUSTOM);
|
|
173
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Pure immutable prepared-data core for v5.
|
|
2
|
+
//
|
|
3
|
+
// Requirements (see also docs/v5/DATA_API.md):
|
|
4
|
+
// - prepare/search-index immutable emoji data outside transient UI state;
|
|
5
|
+
// - cache prepared base data by `emojiData` object identity (WeakMap);
|
|
6
|
+
// - default packaged data shares one prepared core across Roots;
|
|
7
|
+
// - caller-provided data is never mutated or frozen;
|
|
8
|
+
// - prepared public records are deeply frozen once and safely shared;
|
|
9
|
+
// - no JSON stringify/parse of the full dataset per Root;
|
|
10
|
+
// - no React / ShipStyles imports in this module graph.
|
|
11
|
+
|
|
12
|
+
import { defaultEmojiDataOrEmpty } from '../data/defaultEmojiData';
|
|
13
|
+
import { parseNativeEmoji } from '../dataUtils/parseNativeEmoji';
|
|
14
|
+
import type { EmojiData } from '../types/exposedTypes';
|
|
15
|
+
|
|
16
|
+
import type { EmojiInfo } from './types';
|
|
17
|
+
|
|
18
|
+
export interface PreparedCore {
|
|
19
|
+
/** Stable dataset order of canonical base records. */
|
|
20
|
+
readonly records: readonly EmojiInfo[];
|
|
21
|
+
/** Base unified -> record plus variation unified -> base record. */
|
|
22
|
+
readonly byUnified: ReadonlyMap<string, EmojiInfo>;
|
|
23
|
+
/**
|
|
24
|
+
* Single-character bucket: char -> base records whose joined lowercase
|
|
25
|
+
* names include it, in dataset order. Preserves v4's useful O(1)
|
|
26
|
+
* first-keystroke narrowing on top of the shared immutable core, so
|
|
27
|
+
* cold single-char queries never pay a full scan.
|
|
28
|
+
*/
|
|
29
|
+
readonly byChar: ReadonlyMap<string, readonly EmojiInfo[]>;
|
|
30
|
+
/** Per-core query memo: normalized query -> matching records. */
|
|
31
|
+
readonly queryMemo: Map<string, readonly EmojiInfo[]>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const coreCache = new WeakMap<object, PreparedCore>();
|
|
35
|
+
|
|
36
|
+
// Instrumentation for the deterministic multi-root sharing invariant:
|
|
37
|
+
// mounting N Roots against the same dataset identity must construct the
|
|
38
|
+
// base index exactly once. Tests assert on this counter, not on timing.
|
|
39
|
+
let prepareCount = 0;
|
|
40
|
+
|
|
41
|
+
export function __getPrepareCount(): number {
|
|
42
|
+
return prepareCount;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function __resetPrepareCount(): void {
|
|
46
|
+
prepareCount = 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function __clearCoreCacheForTest(): void {
|
|
50
|
+
// WeakMap has no clear(); tests that need a cold cache can use a fresh
|
|
51
|
+
// dataset object identity instead. Kept as explicit no-op guard.
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function normalizeUnified(input: string): string {
|
|
55
|
+
return input.trim().toLowerCase();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function normalizeQuery(input: string): string {
|
|
59
|
+
if (!input || typeof input !== 'string') {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
return input.trim().toLowerCase();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toEmojiInfo(
|
|
66
|
+
unified: string,
|
|
67
|
+
names: readonly string[],
|
|
68
|
+
variations: readonly string[] | undefined,
|
|
69
|
+
addedIn: string,
|
|
70
|
+
): EmojiInfo {
|
|
71
|
+
return Object.freeze({
|
|
72
|
+
unified,
|
|
73
|
+
emoji: parseNativeEmoji(unified),
|
|
74
|
+
name: names[names.length - 1] || '',
|
|
75
|
+
names: Object.freeze([...names]),
|
|
76
|
+
variations: Object.freeze([...(variations ?? [])]),
|
|
77
|
+
addedIn,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function readStringArray(raw: unknown): string[] {
|
|
82
|
+
if (!Array.isArray(raw)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
return (raw.filter((n) => typeof n === 'string') as string[]).map((n) =>
|
|
86
|
+
n.toLowerCase(),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function appendEntry(
|
|
91
|
+
byUnified: Map<string, EmojiInfo>,
|
|
92
|
+
byCharMutable: Map<string, EmojiInfo[]>,
|
|
93
|
+
records: EmojiInfo[],
|
|
94
|
+
entry: unknown,
|
|
95
|
+
): void {
|
|
96
|
+
// Never mutate caller data: read raw fields defensively.
|
|
97
|
+
const rawUnified = (entry as { u?: unknown }).u;
|
|
98
|
+
if (typeof rawUnified !== 'string' || rawUnified.length === 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const unified = rawUnified.toLowerCase();
|
|
102
|
+
if (byUnified.has(unified)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const names = readStringArray((entry as { n?: unknown }).n);
|
|
107
|
+
const variations = readStringArray((entry as { v?: unknown }).v);
|
|
108
|
+
|
|
109
|
+
const rawAddedIn = (entry as { a?: unknown }).a;
|
|
110
|
+
const addedIn =
|
|
111
|
+
typeof rawAddedIn === 'string' ? rawAddedIn : String(rawAddedIn ?? '');
|
|
112
|
+
|
|
113
|
+
const info = toEmojiInfo(unified, names, variations, addedIn);
|
|
114
|
+
records.push(info);
|
|
115
|
+
byUnified.set(unified, info);
|
|
116
|
+
for (const variation of info.variations) {
|
|
117
|
+
if (!byUnified.has(variation)) {
|
|
118
|
+
byUnified.set(variation, info);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
indexCharBucket(byCharMutable, names, info);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// One bucket entry per distinct character keeps the per-record cost
|
|
125
|
+
// proportional to name length, not name length squared.
|
|
126
|
+
function indexCharBucket(
|
|
127
|
+
byCharMutable: Map<string, EmojiInfo[]>,
|
|
128
|
+
names: readonly string[],
|
|
129
|
+
info: EmojiInfo,
|
|
130
|
+
): void {
|
|
131
|
+
const distinctChars = Array.from(new Set(names.join('')));
|
|
132
|
+
for (const char of distinctChars) {
|
|
133
|
+
const bucket = byCharMutable.get(char);
|
|
134
|
+
if (bucket) {
|
|
135
|
+
bucket.push(info);
|
|
136
|
+
} else {
|
|
137
|
+
byCharMutable.set(char, [info]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function getPreparedCore(emojiData?: EmojiData): PreparedCore {
|
|
143
|
+
const source = (emojiData ?? defaultEmojiDataOrEmpty()) as EmojiData;
|
|
144
|
+
const cached = coreCache.get(source);
|
|
145
|
+
if (cached) {
|
|
146
|
+
return cached;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
prepareCount += 1;
|
|
150
|
+
|
|
151
|
+
const byUnified = new Map<string, EmojiInfo>();
|
|
152
|
+
const byCharMutable = new Map<string, EmojiInfo[]>();
|
|
153
|
+
const records: EmojiInfo[] = [];
|
|
154
|
+
|
|
155
|
+
const groups = source.emojis ?? {};
|
|
156
|
+
|
|
157
|
+
for (const key of Object.keys(groups)) {
|
|
158
|
+
const list = groups[key] ?? [];
|
|
159
|
+
for (const entry of list) {
|
|
160
|
+
appendEntry(byUnified, byCharMutable, records, entry);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const byChar = new Map<string, readonly EmojiInfo[]>();
|
|
165
|
+
byCharMutable.forEach((bucket, char) => {
|
|
166
|
+
byChar.set(char, Object.freeze(bucket));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const core: PreparedCore = {
|
|
170
|
+
records,
|
|
171
|
+
byUnified,
|
|
172
|
+
byChar,
|
|
173
|
+
queryMemo: new Map<string, readonly EmojiInfo[]>(),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
coreCache.set(source, core);
|
|
177
|
+
return core;
|
|
178
|
+
}
|