diff --git a/src/components/EmojiPicker/index.web.tsx b/src/components/EmojiPicker/index.web.tsx index 8d5e7788ec..41a80a5d60 100644 --- a/src/components/EmojiPicker/index.web.tsx +++ b/src/components/EmojiPicker/index.web.tsx @@ -1,5 +1,13 @@ -import {createContext, useContext, useEffect, useMemo, useRef} from 'react' -import EmojiPicker from '@emoji-mart/react' +import { + createContext, + lazy, + Suspense, + useContext, + useEffect, + useMemo, + useRef, +} from 'react' +import {View} from 'react-native' import {DropdownMenu} from 'radix-ui' import {useA11y} from '#/state/a11y' @@ -16,6 +24,24 @@ import { export * from './types' +/** + * The emoji-mart picker is code-split into its own chunk (`emoji-mart`) so its + * weight stays out of the main bundle and is only fetched when the picker + * actually mounts (i.e. when the dropdown opens). {@link useWebPreloadEmoji} + * warms the same chunk ahead of time. + */ +const EmojiPickerLazy = lazy( + () => import(/* webpackChunkName: "emoji-mart" */ '@emoji-mart/react'), +) + +/** + * Fixed-size placeholder shown while the emoji-mart chunk loads, sized to match + * emoji-mart's default picker so the dropdown doesn't visually jump when the + * real picker mounts. + */ +const PICKER_WIDTH = 352 +const PICKER_HEIGHT = 435 + const EmojiPickerContext = createContext<{ onEmojiSelect: (emoji: Emoji) => void nextFocusRef: RootProps['nextFocusRef'] @@ -124,16 +150,21 @@ export function Picker({keepOpenWhenShiftHeld = true}: PickerProps) {
evt.stopPropagation()} style={flatten([!reduceMotionEnabled && a.zoom_fade_in])}> - { - onEmojiSelect(emoji) + + }> + { + onEmojiSelect(emoji) - if (!keepOpenWhenShiftHeld || !isShiftDown.current) { - control.close() - } - }} - /> + if (!keepOpenWhenShiftHeld || !isShiftDown.current) { + control.close() + } + }} + /> +
diff --git a/src/components/EmojiPicker/preload.web.ts b/src/components/EmojiPicker/preload.web.ts index 4456153b71..97f20b78e2 100644 --- a/src/components/EmojiPicker/preload.web.ts +++ b/src/components/EmojiPicker/preload.web.ts @@ -1,5 +1,4 @@ import {useCallback} from 'react' -import {init} from 'emoji-mart' /** * Only load the emoji picker data once per page load. @@ -21,7 +20,10 @@ export function useWebPreloadEmoji({immediate}: {immediate?: boolean} = {}) { if (loadRequested) return loadRequested = true try { - const data = (await import('@emoji-mart/data')).default + const [{init}, {default: data}] = await Promise.all([ + import(/* webpackChunkName: "emoji-mart" */ 'emoji-mart'), + import(/* webpackChunkName: "emoji-mart-data" */ '@emoji-mart/data'), + ]) init({data}) } catch (e) {} }, [])