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
|
@@ -1,185 +1,660 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { isJsdom } from '../../DomUtils/isJsdom';
|
|
4
5
|
import {
|
|
6
|
+
useEmojiStyleConfig,
|
|
7
|
+
useGetEmojiUrlConfig,
|
|
8
|
+
useCustomEmojisConfig,
|
|
5
9
|
useDefaultSkinToneConfig,
|
|
10
|
+
useSkinToneConfig,
|
|
11
|
+
useDefaultSearchValueConfig,
|
|
6
12
|
useReactionsOpenConfig,
|
|
13
|
+
useSearchValueConfig,
|
|
7
14
|
} from '../../config/useConfig';
|
|
8
15
|
import { DataEmoji } from '../../dataUtils/DataTypes';
|
|
16
|
+
import {
|
|
17
|
+
addedIn,
|
|
18
|
+
emojiUnified,
|
|
19
|
+
emojiVariations,
|
|
20
|
+
} from '../../dataUtils/emojiUtils';
|
|
21
|
+
import { NATIVE_PROBE_BATCH } from '../../dataUtils/nativeEmojiSequenceSupport';
|
|
22
|
+
import {
|
|
23
|
+
NativeEmojiProbe,
|
|
24
|
+
NativeEmojiSupport,
|
|
25
|
+
detectNativeEmojiSupport,
|
|
26
|
+
isNativeEmojiSupported,
|
|
27
|
+
nativeSupportSnapshot,
|
|
28
|
+
} from '../../dataUtils/nativeEmojiSupport';
|
|
9
29
|
import { useDebouncedState } from '../../hooks/useDebouncedState';
|
|
10
|
-
import { useDisallowedEmojis } from '../../hooks/useDisallowedEmojis';
|
|
11
30
|
import { FilterDict } from '../../hooks/useFilter';
|
|
12
31
|
import { useMarkInitialLoad } from '../../hooks/useInitialLoad';
|
|
13
|
-
import {
|
|
32
|
+
import { useIsomorphicLayoutEffect } from '../../hooks/useIsomorphicLayoutEffect';
|
|
33
|
+
import { createActiveEmojiStore } from '../../state/activeEmojiStore';
|
|
34
|
+
import { NavigationRegistry } from '../../state/navigationRegistry';
|
|
35
|
+
import { isCustomEmoji } from '../../typeRefinements/typeRefinements';
|
|
36
|
+
import { EmojiStyle, SkinTones } from '../../types/exposedTypes';
|
|
14
37
|
|
|
38
|
+
import { usePickerMainRef } from './ElementRefContext';
|
|
15
39
|
import { usePickerDataContext } from './PickerDataContext';
|
|
16
40
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
// One Root-scoped controller, narrowly sliced.
|
|
42
|
+
//
|
|
43
|
+
// The v4 provider exposed a single omnibus context whose value identity
|
|
44
|
+
// changed for unrelated state, so every subscriber rerendered on every
|
|
45
|
+
// update. This module still owns the same state (same hook names, same
|
|
46
|
+
// defaults, same behavior) but splits it into one stable services context
|
|
47
|
+
// plus narrow per-domain contexts. Each slice value is memoized on its own
|
|
48
|
+
// state only, so a reactions toggle never rerenders search subscribers,
|
|
49
|
+
// scroll/geometry work never rerenders search/category/preview/reactions
|
|
50
|
+
// subscribers, and each Root instance is isolated by construction.
|
|
51
|
+
//
|
|
52
|
+
// Active hover/focus subscriptions are keyed by cell so only the previous
|
|
53
|
+
// and next active cells rerender, while custom previews subscribe to the shared
|
|
54
|
+
// slice could provide.
|
|
55
|
+
//
|
|
56
|
+
// Only React-16.8-compatible runtime APIs are used here; the React floor
|
|
57
|
+
// scan (npm run check:react-floor) guards against newer hook APIs.
|
|
22
58
|
|
|
23
|
-
|
|
24
|
-
const filterRef = React.useRef<FilterState>(searchIndex);
|
|
25
|
-
|
|
26
|
-
React.useEffect(() => {
|
|
27
|
-
filterRef.current = searchIndex;
|
|
28
|
-
}, [searchIndex]);
|
|
29
|
-
const disallowClickRef = React.useRef<boolean>(false);
|
|
30
|
-
const disallowMouseRef = React.useRef<boolean>(false);
|
|
31
|
-
const disallowedEmojisRef =
|
|
32
|
-
React.useRef<Record<string, boolean>>(disallowedEmojis);
|
|
59
|
+
type ReactState<T> = [T, React.Dispatch<React.SetStateAction<T>>];
|
|
33
60
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const emojiSizeState = useState<number | null>(null);
|
|
61
|
+
// Memoize a state tuple on its state value alone. Setters from useState are
|
|
62
|
+
// stable; debounced setters close over stable setState + timer ref, so any
|
|
63
|
+
// captured instance behaves identically.
|
|
64
|
+
function useSliceValue<T>(tuple: ReactState<T>): ReactState<T> {
|
|
65
|
+
const [state, setState] = tuple;
|
|
66
|
+
// setState from useState is stable; the value intentionally re-memoizes on
|
|
67
|
+
// state changes only.
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
return React.useMemo(() => [state, setState] as ReactState<T>, [state]);
|
|
70
|
+
}
|
|
45
71
|
|
|
46
|
-
|
|
72
|
+
function useDebouncedSliceValue<T>(
|
|
73
|
+
tuple: [T, (value: T) => Promise<T>],
|
|
74
|
+
): [T, (value: T) => Promise<T>] {
|
|
75
|
+
const [state, setState] = tuple;
|
|
76
|
+
// The debounced setter is functionally stable (stable setState + timer
|
|
77
|
+
// ref), so capturing it alongside the state value is safe.
|
|
47
78
|
|
|
48
|
-
return (
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
activeSkinTone,
|
|
53
|
-
disallowClickRef,
|
|
54
|
-
disallowMouseRef,
|
|
55
|
-
disallowedEmojisRef,
|
|
56
|
-
emojiVariationPickerState,
|
|
57
|
-
emojisThatFailedToLoadState,
|
|
58
|
-
filterRef,
|
|
59
|
-
isPastInitialLoad,
|
|
60
|
-
searchTerm,
|
|
61
|
-
skinToneFanOpenState,
|
|
62
|
-
suggestedUpdateState,
|
|
63
|
-
reactionsModeState,
|
|
64
|
-
visibleCategoriesState,
|
|
65
|
-
emojiSizeState,
|
|
66
|
-
}}
|
|
67
|
-
>
|
|
68
|
-
{children}
|
|
69
|
-
</PickerContext.Provider>
|
|
79
|
+
return React.useMemo(
|
|
80
|
+
() => [state, setState] as [T, (value: T) => Promise<T>],
|
|
81
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
82
|
+
[state],
|
|
70
83
|
);
|
|
71
84
|
}
|
|
72
85
|
|
|
73
|
-
|
|
86
|
+
export interface PickerServices {
|
|
87
|
+
activeEmojiStore: ReturnType<typeof createActiveEmojiStore>;
|
|
88
|
+
filterRef: React.MutableRefObject<FilterState>;
|
|
89
|
+
filterQueryOrderRef: React.MutableRefObject<string[]>;
|
|
90
|
+
disallowClickRef: React.MutableRefObject<boolean>;
|
|
91
|
+
disallowMouseRef: React.MutableRefObject<boolean>;
|
|
92
|
+
navigationRegistry: NavigationRegistry;
|
|
93
|
+
requestNativeProbe: RequestNativeProbe;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const PickerServicesContext =
|
|
97
|
+
/* @__PURE__ */ React.createContext<PickerServices>({
|
|
98
|
+
activeEmojiStore: createActiveEmojiStore(),
|
|
99
|
+
filterRef: { current: {} },
|
|
100
|
+
filterQueryOrderRef: { current: [] },
|
|
101
|
+
disallowClickRef: { current: false },
|
|
102
|
+
disallowMouseRef: { current: false },
|
|
103
|
+
navigationRegistry: new NavigationRegistry(),
|
|
104
|
+
requestNativeProbe: () => undefined,
|
|
105
|
+
});
|
|
74
106
|
|
|
75
|
-
const
|
|
107
|
+
const SearchSliceContext = /* @__PURE__ */ React.createContext<{
|
|
76
108
|
searchTerm: [string, (term: string) => Promise<string>];
|
|
77
109
|
suggestedUpdateState: [number, (term: number) => void];
|
|
78
|
-
|
|
110
|
+
}>({
|
|
111
|
+
searchTerm: ['', () => new Promise<string>(() => undefined)],
|
|
112
|
+
suggestedUpdateState: [Date.now(), () => {}],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Raw input/display state for the search transition.
|
|
116
|
+
// Kept separate from the debounced accepted query above so keystrokes only
|
|
117
|
+
// rerender input subscribers, while commits flow through the query slice.
|
|
118
|
+
const SearchInputSliceContext = /* @__PURE__ */ React.createContext<{
|
|
119
|
+
displayValue: ReactState<string>;
|
|
120
|
+
committedValue: ReactState<string>;
|
|
121
|
+
composing: ReactState<boolean>;
|
|
122
|
+
}>({
|
|
123
|
+
displayValue: ['', () => {}],
|
|
124
|
+
committedValue: ['', () => {}],
|
|
125
|
+
composing: [false, () => {}],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const ReactionsSliceContext = /* @__PURE__ */ React.createContext<
|
|
129
|
+
ReactState<boolean>
|
|
130
|
+
>([false, () => {}]);
|
|
131
|
+
|
|
132
|
+
// Hovered/focused emoji (unified + original unified), written by the
|
|
133
|
+
// Viewport's pointer/focus listeners and read by Preview and the public
|
|
134
|
+
// useActiveEmoji hook. Its own slice: hover rerenders only its readers.
|
|
135
|
+
export type ActiveEmojiState = null | {
|
|
136
|
+
unified: string;
|
|
137
|
+
originalUnified: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const VariationSliceContext = /* @__PURE__ */ React.createContext<
|
|
141
|
+
ReactState<DataEmoji | null>
|
|
142
|
+
>([null, () => {}]);
|
|
143
|
+
|
|
144
|
+
const SkinToneSliceContext = /* @__PURE__ */ React.createContext<{
|
|
79
145
|
activeSkinTone: ReactState<SkinTones>;
|
|
80
|
-
emojisThatFailedToLoadState: ReactState<Set<string>>;
|
|
81
|
-
isPastInitialLoad: boolean;
|
|
82
|
-
emojiVariationPickerState: ReactState<DataEmoji | null>;
|
|
83
146
|
skinToneFanOpenState: ReactState<boolean>;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
}>({
|
|
148
|
+
activeSkinTone: [SkinTones.NEUTRAL, () => {}],
|
|
149
|
+
skinToneFanOpenState: [false, () => {}],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const ViewportSliceContext = /* @__PURE__ */ React.createContext<{
|
|
153
|
+
activeCategoryState: ReactState<ActiveCategoryState>;
|
|
89
154
|
visibleCategoriesState: ReactState<Array<string>>;
|
|
90
155
|
emojiSizeState: ReactState<number | null>;
|
|
91
156
|
}>({
|
|
92
157
|
activeCategoryState: [null, () => {}],
|
|
93
|
-
activeSkinTone: [SkinTones.NEUTRAL, () => {}],
|
|
94
|
-
disallowClickRef: { current: false },
|
|
95
|
-
disallowMouseRef: { current: false },
|
|
96
|
-
disallowedEmojisRef: { current: {} },
|
|
97
|
-
emojiVariationPickerState: [null, () => {}],
|
|
98
|
-
emojisThatFailedToLoadState: [new Set(), () => {}],
|
|
99
|
-
filterRef: { current: {} },
|
|
100
|
-
isPastInitialLoad: true,
|
|
101
|
-
searchTerm: ['', () => new Promise<string>(() => undefined)],
|
|
102
|
-
skinToneFanOpenState: [false, () => {}],
|
|
103
|
-
suggestedUpdateState: [Date.now(), () => {}],
|
|
104
|
-
reactionsModeState: [false, () => {}],
|
|
105
158
|
visibleCategoriesState: [[], () => []],
|
|
106
159
|
emojiSizeState: [null, () => {}],
|
|
107
160
|
});
|
|
108
161
|
|
|
162
|
+
const LoadSliceContext = /* @__PURE__ */ React.createContext<{
|
|
163
|
+
emojisThatFailedToLoadState: [Set<string>, (unified: string) => void];
|
|
164
|
+
isPastInitialLoad: boolean;
|
|
165
|
+
}>({
|
|
166
|
+
emojisThatFailedToLoadState: [new Set(), () => {}],
|
|
167
|
+
isPastInitialLoad: true,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Platform emoji support: a version prediction before paint, refined with
|
|
171
|
+
// exact per-sequence results in the background, and refreshed on font
|
|
172
|
+
// changes. `null` means "no filtering": before mount (SSR and the
|
|
173
|
+
// hydration render), or for image emoji styles. An explicit emojiVersion
|
|
174
|
+
// is an additional cap, not an opt-out.
|
|
175
|
+
const NativeSupportContext =
|
|
176
|
+
/* @__PURE__ */ React.createContext<NativeEmojiSupport | null>(null);
|
|
177
|
+
|
|
178
|
+
type RequestNativeProbe = (unifieds: string[]) => void;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Asks for exact checks of identities about to be shown: grid cells in
|
|
182
|
+
* and near the viewport, their skin tone variants, and reaction choices.
|
|
183
|
+
*/
|
|
184
|
+
export function useRequestNativeProbe(): RequestNativeProbe {
|
|
185
|
+
return React.useContext(PickerServicesContext).requestNativeProbe;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function useNativeEmojiSupportState(): [
|
|
189
|
+
NativeEmojiSupport | null,
|
|
190
|
+
RequestNativeProbe,
|
|
191
|
+
] {
|
|
192
|
+
const emojiStyle = useEmojiStyleConfig();
|
|
193
|
+
const { allEmojis } = usePickerDataContext();
|
|
194
|
+
const PickerMainRef = usePickerMainRef();
|
|
195
|
+
const shouldDetect = emojiStyle === EmojiStyle.NATIVE;
|
|
196
|
+
const [snapshot, setSnapshot] = useState<
|
|
197
|
+
[support: NativeEmojiSupport, data: DataEmoji[]] | null
|
|
198
|
+
>(null);
|
|
199
|
+
// Every identity shown in this Root's lifetime, re-checked when the
|
|
200
|
+
// font changes. Requests can arrive before detection starts.
|
|
201
|
+
const requestedRef = React.useRef(new Set<string>());
|
|
202
|
+
const requestRef = React.useRef<RequestNativeProbe>((unifieds) => {
|
|
203
|
+
unifieds.forEach((unified) => requestedRef.current.add(unified));
|
|
204
|
+
});
|
|
205
|
+
const request = React.useCallback<RequestNativeProbe>(
|
|
206
|
+
(unifieds) => requestRef.current(unifieds),
|
|
207
|
+
[],
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
useIsomorphicLayoutEffect(() => {
|
|
211
|
+
if (!shouldDetect || isJsdom()) {
|
|
212
|
+
setSnapshot(null);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Probe with the font the picker actually renders native emojis in,
|
|
216
|
+
// so a consumer font (e.g. a country-flag polyfill set through
|
|
217
|
+
// --epr-emoji-font-family) is what gets measured.
|
|
218
|
+
const root = PickerMainRef.current;
|
|
219
|
+
const view = root?.ownerDocument.defaultView;
|
|
220
|
+
if (!root || !view) return;
|
|
221
|
+
const requested = requestedRef.current;
|
|
222
|
+
const inventory: [unified: string, version: number][] = [];
|
|
223
|
+
// The first emoji of each version in dataset order is its sample.
|
|
224
|
+
const samples = new Map<number, string>();
|
|
225
|
+
allEmojis.forEach((emoji) => {
|
|
226
|
+
if (isCustomEmoji(emoji)) return;
|
|
227
|
+
const unified = emojiUnified(emoji);
|
|
228
|
+
const version = addedIn(emoji);
|
|
229
|
+
if (!samples.has(version)) samples.set(version, unified);
|
|
230
|
+
[unified, ...emojiVariations(emoji)].forEach((id) =>
|
|
231
|
+
inventory.push([id, version]),
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
let previousFont: string | null = null;
|
|
235
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
236
|
+
let published: NativeEmojiSupport | null = null;
|
|
237
|
+
let detected: NativeEmojiProbe | undefined;
|
|
238
|
+
const pending = new Set<string>();
|
|
239
|
+
// A new snapshot rerenders the whole grid, so publish only when a
|
|
240
|
+
// verdict changes.
|
|
241
|
+
const publish = (next: NativeEmojiSupport) => {
|
|
242
|
+
const current = published;
|
|
243
|
+
if (
|
|
244
|
+
current &&
|
|
245
|
+
inventory.every(
|
|
246
|
+
([unified, version]) =>
|
|
247
|
+
isNativeEmojiSupported(next, unified, version) ===
|
|
248
|
+
isNativeEmojiSupported(current, unified, version),
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
return;
|
|
252
|
+
published = next;
|
|
253
|
+
setSnapshot([next, allEmojis]);
|
|
254
|
+
};
|
|
255
|
+
// One canvas batch per task, so a fast scroll never blocks input.
|
|
256
|
+
const flush = () => {
|
|
257
|
+
timer = undefined;
|
|
258
|
+
if (!detected) return;
|
|
259
|
+
const batch = Array.from(pending).slice(0, NATIVE_PROBE_BATCH);
|
|
260
|
+
batch.forEach((unified) => pending.delete(unified));
|
|
261
|
+
detected.prime(batch);
|
|
262
|
+
// Publish once the backlog is checked, so a font refresh never
|
|
263
|
+
// flashes unchecked glyphs back to their prediction.
|
|
264
|
+
if (pending.size) timer = setTimeout(flush, 0);
|
|
265
|
+
else publish(nativeSupportSnapshot(detected, samples));
|
|
266
|
+
};
|
|
267
|
+
requestRef.current = (unifieds) => {
|
|
268
|
+
unifieds.forEach((unified) => {
|
|
269
|
+
requested.add(unified);
|
|
270
|
+
if (detected && !detected.has(unified)) pending.add(unified);
|
|
271
|
+
});
|
|
272
|
+
if (pending.size && timer === undefined) timer = setTimeout(flush, 0);
|
|
273
|
+
};
|
|
274
|
+
const probe = (refresh = false) => {
|
|
275
|
+
const customFont = view
|
|
276
|
+
.getComputedStyle(root)
|
|
277
|
+
.getPropertyValue('--epr-emoji-font-family')
|
|
278
|
+
.trim();
|
|
279
|
+
// Attribute changes often leave the computed font unchanged.
|
|
280
|
+
if (!refresh && customFont === previousFont) return;
|
|
281
|
+
previousFont = customFont;
|
|
282
|
+
clearTimeout(timer);
|
|
283
|
+
timer = undefined;
|
|
284
|
+
pending.clear();
|
|
285
|
+
const next = detectNativeEmojiSupport(
|
|
286
|
+
customFont || undefined,
|
|
287
|
+
refresh,
|
|
288
|
+
root.ownerDocument,
|
|
289
|
+
);
|
|
290
|
+
// An inconclusive probe filters nothing, just like the initial null.
|
|
291
|
+
// Avoid another synchronous full-grid render for this no-op result.
|
|
292
|
+
if (!('snapshot' in next)) {
|
|
293
|
+
detected = undefined;
|
|
294
|
+
published = null;
|
|
295
|
+
setSnapshot(null);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
detected = next;
|
|
299
|
+
// Publish before paint: cached exact results plus the prediction. A
|
|
300
|
+
// refresh after webfonts load keeps the current results on screen
|
|
301
|
+
// until the identities shown so far are checked again.
|
|
302
|
+
if (!refresh) publish(nativeSupportSnapshot(next, samples));
|
|
303
|
+
requestRef.current(Array.from(requested));
|
|
304
|
+
if (!pending.size) publish(nativeSupportSnapshot(next, samples));
|
|
305
|
+
};
|
|
306
|
+
probe();
|
|
307
|
+
// Any root or ancestor attribute can select another emoji font via CSS.
|
|
308
|
+
const observer = new view.MutationObserver(() => probe());
|
|
309
|
+
for (
|
|
310
|
+
let element: HTMLElement | null = root;
|
|
311
|
+
element;
|
|
312
|
+
element = element.parentElement
|
|
313
|
+
) {
|
|
314
|
+
observer.observe(element, {
|
|
315
|
+
attributes: true,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
const fonts = root.ownerDocument.fonts;
|
|
319
|
+
const refresh = () => probe(true);
|
|
320
|
+
fonts?.addEventListener('loadingdone', refresh);
|
|
321
|
+
return () => {
|
|
322
|
+
clearTimeout(timer);
|
|
323
|
+
detected = undefined;
|
|
324
|
+
observer.disconnect();
|
|
325
|
+
fonts?.removeEventListener('loadingdone', refresh);
|
|
326
|
+
};
|
|
327
|
+
}, [shouldDetect, PickerMainRef, allEmojis]);
|
|
328
|
+
|
|
329
|
+
// A snapshot belongs to the dataset it was computed for; a new dataset
|
|
330
|
+
// waits for its own layout-effect publication.
|
|
331
|
+
return [
|
|
332
|
+
shouldDetect && snapshot?.[1] === allEmojis ? snapshot[0] : null,
|
|
333
|
+
request,
|
|
334
|
+
];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function useNativeEmojiSupport(): NativeEmojiSupport | null {
|
|
338
|
+
return React.useContext(NativeSupportContext);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function PickerContextProvider({ children }: Props) {
|
|
342
|
+
const [nativeSupport, requestNativeProbe] = useNativeEmojiSupportState();
|
|
343
|
+
const defaultSkinTone = useDefaultSkinToneConfig();
|
|
344
|
+
const reactionsDefaultOpen = useReactionsOpenConfig();
|
|
345
|
+
const defaultSearchValue = useDefaultSearchValueConfig();
|
|
346
|
+
|
|
347
|
+
// Per-Root query-result cache only. It never aliases shared snapshot
|
|
348
|
+
// state: query dicts are computed through the shared prepared core and
|
|
349
|
+
// stored here, bounded, so unmounting leaves nothing behind.
|
|
350
|
+
const filterRef = React.useRef<FilterState>({});
|
|
351
|
+
const filterQueryOrderRef = React.useRef<string[]>([]);
|
|
352
|
+
const { queryFilterDict } = usePickerDataContext();
|
|
353
|
+
const previousQueryBuilder = React.useRef(queryFilterDict);
|
|
354
|
+
if (previousQueryBuilder.current !== queryFilterDict) {
|
|
355
|
+
// Data can arrive after a user starts searching. Cached empty results
|
|
356
|
+
// must be rebuilt before descendants render the new dataset.
|
|
357
|
+
previousQueryBuilder.current = queryFilterDict;
|
|
358
|
+
filterRef.current = Object.fromEntries(
|
|
359
|
+
Object.keys(filterRef.current).map((query) => [
|
|
360
|
+
query,
|
|
361
|
+
queryFilterDict(query),
|
|
362
|
+
]),
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
const disallowClickRef = React.useRef<boolean>(false);
|
|
366
|
+
const disallowMouseRef = React.useRef<boolean>(false);
|
|
367
|
+
const activeStoreRef = React.useRef<ReturnType<
|
|
368
|
+
typeof createActiveEmojiStore
|
|
369
|
+
> | null>(null);
|
|
370
|
+
if (!activeStoreRef.current)
|
|
371
|
+
activeStoreRef.current = createActiveEmojiStore();
|
|
372
|
+
|
|
373
|
+
const registryRef = React.useRef<NavigationRegistry | null>(null);
|
|
374
|
+
if (registryRef.current === null) {
|
|
375
|
+
registryRef.current = new NavigationRegistry();
|
|
376
|
+
}
|
|
377
|
+
React.useEffect(() => {
|
|
378
|
+
const registry = registryRef.current as NavigationRegistry;
|
|
379
|
+
// The registry object persists across remounts (ref-held), so revive
|
|
380
|
+
// it on every mount: without this, the unmount cleanup below leaves
|
|
381
|
+
// all generation-guarded navigation permanently dead after any
|
|
382
|
+
// remount (including the StrictMode double-mount).
|
|
383
|
+
registry.revive();
|
|
384
|
+
return () => {
|
|
385
|
+
// Root unmount invalidates pending materialize/scroll/focus work.
|
|
386
|
+
registry.dispose();
|
|
387
|
+
};
|
|
388
|
+
}, []);
|
|
389
|
+
|
|
390
|
+
const servicesValue = React.useMemo<PickerServices>(
|
|
391
|
+
() => ({
|
|
392
|
+
activeEmojiStore: activeStoreRef.current as ReturnType<
|
|
393
|
+
typeof createActiveEmojiStore
|
|
394
|
+
>,
|
|
395
|
+
filterRef,
|
|
396
|
+
filterQueryOrderRef,
|
|
397
|
+
disallowClickRef,
|
|
398
|
+
disallowMouseRef,
|
|
399
|
+
navigationRegistry: registryRef.current as NavigationRegistry,
|
|
400
|
+
requestNativeProbe,
|
|
401
|
+
}),
|
|
402
|
+
// All members are stable refs or callbacks; the identity never changes.
|
|
403
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
404
|
+
[],
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
const searchTerm = useDebouncedSliceValue(useDebouncedState('', 100));
|
|
408
|
+
const suggestedUpdateState = useDebouncedSliceValue(
|
|
409
|
+
useDebouncedState(Date.now(), 200),
|
|
410
|
+
);
|
|
411
|
+
const searchValue = React.useMemo(
|
|
412
|
+
() => ({ searchTerm, suggestedUpdateState }),
|
|
413
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
414
|
+
[searchTerm[0], suggestedUpdateState[0]],
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
// Accepted/display state. A controlled `searchValue` is the visible
|
|
418
|
+
// source of truth from the first paint (including SSR, where effects
|
|
419
|
+
// never run); `defaultSearchValue` is read once per mounted lifetime
|
|
420
|
+
// via the state initializer.
|
|
421
|
+
const searchValueConfig = useSearchValueConfig();
|
|
422
|
+
const initialAccepted = searchValueConfig ?? defaultSearchValue ?? '';
|
|
423
|
+
const displayState = useState<string>(initialAccepted);
|
|
424
|
+
const committedState = useState<string>(initialAccepted);
|
|
425
|
+
const composingState = useState<boolean>(false);
|
|
426
|
+
const searchInputValue = React.useMemo(
|
|
427
|
+
() => ({
|
|
428
|
+
displayValue: displayState as ReactState<string>,
|
|
429
|
+
committedValue: committedState as ReactState<string>,
|
|
430
|
+
composing: composingState as ReactState<boolean>,
|
|
431
|
+
}),
|
|
432
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
433
|
+
[displayState[0], committedState[0], composingState[0]],
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
const reactionsModeState = useState(reactionsDefaultOpen);
|
|
437
|
+
const reactionsValue = useSliceValue(reactionsModeState);
|
|
438
|
+
|
|
439
|
+
const emojiVariationPickerState = useState<DataEmoji | null>(null);
|
|
440
|
+
const variationValue = useSliceValue(emojiVariationPickerState);
|
|
441
|
+
|
|
442
|
+
// Controlled `skinTone` is the visible source of truth; the setter still
|
|
443
|
+
// updates local state (harmless while controlled) so switching back to
|
|
444
|
+
// uncontrolled resumes from the last selection. Selection always reports
|
|
445
|
+
// through onSkinToneChange, which the skin tone picker calls itself.
|
|
446
|
+
const controlledSkinTone = useSkinToneConfig();
|
|
447
|
+
const [localSkinTone, setLocalSkinTone] =
|
|
448
|
+
useState<SkinTones>(defaultSkinTone);
|
|
449
|
+
const effectiveSkinTone = controlledSkinTone ?? localSkinTone;
|
|
450
|
+
const skinToneFanOpenState = useState<boolean>(false);
|
|
451
|
+
const skinToneValue = React.useMemo(
|
|
452
|
+
() => ({
|
|
453
|
+
activeSkinTone: [
|
|
454
|
+
effectiveSkinTone,
|
|
455
|
+
setLocalSkinTone,
|
|
456
|
+
] as ReactState<SkinTones>,
|
|
457
|
+
skinToneFanOpenState: skinToneFanOpenState as ReactState<boolean>,
|
|
458
|
+
}),
|
|
459
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
460
|
+
[effectiveSkinTone, skinToneFanOpenState[0]],
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
const activeCategoryState = useState<ActiveCategoryState>(null);
|
|
464
|
+
const emojiStyle = useEmojiStyleConfig();
|
|
465
|
+
const resolver = useGetEmojiUrlConfig();
|
|
466
|
+
const customEmojis = useCustomEmojisConfig();
|
|
467
|
+
// Each asset source owns its failure cache. Errors from older sources can
|
|
468
|
+
// only update their old cache; they never suppress the current assets.
|
|
469
|
+
const failedIds = React.useMemo(
|
|
470
|
+
() => new Set<string>(),
|
|
471
|
+
// The cache lifetime follows asset inputs, not the current failures.
|
|
472
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
473
|
+
[emojiStyle, resolver, customEmojis],
|
|
474
|
+
);
|
|
475
|
+
const [failureVersion, setFailureVersion] = useState({});
|
|
476
|
+
const setFailed = React.useCallback(
|
|
477
|
+
(unified: string) => {
|
|
478
|
+
failedIds.add(unified);
|
|
479
|
+
setFailureVersion({});
|
|
480
|
+
},
|
|
481
|
+
[failedIds],
|
|
482
|
+
);
|
|
483
|
+
const emojisThatFailedToLoadState: [Set<string>, (unified: string) => void] =
|
|
484
|
+
[failedIds, setFailed];
|
|
485
|
+
const visibleCategoriesState = useState<string[]>([]);
|
|
486
|
+
const emojiSizeState = useState<number | null>(null);
|
|
487
|
+
const viewportValue = React.useMemo(
|
|
488
|
+
() => ({
|
|
489
|
+
activeCategoryState:
|
|
490
|
+
activeCategoryState as ReactState<ActiveCategoryState>,
|
|
491
|
+
visibleCategoriesState: visibleCategoriesState as ReactState<
|
|
492
|
+
Array<string>
|
|
493
|
+
>,
|
|
494
|
+
emojiSizeState: emojiSizeState as ReactState<number | null>,
|
|
495
|
+
}),
|
|
496
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
497
|
+
[activeCategoryState[0], visibleCategoriesState[0], emojiSizeState[0]],
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
const [isPastInitialLoad, setIsPastInitialLoad] = useState(false);
|
|
501
|
+
const loadValue = React.useMemo(
|
|
502
|
+
() => ({
|
|
503
|
+
emojisThatFailedToLoadState,
|
|
504
|
+
isPastInitialLoad,
|
|
505
|
+
}),
|
|
506
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
507
|
+
[failedIds, failureVersion, setFailed, isPastInitialLoad],
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
useMarkInitialLoad(setIsPastInitialLoad);
|
|
511
|
+
|
|
512
|
+
return (
|
|
513
|
+
<PickerServicesContext.Provider value={servicesValue}>
|
|
514
|
+
<NativeSupportContext.Provider value={nativeSupport}>
|
|
515
|
+
<SearchSliceContext.Provider value={searchValue}>
|
|
516
|
+
<SearchInputSliceContext.Provider value={searchInputValue}>
|
|
517
|
+
<ReactionsSliceContext.Provider value={reactionsValue}>
|
|
518
|
+
<VariationSliceContext.Provider value={variationValue}>
|
|
519
|
+
<SkinToneSliceContext.Provider value={skinToneValue}>
|
|
520
|
+
<ViewportSliceContext.Provider value={viewportValue}>
|
|
521
|
+
<LoadSliceContext.Provider value={loadValue}>
|
|
522
|
+
{children}
|
|
523
|
+
</LoadSliceContext.Provider>
|
|
524
|
+
</ViewportSliceContext.Provider>
|
|
525
|
+
</SkinToneSliceContext.Provider>
|
|
526
|
+
</VariationSliceContext.Provider>
|
|
527
|
+
</ReactionsSliceContext.Provider>
|
|
528
|
+
</SearchInputSliceContext.Provider>
|
|
529
|
+
</SearchSliceContext.Provider>
|
|
530
|
+
</NativeSupportContext.Provider>
|
|
531
|
+
</PickerServicesContext.Provider>
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
109
535
|
type Props = Readonly<{
|
|
110
536
|
children: React.ReactNode;
|
|
111
537
|
}>;
|
|
112
538
|
|
|
113
539
|
export function useFilterRef() {
|
|
114
|
-
const { filterRef } = React.useContext(
|
|
540
|
+
const { filterRef } = React.useContext(PickerServicesContext);
|
|
115
541
|
return filterRef;
|
|
116
542
|
}
|
|
117
543
|
|
|
544
|
+
export function useFilterQueryOrderRef() {
|
|
545
|
+
const { filterQueryOrderRef } = React.useContext(PickerServicesContext);
|
|
546
|
+
return filterQueryOrderRef;
|
|
547
|
+
}
|
|
548
|
+
|
|
118
549
|
export function useDisallowClickRef() {
|
|
119
|
-
const { disallowClickRef } = React.useContext(
|
|
550
|
+
const { disallowClickRef } = React.useContext(PickerServicesContext);
|
|
120
551
|
return disallowClickRef;
|
|
121
552
|
}
|
|
122
553
|
|
|
123
554
|
export function useDisallowMouseRef() {
|
|
124
|
-
const { disallowMouseRef } = React.useContext(
|
|
555
|
+
const { disallowMouseRef } = React.useContext(PickerServicesContext);
|
|
125
556
|
return disallowMouseRef;
|
|
126
557
|
}
|
|
127
558
|
|
|
559
|
+
export function useNavigationRegistry(): NavigationRegistry {
|
|
560
|
+
const { navigationRegistry } = React.useContext(PickerServicesContext);
|
|
561
|
+
return navigationRegistry;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export function useActiveEmojiState(): ReactState<ActiveEmojiState> {
|
|
565
|
+
const { activeEmojiStore: store } = React.useContext(PickerServicesContext);
|
|
566
|
+
const [value, setValue] = React.useState(store.get);
|
|
567
|
+
React.useEffect(() => {
|
|
568
|
+
const read = () => setValue(store.get());
|
|
569
|
+
const unsubscribe = store.subscribe(read);
|
|
570
|
+
read();
|
|
571
|
+
return unsubscribe;
|
|
572
|
+
}, [store]);
|
|
573
|
+
return [value, store.set];
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export function useIsActiveEmoji(unified?: string): boolean {
|
|
577
|
+
const { activeEmojiStore: store } = React.useContext(PickerServicesContext);
|
|
578
|
+
const read = React.useCallback(
|
|
579
|
+
() => !!unified && store.get()?.unified === unified,
|
|
580
|
+
[store, unified],
|
|
581
|
+
);
|
|
582
|
+
const [active, setActive] = React.useState(read);
|
|
583
|
+
React.useEffect(() => {
|
|
584
|
+
const update = () => setActive(read());
|
|
585
|
+
const unsubscribe = store.subscribe(update, unified);
|
|
586
|
+
update();
|
|
587
|
+
return unsubscribe;
|
|
588
|
+
}, [store, unified, read]);
|
|
589
|
+
// The identity can change during virtualization before effects run.
|
|
590
|
+
return active && read();
|
|
591
|
+
}
|
|
592
|
+
|
|
128
593
|
export function useReactionsModeState() {
|
|
129
|
-
const
|
|
594
|
+
const reactionsModeState = React.useContext(ReactionsSliceContext);
|
|
130
595
|
return reactionsModeState;
|
|
131
596
|
}
|
|
132
597
|
|
|
133
598
|
export function useSearchTermState() {
|
|
134
|
-
const { searchTerm } = React.useContext(
|
|
599
|
+
const { searchTerm } = React.useContext(SearchSliceContext);
|
|
135
600
|
return searchTerm;
|
|
136
601
|
}
|
|
137
602
|
|
|
603
|
+
export function useSearchDisplayState() {
|
|
604
|
+
const { displayValue } = React.useContext(SearchInputSliceContext);
|
|
605
|
+
return displayValue;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
export function useSearchCommittedState() {
|
|
609
|
+
const { committedValue } = React.useContext(SearchInputSliceContext);
|
|
610
|
+
return committedValue;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
export function useSearchComposingState() {
|
|
614
|
+
const { composing } = React.useContext(SearchInputSliceContext);
|
|
615
|
+
return composing;
|
|
616
|
+
}
|
|
617
|
+
|
|
138
618
|
export function useActiveSkinToneState(): [
|
|
139
619
|
SkinTones,
|
|
140
620
|
(skinTone: SkinTones) => void,
|
|
141
621
|
] {
|
|
142
|
-
const { activeSkinTone } = React.useContext(
|
|
622
|
+
const { activeSkinTone } = React.useContext(SkinToneSliceContext);
|
|
143
623
|
return activeSkinTone;
|
|
144
624
|
}
|
|
145
625
|
|
|
146
626
|
export function useEmojisThatFailedToLoadState() {
|
|
147
|
-
const { emojisThatFailedToLoadState } = React.useContext(
|
|
627
|
+
const { emojisThatFailedToLoadState } = React.useContext(LoadSliceContext);
|
|
148
628
|
return emojisThatFailedToLoadState;
|
|
149
629
|
}
|
|
150
630
|
|
|
151
631
|
export function useIsPastInitialLoad(): boolean {
|
|
152
|
-
const { isPastInitialLoad } = React.useContext(
|
|
632
|
+
const { isPastInitialLoad } = React.useContext(LoadSliceContext);
|
|
153
633
|
return isPastInitialLoad;
|
|
154
634
|
}
|
|
155
635
|
|
|
156
636
|
export function useEmojiVariationPickerState() {
|
|
157
|
-
const
|
|
637
|
+
const emojiVariationPickerState = React.useContext(VariationSliceContext);
|
|
158
638
|
return emojiVariationPickerState;
|
|
159
639
|
}
|
|
160
640
|
|
|
161
641
|
export function useSkinToneFanOpenState() {
|
|
162
|
-
const { skinToneFanOpenState } = React.useContext(
|
|
642
|
+
const { skinToneFanOpenState } = React.useContext(SkinToneSliceContext);
|
|
163
643
|
return skinToneFanOpenState;
|
|
164
644
|
}
|
|
165
645
|
|
|
166
|
-
export function useDisallowedEmojisRef() {
|
|
167
|
-
const { disallowedEmojisRef } = React.useContext(PickerContext);
|
|
168
|
-
return disallowedEmojisRef;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
646
|
export function useVisibleCategoriesState() {
|
|
172
|
-
const { visibleCategoriesState } = React.useContext(
|
|
647
|
+
const { visibleCategoriesState } = React.useContext(ViewportSliceContext);
|
|
173
648
|
return visibleCategoriesState;
|
|
174
649
|
}
|
|
175
650
|
|
|
176
651
|
export function useEmojiSizeState() {
|
|
177
|
-
const { emojiSizeState } = React.useContext(
|
|
652
|
+
const { emojiSizeState } = React.useContext(ViewportSliceContext);
|
|
178
653
|
return emojiSizeState;
|
|
179
654
|
}
|
|
180
655
|
|
|
181
656
|
export function useUpdateSuggested(): [number, () => void] {
|
|
182
|
-
const { suggestedUpdateState } = React.useContext(
|
|
657
|
+
const { suggestedUpdateState } = React.useContext(SearchSliceContext);
|
|
183
658
|
|
|
184
659
|
const [suggestedUpdated, setsuggestedUpdate] = suggestedUpdateState;
|
|
185
660
|
return [
|