@particle-academy/react-fancy 5.60.2 → 5.61.1
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/CHANGELOG.md +81 -0
- package/dist/autocomplete.cjs +4 -3
- package/dist/autocomplete.js +3 -2
- package/dist/{chunk-EEMNTO7L.cjs → chunk-3DMVK74Q.cjs} +4 -4
- package/dist/{chunk-EEMNTO7L.cjs.map → chunk-3DMVK74Q.cjs.map} +1 -1
- package/dist/{chunk-M77BB2QI.cjs → chunk-3I6PE2US.cjs} +12 -12
- package/dist/{chunk-M77BB2QI.cjs.map → chunk-3I6PE2US.cjs.map} +1 -1
- package/dist/{chunk-TGBLDJ72.js → chunk-4FJWHVC7.js} +3 -3
- package/dist/{chunk-TGBLDJ72.js.map → chunk-4FJWHVC7.js.map} +1 -1
- package/dist/{chunk-EXQ33MJR.cjs → chunk-4HUD33OP.cjs} +4 -4
- package/dist/{chunk-EXQ33MJR.cjs.map → chunk-4HUD33OP.cjs.map} +1 -1
- package/dist/chunk-4JLFIPHZ.js +43 -0
- package/dist/chunk-4JLFIPHZ.js.map +1 -0
- package/dist/{chunk-YQTKTEWS.js → chunk-5JFA7NYE.js} +3 -3
- package/dist/{chunk-YQTKTEWS.js.map → chunk-5JFA7NYE.js.map} +1 -1
- package/dist/chunk-5VMILVWD.js +3 -0
- package/dist/chunk-5VMILVWD.js.map +1 -0
- package/dist/chunk-645CRPU6.cjs +53 -0
- package/dist/chunk-645CRPU6.cjs.map +1 -0
- package/dist/{chunk-DN244T6G.cjs → chunk-6GBO7R25.cjs} +4 -4
- package/dist/{chunk-DN244T6G.cjs.map → chunk-6GBO7R25.cjs.map} +1 -1
- package/dist/{chunk-4FZOH7BJ.js → chunk-74MEJWMH.js} +3 -3
- package/dist/{chunk-4FZOH7BJ.js.map → chunk-74MEJWMH.js.map} +1 -1
- package/dist/{chunk-4DGXL6JC.cjs → chunk-7KTBVKNO.cjs} +4 -4
- package/dist/{chunk-4DGXL6JC.cjs.map → chunk-7KTBVKNO.cjs.map} +1 -1
- package/dist/{chunk-XQDGUXMS.js → chunk-BHUSI56C.js} +3 -3
- package/dist/{chunk-XQDGUXMS.js.map → chunk-BHUSI56C.js.map} +1 -1
- package/dist/{chunk-VD3C7IA4.js → chunk-BLS2IGPY.js} +48 -13
- package/dist/chunk-BLS2IGPY.js.map +1 -0
- package/dist/{chunk-XAQQX7J2.cjs → chunk-BMVYOVSW.cjs} +48 -13
- package/dist/chunk-BMVYOVSW.cjs.map +1 -0
- package/dist/{chunk-UIE5FP3A.js → chunk-BQFPC5FL.js} +3 -3
- package/dist/{chunk-UIE5FP3A.js.map → chunk-BQFPC5FL.js.map} +1 -1
- package/dist/chunk-CHQH6M67.js +297 -0
- package/dist/chunk-CHQH6M67.js.map +1 -0
- package/dist/{chunk-UZG6LO4Z.cjs → chunk-FU6K7XXZ.cjs} +4 -4
- package/dist/{chunk-UZG6LO4Z.cjs.map → chunk-FU6K7XXZ.cjs.map} +1 -1
- package/dist/{chunk-5ZNOLPIJ.cjs → chunk-H2YRZYKK.cjs} +5 -5
- package/dist/{chunk-5ZNOLPIJ.cjs.map → chunk-H2YRZYKK.cjs.map} +1 -1
- package/dist/{chunk-7R7HENZG.cjs → chunk-HRYM76ZE.cjs} +9 -9
- package/dist/{chunk-7R7HENZG.cjs.map → chunk-HRYM76ZE.cjs.map} +1 -1
- package/dist/{chunk-ZGQEKDG6.js → chunk-IHQHTJNN.js} +5 -5
- package/dist/{chunk-ZGQEKDG6.js.map → chunk-IHQHTJNN.js.map} +1 -1
- package/dist/{chunk-6HJF55U7.js → chunk-IY6LVALS.js} +3 -3
- package/dist/{chunk-6HJF55U7.js.map → chunk-IY6LVALS.js.map} +1 -1
- package/dist/{chunk-HTNQ5XUR.cjs → chunk-J4FKJ4IR.cjs} +4 -4
- package/dist/{chunk-HTNQ5XUR.cjs.map → chunk-J4FKJ4IR.cjs.map} +1 -1
- package/dist/{chunk-43ZRUYJC.cjs → chunk-JOWAS5A5.cjs} +9 -9
- package/dist/{chunk-43ZRUYJC.cjs.map → chunk-JOWAS5A5.cjs.map} +1 -1
- package/dist/{chunk-JRRYYW3Y.cjs → chunk-K6NADZ7O.cjs} +6 -6
- package/dist/{chunk-JRRYYW3Y.cjs.map → chunk-K6NADZ7O.cjs.map} +1 -1
- package/dist/{chunk-5JA4ENMF.js → chunk-LMOPAY7Q.js} +3 -3
- package/dist/{chunk-5JA4ENMF.js.map → chunk-LMOPAY7Q.js.map} +1 -1
- package/dist/{chunk-DAJPPKPO.js → chunk-M52S3TFI.js} +3 -3
- package/dist/{chunk-DAJPPKPO.js.map → chunk-M52S3TFI.js.map} +1 -1
- package/dist/{chunk-GLGUQGAQ.cjs → chunk-M6MGQI6G.cjs} +4 -4
- package/dist/{chunk-GLGUQGAQ.cjs.map → chunk-M6MGQI6G.cjs.map} +1 -1
- package/dist/chunk-MKHYENKR.cjs +4 -0
- package/dist/chunk-MKHYENKR.cjs.map +1 -0
- package/dist/{chunk-NHGU2BWT.js → chunk-MSGKIWYX.js} +3 -3
- package/dist/{chunk-NHGU2BWT.js.map → chunk-MSGKIWYX.js.map} +1 -1
- package/dist/{chunk-KQYOIPHQ.js → chunk-N7KUGFRG.js} +4 -4
- package/dist/{chunk-KQYOIPHQ.js.map → chunk-N7KUGFRG.js.map} +1 -1
- package/dist/{chunk-XB3H2EEL.js → chunk-NDLESFUH.js} +3 -3
- package/dist/{chunk-XB3H2EEL.js.map → chunk-NDLESFUH.js.map} +1 -1
- package/dist/chunk-NFTTNFQR.js +51 -0
- package/dist/chunk-NFTTNFQR.js.map +1 -0
- package/dist/{chunk-XYOT75HH.js → chunk-NORVXHRU.js} +3 -3
- package/dist/{chunk-XYOT75HH.js.map → chunk-NORVXHRU.js.map} +1 -1
- package/dist/{chunk-5H6IUCOD.cjs → chunk-P6V4QWJK.cjs} +4 -4
- package/dist/{chunk-5H6IUCOD.cjs.map → chunk-P6V4QWJK.cjs.map} +1 -1
- package/dist/{chunk-LZHGXRFD.js → chunk-PKFEJWVI.js} +3 -3
- package/dist/{chunk-LZHGXRFD.js.map → chunk-PKFEJWVI.js.map} +1 -1
- package/dist/{chunk-BJKKW77L.cjs → chunk-QXMQVLRQ.cjs} +4 -4
- package/dist/{chunk-BJKKW77L.cjs.map → chunk-QXMQVLRQ.cjs.map} +1 -1
- package/dist/{chunk-WHEXTDPV.js → chunk-RBCMKPBX.js} +7 -5
- package/dist/chunk-RBCMKPBX.js.map +1 -0
- package/dist/{chunk-LVE6ERRS.cjs → chunk-RRMQGTVB.cjs} +6 -6
- package/dist/{chunk-LVE6ERRS.cjs.map → chunk-RRMQGTVB.cjs.map} +1 -1
- package/dist/{chunk-T67FLC55.js → chunk-SHF44YGG.js} +3 -3
- package/dist/{chunk-T67FLC55.js.map → chunk-SHF44YGG.js.map} +1 -1
- package/dist/{chunk-NBZC6LOB.cjs → chunk-TI7D4QDM.cjs} +6 -3
- package/dist/chunk-TI7D4QDM.cjs.map +1 -0
- package/dist/{chunk-5JK2VDWY.cjs → chunk-TYTENEJQ.cjs} +6 -6
- package/dist/{chunk-5JK2VDWY.cjs.map → chunk-TYTENEJQ.cjs.map} +1 -1
- package/dist/{chunk-WW56U3RV.js → chunk-UBEOB55O.js} +3 -3
- package/dist/{chunk-WW56U3RV.js.map → chunk-UBEOB55O.js.map} +1 -1
- package/dist/{chunk-M6XBF2ZS.js → chunk-UJZJBHMH.js} +3 -3
- package/dist/{chunk-M6XBF2ZS.js.map → chunk-UJZJBHMH.js.map} +1 -1
- package/dist/{chunk-T45LBTXH.js → chunk-ULG4OA2T.js} +3 -3
- package/dist/{chunk-T45LBTXH.js.map → chunk-ULG4OA2T.js.map} +1 -1
- package/dist/{chunk-SIEPD6NR.cjs → chunk-UM4JXBRZ.cjs} +4 -4
- package/dist/{chunk-SIEPD6NR.cjs.map → chunk-UM4JXBRZ.cjs.map} +1 -1
- package/dist/chunk-X6TGRSVH.cjs +299 -0
- package/dist/chunk-X6TGRSVH.cjs.map +1 -0
- package/dist/{chunk-FGI2EC32.cjs → chunk-Z5OTOYWI.cjs} +4 -4
- package/dist/{chunk-FGI2EC32.cjs.map → chunk-Z5OTOYWI.cjs.map} +1 -1
- package/dist/chunk-ZPBCZPMD.cjs +48 -0
- package/dist/chunk-ZPBCZPMD.cjs.map +1 -0
- package/dist/command.cjs +5 -4
- package/dist/command.js +3 -2
- package/dist/composer.cjs +7 -6
- package/dist/composer.js +5 -4
- package/dist/context-menu.cjs +5 -4
- package/dist/context-menu.js +3 -2
- package/dist/drawer.cjs +5 -4
- package/dist/drawer.js +3 -2
- package/dist/dropdown.cjs +5 -4
- package/dist/dropdown.js +3 -2
- package/dist/editor.cjs +8 -3
- package/dist/editor.d.cts +53 -4
- package/dist/editor.d.ts +53 -4
- package/dist/editor.js +6 -1
- package/dist/full-screen.cjs +39 -0
- package/dist/full-screen.cjs.map +1 -0
- package/dist/full-screen.d.cts +54 -0
- package/dist/full-screen.d.ts +54 -0
- package/dist/full-screen.js +10 -0
- package/dist/full-screen.js.map +1 -0
- package/dist/index.cjs +152 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +35 -31
- package/dist/index.js.map +1 -1
- package/dist/input.cjs +6 -5
- package/dist/input.js +5 -4
- package/dist/inputs.cjs +17 -16
- package/dist/inputs.js +9 -8
- package/dist/json-editor.cjs +19 -18
- package/dist/json-editor.js +8 -7
- package/dist/magic-wand.cjs +4 -3
- package/dist/magic-wand.js +3 -2
- package/dist/mobile-menu.cjs +6 -4
- package/dist/mobile-menu.js +4 -2
- package/dist/modal.cjs +5 -4
- package/dist/modal.js +3 -2
- package/dist/paste-pills.cjs +17 -16
- package/dist/paste-pills.js +4 -3
- package/dist/popover.cjs +5 -4
- package/dist/popover.js +3 -2
- package/dist/portal.cjs +7 -2
- package/dist/portal.d.cts +12 -1
- package/dist/portal.d.ts +12 -1
- package/dist/portal.js +2 -1
- package/dist/prompt-input.cjs +7 -6
- package/dist/prompt-input.js +6 -5
- package/dist/reason-tag.cjs +5 -4
- package/dist/reason-tag.js +4 -3
- package/dist/select.cjs +4 -3
- package/dist/select.js +3 -2
- package/dist/sidebar.cjs +1 -0
- package/dist/sidebar.js +1 -0
- package/dist/styles.css +9 -0
- package/dist/styles.css.map +1 -1
- package/dist/toast.cjs +5 -4
- package/dist/toast.js +3 -2
- package/dist/tooltip.cjs +4 -3
- package/dist/tooltip.js +3 -2
- package/dist/use-full-screen-BUJ1ujG4.d.cts +94 -0
- package/dist/use-full-screen-BUJ1ujG4.d.ts +94 -0
- package/docs/Editor.md +24 -0
- package/docs/FullScreen.md +106 -0
- package/package.json +11 -1
- package/dist/chunk-NBZC6LOB.cjs.map +0 -1
- package/dist/chunk-VD3C7IA4.js.map +0 -1
- package/dist/chunk-WHEXTDPV.js.map +0 -1
- package/dist/chunk-XAQQX7J2.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Editor/Editor.context.ts","../src/components/Editor/EditorSourceToggle.tsx","../src/components/Editor/EditorFullScreenToggle.tsx","../src/components/Editor/EditorToolbar.tsx","../src/components/Editor/EditorToolbarSeparator.tsx","../src/components/Editor/EditorContent.tsx","../src/components/Editor/Editor.tsx"],"names":["createContext","useContext","jsx","cn","FullScreenToggle","jsxs","Fragment","useRef","useEffect","useMemo","extensionEditorClasses","CodeView","proseClasses","sanitizeHtml","detectFormat","markdownToEditorHtml","marked","useControllableState","useFullScreen","useFieldMode","useState","mergeExtensions","useCallback","htmlToMarkdown","FullScreenProvider","ContentRenderer"],"mappings":"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","file":"chunk-BMVYOVSW.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { RenderExtension } from \"../ContentRenderer/extensions\";\n\nexport interface EditorContextValue {\n contentRef: RefObject<HTMLDivElement | null>;\n exec: (command: string, arg?: string) => void;\n insertText: (text: string) => void;\n wrapSelection: (before: string, after: string) => void;\n outputFormat: \"html\" | \"markdown\";\n lineSpacing: number;\n placeholder?: string;\n /** Merged render extensions (global + instance). */\n extensions: RenderExtension[];\n /** Whether the raw-source view (textarea) is showing instead of the rich-text surface. */\n showSource: boolean;\n /** Toggle/set the raw-source view. */\n setShowSource: (showSource: boolean) => void;\n /** Whether the editor currently covers the viewport. */\n fullScreen: boolean;\n /** Enter/leave full screen. Goes through `onFullScreenChange` when controlled. */\n setFullScreen: (fullScreen: boolean) => void;\n /** Initial HTML content to load into the editor on mount */\n _initialHtml: string;\n /** @internal Called by EditorContent on input events */\n _onInput: () => void;\n /** @internal Raw source value (`value` in `outputFormat`), for the source textarea. */\n _sourceValue: string;\n /** @internal Commit an edit made directly in the source textarea. */\n _onSourceInput: (value: string) => void;\n}\n\nexport const EditorContext = createContext<EditorContextValue | null>(null);\n\nexport function useEditor(): EditorContextValue {\n const ctx = useContext(EditorContext);\n if (!ctx) {\n throw new Error(\"useEditor must be used within an <Editor> component\");\n }\n return ctx;\n}\n","import { cn } from \"../../utils/cn\";\nimport { useEditor } from \"./Editor.context\";\nimport type { EditorSourceToggleProps } from \"./Editor.types\";\n\n/**\n * Toolbar button that reveals the raw HTML/Markdown behind the editor. Reads\n * `showSource` / `setShowSource` from context, so it works in the default\n * toolbar and in any custom toolbar composed with `useEditor()`.\n */\nexport function EditorSourceToggle({\n className,\n icon = \"</>\",\n title = \"Source\",\n activeTitle = \"Rich text\",\n}: EditorSourceToggleProps) {\n const { showSource, setShowSource } = useEditor();\n\n return (\n <button\n type=\"button\"\n onClick={() => setShowSource(!showSource)}\n title={showSource ? activeTitle : title}\n aria-pressed={showSource}\n data-react-fancy-editor-source-toggle=\"\"\n className={cn(\n \"inline-flex h-8 items-center justify-center rounded-md px-2 font-mono text-xs transition-colors\",\n showSource\n ? \"bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n : \"hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n className,\n )}\n >\n {icon}\n </button>\n );\n}\n\nEditorSourceToggle.displayName = \"EditorSourceToggle\";\n","import { cn } from \"../../utils/cn\";\nimport { FullScreenToggle } from \"../FullScreen/FullScreenToggle\";\nimport type { EditorFullScreenToggleProps } from \"./Editor.types\";\n\n/**\n * Toolbar button that takes the editor full screen and back. The shared\n * `FullScreen.Toggle`, styled for the editor toolbar and carrying the editor's\n * own handle (`data-react-fancy-editor-fullscreen-toggle`) next to the shared\n * one (`data-react-fancy-fullscreen-toggle`).\n */\nexport function EditorFullScreenToggle({ className, enterIcon, exitIcon }: EditorFullScreenToggleProps) {\n return (\n <FullScreenToggle\n data-react-fancy-editor-fullscreen-toggle=\"\"\n enterIcon={enterIcon}\n exitIcon={exitIcon}\n className={cn(className)}\n />\n );\n}\n\nEditorFullScreenToggle.displayName = \"EditorFullScreenToggle\";\n","import { cn } from \"../../utils/cn\";\nimport { useEditor } from \"./Editor.context\";\nimport { EditorSourceToggle } from \"./EditorSourceToggle\";\nimport { EditorFullScreenToggle } from \"./EditorFullScreenToggle\";\nimport type { EditorToolbarProps } from \"./Editor.types\";\n\nconst DEFAULT_ACTIONS = [\n { icon: \"B\", label: \"Bold\", command: \"bold\" },\n { icon: \"I\", label: \"Italic\", command: \"italic\" },\n { icon: \"U\", label: \"Underline\", command: \"underline\" },\n { icon: \"S\", label: \"Strikethrough\", command: \"strikeThrough\" },\n];\n\nexport function EditorToolbar({\n actions = DEFAULT_ACTIONS,\n onAction,\n children,\n className,\n showSourceToggle = true,\n showFullScreenToggle = false,\n}: EditorToolbarProps) {\n const { exec, showSource } = useEditor();\n\n return (\n <div\n data-react-fancy-editor-toolbar=\"\"\n className={cn(\n \"flex shrink-0 items-center gap-0.5 border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-2 py-1.5 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children ?? (\n <>\n {actions.map((action) => (\n <button\n key={`${action.command}-${action.commandArg ?? \"\"}`}\n type=\"button\"\n // Rich-text commands don't apply to the raw-source textarea.\n disabled={showSource}\n onClick={() => {\n if (onAction) {\n onAction(action.command);\n } else {\n exec(action.command, action.commandArg);\n }\n }}\n title={action.label}\n className={cn(\n \"inline-flex h-8 w-8 items-center justify-center rounded-md text-sm transition-colors\",\n action.active\n ? \"bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n : \"hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n showSource && \"cursor-not-allowed opacity-40 hover:bg-transparent\",\n )}\n >\n {action.icon}\n </button>\n ))}\n {showSourceToggle && <EditorSourceToggle className=\"ml-auto\" />}\n {showFullScreenToggle && <EditorFullScreenToggle className={showSourceToggle ? undefined : \"ml-auto\"} />}\n </>\n )}\n </div>\n );\n}\n\nEditorToolbar.displayName = \"EditorToolbar\";\n","export function EditorToolbarSeparator() {\n return (\n <span\n data-react-fancy-editor-toolbar-separator=\"\"\n className=\"mx-1 h-5 w-px bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n />\n );\n}\n\nEditorToolbarSeparator.displayName = \"EditorToolbarSeparator\";\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CodeView } from \"../CodeView\";\nimport { useEditor } from \"./Editor.context\";\nimport { proseClasses, extensionEditorClasses } from \"./editor.utils\";\nimport type { EditorContentProps } from \"./Editor.types\";\n\nexport function EditorContent({ className, maxHeight: maxHeightProp, sourceClassName }: EditorContentProps) {\n const {\n contentRef,\n lineSpacing,\n placeholder,\n extensions,\n outputFormat,\n showSource,\n _initialHtml,\n _onInput,\n _sourceValue,\n _onSourceInput,\n fullScreen,\n } = useEditor();\n // Full screen means \"fill the viewport\": a height cap would leave the bottom\n // of the screen empty under a scrolled box.\n const maxHeight = fullScreen ? undefined : maxHeightProp;\n // Tracks which seed HTML is currently in the contentEditable. Seeding on the\n // seed VALUE (not a one-shot boolean) re-seeds when the source view rewrites\n // `value`, while still never re-seeding on plain keystrokes — typing leaves\n // `_initialHtml` untouched, so `seededHtml.current === _initialHtml` holds.\n const seededHtml = useRef<string | null>(null);\n\n useEffect(() => {\n // Source view replaces the contentEditable in the tree, so it unmounts.\n // Forget what we seeded — the div that returns is a fresh, empty one and\n // must always be re-seeded, even if `value` was left untouched.\n if (showSource) {\n seededHtml.current = null;\n return;\n }\n const el = contentRef.current;\n if (el && seededHtml.current !== _initialHtml) {\n el.innerHTML = _initialHtml;\n seededHtml.current = _initialHtml;\n }\n }, [contentRef, _initialHtml, showSource]);\n\n const extClasses = useMemo(\n () => extensionEditorClasses(extensions),\n [extensions],\n );\n\n if (showSource) {\n // Raw-source view — a syntax-highlighted code surface (HTML highlighted;\n // markdown/plain un-highlighted), built on the shared fancy-file-commons\n // primitives. It's a DIRECT child of the flex-column editor root (no\n // wrapper — a nested flex box collapses the fill), so `flex-auto` makes it\n // fill the editor body when height-constrained and grow with content\n // (≥ minHeight) when not. `maxHeight` caps + scrolls.\n return (\n <CodeView\n value={_sourceValue}\n onChange={_onSourceInput}\n language={outputFormat === \"html\" ? \"html\" : \"plaintext\"}\n placeholder={placeholder}\n maxHeight={maxHeight}\n className={cn(\"min-h-0 flex-auto\", sourceClassName)}\n />\n );\n }\n\n return (\n <div\n ref={contentRef}\n contentEditable\n suppressContentEditableWarning\n data-react-fancy-editor-content=\"\"\n data-placeholder={placeholder}\n onInput={_onInput}\n style={{\n lineHeight: lineSpacing,\n maxHeight: maxHeight ? `${maxHeight}px` : undefined,\n }}\n className={cn(\n \"min-h-[120px] flex-auto overflow-y-auto px-4 py-3 text-sm outline-none\",\n \"focus:outline-none\",\n proseClasses,\n extClasses,\n \"empty:before:content-[attr(data-placeholder)] empty:before:text-zinc-400 empty:before:pointer-events-none\",\n className,\n )}\n />\n );\n}\n\nEditorContent.displayName = \"EditorContent\";\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { marked } from \"marked\";\nimport { cn } from \"../../utils/cn\";\nimport { sanitizeHtml } from \"../../utils/sanitize\";\nimport { useControllableState } from \"../../hooks\";\nimport { useFullScreen } from \"../../hooks/use-full-screen\";\nimport { FullScreenProvider } from \"../FullScreen/FullScreen.context\";\nimport { EditorContext } from \"./Editor.context\";\nimport { EditorToolbar } from \"./EditorToolbar\";\nimport { EditorToolbarSeparator } from \"./EditorToolbarSeparator\";\nimport { EditorSourceToggle } from \"./EditorSourceToggle\";\nimport { EditorContent } from \"./EditorContent\";\nimport { EditorFullScreenToggle } from \"./EditorFullScreenToggle\";\nimport { htmlToMarkdown, detectFormat, markdownToEditorHtml, type MarkdownSource } from \"./editor.utils\";\nimport { mergeExtensions } from \"../ContentRenderer/extensions\";\nimport { ContentRenderer } from \"../ContentRenderer/ContentRenderer\";\nimport { useFieldMode } from \"../inputs/mode/FieldMode.context\";\nimport type { EditorProps } from \"./Editor.types\";\n\ninterface Seed {\n html: string;\n /** Source map for source-preserving markdown output; null when there is none. */\n source: MarkdownSource | null;\n}\n\nfunction toHtml(\n value: string,\n outputFormat: \"html\" | \"markdown\",\n unsafe: boolean,\n valueFormat: \"markdown\" | \"html\" | \"auto\" = \"auto\",\n): Seed {\n if (!value) return { html: \"\", source: null };\n const sanitize = (html: string) => (unsafe ? html : sanitizeHtml(html));\n // An explicit valueFormat is authoritative — the sniff misclassifies\n // markdown that merely MENTIONS HTML-ish snippets (`<code>`, `<table`),\n // collapsing it into an innerHTML wall of text (#10).\n const format =\n valueFormat !== \"auto\"\n ? valueFormat\n : outputFormat === \"html\"\n ? \"html\"\n : detectFormat(value);\n if (format === \"html\") return { html: sanitize(value), source: null };\n // Markdown in, markdown out: tag each block with its source so untouched\n // blocks are emitted byte-identical.\n if (outputFormat === \"markdown\") return markdownToEditorHtml(value, sanitize);\n return { html: sanitize((marked.parse(value, { async: false }) as string).trim()), source: null };\n}\n\nfunction EditorRoot({\n children,\n className,\n value: controlledValue,\n defaultValue = \"\",\n onChange,\n outputFormat = \"html\",\n valueFormat = \"auto\",\n lineSpacing = 1.6,\n placeholder,\n mode: modeProp,\n extensions: instanceExtensions,\n unsafe = false,\n showSource: showSourceProp,\n defaultShowSource = false,\n onShowSourceChange,\n fullScreen: fullScreenProp,\n defaultFullScreen = false,\n onFullScreenChange,\n fullScreenMode = \"overlay\",\n}: EditorProps) {\n const contentRef = useRef<HTMLDivElement | null>(null);\n const [value, setValue] = useControllableState(controlledValue, defaultValue, onChange);\n const [showSource, setShowSource] = useControllableState(\n showSourceProp,\n defaultShowSource,\n onShowSourceChange,\n );\n // Full screen is the element itself going `position: fixed`, not a portal:\n // reparenting would remount the contentEditable and lose the caret, the\n // browser's undo stack and the seeded HTML.\n const fs = useFullScreen<HTMLDivElement>({\n fullScreen: fullScreenProp,\n defaultFullScreen,\n onFullScreenChange,\n mode: fullScreenMode,\n });\n // View/edit mode — same resolution as the inputs: prop → <Form> context → \"edit\".\n const mode = useFieldMode(modeProp);\n const isView = mode === \"view\";\n\n // The value this editor last emitted through `onChange`. An incoming `value`\n // equal to it is our own keystroke echoing back; anything else came from\n // OUTSIDE — an async load, a host reset, a form repopulating.\n const lastEmitted = useRef<string | null>(null);\n\n // Bumped only on an external `value` change, so the seed memo below recomputes\n // for those and stays put while the user types. Without this, `value` was\n // excluded from the deps to avoid re-seeding on keystrokes, which also meant a\n // value arriving after mount was silently dropped and the editor stayed blank\n // forever (#15).\n const [externalSeed, setExternalSeed] = useState(0);\n useEffect(() => {\n if (value !== lastEmitted.current) setExternalSeed((n) => n + 1);\n }, [value]);\n\n const seed = useMemo(\n () => toHtml(value, outputFormat, unsafe, valueFormat),\n // Seed the contentEditable from the LIVE value when (re)entering edit mode —\n // and when returning from the raw-source view, which may have rewritten the\n // value out from under the rich-text surface. `value` itself stays out of\n // the deps so typing never re-seeds (which would fight the caret);\n // `externalSeed` covers the externally-driven case instead.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [isView, outputFormat, unsafe, valueFormat, showSource, externalSeed],\n );\n const initialHtml = seed.html;\n const seedSource = seed.source;\n\n const extensions = useMemo(\n () => mergeExtensions(instanceExtensions),\n [instanceExtensions],\n );\n\n const getOutputValue = useCallback(\n (html: string): string => {\n return outputFormat === \"markdown\" ? htmlToMarkdown(html, seedSource) : html;\n },\n [outputFormat, seedSource],\n );\n\n const handleInput = useCallback(() => {\n const el = contentRef.current;\n if (!el) return;\n const next = getOutputValue(el.innerHTML);\n // Record what we emitted BEFORE publishing it, so the value coming back in\n // is recognised as our own and does not trigger a re-seed mid-keystroke.\n lastEmitted.current = next;\n setValue(next);\n }, [setValue, getOutputValue]);\n\n const exec = useCallback(\n (command: string, arg?: string) => {\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(command, false, arg);\n handleInput();\n },\n [handleInput],\n );\n\n const insertText = useCallback(\n (text: string) => {\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(\"insertText\", false, text);\n handleInput();\n },\n [handleInput],\n );\n\n // The source textarea edits `value` directly — it is already the canonical\n // source in `outputFormat` (html or markdown), so no conversion round-trip.\n const handleSourceInput = useCallback(\n (next: string) => {\n // Also an internal emission — record it so typing in the source view is\n // not mistaken for an external change on every keystroke.\n lastEmitted.current = next;\n setValue(next);\n },\n [setValue],\n );\n\n const wrapSelection = useCallback(\n (before: string, after: string) => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n const selectedText = range.toString();\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(\"insertText\", false, `${before}${selectedText}${after}`);\n handleInput();\n },\n [handleInput],\n );\n\n const contextValue = {\n contentRef,\n exec,\n insertText,\n wrapSelection,\n outputFormat,\n lineSpacing,\n placeholder,\n extensions,\n showSource,\n setShowSource,\n fullScreen: fs.fullScreen,\n setFullScreen: fs.setFullScreen,\n _initialHtml: initialHtml,\n _onInput: handleInput,\n _sourceValue: value,\n _onSourceInput: handleSourceInput,\n };\n\n // View mode — render the value read-only through ContentRenderer, matching the\n // editor's own format (markdown/html), instead of the editable toolbar+content\n // tree. Driven by `mode` / a `<Form mode=\"view\">`, exactly like the inputs.\n if (isView) {\n return (\n <FullScreenProvider value={fs}>\n <div\n {...fs.targetProps}\n data-react-fancy-editor=\"\"\n data-mode=\"view\"\n className={cn(\n \"overflow-hidden rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n // Read-only content taller than the viewport must scroll in place.\n fs.fullScreen && \"overflow-auto\",\n )}\n >\n <ContentRenderer\n value={value}\n format={valueFormat !== \"auto\" ? valueFormat : outputFormat}\n lineSpacing={lineSpacing}\n extensions={instanceExtensions}\n unsafe={unsafe}\n className=\"px-4 py-3\"\n />\n </div>\n </FullScreenProvider>\n );\n }\n\n return (\n <EditorContext.Provider value={contextValue}>\n <FullScreenProvider value={fs}>\n <div\n {...fs.targetProps}\n data-react-fancy-editor=\"\"\n data-mode=\"edit\"\n className={cn(\n \"flex flex-col overflow-hidden rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {children}\n </div>\n </FullScreenProvider>\n </EditorContext.Provider>\n );\n}\n\nconst ToolbarWithSeparator = Object.assign(EditorToolbar, {\n Separator: EditorToolbarSeparator,\n});\n\nexport const Editor = Object.assign(EditorRoot, {\n Toolbar: ToolbarWithSeparator,\n Content: EditorContent,\n SourceToggle: EditorSourceToggle,\n FullScreenToggle: EditorFullScreenToggle,\n});\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Portal } from './chunk-
|
|
1
|
+
import { Portal } from './chunk-RBCMKPBX.js';
|
|
2
2
|
import { Badge } from './chunk-6FCQD2KQ.js';
|
|
3
3
|
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
4
4
|
import { cn } from './chunk-MMW2JGKZ.js';
|
|
@@ -301,5 +301,5 @@ var Toast = {
|
|
|
301
301
|
};
|
|
302
302
|
|
|
303
303
|
export { Toast, useToast };
|
|
304
|
-
//# sourceMappingURL=chunk-
|
|
305
|
-
//# sourceMappingURL=chunk-
|
|
304
|
+
//# sourceMappingURL=chunk-BQFPC5FL.js.map
|
|
305
|
+
//# sourceMappingURL=chunk-BQFPC5FL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Toast/Toast.context.ts","../src/components/Toast/ToastItem.tsx","../src/components/Toast/ToastStack.tsx","../src/components/Toast/Toast.tsx"],"names":["useEffect","jsx","jsxs","POSITION_STYLES","useRef"],"mappings":"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","file":"chunk-UIE5FP3A.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ToastContextValue } from \"./Toast.types\";\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a <Toast.Provider>\");\n }\n return ctx;\n}\n","import { useEffect } from \"react\";\nimport { AlertTriangle, Check, Info, X, XCircle } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { ToastItemProps } from \"./Toast.types\";\n\nconst VARIANT_STYLES = {\n default:\n \"border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n success:\n \"border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950\",\n error:\n \"border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950\",\n warning:\n \"border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950\",\n info: \"border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950\",\n} as const;\n\nconst VARIANT_ICON_COLORS = {\n default: \"text-zinc-400\",\n success: \"text-emerald-500\",\n error: \"text-red-500\",\n warning: \"text-amber-500\",\n info: \"text-blue-500\",\n} as const;\n\nexport function ToastItem({ data, onDismiss }: ToastItemProps) {\n const { id, title, description, variant = \"default\", action } = data;\n // An action toast does not expire by default.\n const duration = data.duration ?? (action ? 0 : 5000);\n\n useEffect(() => {\n if (duration <= 0) return;\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }, [id, duration, onDismiss]);\n\n return (\n <div\n data-react-fancy-toast-item=\"\"\n role=\"alert\"\n // Scoped to the toast rather than the document: a global Escape handler\n // would fight whatever modal or drawer is already listening.\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onDismiss(id);\n }}\n className={cn(\n \"fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg\",\n VARIANT_STYLES[variant],\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className={cn(\"mt-0.5 shrink-0\", VARIANT_ICON_COLORS[variant])}>\n {variant === \"success\" && <Check size={16} />}\n {variant === \"error\" && <XCircle size={16} />}\n {variant === \"warning\" && <AlertTriangle size={16} />}\n {variant === \"info\" && <Info size={16} />}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{title}</p>\n {description && (\n <p className=\"mt-1 text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {description}\n </p>\n )}\n </div>\n {action && (\n <button\n type=\"button\"\n onClick={() => {\n action.onClick();\n // The offer is consumed; leaving it up invites undoing an\n // already-undone action.\n onDismiss(id);\n }}\n className=\"shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:underline dark:text-zinc-200 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {action.label}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDismiss(id)}\n className=\"shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label=\"Dismiss\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n );\n}\n\nToastItem.displayName = \"ToastItem\";\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport { Portal } from \"../Portal\";\nimport { Badge } from \"../Badge\";\nimport type { ToastPosition } from \"./Toast.types\";\n\nexport interface ToastStackProps<T> {\n /**\n * Everything to show — the stack is a VIEW of this list and owns none of it.\n * There is no limit and no timer: an item leaves only when you remove it.\n */\n items: readonly T[];\n /** One card's content, actions included. Only the front card is interactive. */\n renderItem: (item: T, state: { index: number; isFront: boolean }) => ReactNode;\n /** A stable key per item. Defaults to `item.id`, then the index. */\n getKey?: (item: T, index: number) => string;\n /** How many cards show behind the front one. Default 2. */\n depth?: number;\n /** How far each card behind peeks out above the one in front, in px. Default 8. */\n offset?: number;\n /** How much smaller each card behind is than the one in front. Default 0.05. */\n scaleStep?: number;\n /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */\n frontIndex?: number;\n defaultFrontIndex?: number;\n onFrontIndexChange?: (index: number) => void;\n /** A screen corner, or `\"inline\"` to render where it is placed. Default `\"bottom-right\"`. */\n position?: ToastPosition | \"inline\";\n /** The stack's accessible name. Default \"Notifications\". */\n label?: string;\n /** Classes for each card's shell, merged onto the defaults. */\n cardClassName?: string;\n className?: string;\n}\n\nconst POSITION_STYLES: Record<ToastPosition, string> = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n};\n\n/** Pixels of wheel travel that count as one step. A mouse notch is ~100; a trackpad sends many small ones. */\nconst WHEEL_STEP = 50;\n\nconst CARD =\n \"rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\";\n\nfunction defaultKey(item: unknown, index: number): string {\n const id = (item as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\" ? String(id) : String(index);\n}\n\nfunction isTextField(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.getAttribute(\"contenteditable\") === \"true\" ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)\n );\n}\n\n/**\n * A controlled stack of actionable toasts — approval requests, say — that the\n * person walks through rather than races.\n *\n * Built for react-fancy#33. The owner's requirements were that requests stack\n * behind each other with a slight top offset, that scrolling over the stack\n * walks through them, and that a pending request NEVER expires or disappears.\n * The last is why this is a view of the caller's list rather than a queue it\n * keeps: there is nothing here that can drop an item, because nothing here owns\n * one. (The imperative provider's `maxToasts` silently drops the oldest.)\n */\nexport function ToastStack<T>({\n items,\n renderItem,\n getKey = defaultKey,\n depth = 2,\n offset = 8,\n scaleStep = 0.05,\n frontIndex: controlledFront,\n defaultFrontIndex = 0,\n onFrontIndexChange,\n position = \"bottom-right\",\n label = \"Notifications\",\n cardClassName,\n className,\n}: ToastStackProps<T>) {\n const [rawFront, setFront] = useControllableState(\n controlledFront,\n defaultFrontIndex,\n onFrontIndexChange,\n );\n const count = items.length;\n // Clamped for display rather than corrected through onChange: a list that\n // shrinks under a far-forward index must not make render report a change.\n const front = count === 0 ? 0 : ((rawFront % count) + count) % count;\n\n const stackRef = useRef<HTMLDivElement>(null);\n const wheelTravel = useRef(0);\n const live = useRef({ front, count });\n live.current = { front, count };\n\n const step = (by: number) => {\n const { front: current, count: n } = live.current;\n if (n < 2) return;\n setFront((((current + by) % n) + n) % n);\n };\n const stepRef = useRef(step);\n stepRef.current = step;\n\n /*\n * A native listener, because React's wheel listener is passive and cannot stop\n * the page scrolling underneath — and a stack that cycles AND scrolls the page\n * moves two things at once under the person's hand.\n */\n useEffect(() => {\n const el = stackRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (live.current.count < 2 || e.deltaY === 0) return;\n e.preventDefault();\n\n // Line or page mode: every event is a notch.\n if (e.deltaMode !== 0) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n // A notch-sized event steps at once; small trackpad deltas add up first.\n if (Math.abs(e.deltaY) >= WHEEL_STEP) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n wheelTravel.current += e.deltaY;\n if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {\n stepRef.current(Math.sign(wheelTravel.current));\n wheelTravel.current = 0;\n }\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n // Re-bound when the element can change: it appears with the first item, and\n // moving between a corner and inline remounts it.\n }, [count > 0, position]);\n\n if (count === 0) return null;\n\n const visibleBehind = Math.min(Math.max(0, depth), count - 1);\n const hidden = count - 1 - visibleBehind;\n\n const card = (index: number, k: number) => {\n const item = items[index];\n const isFront = k === 0;\n return (\n <div\n key={getKey(item, index)}\n data-react-fancy-toast-stack-card={isFront ? \"front\" : \"behind\"}\n aria-hidden={isFront ? undefined : true}\n inert={isFront ? undefined : true}\n className={cn(\n CARD,\n \"origin-top transition-transform duration-200\",\n isFront ? \"relative\" : \"pointer-events-none absolute inset-0 overflow-hidden\",\n cardClassName,\n )}\n style={{\n zIndex: depth + 1 - k,\n transform: isFront ? undefined : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`,\n }}\n >\n {renderItem(item, { index, isFront })}\n </div>\n );\n };\n\n const stackEl = (\n <div\n ref={stackRef}\n data-react-fancy-toast-stack=\"\"\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n onKeyDown={(e) => {\n if (isTextField(e.target)) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n step(1);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n step(-1);\n }\n }}\n className={cn(\n \"pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2\",\n className,\n )}\n style={{ paddingTop: visibleBehind * offset }}\n >\n <div className=\"relative\">\n {/*\n * z-index decides what paints on top; the front card sizes the box.\n * The front card comes FIRST in the DOM, then the cards behind in walk\n * order: the ones behind are absolutely positioned against this box, so\n * their place in the source changes nothing visible -- but it is what\n * a DOM query, `textContent` and copy-paste read.\n */}\n {card(front, 0)}\n {Array.from({ length: visibleBehind }, (_, i) => i + 1).map((k) =>\n card((front + k) % count, k),\n )}\n </div>\n {hidden > 0 && (\n /*\n * Opaque in BOTH themes, because it sits over the cards peeking out\n * behind the front one -- often a light image header. The soft zinc\n * Badge is `dark:bg-zinc-900/30`, which let that image through and left\n * zinc-300 text on a light screenshot (fancy-app-update#1). The dark\n * pair is overridden here, not in Badge, so every other soft badge\n * keeps its look; the ring separates it from a zinc-900 card edge.\n */\n <Badge\n data-react-fancy-toast-stack-more=\"\"\n size=\"sm\"\n variant=\"soft\"\n color=\"zinc\"\n className=\"absolute -top-2 right-2 z-20 shadow-sm ring-1 ring-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-zinc-800 dark:text-zinc-100 dark:ring-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n >\n +{hidden}\n </Badge>\n )}\n <span data-react-fancy-toast-stack-status=\"\" aria-live=\"polite\" className=\"sr-only\">\n {count > 1 ? `${front + 1} of ${count}` : \"\"}\n </span>\n </div>\n );\n\n if (position === \"inline\") return stackEl;\n\n return (\n <Portal>\n <div\n data-react-fancy-toast-stack-position={position}\n className={cn(\"pointer-events-none fixed z-[100]\", POSITION_STYLES[position])}\n >\n {stackEl}\n </div>\n </Portal>\n );\n}\n\nToastStack.displayName = \"ToastStack\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ToastContext } from \"./Toast.context\";\nimport { ToastItem } from \"./ToastItem\";\nimport { ToastStack } from \"./ToastStack\";\nimport type { ToastData, ToastProviderProps } from \"./Toast.types\";\n\nconst POSITION_STYLES = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n} as const;\n\nfunction ToastProvider({\n children,\n position = \"bottom-right\",\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n const idCounter = useRef(0);\n\n const toast = useCallback(\n (data: Omit<ToastData, \"id\">) => {\n const id = `toast-${++idCounter.current}`;\n setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);\n return id;\n },\n [maxToasts],\n );\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const ctx = useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);\n\n return (\n <ToastContext.Provider value={ctx}>\n {children}\n <Portal>\n <div\n data-react-fancy-toast=\"\"\n className={cn(\n \"fixed z-[100] flex flex-col gap-2 pointer-events-none\",\n POSITION_STYLES[position],\n )}\n >\n {toasts.map((t) => (\n <ToastItem key={t.id} data={t} onDismiss={dismiss} />\n ))}\n </div>\n </Portal>\n </ToastContext.Provider>\n );\n}\n\nexport const Toast = {\n Provider: ToastProvider,\n Stack: ToastStack,\n Item: ToastItem,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Toast/Toast.context.ts","../src/components/Toast/ToastItem.tsx","../src/components/Toast/ToastStack.tsx","../src/components/Toast/Toast.tsx"],"names":["useEffect","jsx","jsxs","POSITION_STYLES","useRef"],"mappings":";;;;;;;;AAGO,IAAM,YAAA,GAAe,cAAwC,IAAI,CAAA;AAEjE,SAAS,QAAA,GAA8B;AAC5C,EAAA,MAAM,GAAA,GAAM,WAAW,YAAY,CAAA;AACnC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,OAAO,GAAA;AACT;ACNA,IAAM,cAAA,GAAiB;AAAA,EACrB,OAAA,EACE,gPAAA;AAAA,EACF,OAAA,EACE,8EAAA;AAAA,EACF,KAAA,EACE,8DAAA;AAAA,EACF,OAAA,EACE,sEAAA;AAAA,EACF,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,mBAAA,GAAsB;AAAA,EAC1B,OAAA,EAAS,eAAA;AAAA,EACT,OAAA,EAAS,kBAAA;AAAA,EACT,KAAA,EAAO,cAAA;AAAA,EACP,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAA;AAEO,SAAS,SAAA,CAAU,EAAE,IAAA,EAAM,SAAA,EAAU,EAAmB;AAC7D,EAAA,MAAM,EAAE,EAAA,EAAI,KAAA,EAAO,aAAa,OAAA,GAAU,SAAA,EAAW,QAAO,GAAI,IAAA;AAEhE,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,KAAa,MAAA,GAAS,CAAA,GAAI,GAAA,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAY,CAAA,EAAG;AACnB,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,SAAA,CAAU,EAAE,GAAG,QAAQ,CAAA;AACtD,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,EAAA,EAAI,QAAA,EAAU,SAAS,CAAC,CAAA;AAE5B,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,6BAAA,EAA4B,EAAA;AAAA,MAC5B,IAAA,EAAK,OAAA;AAAA,MAGL,SAAA,EAAW,CAAC,CAAA,KAAM;AAChB,QAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,QAAA,EAAU,SAAA,CAAU,EAAE,CAAA;AAAA,MACtC,CAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,yEAAA;AAAA,QACA,eAAe,OAAO;AAAA,OACxB;AAAA,MAEA,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,SAAI,SAAA,EAAW,EAAA,CAAG,mBAAmB,mBAAA,CAAoB,OAAO,CAAC,CAAA,EAC/D,QAAA,EAAA;AAAA,UAAA,OAAA,KAAY,SAAA,oBAAa,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI,CAAA;AAAA,UAC1C,OAAA,KAAY,OAAA,oBAAW,GAAA,CAAC,OAAA,EAAA,EAAQ,MAAM,EAAA,EAAI,CAAA;AAAA,UAC1C,OAAA,KAAY,SAAA,oBAAa,GAAA,CAAC,aAAA,EAAA,EAAc,MAAM,EAAA,EAAI,CAAA;AAAA,UAClD,OAAA,KAAY,MAAA,oBAAU,GAAA,CAAC,IAAA,EAAA,EAAK,MAAM,EAAA,EAAI;AAAA,SAAA,EACzC,CAAA;AAAA,wBACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yIAAA,EAA2I,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,UAC7J,WAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,gJACV,QAAA,EAAA,WAAA,EACH;AAAA,SAAA,EAEJ,CAAA;AAAA,QACC,MAAA,oBACC,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,SAAS,MAAM;AACb,cAAA,MAAA,CAAO,OAAA,EAAQ;AAGf,cAAA,SAAA,CAAU,EAAE,CAAA;AAAA,YACd,CAAA;AAAA,YACA,SAAA,EAAU,mSAAA;AAAA,YAET,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV;AAAA,wBAEF,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAS,MAAM,SAAA,CAAU,EAAE,CAAA;AAAA,YAC3B,SAAA,EAAU,qGAAA;AAAA,YACV,YAAA,EAAW,SAAA;AAAA,YAEX,QAAA,kBAAA,GAAA,CAAC,CAAA,EAAA,EAAE,IAAA,EAAM,EAAA,EAAI;AAAA;AAAA;AACf,OAAA,EACF;AAAA;AAAA,GACF;AAEJ;AAEA,SAAA,CAAU,WAAA,GAAc,WAAA;ACxDxB,IAAM,eAAA,GAAiD;AAAA,EACrD,WAAA,EAAa,eAAA;AAAA,EACb,UAAA,EAAY,cAAA;AAAA,EACZ,cAAA,EAAgB,kBAAA;AAAA,EAChB,aAAA,EAAe;AACjB,CAAA;AAGA,IAAM,UAAA,GAAa,EAAA;AAEnB,IAAM,IAAA,GACJ,gRAAA;AAEF,SAAS,UAAA,CAAW,MAAe,KAAA,EAAuB;AACxD,EAAA,MAAM,KAAM,IAAA,EAAkC,EAAA;AAC9C,EAAA,OAAO,OAAO,EAAA,KAAO,QAAA,IAAY,OAAO,EAAA,KAAO,WAAW,MAAA,CAAO,EAAE,CAAA,GAAI,MAAA,CAAO,KAAK,CAAA;AACrF;AAEA,SAAS,YAAY,MAAA,EAAqC;AACxD,EAAA,IAAI,EAAE,MAAA,YAAkB,WAAA,CAAA,EAAc,OAAO,KAAA;AAC7C,EAAA,OACE,MAAA,CAAO,iBAAA,IACP,MAAA,CAAO,YAAA,CAAa,iBAAiB,MAAM,MAAA,IAC3C,2BAAA,CAA4B,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA;AAEnD;AAaO,SAAS,UAAA,CAAc;AAAA,EAC5B,KAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA,GAAS,UAAA;AAAA,EACT,KAAA,GAAQ,CAAA;AAAA,EACR,MAAA,GAAS,CAAA;AAAA,EACT,SAAA,GAAY,IAAA;AAAA,EACZ,UAAA,EAAY,eAAA;AAAA,EACZ,iBAAA,GAAoB,CAAA;AAAA,EACpB,kBAAA;AAAA,EACA,QAAA,GAAW,cAAA;AAAA,EACX,KAAA,GAAQ,eAAA;AAAA,EACR,aAAA;AAAA,EACA;AACF,CAAA,EAAuB;AACrB,EAAA,MAAM,CAAC,QAAA,EAAU,QAAQ,CAAA,GAAI,oBAAA;AAAA,IAC3B,eAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,QAAQ,KAAA,CAAM,MAAA;AAGpB,EAAA,MAAM,QAAQ,KAAA,KAAU,CAAA,GAAI,CAAA,GAAA,CAAM,QAAA,GAAW,QAAS,KAAA,IAAS,KAAA;AAE/D,EAAA,MAAM,QAAA,GAAW,OAAuB,IAAI,CAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,OAAO,CAAC,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,EAAE,KAAA,EAAO,OAAO,CAAA;AACpC,EAAA,IAAA,CAAK,OAAA,GAAU,EAAE,KAAA,EAAO,KAAA,EAAM;AAE9B,EAAA,MAAM,IAAA,GAAO,CAAC,EAAA,KAAe;AAC3B,IAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,CAAA,KAAM,IAAA,CAAK,OAAA;AAC1C,IAAA,IAAI,IAAI,CAAA,EAAG;AACX,IAAA,QAAA,CAAA,CAAA,CAAY,OAAA,GAAU,EAAA,IAAM,CAAA,GAAK,CAAA,IAAK,CAAC,CAAA;AAAA,EACzC,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,OAAO,IAAI,CAAA;AAC3B,EAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAOlB,EAAAA,UAAU,MAAM;AACd,IAAA,MAAM,KAAK,QAAA,CAAS,OAAA;AACpB,IAAA,IAAI,CAAC,EAAA,EAAI;AAET,IAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAkB;AACjC,MAAA,IAAI,KAAK,OAAA,CAAQ,KAAA,GAAQ,CAAA,IAAK,CAAA,CAAE,WAAW,CAAA,EAAG;AAC9C,MAAA,CAAA,CAAE,cAAA,EAAe;AAGjB,MAAA,IAAI,CAAA,CAAE,cAAc,CAAA,EAAG;AACrB,QAAA,WAAA,CAAY,OAAA,GAAU,CAAA;AACtB,QAAA,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,MAAM,CAAC,CAAA;AACnC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAM,KAAK,UAAA,EAAY;AACpC,QAAA,WAAA,CAAY,OAAA,GAAU,CAAA;AACtB,QAAA,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,CAAA,CAAE,MAAM,CAAC,CAAA;AACnC,QAAA;AAAA,MACF;AACA,MAAA,WAAA,CAAY,WAAW,CAAA,CAAE,MAAA;AACzB,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,WAAA,CAAY,OAAO,KAAK,UAAA,EAAY;AAC/C,QAAA,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,WAAA,CAAY,OAAO,CAAC,CAAA;AAC9C,QAAA,WAAA,CAAY,OAAA,GAAU,CAAA;AAAA,MACxB;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,OAAA,EAAS,OAAO,CAAA;AACxD,IAAA,OAAO,MAAM,EAAA,CAAG,mBAAA,CAAoB,OAAA,EAAS,OAAO,CAAA;AAAA,EAGtD,CAAA,EAAG,CAAC,KAAA,GAAQ,CAAA,EAAG,QAAQ,CAAC,CAAA;AAExB,EAAA,IAAI,KAAA,KAAU,GAAG,OAAO,IAAA;AAExB,EAAA,MAAM,aAAA,GAAgB,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG,KAAK,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAA;AAC5D,EAAA,MAAM,MAAA,GAAS,QAAQ,CAAA,GAAI,aAAA;AAE3B,EAAA,MAAM,IAAA,GAAO,CAAC,KAAA,EAAe,CAAA,KAAc;AACzC,IAAA,MAAM,IAAA,GAAO,MAAM,KAAK,CAAA;AACxB,IAAA,MAAM,UAAU,CAAA,KAAM,CAAA;AACtB,IAAA,uBACEC,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QAEC,mCAAA,EAAmC,UAAU,OAAA,GAAU,QAAA;AAAA,QACvD,aAAA,EAAa,UAAU,MAAA,GAAY,IAAA;AAAA,QACnC,KAAA,EAAO,UAAU,MAAA,GAAY,IAAA;AAAA,QAC7B,SAAA,EAAW,EAAA;AAAA,UACT,IAAA;AAAA,UACA,8CAAA;AAAA,UACA,UAAU,UAAA,GAAa,sDAAA;AAAA,UACvB;AAAA,SACF;AAAA,QACA,KAAA,EAAO;AAAA,UACL,MAAA,EAAQ,QAAQ,CAAA,GAAI,CAAA;AAAA,UACpB,SAAA,EAAW,UAAU,MAAA,GAAY,CAAA,YAAA,EAAe,IAAI,MAAM,CAAA,UAAA,EAAa,CAAA,GAAI,CAAA,GAAI,SAAS,CAAA,CAAA;AAAA,SAC1F;AAAA,QAEC,QAAA,EAAA,UAAA,CAAW,IAAA,EAAM,EAAE,KAAA,EAAO,SAAS;AAAA,OAAA;AAAA,MAf/B,MAAA,CAAO,MAAM,KAAK;AAAA,KAgBzB;AAAA,EAEJ,CAAA;AAEA,EAAA,MAAM,0BACJC,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,QAAA;AAAA,MACL,8BAAA,EAA6B,EAAA;AAAA,MAC7B,IAAA,EAAK,QAAA;AAAA,MACL,YAAA,EAAY,KAAA;AAAA,MACZ,QAAA,EAAU,CAAA;AAAA,MACV,SAAA,EAAW,CAAC,CAAA,KAAM;AAChB,QAAA,IAAI,WAAA,CAAY,CAAA,CAAE,MAAM,CAAA,EAAG;AAC3B,QAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,WAAA,IAAe,CAAA,CAAE,QAAQ,YAAA,EAAc;AACnD,UAAA,CAAA,CAAE,cAAA,EAAe;AACjB,UAAA,IAAA,CAAK,CAAC,CAAA;AAAA,QACR,WAAW,CAAA,CAAE,GAAA,KAAQ,SAAA,IAAa,CAAA,CAAE,QAAQ,WAAA,EAAa;AACvD,UAAA,CAAA,CAAE,cAAA,EAAe;AACjB,UAAA,IAAA,CAAK,EAAE,CAAA;AAAA,QACT;AAAA,MACF,CAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,0IAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,KAAA,EAAO,EAAE,UAAA,EAAY,aAAA,GAAgB,MAAA,EAAO;AAAA,MAE5C,QAAA,EAAA;AAAA,wBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EAQZ,QAAA,EAAA;AAAA,UAAA,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,UACb,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,aAAA,EAAc,EAAG,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,CAAE,GAAA;AAAA,YAAI,CAAC,CAAA,KAC3D,IAAA,CAAA,CAAM,KAAA,GAAQ,CAAA,IAAK,OAAO,CAAC;AAAA;AAC7B,SAAA,EACF,CAAA;AAAA,QACC,MAAA,GAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASRA,IAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,mCAAA,EAAkC,EAAA;AAAA,YAClC,IAAA,EAAK,IAAA;AAAA,YACL,OAAA,EAAQ,MAAA;AAAA,YACR,KAAA,EAAM,MAAA;AAAA,YACN,SAAA,EAAU,2MAAA;AAAA,YACX,QAAA,EAAA;AAAA,cAAA,GAAA;AAAA,cACG;AAAA;AAAA;AAAA,SACJ;AAAA,wBAEFD,GAAAA,CAAC,MAAA,EAAA,EAAK,qCAAA,EAAoC,EAAA,EAAG,aAAU,QAAA,EAAS,SAAA,EAAU,SAAA,EACvE,QAAA,EAAA,KAAA,GAAQ,IAAI,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAA,IAAA,EAAO,KAAK,KAAK,EAAA,EAC5C;AAAA;AAAA;AAAA,GACF;AAGF,EAAA,IAAI,QAAA,KAAa,UAAU,OAAO,OAAA;AAElC,EAAA,uBACEA,GAAAA,CAAC,MAAA,EAAA,EACC,QAAA,kBAAAA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,uCAAA,EAAuC,QAAA;AAAA,MACvC,SAAA,EAAW,EAAA,CAAG,mCAAA,EAAqC,eAAA,CAAgB,QAAQ,CAAC,CAAA;AAAA,MAE3E,QAAA,EAAA;AAAA;AAAA,GACH,EACF,CAAA;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,YAAA;ACvPzB,IAAME,gBAAAA,GAAkB;AAAA,EACtB,WAAA,EAAa,eAAA;AAAA,EACb,UAAA,EAAY,cAAA;AAAA,EACZ,cAAA,EAAgB,kBAAA;AAAA,EAChB,aAAA,EAAe;AACjB,CAAA;AAEA,SAAS,aAAA,CAAc;AAAA,EACrB,QAAA;AAAA,EACA,QAAA,GAAW,cAAA;AAAA,EACX,SAAA,GAAY;AACd,CAAA,EAAuB;AACrB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAA,CAAsB,EAAE,CAAA;AACpD,EAAA,MAAM,SAAA,GAAYC,OAAO,CAAC,CAAA;AAE1B,EAAA,MAAM,KAAA,GAAQ,WAAA;AAAA,IACZ,CAAC,IAAA,KAAgC;AAC/B,MAAA,MAAM,EAAA,GAAK,CAAA,MAAA,EAAS,EAAE,SAAA,CAAU,OAAO,CAAA,CAAA;AACvC,MAAA,SAAA,CAAU,CAAC,IAAA,KAAS,CAAC,GAAG,KAAK,KAAA,CAAM,EAAE,SAAA,GAAY,CAAA,CAAE,GAAG,EAAE,GAAG,IAAA,EAAM,EAAA,EAAI,CAAC,CAAA;AACtE,MAAA,OAAO,EAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,SAAS;AAAA,GACZ;AAEA,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,CAAC,EAAA,KAAe;AAC1C,IAAA,SAAA,CAAU,CAAC,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AAAA,EACrD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAQ,CAAA,EAAI,CAAC,MAAA,EAAQ,KAAA,EAAO,OAAO,CAAC,CAAA;AAEhF,EAAA,uBACEF,IAAAA,CAAC,YAAA,CAAa,QAAA,EAAb,EAAsB,OAAO,GAAA,EAC3B,QAAA,EAAA;AAAA,IAAA,QAAA;AAAA,oBACDD,GAAAA,CAAC,MAAA,EAAA,EACC,QAAA,kBAAAA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,wBAAA,EAAuB,EAAA;AAAA,QACvB,SAAA,EAAW,EAAA;AAAA,UACT,uDAAA;AAAA,UACAE,iBAAgB,QAAQ;AAAA,SAC1B;AAAA,QAEC,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,qBACXF,GAAAA,CAAC,SAAA,EAAA,EAAqB,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,OAAA,EAAA,EAA1B,CAAA,CAAE,EAAiC,CACpD;AAAA;AAAA,KACH,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;AAEO,IAAM,KAAA,GAAQ;AAAA,EACnB,QAAA,EAAU,aAAA;AAAA,EACV,KAAA,EAAO,UAAA;AAAA,EACP,IAAA,EAAM;AACR","file":"chunk-BQFPC5FL.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ToastContextValue } from \"./Toast.types\";\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) {\n throw new Error(\"useToast must be used within a <Toast.Provider>\");\n }\n return ctx;\n}\n","import { useEffect } from \"react\";\nimport { AlertTriangle, Check, Info, X, XCircle } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport type { ToastItemProps } from \"./Toast.types\";\n\nconst VARIANT_STYLES = {\n default:\n \"border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n success:\n \"border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950\",\n error:\n \"border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950\",\n warning:\n \"border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950\",\n info: \"border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950\",\n} as const;\n\nconst VARIANT_ICON_COLORS = {\n default: \"text-zinc-400\",\n success: \"text-emerald-500\",\n error: \"text-red-500\",\n warning: \"text-amber-500\",\n info: \"text-blue-500\",\n} as const;\n\nexport function ToastItem({ data, onDismiss }: ToastItemProps) {\n const { id, title, description, variant = \"default\", action } = data;\n // An action toast does not expire by default.\n const duration = data.duration ?? (action ? 0 : 5000);\n\n useEffect(() => {\n if (duration <= 0) return;\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }, [id, duration, onDismiss]);\n\n return (\n <div\n data-react-fancy-toast-item=\"\"\n role=\"alert\"\n // Scoped to the toast rather than the document: a global Escape handler\n // would fight whatever modal or drawer is already listening.\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onDismiss(id);\n }}\n className={cn(\n \"fancy-toast-in pointer-events-auto w-80 rounded-xl border p-4 shadow-lg\",\n VARIANT_STYLES[variant],\n )}\n >\n <div className=\"flex items-start gap-3\">\n <div className={cn(\"mt-0.5 shrink-0\", VARIANT_ICON_COLORS[variant])}>\n {variant === \"success\" && <Check size={16} />}\n {variant === \"error\" && <XCircle size={16} />}\n {variant === \"warning\" && <AlertTriangle size={16} />}\n {variant === \"info\" && <Info size={16} />}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{title}</p>\n {description && (\n <p className=\"mt-1 text-xs text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\">\n {description}\n </p>\n )}\n </div>\n {action && (\n <button\n type=\"button\"\n onClick={() => {\n action.onClick();\n // The offer is consumed; leaving it up invites undoing an\n // already-undone action.\n onDismiss(id);\n }}\n className=\"shrink-0 self-center rounded-md px-2 py-1 text-xs font-medium text-zinc-700 underline-offset-2 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:underline dark:text-zinc-200 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {action.label}\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onDismiss(id)}\n className=\"shrink-0 rounded p-0.5 text-zinc-400 transition-colors hover:text-zinc-600 dark:hover:text-zinc-300\"\n aria-label=\"Dismiss\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n );\n}\n\nToastItem.displayName = \"ToastItem\";\n","import { useEffect, useRef, type ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport { Portal } from \"../Portal\";\nimport { Badge } from \"../Badge\";\nimport type { ToastPosition } from \"./Toast.types\";\n\nexport interface ToastStackProps<T> {\n /**\n * Everything to show — the stack is a VIEW of this list and owns none of it.\n * There is no limit and no timer: an item leaves only when you remove it.\n */\n items: readonly T[];\n /** One card's content, actions included. Only the front card is interactive. */\n renderItem: (item: T, state: { index: number; isFront: boolean }) => ReactNode;\n /** A stable key per item. Defaults to `item.id`, then the index. */\n getKey?: (item: T, index: number) => string;\n /** How many cards show behind the front one. Default 2. */\n depth?: number;\n /** How far each card behind peeks out above the one in front, in px. Default 8. */\n offset?: number;\n /** How much smaller each card behind is than the one in front. Default 0.05. */\n scaleStep?: number;\n /** Which item is in front, if you want to own it. Wraps; out-of-range values are clamped. */\n frontIndex?: number;\n defaultFrontIndex?: number;\n onFrontIndexChange?: (index: number) => void;\n /** A screen corner, or `\"inline\"` to render where it is placed. Default `\"bottom-right\"`. */\n position?: ToastPosition | \"inline\";\n /** The stack's accessible name. Default \"Notifications\". */\n label?: string;\n /** Classes for each card's shell, merged onto the defaults. */\n cardClassName?: string;\n className?: string;\n}\n\nconst POSITION_STYLES: Record<ToastPosition, string> = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n};\n\n/** Pixels of wheel travel that count as one step. A mouse notch is ~100; a trackpad sends many small ones. */\nconst WHEEL_STEP = 50;\n\nconst CARD =\n \"rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] p-4 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\";\n\nfunction defaultKey(item: unknown, index: number): string {\n const id = (item as { id?: unknown } | null)?.id;\n return typeof id === \"string\" || typeof id === \"number\" ? String(id) : String(index);\n}\n\nfunction isTextField(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.isContentEditable ||\n target.getAttribute(\"contenteditable\") === \"true\" ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName)\n );\n}\n\n/**\n * A controlled stack of actionable toasts — approval requests, say — that the\n * person walks through rather than races.\n *\n * Built for react-fancy#33. The owner's requirements were that requests stack\n * behind each other with a slight top offset, that scrolling over the stack\n * walks through them, and that a pending request NEVER expires or disappears.\n * The last is why this is a view of the caller's list rather than a queue it\n * keeps: there is nothing here that can drop an item, because nothing here owns\n * one. (The imperative provider's `maxToasts` silently drops the oldest.)\n */\nexport function ToastStack<T>({\n items,\n renderItem,\n getKey = defaultKey,\n depth = 2,\n offset = 8,\n scaleStep = 0.05,\n frontIndex: controlledFront,\n defaultFrontIndex = 0,\n onFrontIndexChange,\n position = \"bottom-right\",\n label = \"Notifications\",\n cardClassName,\n className,\n}: ToastStackProps<T>) {\n const [rawFront, setFront] = useControllableState(\n controlledFront,\n defaultFrontIndex,\n onFrontIndexChange,\n );\n const count = items.length;\n // Clamped for display rather than corrected through onChange: a list that\n // shrinks under a far-forward index must not make render report a change.\n const front = count === 0 ? 0 : ((rawFront % count) + count) % count;\n\n const stackRef = useRef<HTMLDivElement>(null);\n const wheelTravel = useRef(0);\n const live = useRef({ front, count });\n live.current = { front, count };\n\n const step = (by: number) => {\n const { front: current, count: n } = live.current;\n if (n < 2) return;\n setFront((((current + by) % n) + n) % n);\n };\n const stepRef = useRef(step);\n stepRef.current = step;\n\n /*\n * A native listener, because React's wheel listener is passive and cannot stop\n * the page scrolling underneath — and a stack that cycles AND scrolls the page\n * moves two things at once under the person's hand.\n */\n useEffect(() => {\n const el = stackRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (live.current.count < 2 || e.deltaY === 0) return;\n e.preventDefault();\n\n // Line or page mode: every event is a notch.\n if (e.deltaMode !== 0) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n // A notch-sized event steps at once; small trackpad deltas add up first.\n if (Math.abs(e.deltaY) >= WHEEL_STEP) {\n wheelTravel.current = 0;\n stepRef.current(Math.sign(e.deltaY));\n return;\n }\n wheelTravel.current += e.deltaY;\n if (Math.abs(wheelTravel.current) >= WHEEL_STEP) {\n stepRef.current(Math.sign(wheelTravel.current));\n wheelTravel.current = 0;\n }\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n // Re-bound when the element can change: it appears with the first item, and\n // moving between a corner and inline remounts it.\n }, [count > 0, position]);\n\n if (count === 0) return null;\n\n const visibleBehind = Math.min(Math.max(0, depth), count - 1);\n const hidden = count - 1 - visibleBehind;\n\n const card = (index: number, k: number) => {\n const item = items[index];\n const isFront = k === 0;\n return (\n <div\n key={getKey(item, index)}\n data-react-fancy-toast-stack-card={isFront ? \"front\" : \"behind\"}\n aria-hidden={isFront ? undefined : true}\n inert={isFront ? undefined : true}\n className={cn(\n CARD,\n \"origin-top transition-transform duration-200\",\n isFront ? \"relative\" : \"pointer-events-none absolute inset-0 overflow-hidden\",\n cardClassName,\n )}\n style={{\n zIndex: depth + 1 - k,\n transform: isFront ? undefined : `translateY(-${k * offset}px) scale(${1 - k * scaleStep})`,\n }}\n >\n {renderItem(item, { index, isFront })}\n </div>\n );\n };\n\n const stackEl = (\n <div\n ref={stackRef}\n data-react-fancy-toast-stack=\"\"\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n onKeyDown={(e) => {\n if (isTextField(e.target)) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n step(1);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n step(-1);\n }\n }}\n className={cn(\n \"pointer-events-auto relative w-80 rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-violet-500 focus-visible:ring-offset-2\",\n className,\n )}\n style={{ paddingTop: visibleBehind * offset }}\n >\n <div className=\"relative\">\n {/*\n * z-index decides what paints on top; the front card sizes the box.\n * The front card comes FIRST in the DOM, then the cards behind in walk\n * order: the ones behind are absolutely positioned against this box, so\n * their place in the source changes nothing visible -- but it is what\n * a DOM query, `textContent` and copy-paste read.\n */}\n {card(front, 0)}\n {Array.from({ length: visibleBehind }, (_, i) => i + 1).map((k) =>\n card((front + k) % count, k),\n )}\n </div>\n {hidden > 0 && (\n /*\n * Opaque in BOTH themes, because it sits over the cards peeking out\n * behind the front one -- often a light image header. The soft zinc\n * Badge is `dark:bg-zinc-900/30`, which let that image through and left\n * zinc-300 text on a light screenshot (fancy-app-update#1). The dark\n * pair is overridden here, not in Badge, so every other soft badge\n * keeps its look; the ring separates it from a zinc-900 card edge.\n */\n <Badge\n data-react-fancy-toast-stack-more=\"\"\n size=\"sm\"\n variant=\"soft\"\n color=\"zinc\"\n className=\"absolute -top-2 right-2 z-20 shadow-sm ring-1 ring-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-zinc-800 dark:text-zinc-100 dark:ring-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n >\n +{hidden}\n </Badge>\n )}\n <span data-react-fancy-toast-stack-status=\"\" aria-live=\"polite\" className=\"sr-only\">\n {count > 1 ? `${front + 1} of ${count}` : \"\"}\n </span>\n </div>\n );\n\n if (position === \"inline\") return stackEl;\n\n return (\n <Portal>\n <div\n data-react-fancy-toast-stack-position={position}\n className={cn(\"pointer-events-none fixed z-[100]\", POSITION_STYLES[position])}\n >\n {stackEl}\n </div>\n </Portal>\n );\n}\n\nToastStack.displayName = \"ToastStack\";\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ToastContext } from \"./Toast.context\";\nimport { ToastItem } from \"./ToastItem\";\nimport { ToastStack } from \"./ToastStack\";\nimport type { ToastData, ToastProviderProps } from \"./Toast.types\";\n\nconst POSITION_STYLES = {\n \"top-right\": \"top-4 right-4\",\n \"top-left\": \"top-4 left-4\",\n \"bottom-right\": \"bottom-4 right-4\",\n \"bottom-left\": \"bottom-4 left-4\",\n} as const;\n\nfunction ToastProvider({\n children,\n position = \"bottom-right\",\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n const idCounter = useRef(0);\n\n const toast = useCallback(\n (data: Omit<ToastData, \"id\">) => {\n const id = `toast-${++idCounter.current}`;\n setToasts((prev) => [...prev.slice(-(maxToasts - 1)), { ...data, id }]);\n return id;\n },\n [maxToasts],\n );\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const ctx = useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);\n\n return (\n <ToastContext.Provider value={ctx}>\n {children}\n <Portal>\n <div\n data-react-fancy-toast=\"\"\n className={cn(\n \"fixed z-[100] flex flex-col gap-2 pointer-events-none\",\n POSITION_STYLES[position],\n )}\n >\n {toasts.map((t) => (\n <ToastItem key={t.id} data={t} onDismiss={dismiss} />\n ))}\n </div>\n </Portal>\n </ToastContext.Provider>\n );\n}\n\nexport const Toast = {\n Provider: ToastProvider,\n Stack: ToastStack,\n Item: ToastItem,\n};\n"]}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
2
|
+
import { useRef, useState, useCallback, useLayoutEffect, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
// src/utils/scroll-lock.ts
|
|
5
|
+
var holders = 0;
|
|
6
|
+
var saved = "";
|
|
7
|
+
function lockBodyScroll() {
|
|
8
|
+
if (holders === 0) {
|
|
9
|
+
saved = document.body.style.overflow;
|
|
10
|
+
document.body.style.overflow = "hidden";
|
|
11
|
+
}
|
|
12
|
+
holders++;
|
|
13
|
+
let released = false;
|
|
14
|
+
return () => {
|
|
15
|
+
if (released) return;
|
|
16
|
+
released = true;
|
|
17
|
+
holders--;
|
|
18
|
+
if (holders === 0) document.body.style.overflow = saved;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/hooks/use-full-screen.ts
|
|
23
|
+
var FOCUSABLE = [
|
|
24
|
+
"a[href]",
|
|
25
|
+
"button:not([disabled])",
|
|
26
|
+
"input:not([disabled])",
|
|
27
|
+
"textarea:not([disabled])",
|
|
28
|
+
"select:not([disabled])",
|
|
29
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
30
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
31
|
+
].join(", ");
|
|
32
|
+
var activeStack = [];
|
|
33
|
+
var OVERLAY_STYLE = {
|
|
34
|
+
position: "fixed",
|
|
35
|
+
top: 0,
|
|
36
|
+
right: 0,
|
|
37
|
+
bottom: 0,
|
|
38
|
+
left: 0,
|
|
39
|
+
width: "100%",
|
|
40
|
+
height: "100%",
|
|
41
|
+
maxWidth: "none",
|
|
42
|
+
maxHeight: "none",
|
|
43
|
+
margin: 0,
|
|
44
|
+
borderRadius: 0,
|
|
45
|
+
boxSizing: "border-box"
|
|
46
|
+
};
|
|
47
|
+
var promoted = /* @__PURE__ */ new Map();
|
|
48
|
+
function promoteToTopLayer(el, onLost) {
|
|
49
|
+
const p = el;
|
|
50
|
+
if (typeof p.showPopover !== "function" || typeof p.hidePopover !== "function") return null;
|
|
51
|
+
if (el.hasAttribute("popover")) return null;
|
|
52
|
+
el.setAttribute("popover", "manual");
|
|
53
|
+
try {
|
|
54
|
+
p.showPopover();
|
|
55
|
+
} catch {
|
|
56
|
+
el.removeAttribute("popover");
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
let open = true;
|
|
60
|
+
let raising = false;
|
|
61
|
+
const onToggle = (e) => {
|
|
62
|
+
if (raising || e.newState !== "closed" || !open) return;
|
|
63
|
+
open = false;
|
|
64
|
+
promoted.delete(el);
|
|
65
|
+
el.removeEventListener("toggle", onToggle);
|
|
66
|
+
el.removeAttribute("popover");
|
|
67
|
+
onLost();
|
|
68
|
+
};
|
|
69
|
+
el.addEventListener("toggle", onToggle);
|
|
70
|
+
for (const [other, raise] of promoted) {
|
|
71
|
+
if (other !== el && el.contains(other)) raise();
|
|
72
|
+
}
|
|
73
|
+
promoted.set(el, () => {
|
|
74
|
+
raising = true;
|
|
75
|
+
try {
|
|
76
|
+
p.hidePopover();
|
|
77
|
+
p.showPopover();
|
|
78
|
+
} catch {
|
|
79
|
+
} finally {
|
|
80
|
+
raising = false;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return () => {
|
|
84
|
+
promoted.delete(el);
|
|
85
|
+
el.removeEventListener("toggle", onToggle);
|
|
86
|
+
if (open) {
|
|
87
|
+
open = false;
|
|
88
|
+
try {
|
|
89
|
+
p.hidePopover();
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
el.removeAttribute("popover");
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function useFullScreen(options = {}) {
|
|
97
|
+
const {
|
|
98
|
+
fullScreen: controlled,
|
|
99
|
+
defaultFullScreen = false,
|
|
100
|
+
onFullScreenChange,
|
|
101
|
+
mode = "overlay",
|
|
102
|
+
closeOnEscape = true,
|
|
103
|
+
lockScroll = true,
|
|
104
|
+
zIndex = 50,
|
|
105
|
+
labels
|
|
106
|
+
} = options;
|
|
107
|
+
const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);
|
|
108
|
+
const ref = useRef(null);
|
|
109
|
+
const token = useRef({});
|
|
110
|
+
const [nativeActive, setNativeActive] = useState(false);
|
|
111
|
+
const [portalContainer, setPortalContainer] = useState(null);
|
|
112
|
+
const [applied, setApplied] = useState(fullScreen);
|
|
113
|
+
const [layer, setLayer] = useState("fixed");
|
|
114
|
+
const topRelease = useRef(null);
|
|
115
|
+
const promote = (el) => {
|
|
116
|
+
if (topRelease.current) return;
|
|
117
|
+
topRelease.current = promoteToTopLayer(el, () => {
|
|
118
|
+
topRelease.current = null;
|
|
119
|
+
setLayer("fixed");
|
|
120
|
+
});
|
|
121
|
+
setLayer(topRelease.current ? "top" : "fixed");
|
|
122
|
+
};
|
|
123
|
+
const demote = () => {
|
|
124
|
+
topRelease.current?.();
|
|
125
|
+
topRelease.current = null;
|
|
126
|
+
};
|
|
127
|
+
const current = useRef(fullScreen);
|
|
128
|
+
current.current = fullScreen;
|
|
129
|
+
const setFullScreen = useCallback(
|
|
130
|
+
(next) => {
|
|
131
|
+
if (current.current === next) return;
|
|
132
|
+
current.current = next;
|
|
133
|
+
setState(next);
|
|
134
|
+
},
|
|
135
|
+
[setState]
|
|
136
|
+
);
|
|
137
|
+
const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);
|
|
138
|
+
useLayoutEffect(() => {
|
|
139
|
+
if (!fullScreen) return;
|
|
140
|
+
const el = ref.current;
|
|
141
|
+
if (!el) return;
|
|
142
|
+
const scrolled = [];
|
|
143
|
+
for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {
|
|
144
|
+
if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });
|
|
145
|
+
}
|
|
146
|
+
const winX = window.scrollX;
|
|
147
|
+
const winY = window.scrollY;
|
|
148
|
+
const release = lockScroll ? lockBodyScroll() : null;
|
|
149
|
+
activeStack.push(token.current);
|
|
150
|
+
setPortalContainer(el);
|
|
151
|
+
setApplied(true);
|
|
152
|
+
const native = mode === "native" && typeof el.requestFullscreen === "function" && document.fullscreenEnabled !== false;
|
|
153
|
+
if (!native) promote(el);
|
|
154
|
+
return () => {
|
|
155
|
+
const i = activeStack.indexOf(token.current);
|
|
156
|
+
if (i >= 0) activeStack.splice(i, 1);
|
|
157
|
+
demote();
|
|
158
|
+
setLayer("fixed");
|
|
159
|
+
release?.();
|
|
160
|
+
for (const m of scrolled) {
|
|
161
|
+
if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;
|
|
162
|
+
if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;
|
|
163
|
+
}
|
|
164
|
+
if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);
|
|
165
|
+
setPortalContainer(null);
|
|
166
|
+
setApplied(false);
|
|
167
|
+
};
|
|
168
|
+
}, [fullScreen, lockScroll, mode]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!fullScreen) return;
|
|
171
|
+
const el = ref.current;
|
|
172
|
+
if (!el) return;
|
|
173
|
+
const opener = document.activeElement instanceof HTMLElement && document.activeElement !== document.body ? document.activeElement : null;
|
|
174
|
+
if (!el.contains(document.activeElement)) {
|
|
175
|
+
el.querySelector(FOCUSABLE)?.focus({ preventScroll: true });
|
|
176
|
+
}
|
|
177
|
+
return () => {
|
|
178
|
+
const active = document.activeElement;
|
|
179
|
+
if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {
|
|
180
|
+
opener.focus({ preventScroll: true });
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}, [fullScreen]);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (!fullScreen || mode !== "native") return;
|
|
186
|
+
const el = ref.current;
|
|
187
|
+
if (!el || typeof el.requestFullscreen !== "function" || document.fullscreenEnabled === false) return;
|
|
188
|
+
let cancelled = false;
|
|
189
|
+
let entered = false;
|
|
190
|
+
const onChange = () => {
|
|
191
|
+
if (document.fullscreenElement === el) {
|
|
192
|
+
entered = true;
|
|
193
|
+
setNativeActive(true);
|
|
194
|
+
setLayer("top");
|
|
195
|
+
} else if (entered) {
|
|
196
|
+
entered = false;
|
|
197
|
+
setNativeActive(false);
|
|
198
|
+
setLayer("fixed");
|
|
199
|
+
if (!cancelled) setFullScreen(false);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
document.addEventListener("fullscreenchange", onChange);
|
|
203
|
+
const refused = () => {
|
|
204
|
+
if (!cancelled && current.current && ref.current === el) promote(el);
|
|
205
|
+
};
|
|
206
|
+
try {
|
|
207
|
+
Promise.resolve(el.requestFullscreen()).then(onChange, refused);
|
|
208
|
+
} catch {
|
|
209
|
+
refused();
|
|
210
|
+
}
|
|
211
|
+
return () => {
|
|
212
|
+
cancelled = true;
|
|
213
|
+
document.removeEventListener("fullscreenchange", onChange);
|
|
214
|
+
if (document.fullscreenElement === el) {
|
|
215
|
+
try {
|
|
216
|
+
Promise.resolve(document.exitFullscreen()).catch(() => {
|
|
217
|
+
});
|
|
218
|
+
} catch {
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
setNativeActive(false);
|
|
222
|
+
};
|
|
223
|
+
}, [fullScreen, mode, setFullScreen]);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (!fullScreen || !closeOnEscape) return;
|
|
226
|
+
const onKey = (e) => {
|
|
227
|
+
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
228
|
+
const t = e.target;
|
|
229
|
+
if (t !== document.body && t !== document.documentElement && t !== document) return;
|
|
230
|
+
if (activeStack[activeStack.length - 1] !== token.current) return;
|
|
231
|
+
setFullScreen(false);
|
|
232
|
+
};
|
|
233
|
+
document.addEventListener("keydown", onKey);
|
|
234
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
235
|
+
}, [fullScreen, closeOnEscape, setFullScreen]);
|
|
236
|
+
const onKeyDown = useCallback(
|
|
237
|
+
(e) => {
|
|
238
|
+
if (!current.current || e.defaultPrevented) return;
|
|
239
|
+
const el = ref.current;
|
|
240
|
+
if (!el) return;
|
|
241
|
+
if (e.key === "Tab") {
|
|
242
|
+
const items = Array.from(el.querySelectorAll(FOCUSABLE));
|
|
243
|
+
if (items.length === 0) return;
|
|
244
|
+
const first = items[0];
|
|
245
|
+
const last = items[items.length - 1];
|
|
246
|
+
const active = document.activeElement;
|
|
247
|
+
if (e.shiftKey && (active === first || active === el)) {
|
|
248
|
+
e.preventDefault();
|
|
249
|
+
last.focus();
|
|
250
|
+
} else if (!e.shiftKey && active === last) {
|
|
251
|
+
e.preventDefault();
|
|
252
|
+
first.focus();
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (e.key !== "Escape" || !closeOnEscape) return;
|
|
257
|
+
const layer2 = e.target.closest?.("[data-react-fancy-portal]");
|
|
258
|
+
if (layer2 && !layer2.contains(el)) return;
|
|
259
|
+
e.preventDefault();
|
|
260
|
+
e.stopPropagation();
|
|
261
|
+
setFullScreen(false);
|
|
262
|
+
},
|
|
263
|
+
[closeOnEscape, setFullScreen]
|
|
264
|
+
);
|
|
265
|
+
const activeMode = fullScreen ? nativeActive ? "native" : "overlay" : null;
|
|
266
|
+
const enterLabel = labels?.enter ?? "Enter full screen";
|
|
267
|
+
const exitLabel = labels?.exit ?? "Exit full screen";
|
|
268
|
+
return {
|
|
269
|
+
fullScreen,
|
|
270
|
+
setFullScreen,
|
|
271
|
+
toggle,
|
|
272
|
+
activeMode,
|
|
273
|
+
layer: activeMode ? layer : null,
|
|
274
|
+
ref,
|
|
275
|
+
portalContainer,
|
|
276
|
+
targetProps: {
|
|
277
|
+
ref,
|
|
278
|
+
"data-fullscreen": fullScreen ? "true" : "false",
|
|
279
|
+
...activeMode ? { "data-fullscreen-mode": activeMode, "data-fullscreen-layer": layer } : {},
|
|
280
|
+
...fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {},
|
|
281
|
+
onKeyDown
|
|
282
|
+
},
|
|
283
|
+
toggleProps: {
|
|
284
|
+
type: "button",
|
|
285
|
+
onClick: toggle,
|
|
286
|
+
"aria-pressed": fullScreen,
|
|
287
|
+
"aria-label": fullScreen ? exitLabel : enterLabel,
|
|
288
|
+
title: fullScreen ? exitLabel : enterLabel,
|
|
289
|
+
"data-react-fancy-fullscreen-toggle": "",
|
|
290
|
+
"data-fullscreen": fullScreen ? "true" : "false"
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export { useFullScreen };
|
|
296
|
+
//# sourceMappingURL=chunk-CHQH6M67.js.map
|
|
297
|
+
//# sourceMappingURL=chunk-CHQH6M67.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/scroll-lock.ts","../src/hooks/use-full-screen.ts"],"names":["layer"],"mappings":"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","file":"chunk-CHQH6M67.js","sourcesContent":["/**\n * Reference-counted body scroll lock.\n *\n * Two surfaces locking independently with the save-and-restore pattern\n * (`const original = body.style.overflow`) only unwind correctly in strict LIFO\n * order. Exit them out of order and the first one out restores `\"\"` while the\n * second is still covering the viewport, so the page scrolls behind it. Counting\n * holders keeps the lock until the last one lets go, and restores the value that\n * was there before the FIRST took it.\n *\n * Call only from an effect: it touches `document`.\n */\nlet holders = 0;\nlet saved = \"\";\n\nexport function lockBodyScroll(): () => void {\n if (holders === 0) {\n saved = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n holders++;\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n holders--;\n if (holders === 0) document.body.style.overflow = saved;\n };\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport { useControllableState } from \"./use-controllable-state\";\nimport { lockBodyScroll } from \"../utils/scroll-lock\";\n\n/**\n * How a surface goes full screen.\n *\n * - `\"overlay\"` (default): the element itself becomes `position: fixed` over the\n * viewport, in place. It always works: inside an iframe without\n * `allow=\"fullscreen\"`, inside a dialog, without a user gesture. Nothing is\n * reparented, so an editor keeps its caret, undo stack and DOM.\n * - `\"native\"`: the browser Fullscreen API (`element.requestFullscreen()`),\n * which hides the browser chrome too. The overlay is applied first and stays\n * if the request is rejected or the API is missing, so the user gets full\n * screen either way; `activeMode` reports which one took.\n */\nexport type FullScreenMode = \"overlay\" | \"native\";\n\nexport interface UseFullScreenOptions {\n /** Controlled flag. Pair with `onFullScreenChange`. */\n fullScreen?: boolean;\n /** Initial flag when uncontrolled. @default false */\n defaultFullScreen?: boolean;\n /**\n * Fired with the requested state — from the toggle, Escape, an agent calling\n * `setFullScreen`, or the user leaving the browser's own full screen.\n */\n onFullScreenChange?: (fullScreen: boolean) => void;\n /** @default \"overlay\" */\n mode?: FullScreenMode;\n /** Leave full screen on Escape. @default true */\n closeOnEscape?: boolean;\n /** Stop the page behind from scrolling while active. @default true */\n lockScroll?: boolean;\n /** Stacking order of the overlay. Matches `Modal`. @default 50 */\n zIndex?: number;\n /** Accessible names for the toggle. */\n labels?: { enter?: string; exit?: string };\n}\n\nexport interface FullScreenTargetProps<T extends HTMLElement> {\n ref: RefObject<T | null>;\n \"data-fullscreen\": \"true\" | \"false\";\n \"data-fullscreen-mode\"?: FullScreenMode;\n \"data-fullscreen-layer\"?: FullScreenLayer;\n style?: CSSProperties;\n onKeyDown: (event: ReactKeyboardEvent<T>) => void;\n}\n\nexport interface FullScreenToggleProps {\n type: \"button\";\n onClick: () => void;\n \"aria-pressed\": boolean;\n \"aria-label\": string;\n title: string;\n \"data-react-fancy-fullscreen-toggle\": \"\";\n \"data-fullscreen\": \"true\" | \"false\";\n}\n\nexport interface UseFullScreenResult<T extends HTMLElement = HTMLElement> {\n fullScreen: boolean;\n setFullScreen: (fullScreen: boolean) => void;\n toggle: () => void;\n /** The mechanism in effect while active; `null` when not full screen. */\n activeMode: FullScreenMode | null;\n /**\n * `\"top\"` while the surface is in the browser's top layer (a manual popover,\n * or the native full screen), `\"fixed\"` while it relies on `position: fixed`\n * (no popover API, or the browser refused). `null` when not full screen.\n */\n layer: FullScreenLayer | null;\n /** Attach to the element that goes full screen. Also inside `targetProps`. */\n ref: RefObject<T | null>;\n /**\n * Spread onto the surface's root. Carries the ref, the `data-fullscreen`\n * handle, the overlay style and the Escape/Tab handler. Merge your own\n * `style` / `onKeyDown` if the root has them.\n */\n targetProps: FullScreenTargetProps<T>;\n /** Spread onto a `<button>` to make it the toggle. */\n toggleProps: FullScreenToggleProps;\n /**\n * The element to portal into while active, else `null`. Provide it through\n * `PortalContainerContext` so menus opened inside stay visible.\n */\n portalContainer: HTMLElement | null;\n}\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\n/** Active surfaces, innermost last. Only the top one answers a stray Escape. */\nconst activeStack: object[] = [];\n\nconst OVERLAY_STYLE: CSSProperties = {\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n maxWidth: \"none\",\n maxHeight: \"none\",\n margin: 0,\n borderRadius: 0,\n boxSizing: \"border-box\",\n};\n\n/**\n * Lift `el` into the browser's top layer with `popover=\"manual\"`.\n *\n * Why: `position: fixed` is only fixed to the viewport while no ancestor has a\n * transform, filter, perspective or paint containment. With one, the overlay\n * is fixed to THAT box. In the showcase a surface in a Tabs panel came out\n * 1248x95, because `.fancy-fade-in` held `transform: matrix(1,0,0,1,0,0)` via\n * `animation-fill-mode: both`. Transform-centred dialogs do the same. A\n * top-layer element's containing block is the viewport whatever its ancestors\n * do, and the popover API gets it there without moving it in the DOM.\n *\n * `manual` because `auto` light-dismisses on an outside click and on Escape;\n * Escape stays with the surface's own handler.\n *\n * Returns a release function, or `null` where the API is missing or refuses\n * (the caller keeps the fixed overlay). `onLost` fires if something else\n * closes the popover: a `[popover]` that is not open is `display: none`, so the\n * attribute must go at once or the surface vanishes while still \"full screen\".\n */\n/** Surfaces currently in the top layer through a popover, with a \"re-show\" each. */\nconst promoted = new Map<HTMLElement, () => void>();\n\nfunction promoteToTopLayer(el: HTMLElement, onLost: () => void): (() => void) | null {\n const p = el as HTMLElement & { showPopover?: () => void; hidePopover?: () => void };\n if (typeof p.showPopover !== \"function\" || typeof p.hidePopover !== \"function\") return null;\n // The consumer made it a popover themselves; do not fight over it.\n if (el.hasAttribute(\"popover\")) return null;\n\n el.setAttribute(\"popover\", \"manual\");\n try {\n p.showPopover();\n } catch {\n el.removeAttribute(\"popover\");\n return null;\n }\n\n let open = true;\n let raising = false;\n const onToggle = (e: Event) => {\n if (raising || (e as Event & { newState?: string }).newState !== \"closed\" || !open) return;\n open = false;\n promoted.delete(el);\n el.removeEventListener(\"toggle\", onToggle);\n el.removeAttribute(\"popover\");\n onLost();\n };\n el.addEventListener(\"toggle\", onToggle);\n\n // The top layer stacks in SHOW order. React runs a child's layout effects\n // before its parent's, so a surface nested in another that goes full screen\n // in the same commit is shown first and then buried by its parent. Re-show\n // any promoted descendant so the innermost stays on top.\n for (const [other, raise] of promoted) {\n if (other !== el && el.contains(other)) raise();\n }\n promoted.set(el, () => {\n raising = true;\n try {\n p.hidePopover!();\n p.showPopover!();\n } catch {\n /* leave it where it is */\n } finally {\n raising = false;\n }\n });\n\n return () => {\n promoted.delete(el);\n el.removeEventListener(\"toggle\", onToggle);\n if (open) {\n open = false;\n try {\n p.hidePopover!();\n } catch {\n /* already hidden, e.g. removed from the document */\n }\n }\n el.removeAttribute(\"popover\");\n };\n}\n\n/** Which mechanism keeps the surface over the page. */\nexport type FullScreenLayer = \"top\" | \"fixed\";\n\ninterface ScrollMemo {\n el: Element;\n top: number;\n left: number;\n}\n\n/**\n * A controlled full-screen state for any surface: Editor today, DeckEditor and\n * SheetWorkbook next. Render-time output is pure (no `window`/`document`), so it\n * server-renders; everything that touches the DOM runs in effects.\n */\nexport function useFullScreen<T extends HTMLElement = HTMLElement>(\n options: UseFullScreenOptions = {},\n): UseFullScreenResult<T> {\n const {\n fullScreen: controlled,\n defaultFullScreen = false,\n onFullScreenChange,\n mode = \"overlay\",\n closeOnEscape = true,\n lockScroll = true,\n zIndex = 50,\n labels,\n } = options;\n\n const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);\n const ref = useRef<T | null>(null);\n const token = useRef({});\n const [nativeActive, setNativeActive] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);\n // Whether the overlay STYLE is on. It trails `fullScreen` by one synchronous\n // commit on entry, so the layout effect below reads scroll offsets while the\n // surface is still in flow. Read after the style lands and the browser has\n // already clamped every scroll container around it: a panel at 569 read as\n // 342 in Chromium, and that is where the user was sent back to. The re-render\n // happens inside the layout phase, before paint, so nothing flashes.\n // Initialised from `fullScreen` so a surface that starts full screen renders\n // the overlay on the server and on hydration alike.\n const [applied, setApplied] = useState(fullScreen);\n // \"fixed\" until a layout effect has actually promoted the surface, so the\n // server and the hydrating client agree, and a refused promotion reads true.\n const [layer, setLayer] = useState<FullScreenLayer>(\"fixed\");\n const topRelease = useRef<(() => void) | null>(null);\n\n const promote = (el: HTMLElement) => {\n if (topRelease.current) return;\n topRelease.current = promoteToTopLayer(el, () => {\n topRelease.current = null;\n setLayer(\"fixed\");\n });\n setLayer(topRelease.current ? \"top\" : \"fixed\");\n };\n const demote = () => {\n topRelease.current?.();\n topRelease.current = null;\n };\n\n const current = useRef(fullScreen);\n current.current = fullScreen;\n\n // Only report real transitions: Escape on an inactive surface, or a second\n // click racing a re-render, must not fire `onFullScreenChange(false)` twice.\n const setFullScreen = useCallback(\n (next: boolean) => {\n if (current.current === next) return;\n current.current = next;\n setState(next);\n },\n [setState],\n );\n const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);\n\n // Enter / exit bookkeeping. A LAYOUT effect so the cleanup runs after the\n // overlay style has been removed from the DOM but before paint: scroll offsets\n // restored there never flash, and the surface is back in flow to measure.\n useLayoutEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n // Taking the surface out of flow shrinks every scroll container around it,\n // which clamps their scrollTop. Remember them so exit lands where it began.\n const scrolled: ScrollMemo[] = [];\n for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {\n if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });\n }\n const winX = window.scrollX;\n const winY = window.scrollY;\n\n const release = lockScroll ? lockBodyScroll() : null;\n activeStack.push(token.current);\n setPortalContainer(el);\n setApplied(true);\n\n // Native mode asks the browser first: Chromium rejects requestFullscreen()\n // on an element that is already an open popover (\"already open as a\n // Popover, and therefore cannot be opened via the fullscreen API\"). The\n // native effect promotes on refusal instead.\n const native = mode === \"native\" && typeof el.requestFullscreen === \"function\" && document.fullscreenEnabled !== false;\n if (!native) promote(el);\n\n return () => {\n const i = activeStack.indexOf(token.current);\n if (i >= 0) activeStack.splice(i, 1);\n // Out of the top layer first, so the surface is back in flow before the\n // scroll offsets are put back.\n demote();\n setLayer(\"fixed\");\n release?.();\n for (const m of scrolled) {\n if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;\n if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;\n }\n if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);\n setPortalContainer(null);\n setApplied(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fullScreen, lockScroll, mode]);\n\n // Focus in and back out. A PASSIVE effect on purpose: React re-focuses\n // whatever had focus before a commit once the commit's mutations finish, so a\n // focus() issued from a layout-effect cleanup is silently undone.\n useEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n const opener =\n document.activeElement instanceof HTMLElement && document.activeElement !== document.body\n ? document.activeElement\n : null;\n\n // Focus must not stay behind the overlay, where the user cannot see it.\n if (!el.contains(document.activeElement)) {\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true });\n }\n\n return () => {\n // Give focus back only if it is still ours to give: inside the surface,\n // or lost to <body>. A user who clicked elsewhere keeps their choice.\n const active = document.activeElement;\n if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {\n opener.focus({ preventScroll: true });\n }\n };\n }, [fullScreen]);\n\n // The browser Fullscreen API, on top of the overlay.\n useEffect(() => {\n if (!fullScreen || mode !== \"native\") return;\n const el = ref.current;\n if (!el || typeof el.requestFullscreen !== \"function\" || document.fullscreenEnabled === false) return;\n\n let cancelled = false;\n let entered = false;\n\n const onChange = () => {\n if (document.fullscreenElement === el) {\n entered = true;\n setNativeActive(true);\n // The browser's full screen is the top layer too.\n setLayer(\"top\");\n } else if (entered) {\n // The user left through the browser's own UI (Esc, F11, the close\n // pill). Keep the controlled state honest rather than leaving an\n // overlay up that they believe they dismissed.\n entered = false;\n setNativeActive(false);\n setLayer(\"fixed\");\n if (!cancelled) setFullScreen(false);\n }\n };\n document.addEventListener(\"fullscreenchange\", onChange);\n\n // Blocked requests (iframe without allow=\"fullscreen\", no user gesture, a\n // permissions policy) reject, and some engines throw instead. Either way\n // the user stays full screen in the overlay, lifted into the top layer.\n const refused = () => {\n if (!cancelled && current.current && ref.current === el) promote(el);\n };\n try {\n Promise.resolve(el.requestFullscreen()).then(onChange, refused);\n } catch {\n refused();\n }\n\n return () => {\n cancelled = true;\n document.removeEventListener(\"fullscreenchange\", onChange);\n if (document.fullscreenElement === el) {\n try {\n Promise.resolve(document.exitFullscreen()).catch(() => {});\n } catch {\n /* already left */\n }\n }\n setNativeActive(false);\n };\n }, [fullScreen, mode, setFullScreen]);\n\n // Escape with nothing focused never reaches the surface's own handler.\n useEffect(() => {\n if (!fullScreen || !closeOnEscape) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented) return;\n const t = e.target;\n if (t !== document.body && t !== document.documentElement && t !== document) return;\n if (activeStack[activeStack.length - 1] !== token.current) return;\n setFullScreen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [fullScreen, closeOnEscape, setFullScreen]);\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<T>) => {\n if (!current.current || e.defaultPrevented) return;\n const el = ref.current;\n if (!el) return;\n\n if (e.key === \"Tab\") {\n // Keep Tab inside the surface; what is behind the overlay is invisible.\n const items = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE));\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (e.shiftKey && (active === first || active === el)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n return;\n }\n\n if (e.key !== \"Escape\" || !closeOnEscape) return;\n // An Escape from inside a layer opened FROM this surface (a menu, a\n // popover, a dialog) belongs to that layer. React bubbles portal events\n // through the component tree, so check the DOM: a portal wrapper that\n // does not contain this surface is nested inside it.\n const layer = (e.target as Element).closest?.(\"[data-react-fancy-portal]\");\n if (layer && !layer.contains(el)) return;\n // Stop it here so an enclosing dialog's document listener does not also\n // close: one Escape, one step back.\n e.preventDefault();\n e.stopPropagation();\n setFullScreen(false);\n },\n [closeOnEscape, setFullScreen],\n );\n\n const activeMode: FullScreenMode | null = fullScreen ? (nativeActive ? \"native\" : \"overlay\") : null;\n const enterLabel = labels?.enter ?? \"Enter full screen\";\n const exitLabel = labels?.exit ?? \"Exit full screen\";\n\n return {\n fullScreen,\n setFullScreen,\n toggle,\n activeMode,\n layer: activeMode ? layer : null,\n ref,\n portalContainer,\n targetProps: {\n ref,\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n ...(activeMode ? { \"data-fullscreen-mode\": activeMode, \"data-fullscreen-layer\": layer } : {}),\n ...(fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {}),\n onKeyDown,\n },\n toggleProps: {\n type: \"button\",\n onClick: toggle,\n \"aria-pressed\": fullScreen,\n \"aria-label\": fullScreen ? exitLabel : enterLabel,\n title: fullScreen ? exitLabel : enterLabel,\n \"data-react-fancy-fullscreen-toggle\": \"\",\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n },\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkJ2DI6RMR_cjs = require('./chunk-J2DI6RMR.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkTI7D4QDM_cjs = require('./chunk-TI7D4QDM.cjs');
|
|
5
5
|
var chunk57FQGQJK_cjs = require('./chunk-57FQGQJK.cjs');
|
|
6
6
|
var chunkRXDRYWVD_cjs = require('./chunk-RXDRYWVD.cjs');
|
|
7
7
|
var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
@@ -48,7 +48,7 @@ function PopoverContent({ children, className, style, ...rest }) {
|
|
|
48
48
|
chunkRXDRYWVD_cjs.useEscapeKey(close, open);
|
|
49
49
|
const positioned = position.x !== -9999 && position.y !== -9999;
|
|
50
50
|
if (!open) return null;
|
|
51
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
51
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkTI7D4QDM_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
52
|
"div",
|
|
53
53
|
{
|
|
54
54
|
...rest,
|
|
@@ -117,5 +117,5 @@ var Popover = Object.assign(PopoverRoot, {
|
|
|
117
117
|
|
|
118
118
|
exports.Popover = Popover;
|
|
119
119
|
exports.usePopover = usePopover;
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-FU6K7XXZ.cjs.map
|
|
121
|
+
//# sourceMappingURL=chunk-FU6K7XXZ.cjs.map
|