@xom11/whiteboard 0.25.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ExcalidrawWithMenus-WENZRYYE.mjs → ExcalidrawWithMenus-2QPPTXJM.mjs} +3 -2
- package/dist/ExcalidrawWithMenus-2QPPTXJM.mjs.map +1 -0
- package/dist/ai.d.mts +3035 -108
- package/dist/ai.d.ts +3035 -108
- package/dist/ai.js +6780 -788
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +5140 -577
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +5 -5
- package/dist/{chunk-NDEZJKNY.mjs → chunk-5JM35CXV.mjs} +4 -4
- package/dist/{chunk-NDEZJKNY.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
- package/dist/{chunk-VNCCIV6O.mjs → chunk-AJAHD35N.mjs} +779 -9
- package/dist/chunk-AJAHD35N.mjs.map +1 -0
- package/dist/{chunk-M42TGYT6.mjs → chunk-BNBOIDO5.mjs} +3 -3
- package/dist/{chunk-M42TGYT6.mjs.map → chunk-BNBOIDO5.mjs.map} +1 -1
- package/dist/{chunk-ONBCUWVI.mjs → chunk-BU5KLO3P.mjs} +3 -3
- package/dist/{chunk-ONBCUWVI.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
- package/dist/{chunk-CJBLJUWG.mjs → chunk-CXHNVYMD.mjs} +4 -4
- package/dist/{chunk-CJBLJUWG.mjs.map → chunk-CXHNVYMD.mjs.map} +1 -1
- package/dist/chunk-H22OZYTW.mjs +265 -0
- package/dist/chunk-H22OZYTW.mjs.map +1 -0
- package/dist/chunk-J5LGTIGS.mjs +10 -0
- package/dist/chunk-J5LGTIGS.mjs.map +1 -0
- package/dist/{chunk-TB4CL25L.mjs → chunk-OQIQNKPQ.mjs} +206 -66
- package/dist/chunk-OQIQNKPQ.mjs.map +1 -0
- package/dist/{chunk-SGFJLHHG.mjs → chunk-PPKHCRRE.mjs} +3 -3
- package/dist/{chunk-SGFJLHHG.mjs.map → chunk-PPKHCRRE.mjs.map} +1 -1
- package/dist/{chunk-YSJOVBCD.mjs → chunk-QCZVFEN4.mjs} +4 -4
- package/dist/{chunk-YSJOVBCD.mjs.map → chunk-QCZVFEN4.mjs.map} +1 -1
- package/dist/{chunk-ESVPQWHX.mjs → chunk-QRUAEXLR.mjs} +5 -5
- package/dist/{chunk-ESVPQWHX.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
- package/dist/{chunk-AYSFWUPK.mjs → chunk-SZDAS7LK.mjs} +79 -2
- package/dist/chunk-SZDAS7LK.mjs.map +1 -0
- package/dist/chunk-T3SOHYB2.mjs +851 -0
- package/dist/chunk-T3SOHYB2.mjs.map +1 -0
- package/dist/{chunk-I24QOHPU.mjs → chunk-V3YJ6JFL.mjs} +3 -3
- package/dist/{chunk-I24QOHPU.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
- package/dist/{chunk-REIJZDVZ.mjs → chunk-ZTQBUKLJ.mjs} +960 -196
- package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
- package/dist/geometry-2d.d.mts +1 -1
- package/dist/geometry-2d.d.ts +1 -1
- package/dist/geometry-2d.js +5521 -1384
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +5 -4
- package/dist/geometry-3d.d.mts +1 -1
- package/dist/geometry-3d.d.ts +1 -1
- package/dist/geometry-3d.js +1351 -252
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +4 -3
- package/dist/graph-2d.d.mts +1 -1
- package/dist/graph-2d.d.ts +1 -1
- package/dist/graph-2d.js +1517 -341
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +7 -6
- package/dist/handleExtractProblem-C-U5KluK.d.mts +158 -0
- package/dist/handleExtractProblem-C-U5KluK.d.ts +158 -0
- package/dist/{host-A64ITWVX.mjs → host-2ISGVO7O.mjs} +6 -5
- package/dist/host-2ISGVO7O.mjs.map +1 -0
- package/dist/{host-L7FMFZUW.mjs → host-4P766V4J.mjs} +1363 -463
- package/dist/host-4P766V4J.mjs.map +1 -0
- package/dist/{host-QK53UYMD.mjs → host-HOSJHQ5H.mjs} +10 -9
- package/dist/host-HOSJHQ5H.mjs.map +1 -0
- package/dist/{host-QS2EOTRJ.mjs → host-ZQCDAT6O.mjs} +3 -2
- package/dist/host-ZQCDAT6O.mjs.map +1 -0
- package/dist/index.d.mts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +5746 -1603
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +26 -22
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +1 -1
- package/dist/latex.d.ts +1 -1
- package/dist/latex.mjs +2 -1
- package/dist/render-ZX2O2IK7.mjs +10 -0
- package/dist/{render-3WTY7NZB.mjs.map → render-ZX2O2IK7.mjs.map} +1 -1
- package/dist/serialize-N4G6RFBB.mjs +9 -0
- package/dist/{serialize-SRJVKYUG.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
- package/dist/{types-DWRyCa2m.d.ts → types-BHYC2Fiw.d.mts} +130 -1
- package/dist/{types-DWRyCa2m.d.mts → types-BHYC2Fiw.d.ts} +130 -1
- package/package.json +10 -1
- package/dist/ExcalidrawWithMenus-WENZRYYE.mjs.map +0 -1
- package/dist/chunk-AYSFWUPK.mjs.map +0 -1
- package/dist/chunk-REIJZDVZ.mjs.map +0 -1
- package/dist/chunk-TB4CL25L.mjs.map +0 -1
- package/dist/chunk-VNCCIV6O.mjs.map +0 -1
- package/dist/chunk-VRHWDZ66.mjs +0 -96
- package/dist/chunk-VRHWDZ66.mjs.map +0 -1
- package/dist/host-A64ITWVX.mjs.map +0 -1
- package/dist/host-L7FMFZUW.mjs.map +0 -1
- package/dist/host-QK53UYMD.mjs.map +0 -1
- package/dist/host-QS2EOTRJ.mjs.map +0 -1
- package/dist/render-3WTY7NZB.mjs +0 -9
- package/dist/serialize-SRJVKYUG.mjs +0 -8
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stamps/shared/catalog.ts","../src/stamps/shared/registry.ts","../src/stamps/shared/ToolbarInjector.tsx","../src/stamps/shared/useShortcuts.ts","../src/pdf/PdfImporterButton.tsx","../src/pdf/parseRange.ts","../src/pdf/rasterize.ts","../src/pdf/PageRangeDialog.tsx","../src/stamps/shared/useStampDoubleClick.ts","../src/stamps/shared/useStampShortcutBlocker.ts","../src/stamps/shared/useStampClickOutside.ts","../src/hooks/useExcalidrawApi.ts","../src/hooks/useActiveStamp.ts","../src/pdf/insertPdfPages.ts","../src/hooks/usePdfImporter.ts","../src/serialize.ts","../src/stamps/shared/restoreStampFiles.ts","../src/core/persistence/validation.ts","../src/core/persistence/sceneStore.ts","../src/core/persistence/fileStore.ts","../src/hooks/useScenePersist.ts","../src/Whiteboard.tsx"],"names":["useEffect","POPOVER_SELECTOR","useState","useRef","jsx","jsxs","Fragment","createPortal","useMemo","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["// src/stamps/shared/catalog.ts\n//\n// STAMP_CATALOG — manifest tra cứu mọi stamp có sẵn trong package (B½.1,\n// issue #29). Consumer build admin UI / picker / docs page chỉ cần import\n// hằng số này; không phải tự đọc source.\n//\n// `bundleSize` được populate bởi `scripts/build-catalog.mjs` (chạy postbuild)\n// — số đo gzip size thực tế của `dist/{kind}.mjs`. Build script replace giá\n// trị placeholder `{ js: 0, css: 0 }` thành số KB chính xác đồng thời ghi\n// `dist/catalog.json` để consumer có thể fetch runtime nếu cần.\n//\n// Khi thêm stamp mới (xem `docs/superpowers/specs/add-new-stamp-howto.md`),\n// thêm entry vào mảng này — entry phải match `stamp.kind` của registry.\n\n/**\n * Mô tả 1 stamp trong catalog. Bundle size đo bằng KB (kilobytes) gzip — tính\n * trên file entry `dist/{id}.mjs`. Đây là bound trên: code thực sự nạp khi\n * user dùng stamp có thể nhỏ hơn nếu shared chunks đã load cho stamp khác.\n */\nexport interface StampCatalogEntry {\n /** Khớp với `StampType.kind`. Vd 'geometry', 'latex', 'geometry3d', 'graph2d'. */\n id: string;\n /** Tên hiển thị cho admin UI (tiếng Việt). */\n title: string;\n /** Phiên bản schema customData. Bump khi BREAKING change format. */\n version: number;\n /** true nếu stamp chưa production-ready (EXPERIMENTAL_STAMPS). */\n experimental: boolean;\n /** Dependency runtime mà consumer phải cài qua peerDependency. */\n runtimeDeps: ReadonlyArray<string>;\n /** Size dist/{id}.{mjs,css} sau gzip (KB). Populated postbuild. */\n bundleSize: { js: number; css: number };\n}\n\n/**\n * Catalog tĩnh của 4 stamps hiện tại. `bundleSize` ở đây là PLACEHOLDER —\n * `scripts/build-catalog.mjs` sẽ override giá trị này trong `dist/`. Tại\n * source (chạy jest / dev), bundleSize sẽ là 0 — đừng dùng cho quyết định\n * production, chỉ dùng entries trong build artifact.\n */\nexport const STAMP_CATALOG: ReadonlyArray<StampCatalogEntry> = Object.freeze([\n {\n id: 'geometry',\n title: 'Hình học 2D (JSXGraph)',\n version: 1,\n experimental: false,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'latex',\n title: 'Công thức LaTeX (KaTeX)',\n version: 1,\n experimental: false,\n runtimeDeps: ['katex'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'geometry3d',\n title: 'Hình học 3D (JSXGraph view3d)',\n version: 2,\n experimental: true,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'graph2d',\n title: 'Đồ thị hàm số 2D (JSXGraph)',\n version: 2,\n experimental: true,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n]);\n\n/** Lấy entry theo stamp.kind. Trả null nếu không có. */\nexport function findCatalogEntry(id: string): StampCatalogEntry | null {\n return STAMP_CATALOG.find((entry) => entry.id === id) ?? null;\n}\n","import { geometryStamp } from '../geometry-2d';\nimport { latexStamp } from '../latex';\nimport { geometry3dStamp } from '../geometry-3d';\nimport { graph2dStamp } from '../graph-2d';\nimport type { StampType } from './types';\n\nexport { geometryStamp, type GeometryCustomData } from '../geometry-2d';\nexport { latexStamp, type LatexCustomData } from '../latex';\nexport { geometry3dStamp, type Geometry3DCustomData } from '../geometry-3d';\nexport { graph2dStamp, type Graph2DCustomData } from '../graph-2d';\nexport type { StampType, BaseStampCustomData } from './types';\nexport {\n STAMP_CATALOG,\n findCatalogEntry,\n type StampCatalogEntry,\n} from './catalog';\n\n/** Stamp ổn định, sẵn sàng production. */\nexport const STABLE_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n geometryStamp,\n latexStamp,\n]);\n\n/** Stamp experimental — chưa ổn định cho production. Consumer phải opt-in. */\nexport const EXPERIMENTAL_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n geometry3dStamp,\n graph2dStamp,\n]);\n\n/** Tất cả stamp (stable + experimental). */\nexport const ALL_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n ...STABLE_STAMPS,\n ...EXPERIMENTAL_STAMPS,\n]);\n\nexport const DEFAULT_STAMPS: ReadonlyArray<StampType> = ALL_STAMPS;\n\n/** Tìm stamp tương ứng với customData của element. null nếu không match. */\nexport function findStampForCustomData(\n data: unknown,\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): StampType | null {\n for (const s of stamps) {\n if (s.matchesCustomData(data)) return s;\n }\n return null;\n}\n\n/** isMathStamp version dựa trên registry. */\nexport function isStampElement<T extends { customData?: unknown }>(\n element: T,\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): boolean {\n return findStampForCustomData(element.customData, stamps) !== null;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { DEFAULT_STAMPS } from './registry';\nimport type { StampType } from './types';\n\ninterface Props {\n /** Bật/tắt theo role. Khi disabled → không mount portal. */\n enabled: boolean;\n /** Kind stamp đang active, hoặc null nếu không có stamp nào mở. */\n activeStampKind: string | null;\n /** Toggle stamp theo kind. */\n onToggle: (kind: string) => void;\n /** Danh sách stamp đăng ký. Mặc định DEFAULT_STAMPS. */\n stamps?: ReadonlyArray<StampType>;\n}\n\nconst MENU_WRAPPER_ID = 'stamp-menu-portal-wrapper';\n/**\n * Excalidraw 0.18 áp dụng class `App-toolbar__extra-tools-dropdown` lên\n * popover wrapper của More tools cho cả desktop lẫn mobile. Mobile có\n * thêm modifier `dropdown-menu--mobile`. Selector này cover cả hai mode.\n */\nconst POPOVER_SELECTOR =\n '.App-toolbar__extra-tools-dropdown .dropdown-menu-container';\n\n/**\n * Inject stamp buttons vào popover \"More tools\" của Excalidraw.\n *\n * v0.7.0: thay vì inject inline vào main toolbar (desktop) hoặc dropdown\n * riêng cho mobile, ta chỉ inject vào dropdown-menu-container bên trong\n * popover của Excalidraw. Selector cover cả desktop lẫn mobile vì hai\n * mode dùng cùng cấu trúc DOM (DropdownMenu.Content).\n *\n * Popover mount/unmount theo trigger click → MutationObserver dò DOM,\n * mount lại wrapper khi cần.\n */\nexport function ToolbarInjector({\n enabled,\n activeStampKind,\n onToggle,\n stamps = DEFAULT_STAMPS,\n}: Props) {\n const [menuMount, setMenuMount] = useState<HTMLElement | null>(null);\n const menuMountRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n if (menuMountRef.current !== null) {\n menuMountRef.current = null;\n setMenuMount(null);\n }\n document.getElementById(MENU_WRAPPER_ID)?.remove();\n return;\n }\n\n let cancelled = false;\n let observer: MutationObserver | null = null;\n let rafId: number | null = null;\n let observedRoot: Element | null = null;\n\n const apply = (next: HTMLElement | null) => {\n if (cancelled || menuMountRef.current === next) return;\n menuMountRef.current = next;\n queueMicrotask(() => {\n if (!cancelled) setMenuMount(next);\n });\n };\n\n const findMenu = () => {\n if (cancelled) return;\n const container = document.querySelector<HTMLElement>(POPOVER_SELECTOR);\n if (!container) {\n apply(null);\n return;\n }\n let wrapper = container.querySelector<HTMLDivElement>('#' + MENU_WRAPPER_ID);\n if (!wrapper) {\n wrapper = document.createElement('div');\n wrapper.id = MENU_WRAPPER_ID;\n wrapper.setAttribute('data-stamp-menu', 'true');\n wrapper.setAttribute('data-stamp-area', 'true');\n wrapper.style.display = 'contents';\n container.insertBefore(wrapper, container.firstChild);\n }\n apply(wrapper);\n };\n\n /**\n * Scope observer xuống `.excalidraw` để giảm tần suất callback trigger\n * (mutation ở các node ngoài Excalidraw không liên quan tới popover).\n * Nếu `.excalidraw` chưa mount → tạm observe `document.body` để bắt\n * lúc nó xuất hiện, rồi switch sang root nhỏ hơn.\n */\n const attachObserver = () => {\n if (cancelled) return;\n const excalidraw = document.querySelector<HTMLElement>('.excalidraw');\n const nextRoot: Element = excalidraw ?? document.body;\n if (observedRoot === nextRoot) return;\n observer?.disconnect();\n observedRoot = nextRoot;\n observer = new MutationObserver(onMutation);\n observer.observe(nextRoot, { childList: true, subtree: true });\n };\n\n /**\n * rAF debounce: gộp nhiều mutation cùng tick thành 1 lần xử lý.\n * Excalidraw có thể trigger hàng chục mutation khi mở/đóng popover —\n * mỗi pass chỉ tốn 1 lần querySelector + DOM insert.\n */\n const onMutation = () => {\n if (rafId != null) return;\n rafId = requestAnimationFrame(() => {\n rafId = null;\n if (cancelled) return;\n // Nếu đang observe body mà giờ `.excalidraw` đã mount → switch sang nó.\n if (observedRoot !== document.querySelector('.excalidraw')) {\n attachObserver();\n }\n findMenu();\n });\n };\n\n findMenu();\n attachObserver();\n\n return () => {\n cancelled = true;\n if (rafId != null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n observer?.disconnect();\n observer = null;\n observedRoot = null;\n document.getElementById(MENU_WRAPPER_ID)?.remove();\n };\n }, [enabled]);\n\n if (!enabled || !menuMount) return null;\n\n const closePopover = () => {\n const trigger = document.querySelector<HTMLButtonElement>(\n '.App-toolbar__extra-tools-trigger',\n );\n trigger?.click();\n };\n\n return createPortal(\n <>\n {stamps.map((stamp) => {\n const { displayLabel, shortcut } = splitTitleAndShortcut(\n stamp.toolbarTitle,\n stamp.toolbarLabel,\n );\n return (\n <StampMenuItem\n key={stamp.kind}\n icon={stamp.toolbarIcon}\n label={displayLabel}\n ariaLabel={stamp.toolbarTitle}\n shortcut={shortcut}\n active={activeStampKind === stamp.kind}\n onClick={() => {\n onToggle(stamp.kind);\n closePopover();\n }}\n dataTestId={stamp.toolbarTestId}\n />\n );\n })}\n <div\n aria-hidden=\"true\"\n style={{\n height: 1,\n background: 'var(--default-border-color, rgba(0,0,0,0.08))',\n margin: '6px 4px',\n }}\n />\n </>,\n menuMount,\n );\n}\n\n/**\n * Tách \"(X)\" cuối toolbarTitle thành shortcut hiển thị riêng ở góc phải\n * (giống các tool gốc Excalidraw: Frame F, Laser K, ...). Nếu title không\n * có pattern \"(...)\", fallback dùng toolbarLabel.\n */\nfunction splitTitleAndShortcut(\n title: string,\n fallbackShortcut: string,\n): { displayLabel: string; shortcut: string } {\n const match = title.match(/^(.*?)\\s*\\(([^()]+)\\)\\s*$/);\n if (match) {\n return { displayLabel: match[1].trim(), shortcut: match[2].trim() };\n }\n return { displayLabel: title, shortcut: fallbackShortcut };\n}\n\ninterface StampMenuItemProps {\n icon: React.ReactNode;\n label: string;\n ariaLabel: string;\n shortcut: string;\n active: boolean;\n onClick: () => void;\n dataTestId?: string;\n}\n\nfunction StampMenuItem({\n icon,\n label,\n ariaLabel,\n shortcut,\n active,\n onClick,\n dataTestId,\n}: StampMenuItemProps) {\n const className = [\n 'dropdown-menu-item',\n 'dropdown-menu-item-base',\n active ? 'dropdown-menu-item--selected' : '',\n ]\n .filter(Boolean)\n .join(' ');\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={ariaLabel}\n aria-label={ariaLabel}\n aria-pressed={active}\n data-testid={dataTestId}\n className={className}\n >\n <div className=\"dropdown-menu-item__icon\" aria-hidden=\"true\">\n {icon}\n </div>\n <div className=\"dropdown-menu-item__text\">{label}</div>\n {shortcut ? (\n <div className=\"dropdown-menu-item__shortcut\">{shortcut}</div>\n ) : null}\n </button>\n );\n}\n","import { useEffect } from 'react';\nimport { DEFAULT_STAMPS } from './registry';\nimport type { StampType } from './types';\n\ninterface Options {\n enabled: boolean;\n /** Toggle stamp theo kind khi user bấm shortcut tương ứng. */\n onToggle: (kind: string) => void;\n /** Registry. Mặc định DEFAULT_STAMPS. */\n stamps?: ReadonlyArray<StampType>;\n}\n\nfunction isEditableTarget(t: EventTarget | null): boolean {\n if (!t || !(t instanceof HTMLElement)) return false;\n if (t.isContentEditable) return true;\n const tag = t.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';\n}\n\n/**\n * Bind keyboard shortcut cho mỗi stamp trong registry. Capture phase +\n * stopPropagation để chặn trước Excalidraw's bubble-phase handlers (Excalidraw\n * dùng `L` cho Line tool, nếu không chặn → bấm L lại chuyển tool thay vì\n * toggle LaTeX panel).\n */\nexport function useShortcuts({\n enabled,\n onToggle,\n stamps = DEFAULT_STAMPS,\n}: Options): void {\n useEffect(() => {\n if (!enabled) return;\n const keyToKind = new Map<string, string>();\n for (const s of stamps) keyToKind.set(s.shortcutKey, s.kind);\n\n const handler = (e: KeyboardEvent) => {\n if (e.metaKey || e.ctrlKey || e.altKey) return;\n if (isEditableTarget(e.target)) return;\n const key = e.key.toLowerCase();\n const kind = keyToKind.get(key);\n if (!kind) return;\n e.preventDefault();\n e.stopPropagation();\n onToggle(kind);\n };\n window.addEventListener('keydown', handler, { capture: true });\n return () => window.removeEventListener('keydown', handler, { capture: true });\n }, [enabled, onToggle, stamps]);\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\ninterface Props {\n enabled: boolean;\n onPick: (file: File) => void;\n}\n\nconst WRAPPER_ID = 'pdf-import-portal-wrapper';\nconst POPOVER_SELECTOR =\n '.App-toolbar__extra-tools-dropdown .dropdown-menu-container';\n\n/**\n * Button \"Chèn PDF\" portal vào More tools dropdown của Excalidraw, ngay\n * dưới các stamp buttons. Click → mở native file picker (hidden input).\n *\n * Tách riêng khỏi ToolbarInjector vì PDF không phải stamp (không có Host,\n * không re-edit). Cùng pattern observer như ToolbarInjector để bắt\n * popover mount/unmount.\n */\nexport function PdfImporterButton({ enabled, onPick }: Props) {\n const [mount, setMount] = useState<HTMLElement | null>(null);\n const mountRef = useRef<HTMLElement | null>(null);\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n mountRef.current = null;\n setMount(null);\n document.getElementById(WRAPPER_ID)?.remove();\n return;\n }\n\n let cancelled = false;\n let observer: MutationObserver | null = null;\n let rafId: number | null = null;\n let observedRoot: Element | null = null;\n\n const apply = (next: HTMLElement | null) => {\n if (cancelled || mountRef.current === next) return;\n mountRef.current = next;\n queueMicrotask(() => {\n if (!cancelled) setMount(next);\n });\n };\n\n const findMenu = () => {\n if (cancelled) return;\n const container = document.querySelector<HTMLElement>(POPOVER_SELECTOR);\n if (!container) {\n apply(null);\n return;\n }\n let wrapper = container.querySelector<HTMLDivElement>('#' + WRAPPER_ID);\n if (!wrapper) {\n wrapper = document.createElement('div');\n wrapper.id = WRAPPER_ID;\n wrapper.setAttribute('data-pdf-import', 'true');\n wrapper.style.display = 'contents';\n // Append cuối để PDF button nằm sau stamps + divider.\n container.appendChild(wrapper);\n }\n apply(wrapper);\n };\n\n const attachObserver = () => {\n if (cancelled) return;\n const excalidraw = document.querySelector<HTMLElement>('.excalidraw');\n const nextRoot: Element = excalidraw ?? document.body;\n if (observedRoot === nextRoot) return;\n observer?.disconnect();\n observedRoot = nextRoot;\n observer = new MutationObserver(onMutation);\n observer.observe(nextRoot, { childList: true, subtree: true });\n };\n\n const onMutation = () => {\n if (rafId != null) return;\n rafId = requestAnimationFrame(() => {\n rafId = null;\n if (cancelled) return;\n if (observedRoot !== document.querySelector('.excalidraw')) {\n attachObserver();\n }\n findMenu();\n });\n };\n\n findMenu();\n attachObserver();\n\n return () => {\n cancelled = true;\n if (rafId != null) cancelAnimationFrame(rafId);\n observer?.disconnect();\n document.getElementById(WRAPPER_ID)?.remove();\n };\n }, [enabled]);\n\n const closePopover = () => {\n const trigger = document.querySelector<HTMLButtonElement>(\n '.App-toolbar__extra-tools-trigger',\n );\n trigger?.click();\n };\n\n const handleClick = () => {\n inputRef.current?.click();\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) onPick(file);\n // Reset để chọn lại cùng file lần sau vẫn fire onChange.\n e.target.value = '';\n closePopover();\n };\n\n if (!enabled || !mount) {\n // Vẫn render hidden input để parent có thể gọi qua ref nếu muốn — nhưng\n // không cần. Giữ null khi chưa mount để tránh DOM thừa.\n return (\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"application/pdf,.pdf\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n );\n }\n\n return (\n <>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"application/pdf,.pdf\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n {createPortal(\n <button\n type=\"button\"\n onClick={handleClick}\n title=\"Chèn PDF (P)\"\n aria-label=\"Chèn PDF\"\n data-testid=\"pdf-import-button\"\n className=\"dropdown-menu-item dropdown-menu-item-base\"\n >\n <div className=\"dropdown-menu-item__icon\" aria-hidden=\"true\">\n <PdfIcon />\n </div>\n <div className=\"dropdown-menu-item__text\">Chèn PDF</div>\n <div className=\"dropdown-menu-item__shortcut\">P</div>\n </button>,\n mount,\n )}\n </>\n );\n}\n\nfunction PdfIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 3v5h5\" />\n <text x=\"7.5\" y=\"17\" fontSize=\"6\" fontFamily=\"sans-serif\" fontWeight=\"700\" stroke=\"none\" fill=\"currentColor\">\n PDF\n </text>\n </svg>\n );\n}\n","/**\n * Parse chuỗi range trang dạng \"1,3,5-10\" → array số 1-based đã sort + dedupe.\n *\n * - Tokens cách nhau bằng dấu phẩy hoặc khoảng trắng.\n * - Token có gạch \"-\" → range inclusive (5-10 = [5,6,7,8,9,10]).\n * - Khoảng trắng quanh số bị bỏ qua.\n * - Empty / chỉ space → [].\n *\n * Throws `Error` với message tiếng Việt khi:\n * - Token không phải số / không phải range hợp lệ.\n * - Số <= 0 hoặc > totalPages.\n * - Range đảo ngược (vd \"10-5\") — coi là lỗi user thay vì auto-reverse để\n * tránh nuốt typo.\n */\nexport function parsePageRange(input: string, totalPages: number): number[] {\n if (!Number.isInteger(totalPages) || totalPages <= 0) {\n throw new Error('Số trang phải là số nguyên dương.');\n }\n const trimmed = input.trim();\n if (trimmed === '') return [];\n\n const tokens = trimmed\n .split(/[,\\s]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n\n const set = new Set<number>();\n\n for (const token of tokens) {\n if (token.includes('-')) {\n const parts = token.split('-');\n if (parts.length !== 2) {\n throw new Error(`Khoảng trang không hợp lệ: \"${token}\".`);\n }\n const start = parseStrictInt(parts[0]);\n const end = parseStrictInt(parts[1]);\n if (start === null || end === null) {\n throw new Error(`Khoảng trang không hợp lệ: \"${token}\".`);\n }\n if (start > end) {\n throw new Error(`Khoảng trang ngược: \"${token}\" (đầu > cuối).`);\n }\n if (start < 1 || end > totalPages) {\n throw new Error(\n `Khoảng trang vượt giới hạn: \"${token}\". PDF có ${totalPages} trang.`,\n );\n }\n for (let i = start; i <= end; i++) set.add(i);\n } else {\n const n = parseStrictInt(token);\n if (n === null) {\n throw new Error(`Số trang không hợp lệ: \"${token}\".`);\n }\n if (n < 1 || n > totalPages) {\n throw new Error(\n `Số trang vượt giới hạn: ${n}. PDF có ${totalPages} trang.`,\n );\n }\n set.add(n);\n }\n }\n\n return Array.from(set).sort((a, b) => a - b);\n}\n\nfunction parseStrictInt(s: string): number | null {\n if (!/^-?\\d+$/.test(s)) return null;\n const n = Number(s);\n return Number.isInteger(n) ? n : null;\n}\n","/**\n * Rasterize PDF → PNG dataURLs cho từng trang.\n *\n * Worker config:\n * - pdfjs-dist 5.x cần `GlobalWorkerOptions.workerSrc` (URL tới worker .mjs).\n * - Mặc định trỏ CDN (jsdelivr). Consumer có thể override qua\n * `configurePdfWorker(src)` trước khi gọi rasterize lần đầu.\n * - Lý do CDN thay vì bundled worker: tsup không có cách clean để emit\n * worker chunk ra cùng dist/ với URL ổn định, và consumer (Next.js)\n * có thể self-host nếu cần offline.\n *\n * Lazy import pdfjs-dist để không phình bundle khi user không dùng PDF.\n */\nimport type { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\nlet workerSrcOverride: string | null = null;\nlet pdfjsCache: typeof import('pdfjs-dist') | null = null;\n\n/**\n * Override workerSrc trước khi rasterize. Gọi từ consumer khi cần self-host\n * worker file (vd offline mode, CSP cấm CDN).\n *\n * Mặc định nếu không gọi: dùng CDN jsdelivr theo version pdfjs-dist đã cài.\n */\nexport function configurePdfWorker(workerSrc: string): void {\n workerSrcOverride = workerSrc;\n if (pdfjsCache) {\n pdfjsCache.GlobalWorkerOptions.workerSrc = workerSrc;\n }\n}\n\nasync function loadPdfjs(): Promise<typeof import('pdfjs-dist')> {\n if (pdfjsCache) return pdfjsCache;\n const mod = await import('pdfjs-dist');\n const workerSrc =\n workerSrcOverride ??\n `https://cdn.jsdelivr.net/npm/pdfjs-dist@${mod.version}/build/pdf.worker.min.mjs`;\n mod.GlobalWorkerOptions.workerSrc = workerSrc;\n pdfjsCache = mod;\n return mod;\n}\n\nexport interface RasterizedPage {\n pageNumber: number;\n dataURL: string;\n width: number;\n height: number;\n mimeType: 'image/png';\n}\n\nexport interface RasterizeOptions {\n /** Scale render. Mặc định 2 (HiDPI sharp). */\n scale?: number;\n /** Danh sách trang 1-based. Mặc định: tất cả. */\n pages?: number[];\n /** Callback progress sau mỗi page. */\n onProgress?: (done: number, total: number) => void;\n /** AbortSignal để cancel giữa chừng. */\n signal?: AbortSignal;\n}\n\n/**\n * Load PDF chỉ để lấy `numPages` (vd hiển thị tổng số trang trên dialog).\n * Caller phải tự đóng document bằng `closePdfDocument(doc)` khi xong.\n */\nexport async function loadPdfDocument(source: File | Blob | ArrayBuffer): Promise<PDFDocumentProxy> {\n const pdfjs = await loadPdfjs();\n const data = source instanceof ArrayBuffer ? source : await source.arrayBuffer();\n const task = pdfjs.getDocument({ data: new Uint8Array(data) });\n return task.promise;\n}\n\nexport async function closePdfDocument(doc: PDFDocumentProxy): Promise<void> {\n try {\n await doc.cleanup();\n await doc.destroy();\n } catch {\n /* ignore — best-effort cleanup */\n }\n}\n\n/**\n * Render danh sách trang ra PNG dataURL.\n *\n * Lưu ý:\n * - Sử dụng `OffscreenCanvas` nếu có (browser hiện đại) để không touch DOM,\n * fallback `<canvas>` document.createElement.\n * - Mỗi page render xong sẽ release canvas (cho GC sớm với PDF nhiều trang).\n */\nexport async function rasterizePdf(\n doc: PDFDocumentProxy,\n options: RasterizeOptions = {},\n): Promise<RasterizedPage[]> {\n const scale = options.scale ?? 2;\n const total = doc.numPages;\n const pages = options.pages ?? Array.from({ length: total }, (_, i) => i + 1);\n const signal = options.signal;\n\n const result: RasterizedPage[] = [];\n for (let i = 0; i < pages.length; i++) {\n if (signal?.aborted) {\n throw new DOMException('Rasterize PDF bị huỷ.', 'AbortError');\n }\n const pageNum = pages[i];\n const page = await doc.getPage(pageNum);\n try {\n const rendered = await renderPageToPng(page, scale);\n result.push({ pageNumber: pageNum, mimeType: 'image/png', ...rendered });\n } finally {\n page.cleanup();\n }\n options.onProgress?.(i + 1, pages.length);\n }\n return result;\n}\n\nasync function renderPageToPng(\n page: PDFPageProxy,\n scale: number,\n): Promise<{ dataURL: string; width: number; height: number }> {\n const viewport = page.getViewport({ scale });\n const width = Math.ceil(viewport.width);\n const height = Math.ceil(viewport.height);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Không lấy được 2D context của canvas.');\n await page.render({ canvasContext: ctx, viewport, canvas }).promise;\n const dataURL = canvas.toDataURL('image/png');\n return { dataURL, width, height };\n}\n\n/**\n * Render thumbnail nhẹ cho 1 trang — JPEG 0.7 quality + scale nhỏ (mặc định\n * 0.3). Tối ưu cho preview grid: ~10KB/thumb thay vì ~500KB PNG full scale.\n */\nexport async function renderPageThumbnail(\n page: PDFPageProxy,\n scale = 0.3,\n quality = 0.7,\n): Promise<{ dataURL: string; width: number; height: number }> {\n const viewport = page.getViewport({ scale });\n const width = Math.ceil(viewport.width);\n const height = Math.ceil(viewport.height);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Không lấy được 2D context của canvas.');\n // Nền trắng vì JPEG không support alpha.\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, width, height);\n await page.render({ canvasContext: ctx, viewport, canvas }).promise;\n const dataURL = canvas.toDataURL('image/jpeg', quality);\n return { dataURL, width, height };\n}\n\n/**\n * Render thumbnails cho tất cả trang với concurrency. Callback `onEach` được\n * gọi sau mỗi trang xong (theo thứ tự completion, không phải pageNumber) để\n * UI có thể progressive update. Tôn trọng `signal` để cancel sớm.\n */\nexport async function renderAllThumbnails(\n doc: PDFDocumentProxy,\n onEach: (pageNumber: number, dataURL: string, width: number, height: number) => void,\n options: { scale?: number; quality?: number; concurrency?: number; signal?: AbortSignal } = {},\n): Promise<void> {\n const total = doc.numPages;\n const scale = options.scale ?? 0.3;\n const quality = options.quality ?? 0.7;\n const concurrency = Math.max(1, options.concurrency ?? 3);\n const signal = options.signal;\n let next = 1;\n\n async function worker() {\n while (true) {\n if (signal?.aborted) return;\n const pageNum = next++;\n if (pageNum > total) return;\n const page = await doc.getPage(pageNum);\n try {\n if (signal?.aborted) return;\n const { dataURL, width, height } = await renderPageThumbnail(page, scale, quality);\n if (signal?.aborted) return;\n onEach(pageNum, dataURL, width, height);\n } finally {\n page.cleanup();\n }\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(concurrency, total) }, () => worker()),\n );\n}\n","'use client';\n \n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { parsePageRange } from './parseRange';\nimport { renderAllThumbnails } from './rasterize';\n\ninterface Props {\n doc: PDFDocumentProxy;\n fileName: string;\n onConfirm: (pages: number[]) => void;\n onCancel: () => void;\n}\n\ninterface ThumbInfo {\n dataURL: string;\n width: number;\n height: number;\n}\n\n/**\n * Set<number> → chuỗi range compact dạng \"1-3,5,7-9\".\n * Dùng cho hiển thị + sync ngược về text input khi user click thumbnails.\n */\nfunction serializeSelection(pages: number[]): string {\n if (pages.length === 0) return '';\n const sorted = [...pages].sort((a, b) => a - b);\n const groups: string[] = [];\n let start = sorted[0];\n let prev = start;\n for (let i = 1; i < sorted.length; i++) {\n const n = sorted[i];\n if (n === prev + 1) {\n prev = n;\n } else {\n groups.push(start === prev ? `${start}` : `${start}-${prev}`);\n start = n;\n prev = n;\n }\n }\n groups.push(start === prev ? `${start}` : `${start}-${prev}`);\n return groups.join(',');\n}\n\n/**\n * Modal chọn trang PDF với thumbnail grid.\n *\n * Hai chiều sync:\n * - Gõ text input → parse → update selectedSet → highlight thumbnails.\n * - Click thumbnail → toggle pageNum trong selectedSet → re-serialize text.\n *\n * Source of truth: `selectedSet`. Text input là derived view (user-editable).\n * Khi user đang gõ (focus) → giữ raw `inputValue`, không overwrite. Chỉ\n * re-derive text khi click thumbnail HOẶC input mất focus với value valid.\n */\nexport function PageRangeDialog({ doc, fileName, onConfirm, onCancel }: Props) {\n const totalPages = doc.numPages;\n const defaultPages = useMemo(\n () => Array.from({ length: totalPages }, (_, i) => i + 1),\n [totalPages],\n );\n\n const [selectedSet, setSelectedSet] = useState<Set<number>>(\n () => new Set(defaultPages),\n );\n const [inputValue, setInputValue] = useState(serializeSelection(defaultPages));\n const [inputError, setInputError] = useState<string | null>(null);\n const [thumbs, setThumbs] = useState<Record<number, ThumbInfo>>({});\n const [thumbProgress, setThumbProgress] = useState(0);\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // ---- Render thumbnails khi mount ----\n useEffect(() => {\n const ctrl = new AbortController();\n void renderAllThumbnails(\n doc,\n (pageNum, dataURL, width, height) => {\n setThumbs((prev) => ({ ...prev, [pageNum]: { dataURL, width, height } }));\n setThumbProgress((prev) => prev + 1);\n },\n { scale: 0.3, quality: 0.7, concurrency: 3, signal: ctrl.signal },\n ).catch((err) => {\n if (ctrl.signal.aborted) return;\n console.warn('[PageRangeDialog] render thumbnails lỗi:', err);\n });\n return () => ctrl.abort();\n }, [doc]);\n\n // ---- Esc đóng dialog ----\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n onCancel();\n }\n };\n window.addEventListener('keydown', onKey, { capture: true });\n return () => window.removeEventListener('keydown', onKey, { capture: true });\n }, [onCancel]);\n\n // ---- Text input handlers ----\n const handleInputChange = (next: string) => {\n setInputValue(next);\n try {\n const pages = parsePageRange(next, totalPages);\n setInputError(null);\n setSelectedSet(new Set(pages));\n } catch (e) {\n setInputError((e as Error).message);\n }\n };\n\n // ---- Thumbnail click handler ----\n const toggleThumb = (pageNum: number) => {\n setSelectedSet((prev) => {\n const next = new Set(prev);\n if (next.has(pageNum)) next.delete(pageNum);\n else next.add(pageNum);\n const serialized = serializeSelection([...next]);\n setInputValue(serialized);\n setInputError(null);\n return next;\n });\n };\n\n // ---- Quick select helpers ----\n const selectAll = () => {\n setSelectedSet(new Set(defaultPages));\n setInputValue(serializeSelection(defaultPages));\n setInputError(null);\n };\n\n const clearAll = () => {\n setSelectedSet(new Set());\n setInputValue('');\n setInputError(null);\n };\n\n const canSubmit = inputError === null && selectedSet.size > 0;\n const sortedSelected = useMemo(\n () => [...selectedSet].sort((a, b) => a - b),\n [selectedSet],\n );\n\n const handleSubmit = () => {\n if (!canSubmit) return;\n onConfirm(sortedSelected);\n };\n\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"pdf-range-title\"\n style={{\n position: 'fixed',\n inset: 0,\n background: 'rgba(0,0,0,0.55)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget) onCancel();\n }}\n >\n <div\n style={{\n background: 'var(--popup-bg-color, #fff)',\n color: 'var(--text-primary-color, #1b1b1f)',\n borderRadius: 12,\n padding: '20px 22px',\n width: 'min(880px, 92vw)',\n maxHeight: '88vh',\n boxShadow: '0 12px 40px rgba(0,0,0,0.3)',\n fontFamily: 'inherit',\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div>\n <h2\n id=\"pdf-range-title\"\n style={{ margin: 0, fontSize: 16, fontWeight: 600, lineHeight: 1.3 }}\n >\n Chèn PDF\n </h2>\n <p style={{ margin: '4px 0 0', fontSize: 12, opacity: 0.7 }}>\n {fileName} — {totalPages} trang\n {thumbProgress < totalPages && (\n <> · đang tải preview {thumbProgress}/{totalPages}…</>\n )}\n </p>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>\n <div style={{ flex: 1 }}>\n <label\n style={{ display: 'block', fontSize: 12, marginBottom: 4, opacity: 0.75 }}\n >\n Trang cần chèn (vd: 1,3,5-10) — hoặc click thumbnail bên dưới\n </label>\n <input\n ref={inputRef}\n type=\"text\"\n value={inputValue}\n onChange={(e) => handleInputChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSubmit();\n }\n }}\n style={{\n width: '100%',\n boxSizing: 'border-box',\n padding: '8px 10px',\n fontSize: 14,\n borderRadius: 6,\n border: `1px solid ${inputError ? '#dc2626' : 'rgba(0,0,0,0.2)'}`,\n outline: 'none',\n background: 'var(--input-bg-color, #fff)',\n color: 'inherit',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n }}\n />\n </div>\n <div style={{ display: 'flex', gap: 6, paddingTop: 18 }}>\n <button\n type=\"button\"\n onClick={selectAll}\n style={quickBtnStyle}\n title=\"Chọn tất cả trang\"\n >\n Tất cả\n </button>\n <button\n type=\"button\"\n onClick={clearAll}\n style={quickBtnStyle}\n title=\"Bỏ chọn tất cả\"\n >\n Bỏ hết\n </button>\n </div>\n </div>\n\n <div style={{ minHeight: 18, fontSize: 12 }} data-testid=\"pdf-range-status\">\n {inputError ? (\n <span style={{ color: '#dc2626' }}>{inputError}</span>\n ) : (\n <span style={{ opacity: 0.75 }}>\n Đã chọn <strong>{selectedSet.size}</strong> / {totalPages} trang\n </span>\n )}\n </div>\n\n <div\n style={{\n flex: 1,\n minHeight: 240,\n maxHeight: '60vh',\n overflow: 'auto',\n padding: 8,\n background: 'rgba(0,0,0,0.04)',\n borderRadius: 8,\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',\n gap: 10,\n alignContent: 'start',\n }}\n >\n {Array.from({ length: totalPages }, (_, i) => i + 1).map((pageNum) => {\n const thumb = thumbs[pageNum];\n const selected = selectedSet.has(pageNum);\n return (\n <ThumbnailItem\n key={pageNum}\n pageNum={pageNum}\n thumb={thumb}\n selected={selected}\n onToggle={() => toggleThumb(pageNum)}\n />\n );\n })}\n </div>\n\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n paddingTop: 4,\n }}\n >\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n padding: '8px 14px',\n fontSize: 13,\n borderRadius: 6,\n border: '1px solid rgba(0,0,0,0.15)',\n background: 'transparent',\n color: 'inherit',\n cursor: 'pointer',\n }}\n >\n Huỷ\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n style={{\n padding: '8px 16px',\n fontSize: 13,\n borderRadius: 6,\n border: 'none',\n background: canSubmit ? '#4f46e5' : 'rgba(0,0,0,0.15)',\n color: '#fff',\n cursor: canSubmit ? 'pointer' : 'not-allowed',\n fontWeight: 500,\n }}\n >\n Chèn {selectedSet.size > 0 ? `${selectedSet.size} trang` : ''}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n\nconst quickBtnStyle: React.CSSProperties = {\n padding: '7px 10px',\n fontSize: 12,\n borderRadius: 6,\n border: '1px solid rgba(0,0,0,0.15)',\n background: 'transparent',\n color: 'inherit',\n cursor: 'pointer',\n whiteSpace: 'nowrap',\n};\n\ninterface ThumbProps {\n pageNum: number;\n thumb: ThumbInfo | undefined;\n selected: boolean;\n onToggle: () => void;\n}\n\nfunction ThumbnailItem({ pageNum, thumb, selected, onToggle }: ThumbProps) {\n const aspect = thumb ? thumb.width / thumb.height : 0.77; // A4 portrait default\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n aria-pressed={selected}\n aria-label={`Trang ${pageNum}${selected ? ' (đã chọn)' : ''}`}\n title={`Trang ${pageNum}`}\n style={{\n position: 'relative',\n padding: 0,\n background: '#fff',\n border: `2px solid ${selected ? '#4f46e5' : 'rgba(0,0,0,0.12)'}`,\n borderRadius: 6,\n overflow: 'hidden',\n cursor: 'pointer',\n boxShadow: selected ? '0 0 0 3px rgba(79,70,229,0.18)' : 'none',\n transition: 'border-color 80ms ease, box-shadow 80ms ease',\n }}\n >\n <div\n style={{\n width: '100%',\n aspectRatio: aspect.toString(),\n background: '#f5f5f5',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {thumb ? (\n <img\n src={thumb.dataURL}\n alt=\"\"\n style={{ width: '100%', height: '100%', display: 'block', objectFit: 'contain' }}\n draggable={false}\n />\n ) : (\n <div style={{ fontSize: 11, opacity: 0.5 }}>…</div>\n )}\n </div>\n <div\n style={{\n position: 'absolute',\n bottom: 4,\n left: 4,\n fontSize: 10,\n fontWeight: 600,\n padding: '2px 6px',\n borderRadius: 4,\n background: selected ? '#4f46e5' : 'rgba(0,0,0,0.6)',\n color: '#fff',\n }}\n >\n {pageNum}\n </div>\n {selected && (\n <div\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n top: 4,\n right: 4,\n width: 18,\n height: 18,\n borderRadius: '50%',\n background: '#4f46e5',\n color: '#fff',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 11,\n fontWeight: 700,\n boxShadow: '0 1px 3px rgba(0,0,0,0.3)',\n }}\n >\n ✓\n </div>\n )}\n </button>\n );\n}\n","import { useCallback, useRef } from 'react';\nimport { findStampForCustomData } from './registry';\nimport type { StampType } from './types';\n\nconst DOUBLE_CLICK_MS = 400;\n\ninterface Opts {\n enabled: boolean;\n stamps: ReadonlyArray<StampType>;\n onOpen: (\n kind: string,\n editingElement: { id: string; customData: unknown },\n ) => void;\n}\n\n/**\n * Trả về handler cho Excalidraw `onPointerDown`. Phát hiện double-click vào\n * image element thuộc một stamp đã đăng ký → gọi `onOpen(kind, element)`.\n */\nexport function useStampDoubleClick({ enabled, stamps, onOpen }: Opts) {\n const lastClickRef = useRef<{ time: number; elementId: string | null }>({\n time: 0,\n elementId: null,\n });\n\n return useCallback(\n \n (_activeTool: any, pointerDownState: any) => {\n if (!enabled) return;\n const hitElement = pointerDownState?.hit?.element;\n if (!hitElement || hitElement.type !== 'image') return;\n const stamp = findStampForCustomData(hitElement.customData, stamps);\n if (!stamp) return;\n const now = Date.now();\n const isDouble =\n lastClickRef.current.elementId === hitElement.id &&\n now - lastClickRef.current.time < DOUBLE_CLICK_MS;\n lastClickRef.current = { time: now, elementId: hitElement.id };\n if (!isDouble) return;\n onOpen(stamp.kind, {\n id: hitElement.id,\n customData: hitElement.customData,\n });\n },\n [enabled, stamps, onOpen],\n );\n}\n","import { useEffect, useMemo } from 'react';\nimport type { StampType } from './types';\n\nconst ALLOWED_KEYS = new Set([\n 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight',\n 'Shift', 'Control', 'Alt', 'Meta', 'CapsLock',\n 'Home', 'End', 'PageUp', 'PageDown',\n]);\n\nfunction isEditable(el: EventTarget | null): boolean {\n if (!(el instanceof HTMLElement)) return false;\n if (el.isContentEditable) return true;\n const tag = el.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';\n}\n\ninterface Opts {\n /** Active stamp kind. Null = no blocker. */\n activeStamp: string | null;\n /** Stamps đăng ký để allow shortcut keys của chúng đi qua. */\n stamps: ReadonlyArray<StampType>;\n}\n\n/**\n * Khi 1 stamp panel đang mở, block hoàn toàn các phím tắt Excalidraw\n * (1-9, V, R, D...) bằng cách prevent + stop tại capture phase. Cho phép qua:\n * Tab/Arrow/Modifier, Escape, và phím tắt đã đăng ký bởi stamps (V/G/L/D...).\n */\nexport function useStampShortcutBlocker({ activeStamp, stamps }: Opts) {\n const shortcutKeys = useMemo(\n () => new Set(stamps.map((s) => s.shortcutKey.toLowerCase())),\n [stamps],\n );\n\n useEffect(() => {\n if (!activeStamp) return;\n\n const blocker = (e: KeyboardEvent) => {\n if (isEditable(e.target)) return;\n if (e.ctrlKey || e.metaKey) return;\n if (ALLOWED_KEYS.has(e.key)) return;\n if (e.key === 'Escape') return;\n if (shortcutKeys.has(e.key.toLowerCase())) return;\n e.preventDefault();\n e.stopPropagation();\n };\n window.addEventListener('keydown', blocker, { capture: true });\n return () => window.removeEventListener('keydown', blocker, { capture: true });\n }, [activeStamp, shortcutKeys]);\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { StampHostHandle } from './types';\n\ninterface Opts {\n /** Active stamp. Null = no listener. */\n activeStamp: string | null;\n /** Ref tới Host imperative API (tryInsert / hasContent). */\n hostRef: RefObject<StampHostHandle | null>;\n /** Callback đóng panel. */\n onClose: () => void;\n}\n\n/**\n * Khi 1 stamp panel mở, lắng nghe pointer/mouse-down toàn document. Nếu\n * điểm click không nằm trong vùng `[data-stamp-area=\"true\"]`, gọi\n * `hostRef.tryInsert()` để auto-commit (nếu có nội dung) rồi `onClose()`.\n */\nexport function useStampClickOutside({ activeStamp, hostRef, onClose }: Opts) {\n useEffect(() => {\n if (!activeStamp) return;\n let lastFire = 0;\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n if (target.closest('[data-stamp-area=\"true\"]')) return;\n const now = Date.now();\n if (now - lastFire < 50) return;\n lastFire = now;\n hostRef.current?.tryInsert();\n onClose();\n };\n window.addEventListener('pointerdown', handler, { capture: true });\n window.addEventListener('mousedown', handler, { capture: true });\n return () => {\n window.removeEventListener('pointerdown', handler, { capture: true });\n window.removeEventListener('mousedown', handler, { capture: true });\n };\n }, [activeStamp, hostRef, onClose]);\n}\n","import { type MutableRefObject, useCallback, useRef, useState } from 'react';\n\n \ntype ExApi = any;\n\nexport interface UseExcalidrawApiOptions {\n onApi?: (api: ExApi) => void;\n}\n\nexport interface UseExcalidrawApiResult {\n api: ExApi | null;\n apiRef: MutableRefObject<ExApi | null>;\n isDark: boolean;\n isDarkRef: MutableRefObject<boolean>;\n /** Gắn vào Excalidraw prop `excalidrawAPI`. Defer setState qua microtask\n * để tránh React 19 \"update from inside an update function\" warning. */\n setApiFromExcalidraw: (api: ExApi) => void;\n /** Gọi từ onChange. Bail-out qua ref + defer setState. */\n syncThemeFromAppState: (appState: { theme?: string } | undefined) => void;\n}\n\nexport function useExcalidrawApi(\n opts: UseExcalidrawApiOptions = {},\n): UseExcalidrawApiResult {\n const { onApi } = opts;\n const [api, setApi] = useState<ExApi | null>(null);\n const apiRef = useRef<ExApi | null>(null);\n const [isDark, setIsDark] = useState(false);\n const isDarkRef = useRef(false);\n const onApiRef = useRef(onApi);\n onApiRef.current = onApi;\n\n const setApiFromExcalidraw = useCallback((a: ExApi) => {\n if (apiRef.current === a) return;\n apiRef.current = a;\n queueMicrotask(() => {\n setApi(a);\n onApiRef.current?.(a);\n });\n }, []);\n\n const syncThemeFromAppState = useCallback(\n (appState: { theme?: string } | undefined) => {\n const next = appState?.theme === 'dark';\n if (isDarkRef.current !== next) {\n isDarkRef.current = next;\n queueMicrotask(() => setIsDark(next));\n }\n },\n [],\n );\n\n return { api, apiRef, isDark, isDarkRef, setApiFromExcalidraw, syncThemeFromAppState };\n}\n","import { useCallback, useMemo, useState } from 'react';\nimport type { StampType } from '../stamps/shared/registry';\n\nexport interface EditingElement {\n id: string;\n customData: unknown;\n}\n\nexport interface UseActiveStampOptions {\n readOnly: boolean;\n stamps: ReadonlyArray<StampType>;\n}\n\nexport interface UseActiveStampResult {\n activeStamp: string | null;\n editingElement: EditingElement | null;\n stampByKind: Map<string, StampType>;\n activeStampDef: StampType | null;\n HostComponent: StampType['Host'] | null;\n openStamp: (kind: string, element?: EditingElement | null) => void;\n closeStamp: () => void;\n toggleStampByKind: (kind: string) => void;\n}\n\nexport function useActiveStamp(opts: UseActiveStampOptions): UseActiveStampResult {\n const { readOnly, stamps } = opts;\n const [activeStamp, setActiveStamp] = useState<string | null>(null);\n const [editingElement, setEditingElement] = useState<EditingElement | null>(null);\n\n const stampByKind = useMemo(() => {\n const m = new Map<string, StampType>();\n for (const s of stamps) m.set(s.kind, s);\n return m;\n }, [stamps]);\n\n const activeStampDef = activeStamp ? stampByKind.get(activeStamp) ?? null : null;\n const HostComponent = activeStampDef?.Host ?? null;\n\n const openStamp = useCallback(\n (kind: string, element: EditingElement | null = null) => {\n if (readOnly) return;\n if (!stampByKind.has(kind)) return;\n setEditingElement(element);\n setActiveStamp(kind);\n },\n [readOnly, stampByKind],\n );\n\n const closeStamp = useCallback(() => {\n setActiveStamp(null);\n setEditingElement(null);\n }, []);\n\n const toggleStampByKind = useCallback(\n (kind: string) => {\n setActiveStamp((cur) => {\n if (cur === kind) {\n setEditingElement(null);\n return null;\n }\n if (readOnly) return cur;\n if (!stampByKind.has(kind)) return cur;\n setEditingElement(null);\n return kind;\n });\n },\n [readOnly, stampByKind],\n );\n\n return {\n activeStamp,\n editingElement,\n stampByKind,\n activeStampDef,\n HostComponent,\n openStamp,\n closeStamp,\n toggleStampByKind,\n };\n}\n","import type { ExcalidrawElement } from '../types';\nimport { closePdfDocument, loadPdfDocument, rasterizePdf, type RasterizedPage } from './rasterize';\n\n// Excalidraw imperative API — không có public type chính xác.\n \ntype ExApi = any;\n\n/** Khoảng cách dọc giữa các trang PDF khi xếp dọc, ở scene units. */\nconst PAGE_GAP = 24;\n\n/** Scale render mặc định (HiDPI sharp). */\nconst DEFAULT_SCALE = 2;\n\nexport interface InsertRasterizedPagesOptions {\n /** Scale dùng khi rasterize (để chia pixel → scene units). */\n scale: number;\n /** Toạ độ scene gốc cho page đầu tiên. Bỏ qua → giữa viewport. */\n origin?: { x: number; y: number };\n}\n\nexport interface InsertRasterizedPagesResult {\n insertedElementIds: string[];\n fileIds: string[];\n}\n\n/**\n * Chèn array `RasterizedPage` đã có sẵn vào scene. Tách ra để Whiteboard\n * có thể: load doc → hỏi user range → rasterize → insert mà không phải gọi\n * insertPdfPages (load lại từ ArrayBuffer 2 lần).\n */\nexport function insertRasterizedPagesIntoScene(\n api: ExApi,\n rendered: RasterizedPage[],\n options: InsertRasterizedPagesOptions,\n): InsertRasterizedPagesResult {\n if (!api) throw new Error('Excalidraw API chưa sẵn sàng.');\n if (rendered.length === 0) return { insertedElementIds: [], fileIds: [] };\n\n const { scale } = options;\n const filesPayload = rendered.map((p) => ({\n id: generateFileId(),\n dataURL: p.dataURL,\n mimeType: p.mimeType,\n created: Date.now(),\n }));\n api.addFiles(filesPayload);\n\n const origin = options.origin ?? getViewportCenter(api);\n const sceneSizes = rendered.map((p) => pixelsToSceneSize(p.width, p.height, scale));\n const maxSceneWidth = Math.max(...sceneSizes.map((s) => s.width));\n const baseX = origin.x - maxSceneWidth / 2;\n let cursorY = origin.y - sceneSizes[0].height / 2;\n\n const newElements = rendered.map((_, i) => {\n const { width, height } = sceneSizes[i];\n const x = baseX + (maxSceneWidth - width) / 2;\n const y = cursorY;\n cursorY = y + height + PAGE_GAP;\n return buildPdfImageElement(filesPayload[i].id, x, y, width, height);\n });\n\n const existing = api.getSceneElements() as readonly ExcalidrawElement[];\n api.updateScene({\n elements: [...existing, ...newElements],\n appState: { selectedElementIds: {}, croppingElementId: null },\n });\n\n return {\n insertedElementIds: newElements.map((e) => e.id),\n fileIds: filesPayload.map((f) => f.id),\n };\n}\n\n/**\n * Excalidraw lưu width/height theo \"scene units\". File PDF rasterize ở scale 2\n * → pixel = 2 × scene unit. Chia lại để stamp hiển thị đúng kích thước\n * gốc của trang PDF (giấy A4 ≈ 595×842 scene units ở 72 DPI).\n */\nfunction pixelsToSceneSize(pxWidth: number, pxHeight: number, scale: number) {\n return { width: pxWidth / scale, height: pxHeight / scale };\n}\n\nexport interface InsertPdfPagesOptions {\n /** Trang cần chèn (1-based). Bỏ qua → chèn tất cả. */\n pages?: number[];\n /** Scale rasterize. Mặc định 2. */\n scale?: number;\n /** Toạ độ scene gốc cho page đầu tiên. Bỏ qua → giữa viewport. */\n origin?: { x: number; y: number };\n /** Progress callback. */\n onProgress?: (done: number, total: number) => void;\n /** AbortSignal. */\n signal?: AbortSignal;\n}\n\nexport interface InsertPdfPagesResult {\n insertedElementIds: string[];\n pages: RasterizedPage[];\n}\n\n/**\n * Tạo image element cho 1 trang đã rasterize. Trả về object đủ field cho\n * Excalidraw `updateScene`. Lấy `fileId` từ caller để có thể batch addFiles\n * trước khi update elements.\n */\nfunction buildPdfImageElement(\n fileId: string,\n x: number,\n y: number,\n width: number,\n height: number,\n) {\n return {\n type: 'image' as const,\n id: 'pdf_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8),\n x,\n y,\n width,\n height,\n fileId,\n angle: 0,\n strokeColor: 'transparent',\n backgroundColor: 'transparent',\n fillStyle: 'solid',\n strokeWidth: 1,\n strokeStyle: 'solid',\n roughness: 0,\n opacity: 100,\n groupIds: [],\n roundness: null,\n seed: Math.floor(Math.random() * 1e9),\n versionNonce: 0,\n version: 1,\n isDeleted: false,\n boundElements: null,\n updated: Date.now(),\n link: null,\n locked: false,\n status: 'saved',\n scale: [1, 1],\n };\n}\n\nfunction generateFileId(): string {\n return 'pdf_' + Date.now() + '_' + Math.random().toString(36).slice(2, 10);\n}\n\nfunction getViewportCenter(api: ExApi): { x: number; y: number } {\n const appState = api?.getAppState?.() ?? {\n scrollX: 0,\n scrollY: 0,\n width: 800,\n height: 600,\n zoom: { value: 1 },\n };\n const zoom = appState.zoom?.value ?? 1;\n return {\n x: appState.scrollX + (appState.width ?? 800) / 2 / zoom,\n y: appState.scrollY + (appState.height ?? 600) / 2 / zoom,\n };\n}\n\n/**\n * High-level: rasterize PDF + insert thành nhiều image element xếp dọc.\n *\n * Flow:\n * 1. loadPdfDocument(source) → PDFDocumentProxy\n * 2. rasterizePdf(doc, {pages, scale}) → RasterizedPage[]\n * 3. Tạo fileId cho từng page, gọi api.addFiles batch.\n * 4. Tính position: page 1 trung tâm viewport (hoặc origin), các page sau\n * xếp dưới, cách PAGE_GAP.\n * 5. api.updateScene({ elements: [...cũ, ...mới] })\n *\n * Không serialize PDF bytes — sau insert, các page là image element thuần,\n * không thể re-edit qua double-click (theo design quyết định).\n */\nexport async function insertPdfPages(\n api: ExApi,\n source: File | Blob | ArrayBuffer,\n options: InsertPdfPagesOptions = {},\n): Promise<InsertPdfPagesResult> {\n if (!api) throw new Error('Excalidraw API chưa sẵn sàng.');\n\n const scale = options.scale ?? DEFAULT_SCALE;\n const doc = await loadPdfDocument(source);\n let rendered: RasterizedPage[];\n try {\n rendered = await rasterizePdf(doc, {\n pages: options.pages,\n scale,\n onProgress: options.onProgress,\n signal: options.signal,\n });\n } finally {\n void closePdfDocument(doc);\n }\n\n const { insertedElementIds } = insertRasterizedPagesIntoScene(api, rendered, {\n scale,\n origin: options.origin,\n });\n return { insertedElementIds, pages: rendered };\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport {\n loadPdfDocument,\n closePdfDocument,\n rasterizePdf,\n} from '../pdf/rasterize';\nimport { insertRasterizedPagesIntoScene } from '../pdf/insertPdfPages';\n\n// Excalidraw imperative API — không có public type chính xác.\n \ntype ExApi = any;\n\nexport interface PdfPendingState {\n doc: PDFDocumentProxy;\n fileName: string;\n totalPages: number;\n}\n\nexport interface UsePdfImporterOptions {\n readOnly: boolean;\n api: ExApi | null;\n}\n\nexport interface UsePdfImporterResult {\n pdfPending: PdfPendingState | null;\n pdfBusy: boolean;\n handlePdfPick: (file: File) => Promise<void>;\n handlePdfConfirm: (pages: number[]) => Promise<void>;\n handlePdfCancel: () => void;\n}\n\nexport function usePdfImporter(opts: UsePdfImporterOptions): UsePdfImporterResult {\n const { readOnly, api } = opts;\n const [pdfPending, setPdfPending] = useState<PdfPendingState | null>(null);\n const [pdfBusy, setPdfBusy] = useState(false);\n\n const handlePdfPick = useCallback(\n async (file: File) => {\n if (readOnly || pdfBusy) return;\n setPdfBusy(true);\n try {\n const doc = await loadPdfDocument(file);\n setPdfPending({ doc, fileName: file.name, totalPages: doc.numPages });\n } catch (err) {\n console.warn('[whiteboard] Đọc PDF thất bại:', err);\n window.alert('Không đọc được PDF. File có thể đã hỏng hoặc bị mật khẩu bảo vệ.');\n } finally {\n setPdfBusy(false);\n }\n },\n [readOnly, pdfBusy],\n );\n\n const handlePdfPickRef = useRef(handlePdfPick);\n useLayoutEffect(() => {\n handlePdfPickRef.current = handlePdfPick;\n });\n\n const handlePdfConfirm = useCallback(\n async (pages: number[]) => {\n if (!pdfPending || !api) return;\n const { doc } = pdfPending;\n setPdfPending(null);\n setPdfBusy(true);\n const scale = 2;\n try {\n const rendered = await rasterizePdf(doc, { pages, scale });\n await closePdfDocument(doc);\n insertRasterizedPagesIntoScene(api, rendered, { scale });\n } catch (err) {\n console.warn('[whiteboard] Chèn PDF thất bại:', err);\n window.alert('Chèn PDF thất bại. Xem console để biết chi tiết.');\n } finally {\n setPdfBusy(false);\n }\n },\n [pdfPending, api],\n );\n\n const handlePdfCancel = useCallback(() => {\n if (pdfPending) {\n void closePdfDocument(pdfPending.doc);\n }\n setPdfPending(null);\n }, [pdfPending]);\n\n // Drop handler: catch application/pdf trước Excalidraw (nó reject PDF).\n useEffect(() => {\n if (readOnly) return;\n const root = document.querySelector<HTMLElement>('.excalidraw');\n if (!root) return;\n\n const onDragOver = (e: DragEvent) => {\n const items = e.dataTransfer?.items;\n if (!items) return;\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind === 'file' && items[i].type === 'application/pdf') {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';\n return;\n }\n }\n };\n\n const onDrop = (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || files.length === 0) return;\n const pdf = Array.from(files).find((f) => f.type === 'application/pdf');\n if (!pdf) return;\n e.preventDefault();\n e.stopPropagation();\n void handlePdfPickRef.current(pdf);\n };\n\n root.addEventListener('dragover', onDragOver, { capture: true });\n root.addEventListener('drop', onDrop, { capture: true });\n return () => {\n root.removeEventListener('dragover', onDragOver, { capture: true });\n root.removeEventListener('drop', onDrop, { capture: true });\n };\n }, [readOnly, api]);\n\n return { pdfPending, pdfBusy, handlePdfPick, handlePdfConfirm, handlePdfCancel };\n}\n","import type { AppState } from '@excalidraw/excalidraw/types';\nimport type { SyncableAppState } from './types';\n\nexport function pickSyncableAppState(s: AppState): SyncableAppState {\n return {\n viewBackgroundColor: s.viewBackgroundColor,\n zoom: s.zoom,\n scrollX: s.scrollX,\n scrollY: s.scrollY,\n gridSize: s.gridSize ?? null,\n theme: s.theme,\n };\n}\n","// Regenerate Excalidraw BinaryFiles for stamp elements after page reload.\n//\n// Why this exists: VideoRoom only persists the Excalidraw scene (elements +\n// appState) to sessionStorage; binary files (the SVG dataURLs for stamp\n// images) are NOT persisted. After reload, elements still reference a fileId\n// via customData, but the file payload is missing — Excalidraw renders the\n// image area as an empty placeholder.\n//\n// Strategy: tra registry để tìm StampType khớp customData.kind. Nếu stamp có\n// `restoreFileFromCustomData`, gọi trực tiếp với full element (stamp tự lấy\n// fileId + render). Ngược lại, fallback sang `renderSvgFromCustomData` (path\n// cũ: filter type=image + fileId + kiểm tra existing files).\n//\n// Excalidraw key trên fileId chứ không phải hash dataURL nên nếu kết quả\n// render có sai khác nhỏ (vd thứ tự element) cũng không ảnh hưởng.\n//\n// Theme: stamps được render với LIGHT palette (nét đậm). Excalidraw áp dụng\n// `filter: invert(...)` lên canvas trong dark mode → nét tự đảo sáng. KHÔNG\n// cần force regenerate khi user toggle theme.\n\nimport { DEFAULT_STAMPS, findStampForCustomData } from './registry';\nimport type { StampType } from './types';\n\ninterface ElementLike {\n id: string;\n type?: string;\n fileId?: string | null;\n customData?: unknown;\n}\n\ninterface AddFileRecord {\n id: string;\n dataURL: string;\n mimeType: string;\n created: number;\n}\n\nfunction svgToDataURL(svg: string): string {\n const utf8 = unescape(encodeURIComponent(svg));\n return 'data:image/svg+xml;base64,' + btoa(utf8);\n}\n\nasync function buildFileForStamp(\n fileId: string,\n customData: unknown,\n stamp: StampType,\n): Promise<AddFileRecord | null> {\n try {\n if (!stamp.matchesCustomData(customData)) return null;\n const svg = await stamp.renderSvgFromCustomData(customData);\n return { id: fileId, dataURL: svgToDataURL(svg), mimeType: 'image/svg+xml', created: Date.now() };\n } catch (err) {\n console.warn('Stamp restore failed for', fileId, '(' + stamp.kind + ')', err);\n return null;\n }\n}\n\n/**\n * Find stamp elements whose binary file is missing from Excalidraw, then\n * regenerate via registry dispatch. Idempotent: safe to call on every scene\n * update.\n *\n * Stamps that implement `restoreFileFromCustomData` are handled via the new\n * registry-driven path (stamp receives the full element and returns the file\n * record). Stamps that only implement `renderSvgFromCustomData` use the legacy\n * path (filter type=image + fileId, skip already-present files).\n *\n * @param api Excalidraw imperative API.\n * @param elements Tất cả elements trong scene.\n * @param stamps Registry. Default = DEFAULT_STAMPS.\n */\nexport async function restoreMissingStampFiles(\n \n api: any,\n elements: readonly ElementLike[],\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): Promise<void> {\n if (!api) return;\n\n const filesToAdd: AddFileRecord[] = [];\n\n // --- New registry-driven path: stamp.restoreFileFromCustomData ---\n const newPathHandled = new Set<string>();\n for (const el of elements) {\n const stamp = findStampForCustomData(el.customData, stamps);\n if (!stamp?.restoreFileFromCustomData) continue;\n \n const restored = await stamp.restoreFileFromCustomData(el as any);\n if (!restored) continue;\n newPathHandled.add(el.id);\n filesToAdd.push({\n id: restored.fileId,\n dataURL: restored.dataURL,\n mimeType: restored.mimeType,\n created: Date.now(),\n });\n }\n\n // --- Legacy path: stamp.renderSvgFromCustomData (type=image + fileId filter) ---\n const existing = (typeof api.getFiles === 'function') ? api.getFiles() : {};\n const seen = new Set<string>();\n for (const el of elements) {\n if (newPathHandled.has(el.id)) continue;\n if (el.type !== 'image') continue;\n if (!el.fileId) continue;\n if (existing && existing[el.fileId]) continue;\n if (seen.has(el.fileId)) continue;\n const stamp = findStampForCustomData(el.customData, stamps);\n if (!stamp) continue;\n seen.add(el.fileId);\n const built = await buildFileForStamp(el.fileId, el.customData, stamp);\n if (built) filesToAdd.push(built);\n }\n\n if (filesToAdd.length > 0) {\n try { api.addFiles(filesToAdd); } catch (err) { console.warn('addFiles failed:', err); }\n }\n}\n","/**\n * Hardening helpers cho persistence layer:\n *\n * - validateStorageKey: chặn ký tự lạ trong storageKey (consumer-supplied) trước khi\n * ghép vào key prefix (`whiteboard:scene:<key>`) hoặc dùng làm index trong IndexedDB.\n * - safeParseScene: parse JSON với reviver loại bỏ `__proto__/constructor/prototype`\n * để chặn prototype pollution, check max nesting depth, whitelist top-level keys.\n *\n * Các helper này không phụ thuộc DOM nên test được trong jsdom hoặc node thuần.\n */\n\nconst STORAGE_KEY_RE = /^[a-zA-Z0-9_-]{1,128}$/;\n\n/**\n * Validate storageKey từ consumer.\n *\n * Format cho phép: chữ + số + underscore + dash, 1..128 ký tự.\n * Throw nếu không hợp lệ — caller bị buộc handle hoặc crash sớm.\n */\nexport function validateStorageKey(key: unknown): string {\n if (typeof key !== 'string' || !STORAGE_KEY_RE.test(key)) {\n const sample = key === undefined ? 'undefined' : String(key).slice(0, 32);\n throw new Error(\n `[whiteboard] Invalid storageKey: must match ${STORAGE_KEY_RE} (got: ${sample})`,\n );\n }\n return key;\n}\n\nconst DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Reviver dùng cho `JSON.parse`: drop bất kỳ key nào trong DANGEROUS_KEYS,\n * tránh prototype pollution khi parse dữ liệu không tin cậy từ localStorage.\n */\nfunction sanitizingReviver(_key: string, value: unknown): unknown {\n if (DANGEROUS_KEYS.has(_key)) return undefined;\n return value;\n}\n\n/** Max nesting depth cho scene tree (object/array). */\nexport const MAX_NESTED_DEPTH = 64;\n\nfunction depthExceeds(v: unknown, max: number, depth = 0): boolean {\n if (depth > max) return true;\n if (v === null || typeof v !== 'object') return false;\n const children = Array.isArray(v)\n ? v\n : Object.values(v as Record<string, unknown>);\n for (const child of children) {\n if (depthExceeds(child, max, depth + 1)) return true;\n }\n return false;\n}\n\nconst ALLOWED_TOP_LEVEL_KEYS = new Set(['version', 'elements', 'appState', 'savedAt']);\n\n/** Shape của scene đã được validate (chưa check version + element shape — caller lo). */\nexport interface ParsedScene {\n version?: unknown;\n elements: unknown[];\n appState: Record<string, unknown>;\n savedAt?: unknown;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/**\n * Parse + sanitize raw JSON string từ localStorage.\n *\n * 1. JSON.parse với reviver strip dangerous keys.\n * 2. Reject nếu nested depth vượt MAX_NESTED_DEPTH.\n * 3. Whitelist top-level keys (drop extras).\n * 4. `elements` phải là array, mỗi item là object có `id: string` + `type: string`.\n *\n * Trả về `null` nếu bất kỳ check nào fail (caller handle như \"no data\").\n */\nexport function safeParseScene(raw: string): ParsedScene | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw, sanitizingReviver);\n } catch {\n return null;\n }\n if (!isPlainObject(parsed)) return null;\n if (depthExceeds(parsed, MAX_NESTED_DEPTH)) return null;\n\n // Whitelist top-level keys.\n const safe: Record<string, unknown> = {};\n for (const k of Object.keys(parsed)) {\n if (ALLOWED_TOP_LEVEL_KEYS.has(k)) safe[k] = parsed[k];\n }\n\n if (!Array.isArray(safe.elements)) return null;\n for (const el of safe.elements as unknown[]) {\n if (!isPlainObject(el)) return null;\n if (typeof el.id !== 'string' || typeof el.type !== 'string') return null;\n }\n\n const appState = isPlainObject(safe.appState) ? safe.appState : {};\n\n return {\n version: safe.version,\n elements: safe.elements as unknown[],\n appState,\n savedAt: safe.savedAt,\n };\n}\n","import type { ExcalidrawElement, SyncableAppState } from '../../types';\nimport { safeParseScene, validateStorageKey } from './validation';\n\nconst PREFIX = 'whiteboard:scene:';\nconst SCHEMA_VERSION = 1 as const;\n\nexport interface StoredScene {\n version: typeof SCHEMA_VERSION;\n elements: readonly ExcalidrawElement[];\n appState: Partial<SyncableAppState>;\n savedAt: number;\n}\n\nfunction fullKey(key: string): string {\n return PREFIX + key;\n}\n\nexport function readScene(key: string): StoredScene | null {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return null;\n const raw = window.localStorage.getItem(fullKey(validKey));\n if (!raw) return null;\n const parsed = safeParseScene(raw);\n if (!parsed) {\n console.warn('[whiteboard] scene parse/validation failed, clear:', validKey);\n try {\n window.localStorage.removeItem(fullKey(validKey));\n } catch { /* ignore */ }\n return null;\n }\n if (parsed.version !== SCHEMA_VERSION) {\n // Cố ý KHÔNG xoá entry — version mismatch có thể là dữ liệu của client\n // mới hơn (user vừa downgrade). Giữ lại để client tương ứng đọc được sau.\n console.warn(\n `[whiteboard] scene version ${parsed.version} không khớp ${SCHEMA_VERSION}, bỏ qua.`,\n );\n return null;\n }\n return {\n version: SCHEMA_VERSION,\n elements: parsed.elements as readonly ExcalidrawElement[],\n appState: parsed.appState as Partial<SyncableAppState>,\n savedAt: typeof parsed.savedAt === 'number' ? parsed.savedAt : Date.now(),\n };\n}\n\nexport function writeScene(\n key: string,\n payload: { elements: readonly ExcalidrawElement[]; appState: Partial<SyncableAppState> },\n): void {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return;\n const record: StoredScene = {\n version: SCHEMA_VERSION,\n elements: payload.elements,\n appState: payload.appState,\n savedAt: Date.now(),\n };\n try {\n window.localStorage.setItem(fullKey(validKey), JSON.stringify(record));\n } catch (err) {\n console.warn('[whiteboard] scene write failed:', err);\n }\n}\n\nexport function clearScene(key: string): void {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(fullKey(validKey));\n } catch { /* ignore */ }\n}\n","import type { BinaryFiles } from '../../types';\nimport { validateStorageKey } from './validation';\n\nconst DB_NAME = 'whiteboard-files';\nconst DB_VERSION = 1;\nconst STORE = 'files';\n\ninterface FileRecord {\n id: string;\n storageKey: string;\n dataURL: string;\n mimeType: string;\n created: number;\n savedAt: number;\n}\n\nlet dbPromise: Promise<IDBDatabase> | null = null;\nlet idbDisabled = false;\n\nfunction openDb(): Promise<IDBDatabase> {\n if (idbDisabled) return Promise.reject(new Error('IndexedDB disabled'));\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n if (typeof indexedDB === 'undefined') {\n idbDisabled = true;\n reject(new Error('indexedDB undefined'));\n return;\n }\n const req = indexedDB.open(DB_NAME, DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(STORE)) {\n const store = db.createObjectStore(STORE, { keyPath: 'id' });\n store.createIndex('storageKey', 'storageKey', { unique: false });\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => {\n idbDisabled = true;\n reject(req.error ?? new Error('IDB open failed'));\n };\n });\n return dbPromise;\n}\n\nasync function withStore<T>(\n mode: IDBTransactionMode,\n fn: (\n store: IDBObjectStore,\n setResult: (value: T) => void,\n fail: (error: unknown) => void,\n ) => void,\n fallback: T,\n): Promise<T> {\n let db: IDBDatabase;\n try {\n db = await openDb();\n } catch {\n return fallback;\n }\n return new Promise<T>((resolve, reject) => {\n const tx = db.transaction(STORE, mode);\n const store = tx.objectStore(STORE);\n let result = fallback;\n try {\n fn(\n store,\n (value) => {\n result = value;\n },\n reject,\n );\n } catch (err) {\n reject(err);\n return;\n }\n tx.oncomplete = () => resolve(result);\n tx.onerror = () => {\n console.warn('[whiteboard] IDB tx error:', tx.error);\n reject(tx.error ?? new Error('IDB tx error'));\n };\n tx.onabort = () => reject(tx.error ?? new Error('IDB tx aborted'));\n });\n}\n\nexport async function readFiles(storageKey: string): Promise<BinaryFiles> {\n const validKey = validateStorageKey(storageKey);\n try {\n return await withStore(\n 'readonly',\n (store, setResult, fail) => {\n const out: BinaryFiles = {};\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(out);\n return;\n }\n const record = cursor.value as FileRecord;\n \n (out as any)[record.id] = {\n dataURL: record.dataURL,\n mimeType: record.mimeType,\n created: record.created,\n };\n cursor.continue();\n };\n req.onerror = () => fail(req.error);\n },\n {},\n );\n } catch (err) {\n console.warn('[whiteboard] readFiles failed:', err);\n return {};\n }\n}\n\nexport async function writeFiles(storageKey: string, files: BinaryFiles): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n const entries = Object.entries(files);\n if (entries.length === 0) return;\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n let pending = entries.length;\n const finishOne = () => {\n pending -= 1;\n if (pending === 0) setResult(undefined);\n };\n\n const now = Date.now();\n for (const [id, f] of entries) {\n \n const ff = f as any;\n const getReq = store.get(id);\n getReq.onsuccess = () => {\n if (getReq.result) {\n finishOne();\n return;\n }\n const rec: FileRecord = {\n id,\n storageKey: validKey,\n dataURL: ff.dataURL,\n mimeType: ff.mimeType,\n created: ff.created ?? now,\n savedAt: now,\n };\n const putReq = store.put(rec);\n putReq.onsuccess = finishOne;\n putReq.onerror = () => fail(putReq.error);\n };\n getReq.onerror = () => fail(getReq.error);\n };\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] writeFiles failed:', err);\n }\n}\n\nexport async function pruneFiles(\n storageKey: string,\n keepIds: ReadonlySet<string>,\n): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(undefined);\n return;\n }\n const record = cursor.value as FileRecord;\n if (keepIds.has(record.id)) {\n cursor.continue();\n return;\n }\n const deleteReq = cursor.delete();\n deleteReq.onsuccess = () => cursor.continue();\n deleteReq.onerror = () => fail(deleteReq.error);\n };\n req.onerror = () => fail(req.error);\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] pruneFiles failed:', err);\n }\n}\n\nexport async function clearAll(storageKey: string): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(undefined);\n return;\n }\n const deleteReq = cursor.delete();\n deleteReq.onsuccess = () => cursor.continue();\n deleteReq.onerror = () => fail(deleteReq.error);\n };\n req.onerror = () => fail(req.error);\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] clearAll failed:', err);\n }\n}\n","'use client';\nimport { useEffect, useMemo, useRef } from 'react';\nimport type {\n ExcalidrawElement,\n BinaryFiles,\n ExcalidrawSceneSnapshot,\n SyncableAppState,\n} from '../types';\nimport { pickSyncableAppState } from '../serialize';\nimport { isStampElement, type StampType } from '../stamps/shared/registry';\nimport { restoreMissingStampFiles } from '../stamps/shared/restoreStampFiles';\nimport { readScene, writeScene } from '../core/persistence/sceneStore';\nimport { readFiles, writeFiles, pruneFiles } from '../core/persistence/fileStore';\n\nconst SYNC_THROTTLE_MS = 200;\nconst FILE_THROTTLE_MS = 1000;\nconst PRUNE_THROTTLE_MS = 2000;\nconst RESTORE_PASS_DELAY_MS = 400;\n\nexport interface UseScenePersistOptions {\n storageKey: string | null;\n initialScene?: ExcalidrawSceneSnapshot | null;\n initialFiles?: BinaryFiles;\n readOnly: boolean;\n onSceneChange?: (snapshot: ExcalidrawSceneSnapshot) => void;\n onFilesChange?: (files: BinaryFiles, newFileIds: string[]) => void;\n \n api: any;\n \n apiRef: React.MutableRefObject<any>;\n stamps: ReadonlyArray<StampType>;\n}\n\nexport interface UseScenePersistResult {\n effectiveInitialScene: ExcalidrawSceneSnapshot | null;\n \n onSceneTick: (elements: readonly ExcalidrawElement[], appState: any, files: BinaryFiles) => void;\n}\n\n// Bundle toàn bộ persist orchestration cho Whiteboard:\n// - effectiveInitialScene: precedence initialScene > localStorage > blank.\n// - onSceneTick: gọi từ Excalidraw onChange (sau theme-sync + crop intercept).\n// Track new fileIds, throttle scene/file/prune writes.\n// - Mount: load initialFiles (server) + IDB raster + restoreMissingStampFiles.\n// - Unmount: flush mọi pending write trước teardown.\nexport function useScenePersist(opts: UseScenePersistOptions): UseScenePersistResult {\n const {\n storageKey,\n initialScene,\n initialFiles,\n readOnly,\n onSceneChange,\n onFilesChange,\n api,\n apiRef,\n stamps,\n } = opts;\n\n const persistEnabled = typeof storageKey === 'string' && storageKey.length > 0;\n\n const knownFileIdsRef = useRef<Set<string>>(new Set());\n const lastSceneHashRef = useRef<string>('');\n const sceneThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const fileThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pruneThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestSceneRef = useRef<{\n elements: readonly ExcalidrawElement[];\n \n appState: any;\n } | null>(null);\n const pendingFilesRef = useRef<BinaryFiles>({});\n // Cached hashElementsVersion để flushScene chạy sync trong unmount cleanup\n // (cleanup không thể await dynamic import).\n \n const hashElementsVersionRef = useRef<((elements: readonly ExcalidrawElement[]) => any) | null>(null);\n\n const stampsRef = useRef(stamps);\n stampsRef.current = stamps;\n const persistKeyRef = useRef(storageKey);\n persistKeyRef.current = storageKey;\n const onSceneChangeRef = useRef(onSceneChange);\n onSceneChangeRef.current = onSceneChange;\n const onFilesChangeRef = useRef(onFilesChange);\n onFilesChangeRef.current = onFilesChange;\n const persistEnabledRef = useRef(persistEnabled);\n persistEnabledRef.current = persistEnabled;\n\n const persistedInitial = useMemo(\n () => (persistEnabled ? readScene(storageKey as string) : null),\n [persistEnabled, storageKey],\n );\n const effectiveInitialScene: ExcalidrawSceneSnapshot | null =\n initialScene !== undefined\n ? initialScene\n : persistedInitial\n ? {\n elements: persistedInitial.elements,\n appState: persistedInitial.appState as SyncableAppState,\n }\n : null;\n\n const flushSceneRef = useRef<() => void>(() => undefined);\n flushSceneRef.current = () => {\n try {\n const latestScene = latestSceneRef.current;\n if (!latestScene) return;\n const liveElements = latestScene.elements.filter((e) => !e.isDeleted) as readonly ExcalidrawElement[];\n const liveAppState = pickSyncableAppState(latestScene.appState);\n const hashFn = hashElementsVersionRef.current;\n // Chưa load module → bỏ qua hash dedupe, ghi luôn (correctness > perf khi unmount).\n const elementHash = hashFn ? hashFn(liveElements) : liveElements.map((e) => e.id).join('|');\n const sceneHash = `${elementHash}:${JSON.stringify(liveAppState)}`;\n if (sceneHash === lastSceneHashRef.current) return;\n lastSceneHashRef.current = sceneHash;\n onSceneChangeRef.current?.({ elements: liveElements, appState: liveAppState });\n if (persistEnabledRef.current) {\n writeScene(persistKeyRef.current as string, {\n elements: liveElements,\n appState: liveAppState,\n });\n }\n } catch (err) {\n console.warn('[whiteboard] flushScene thất bại:', err);\n }\n };\n\n const flushFilesRef = useRef<() => void>(() => undefined);\n flushFilesRef.current = () => {\n try {\n const pending = pendingFilesRef.current;\n pendingFilesRef.current = {};\n if (Object.keys(pending).length === 0) return;\n const currentElements = (apiRef.current?.getSceneElements?.()\n ?? latestSceneRef.current?.elements\n ?? []) as readonly ExcalidrawElement[];\n const stampIds = new Set<string>();\n for (const el of currentElements) {\n \n const fid = (el as any).fileId as string | undefined;\n if (fid && isStampElement(el)) stampIds.add(fid);\n }\n const raster: BinaryFiles = {};\n for (const [id, f] of Object.entries(pending)) {\n if (!stampIds.has(id)) raster[id] = f;\n }\n if (Object.keys(raster).length > 0) {\n void writeFiles(persistKeyRef.current as string, raster);\n }\n } catch (err) {\n console.warn('[whiteboard] flushFiles thất bại:', err);\n }\n };\n\n const flushPruneRef = useRef<() => void>(() => undefined);\n flushPruneRef.current = () => {\n try {\n const currentElements = (apiRef.current?.getSceneElements?.()\n ?? latestSceneRef.current?.elements\n ?? []) as readonly ExcalidrawElement[];\n const keep = new Set<string>();\n for (const el of currentElements) {\n \n const fid = (el as any).fileId as string | undefined;\n if (fid && !isStampElement(el)) keep.add(fid);\n }\n void pruneFiles(persistKeyRef.current as string, keep);\n } catch (err) {\n console.warn('[whiteboard] flushPrune thất bại:', err);\n }\n };\n\n const onSceneTick: UseScenePersistResult['onSceneTick'] = (elements, appState, files) => {\n if (readOnly) return;\n latestSceneRef.current = { elements, appState };\n\n const fileIds = Object.keys(files);\n const newIds = fileIds.filter((id) => !knownFileIdsRef.current.has(id));\n if (newIds.length > 0) {\n newIds.forEach((id) => knownFileIdsRef.current.add(id));\n onFilesChangeRef.current?.(files, newIds);\n }\n\n if (!sceneThrottleRef.current) {\n sceneThrottleRef.current = setTimeout(async () => {\n sceneThrottleRef.current = null;\n try {\n const mod = await import('@excalidraw/excalidraw');\n \n hashElementsVersionRef.current = (mod as any).hashElementsVersion;\n } catch (err) {\n console.warn('[whiteboard] import excalidraw để flush scene thất bại:', err);\n return;\n }\n flushSceneRef.current();\n }, SYNC_THROTTLE_MS);\n }\n\n if (persistEnabled && newIds.length > 0) {\n for (const id of newIds) {\n if (files[id]) pendingFilesRef.current[id] = files[id];\n }\n if (!fileThrottleRef.current) {\n fileThrottleRef.current = setTimeout(() => {\n fileThrottleRef.current = null;\n flushFilesRef.current();\n }, FILE_THROTTLE_MS);\n }\n }\n\n if (persistEnabled && !pruneThrottleRef.current) {\n pruneThrottleRef.current = setTimeout(() => {\n pruneThrottleRef.current = null;\n flushPruneRef.current();\n }, PRUNE_THROTTLE_MS);\n }\n };\n\n // Mount: load initialFiles (server) → addFiles 1 lần khi api ready.\n const initialFilesAddedRef = useRef(false);\n useEffect(() => {\n if (!api || initialFilesAddedRef.current) return;\n initialFilesAddedRef.current = true;\n if (!initialFiles) return;\n const entries = Object.entries(initialFiles);\n if (entries.length === 0) return;\n try {\n api.addFiles(\n entries.map(([id, f]) => ({\n id,\n \n dataURL: (f as any).dataURL,\n \n mimeType: (f as any).mimeType,\n \n created: (f as any).created ?? Date.now(),\n })),\n );\n entries.forEach(([id]) => knownFileIdsRef.current.add(id));\n } catch (err) {\n console.warn('[whiteboard] addFiles initialFiles thất bại:', err);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api]);\n\n // Mount: load persisted raster files từ IDB → addFiles.\n useEffect(() => {\n if (!api || !persistEnabled) return;\n let cancelled = false;\n void readFiles(storageKey as string).then(\n (files) => {\n // Recheck cancelled — IDB onsuccess có thể fire sau component unmount.\n if (cancelled) return;\n const entries = Object.entries(files);\n if (entries.length === 0) return;\n if (cancelled) return;\n try {\n api.addFiles(\n entries.map(([id, f]) => ({\n id,\n \n dataURL: (f as any).dataURL,\n \n mimeType: (f as any).mimeType,\n \n created: (f as any).created ?? Date.now(),\n })),\n );\n if (cancelled) return;\n entries.forEach(([id]) => knownFileIdsRef.current.add(id));\n } catch (err) {\n if (cancelled) return;\n console.warn('[whiteboard] addFiles từ IDB thất bại:', err);\n }\n },\n (err) => {\n if (cancelled) return;\n console.warn('[whiteboard] readFiles thất bại:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [api, persistEnabled, storageKey]);\n\n useEffect(() => {\n if (!api) return;\n let cancelled = false;\n const run = async () => {\n if (cancelled) return;\n try {\n const elements = api.getSceneElements();\n if (!elements || elements.length === 0) return;\n if (cancelled) return;\n // stamps đọc từ ref — props có thể đã đổi sau 400ms, closure stale.\n await restoreMissingStampFiles(api, elements, stampsRef.current);\n } catch (err) {\n if (cancelled) return;\n console.warn('Math stamp restore pass failed:', err);\n }\n };\n void run();\n const t = setTimeout(() => {\n void run();\n }, RESTORE_PASS_DELAY_MS);\n return () => {\n cancelled = true;\n clearTimeout(t);\n };\n }, [api, persistedInitial]);\n\n // Unmount cleanup: flush pending writes TRƯỚC khi clearTimeout để không\n // mất scene/file write cuối khi user navigate giữa throttle window.\n useEffect(\n () => () => {\n if (sceneThrottleRef.current) {\n clearTimeout(sceneThrottleRef.current);\n sceneThrottleRef.current = null;\n flushSceneRef.current();\n }\n if (fileThrottleRef.current) {\n clearTimeout(fileThrottleRef.current);\n fileThrottleRef.current = null;\n flushFilesRef.current();\n }\n if (pruneThrottleRef.current) {\n clearTimeout(pruneThrottleRef.current);\n pruneThrottleRef.current = null;\n flushPruneRef.current();\n }\n },\n [],\n );\n\n return { effectiveInitialScene, onSceneTick };\n}\n","'use client';\n\nimport { lazy, Suspense, useCallback, useEffect, useRef } from 'react';\nimport type {\n ExcalidrawElement,\n BinaryFiles,\n ExcalidrawSceneSnapshot,\n} from './types';\nimport {\n DEFAULT_STAMPS,\n findStampForCustomData,\n type StampType,\n} from './stamps/shared/registry';\nimport { ToolbarInjector } from './stamps/shared/ToolbarInjector';\nimport { useShortcuts } from './stamps/shared/useShortcuts';\nimport { PdfImporterButton } from './pdf/PdfImporterButton';\nimport { PageRangeDialog } from './pdf/PageRangeDialog';\nimport { useStampDoubleClick } from './stamps/shared/useStampDoubleClick';\nimport { useStampShortcutBlocker } from './stamps/shared/useStampShortcutBlocker';\nimport { useStampClickOutside } from './stamps/shared/useStampClickOutside';\nimport type { GenerateGeometryFigure, StampHostHandle } from './stamps/shared/types';\nimport { useExcalidrawApi } from './hooks/useExcalidrawApi';\nimport { useActiveStamp } from './hooks/useActiveStamp';\nimport { usePdfImporter } from './hooks/usePdfImporter';\nimport { useScenePersist } from './hooks/useScenePersist';\nimport '@excalidraw/excalidraw/index.css';\nimport './stamps/shared/stamp.css';\n\nconst Excalidraw = lazy(() =>\n import('./ExcalidrawWithMenus').then((m) => ({ default: m.ExcalidrawWithMenus })),\n);\n\nconst ExcalidrawLoadingFallback = () => (\n <div className=\"flex h-full items-center justify-center text-sm text-gray-500\">\n Đang tải bảng…\n </div>\n);\n\nexport interface WhiteboardProps {\n /**\n * Storage key cho persist client-side.\n * - Scene -> localStorage['whiteboard:scene:'+storageKey]\n * - Files raster -> IndexedDB 'whiteboard-files' index theo storageKey\n * - Default: 'default'\n * - Truyen `null` de tat persist (consumer drive state qua onApi).\n */\n storageKey?: string | null;\n\n /** View-only (Excalidraw viewModeEnabled). Default false. */\n readOnly?: boolean;\n\n /** Local edits -> consumer broadcast. Optional. */\n onSceneChange?: (snapshot: ExcalidrawSceneSnapshot) => void;\n onFilesChange?: (files: BinaryFiles, newFileIds: string[]) => void;\n\n /** Excalidraw imperative API. Consumer dung inject remote scene khi can. */\n \n onApi?: (api: any) => void;\n\n /** Excalidraw UI language. Defaults to 'vi-VN'. See @excalidraw/excalidraw locales. */\n langCode?: string;\n\n /**\n * Danh sách stamp đăng ký. Mỗi stamp khai báo phím tắt + toolbar button +\n * Host component (UI editing). Mặc định DEFAULT_STAMPS (= ALL_STAMPS,\n * gồm geometry + latex + geometry3d + graph2d).\n * Truyền `[...DEFAULT_STAMPS, customStamp]` để thêm stamp mới hoặc\n * `STABLE_STAMPS` để chỉ bật stamp ổn định.\n */\n stamps?: ReadonlyArray<StampType>;\n\n /**\n * Snapshot từ server. Precedence: `initialScene` > localStorage > blank.\n * - `undefined` (default) → đọc từ localStorage qua `storageKey`\n * - `null` → explicit blank, bỏ qua localStorage\n * - object → dùng làm initialData của Excalidraw, bỏ qua localStorage\n *\n * Dùng để load board từ server. Thường đi cùng `storageKey={null}` để\n * tránh localStorage stale override server data.\n */\n initialScene?: ExcalidrawSceneSnapshot | null;\n\n /**\n * Binary files (raster, base64) từ server. Add vào Excalidraw đúng 1 lần\n * khi api ready. Dùng kèm `initialScene` cho flow load-from-server.\n * Nếu cần inject files động về sau, dùng `onApi` rồi gọi `api.addFiles`.\n */\n initialFiles?: BinaryFiles;\n\n /**\n * Opt-in bridge for the geometry editor AI prompt. This callback should call\n * `generateFigure()` on a server boundary so API credentials never reach the browser.\n */\n generateGeometryFigure?: GenerateGeometryFigure;\n}\n\nexport function Whiteboard({\n storageKey = 'default',\n readOnly = false,\n onSceneChange,\n onFilesChange,\n onApi,\n langCode = 'vi-VN',\n stamps = DEFAULT_STAMPS,\n initialScene,\n initialFiles,\n generateGeometryFigure,\n}: WhiteboardProps) {\n const { api, apiRef, isDark, setApiFromExcalidraw, syncThemeFromAppState } =\n useExcalidrawApi({ onApi });\n\n const {\n activeStamp,\n editingElement,\n HostComponent,\n openStamp,\n closeStamp,\n toggleStampByKind,\n } = useActiveStamp({ readOnly, stamps });\n\n const {\n pdfPending,\n pdfBusy,\n handlePdfPick,\n handlePdfConfirm,\n handlePdfCancel,\n } = usePdfImporter({ readOnly, api });\n\n const { effectiveInitialScene, onSceneTick } = useScenePersist({\n storageKey,\n initialScene,\n initialFiles,\n readOnly,\n onSceneChange,\n onFilesChange,\n api,\n apiRef,\n stamps,\n });\n\n const hostRef = useRef<StampHostHandle | null>(null);\n const handledCropIdRef = useRef<string | null>(null);\n const prevExcalidrawToolRef = useRef<string>('selection');\n\n // Capture local changes: theme sync → crop intercept (re-edit) → persist tick.\n const handleChange = useCallback(\n \n (elements: readonly ExcalidrawElement[], appState: any, files: BinaryFiles) => {\n syncThemeFromAppState(appState);\n\n if (readOnly) return;\n\n // Intercept Excalidraw crop-image flow cho stamps: khi user double-click\n // 1 stamp, Excalidraw set appState.croppingElementId. Ta dismiss crop mode +\n // mở Host editor tương ứng. handlePointerDown phát hiện double-click sớm\n // hơn — đây là fallback (đặc biệt khi click rơi vào selection handle).\n const cropId = appState?.croppingElementId as string | null | undefined;\n if (cropId && cropId !== handledCropIdRef.current && api) {\n const el = elements.find((e: ExcalidrawElement) => e.id === cropId);\n if (el) {\n const stamp = findStampForCustomData((el as { customData?: unknown }).customData, stamps);\n if (stamp) {\n handledCropIdRef.current = cropId;\n // Defer updateScene + openStamp ra khỏi commit-phase của Excalidraw —\n // chạy đồng bộ sẽ trigger React 19 warn \"update scheduled from inside\n // an update function\" (handleChange chạy trong updater).\n const elId = el.id;\n const elCustom = (el as { customData?: unknown }).customData;\n const stampKind = stamp.kind;\n queueMicrotask(() => {\n try {\n api.updateScene({\n appState: { croppingElementId: null, selectedElementIds: {} },\n });\n } catch { /* ignore */ }\n openStamp(stampKind, { id: elId, customData: elCustom });\n });\n return;\n }\n }\n }\n if (!cropId) {\n handledCropIdRef.current = null;\n }\n\n onSceneTick(elements, appState, files);\n },\n [readOnly, api, stamps, openStamp, syncThemeFromAppState, onSceneTick],\n );\n\n // Double-click detection for re-edit.\n const handlePointerDown = useStampDoubleClick({\n enabled: !readOnly,\n stamps,\n onOpen: openStamp,\n });\n\n // Keyboard shortcuts: đọc registry, mỗi stamp tự khai báo phím tắt.\n useShortcuts({\n enabled: !readOnly,\n onToggle: toggleStampByKind,\n stamps,\n });\n\n // Sync Excalidraw activeTool với activeStamp.\n useEffect(() => {\n if (!api) return;\n if (activeStamp) {\n try {\n const cur = api.getAppState?.()?.activeTool?.type ?? 'selection';\n if (cur && cur !== 'hand') prevExcalidrawToolRef.current = cur;\n api.setActiveTool?.({ type: 'hand' });\n } catch { /* ignore */ }\n } else {\n try {\n \n api.setActiveTool?.({ type: prevExcalidrawToolRef.current as any });\n } catch { /* ignore */ }\n }\n }, [activeStamp, api]);\n\n // Block Excalidraw shortcuts khi stamp panel đang mở.\n useStampShortcutBlocker({ activeStamp, stamps });\n\n // Esc đóng panel (capture phase để chạy TRƯỚC Excalidraw).\n useEffect(() => {\n if (!activeStamp) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n const ae = document.activeElement as HTMLElement | null;\n if (ae && (ae.tagName === 'TEXTAREA' || ae.isContentEditable)) {\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n closeStamp();\n };\n window.addEventListener('keydown', onKey, { capture: true });\n return () => window.removeEventListener('keydown', onKey, { capture: true });\n }, [activeStamp, closeStamp]);\n\n useStampClickOutside({ activeStamp, hostRef, onClose: closeStamp });\n\n return (\n <div className={`relative h-full w-full${isDark ? ' theme--dark' : ''}`}>\n <Suspense fallback={<ExcalidrawLoadingFallback />}>\n <Excalidraw\n excalidrawAPI={setApiFromExcalidraw}\n langCode={langCode}\n viewModeEnabled={readOnly}\n initialData={\n effectiveInitialScene\n ? {\n elements: effectiveInitialScene.elements,\n appState: {\n ...effectiveInitialScene.appState,\n gridSize: effectiveInitialScene.appState.gridSize ?? undefined,\n },\n }\n : { appState: { viewBackgroundColor: '#ffffff' } }\n }\n onChange={handleChange}\n onPointerDown={handlePointerDown}\n />\n </Suspense>\n\n <ToolbarInjector\n enabled={!readOnly}\n activeStampKind={activeStamp}\n onToggle={toggleStampByKind}\n stamps={stamps}\n />\n\n <PdfImporterButton enabled={!readOnly} onPick={handlePdfPick} />\n\n {pdfPending && (\n <PageRangeDialog\n doc={pdfPending.doc}\n fileName={pdfPending.fileName}\n onConfirm={handlePdfConfirm}\n onCancel={handlePdfCancel}\n />\n )}\n\n {pdfBusy && !pdfPending && (\n <div\n aria-live=\"polite\"\n role=\"status\"\n style={{\n position: 'fixed',\n bottom: 16,\n right: 16,\n padding: '8px 14px',\n background: 'rgba(0,0,0,0.75)',\n color: '#fff',\n borderRadius: 6,\n fontSize: 12,\n zIndex: 10000,\n }}\n >\n Đang xử lý PDF…\n </div>\n )}\n\n {HostComponent && (\n <HostComponent\n ref={hostRef}\n api={api}\n editingElement={editingElement}\n onClose={closeStamp}\n isDark={isDark}\n generateGeometryFigure={generateGeometryFigure}\n />\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/stamps/shared/catalog.ts","../src/stamps/shared/registry.ts","../src/stamps/shared/ToolbarInjector.tsx","../src/stamps/shared/useShortcuts.ts","../src/pdf/PdfImporterButton.tsx","../src/pdf/parseRange.ts","../src/pdf/rasterize.ts","../src/pdf/PageRangeDialog.tsx","../src/stamps/shared/useStampDoubleClick.ts","../src/stamps/shared/useStampShortcutBlocker.ts","../src/stamps/shared/useStampClickOutside.ts","../src/hooks/useExcalidrawApi.ts","../src/hooks/useActiveStamp.ts","../src/pdf/insertPdfPages.ts","../src/hooks/usePdfImporter.ts","../src/serialize.ts","../src/stamps/shared/restoreStampFiles.ts","../src/core/persistence/validation.ts","../src/core/persistence/sceneStore.ts","../src/core/persistence/fileStore.ts","../src/hooks/useScenePersist.ts","../src/Whiteboard.tsx"],"names":["useEffect","POPOVER_SELECTOR","useState","useRef","jsx","jsxs","Fragment","createPortal","useMemo","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["// src/stamps/shared/catalog.ts\n//\n// STAMP_CATALOG — manifest tra cứu mọi stamp có sẵn trong package (B½.1,\n// issue #29). Consumer build admin UI / picker / docs page chỉ cần import\n// hằng số này; không phải tự đọc source.\n//\n// `bundleSize` được populate bởi `scripts/build-catalog.mjs` (chạy postbuild)\n// — số đo gzip size thực tế của `dist/{kind}.mjs`. Build script replace giá\n// trị placeholder `{ js: 0, css: 0 }` thành số KB chính xác đồng thời ghi\n// `dist/catalog.json` để consumer có thể fetch runtime nếu cần.\n//\n// Khi thêm stamp mới (xem `docs/superpowers/specs/add-new-stamp-howto.md`),\n// thêm entry vào mảng này — entry phải match `stamp.kind` của registry.\n\n/**\n * Mô tả 1 stamp trong catalog. Bundle size đo bằng KB (kilobytes) gzip — tính\n * trên file entry `dist/{id}.mjs`. Đây là bound trên: code thực sự nạp khi\n * user dùng stamp có thể nhỏ hơn nếu shared chunks đã load cho stamp khác.\n */\nexport interface StampCatalogEntry {\n /** Khớp với `StampType.kind`. Vd 'geometry', 'latex', 'geometry3d', 'graph2d'. */\n id: string;\n /** Tên hiển thị cho admin UI (tiếng Việt). */\n title: string;\n /** Phiên bản schema customData. Bump khi BREAKING change format. */\n version: number;\n /** true nếu stamp chưa production-ready (EXPERIMENTAL_STAMPS). */\n experimental: boolean;\n /** Dependency runtime mà consumer phải cài qua peerDependency. */\n runtimeDeps: ReadonlyArray<string>;\n /** Size dist/{id}.{mjs,css} sau gzip (KB). Populated postbuild. */\n bundleSize: { js: number; css: number };\n}\n\n/**\n * Catalog tĩnh của 4 stamps hiện tại. `bundleSize` ở đây là PLACEHOLDER —\n * `scripts/build-catalog.mjs` sẽ override giá trị này trong `dist/`. Tại\n * source (chạy jest / dev), bundleSize sẽ là 0 — đừng dùng cho quyết định\n * production, chỉ dùng entries trong build artifact.\n */\nexport const STAMP_CATALOG: ReadonlyArray<StampCatalogEntry> = Object.freeze([\n {\n id: 'geometry',\n title: 'Hình học 2D (JSXGraph)',\n version: 1,\n experimental: false,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'latex',\n title: 'Công thức LaTeX (KaTeX)',\n version: 1,\n experimental: false,\n runtimeDeps: ['katex'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'geometry3d',\n title: 'Hình học 3D (JSXGraph view3d)',\n version: 2,\n experimental: true,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n {\n id: 'graph2d',\n title: 'Đồ thị hàm số 2D (JSXGraph)',\n version: 2,\n experimental: true,\n runtimeDeps: ['jsxgraph'],\n bundleSize: { js: 0, css: 0 },\n },\n]);\n\n/** Lấy entry theo stamp.kind. Trả null nếu không có. */\nexport function findCatalogEntry(id: string): StampCatalogEntry | null {\n return STAMP_CATALOG.find((entry) => entry.id === id) ?? null;\n}\n","import { geometryStamp } from '../geometry-2d';\nimport { latexStamp } from '../latex';\nimport { geometry3dStamp } from '../geometry-3d';\nimport { graph2dStamp } from '../graph-2d';\nimport type { StampType } from './types';\n\nexport { geometryStamp, type GeometryCustomData } from '../geometry-2d';\nexport { latexStamp, type LatexCustomData } from '../latex';\nexport { geometry3dStamp, type Geometry3DCustomData } from '../geometry-3d';\nexport { graph2dStamp, type Graph2DCustomData } from '../graph-2d';\nexport type { StampType, BaseStampCustomData } from './types';\nexport {\n STAMP_CATALOG,\n findCatalogEntry,\n type StampCatalogEntry,\n} from './catalog';\n\n/** Stamp ổn định, sẵn sàng production. */\nexport const STABLE_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n geometryStamp,\n latexStamp,\n]);\n\n/** Stamp experimental — chưa ổn định cho production. Consumer phải opt-in. */\nexport const EXPERIMENTAL_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n geometry3dStamp,\n graph2dStamp,\n]);\n\n/** Tất cả stamp (stable + experimental). */\nexport const ALL_STAMPS: ReadonlyArray<StampType> = Object.freeze([\n ...STABLE_STAMPS,\n ...EXPERIMENTAL_STAMPS,\n]);\n\nexport const DEFAULT_STAMPS: ReadonlyArray<StampType> = ALL_STAMPS;\n\n/** Tìm stamp tương ứng với customData của element. null nếu không match. */\nexport function findStampForCustomData(\n data: unknown,\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): StampType | null {\n for (const s of stamps) {\n if (s.matchesCustomData(data)) return s;\n }\n return null;\n}\n\n/** isMathStamp version dựa trên registry. */\nexport function isStampElement<T extends { customData?: unknown }>(\n element: T,\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): boolean {\n return findStampForCustomData(element.customData, stamps) !== null;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { DEFAULT_STAMPS } from './registry';\nimport type { StampType } from './types';\n\ninterface Props {\n /** Bật/tắt theo role. Khi disabled → không mount portal. */\n enabled: boolean;\n /** Kind stamp đang active, hoặc null nếu không có stamp nào mở. */\n activeStampKind: string | null;\n /** Toggle stamp theo kind. */\n onToggle: (kind: string) => void;\n /** Danh sách stamp đăng ký. Mặc định DEFAULT_STAMPS. */\n stamps?: ReadonlyArray<StampType>;\n}\n\nconst MENU_WRAPPER_ID = 'stamp-menu-portal-wrapper';\n/**\n * Excalidraw 0.18 áp dụng class `App-toolbar__extra-tools-dropdown` lên\n * popover wrapper của More tools cho cả desktop lẫn mobile. Mobile có\n * thêm modifier `dropdown-menu--mobile`. Selector này cover cả hai mode.\n */\nconst POPOVER_SELECTOR =\n '.App-toolbar__extra-tools-dropdown .dropdown-menu-container';\n\n/**\n * Inject stamp buttons vào popover \"More tools\" của Excalidraw.\n *\n * v0.7.0: thay vì inject inline vào main toolbar (desktop) hoặc dropdown\n * riêng cho mobile, ta chỉ inject vào dropdown-menu-container bên trong\n * popover của Excalidraw. Selector cover cả desktop lẫn mobile vì hai\n * mode dùng cùng cấu trúc DOM (DropdownMenu.Content).\n *\n * Popover mount/unmount theo trigger click → MutationObserver dò DOM,\n * mount lại wrapper khi cần.\n */\nexport function ToolbarInjector({\n enabled,\n activeStampKind,\n onToggle,\n stamps = DEFAULT_STAMPS,\n}: Props) {\n const [menuMount, setMenuMount] = useState<HTMLElement | null>(null);\n const menuMountRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n if (menuMountRef.current !== null) {\n menuMountRef.current = null;\n setMenuMount(null);\n }\n document.getElementById(MENU_WRAPPER_ID)?.remove();\n return;\n }\n\n let cancelled = false;\n let observer: MutationObserver | null = null;\n let rafId: number | null = null;\n let observedRoot: Element | null = null;\n\n const apply = (next: HTMLElement | null) => {\n if (cancelled || menuMountRef.current === next) return;\n menuMountRef.current = next;\n queueMicrotask(() => {\n if (!cancelled) setMenuMount(next);\n });\n };\n\n const findMenu = () => {\n if (cancelled) return;\n const container = document.querySelector<HTMLElement>(POPOVER_SELECTOR);\n if (!container) {\n apply(null);\n return;\n }\n let wrapper = container.querySelector<HTMLDivElement>('#' + MENU_WRAPPER_ID);\n if (!wrapper) {\n wrapper = document.createElement('div');\n wrapper.id = MENU_WRAPPER_ID;\n wrapper.setAttribute('data-stamp-menu', 'true');\n wrapper.setAttribute('data-stamp-area', 'true');\n wrapper.style.display = 'contents';\n container.insertBefore(wrapper, container.firstChild);\n }\n apply(wrapper);\n };\n\n /**\n * Scope observer xuống `.excalidraw` để giảm tần suất callback trigger\n * (mutation ở các node ngoài Excalidraw không liên quan tới popover).\n * Nếu `.excalidraw` chưa mount → tạm observe `document.body` để bắt\n * lúc nó xuất hiện, rồi switch sang root nhỏ hơn.\n */\n const attachObserver = () => {\n if (cancelled) return;\n const excalidraw = document.querySelector<HTMLElement>('.excalidraw');\n const nextRoot: Element = excalidraw ?? document.body;\n if (observedRoot === nextRoot) return;\n observer?.disconnect();\n observedRoot = nextRoot;\n observer = new MutationObserver(onMutation);\n observer.observe(nextRoot, { childList: true, subtree: true });\n };\n\n /**\n * rAF debounce: gộp nhiều mutation cùng tick thành 1 lần xử lý.\n * Excalidraw có thể trigger hàng chục mutation khi mở/đóng popover —\n * mỗi pass chỉ tốn 1 lần querySelector + DOM insert.\n */\n const onMutation = () => {\n if (rafId != null) return;\n rafId = requestAnimationFrame(() => {\n rafId = null;\n if (cancelled) return;\n // Nếu đang observe body mà giờ `.excalidraw` đã mount → switch sang nó.\n if (observedRoot !== document.querySelector('.excalidraw')) {\n attachObserver();\n }\n findMenu();\n });\n };\n\n findMenu();\n attachObserver();\n\n return () => {\n cancelled = true;\n if (rafId != null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n observer?.disconnect();\n observer = null;\n observedRoot = null;\n document.getElementById(MENU_WRAPPER_ID)?.remove();\n };\n }, [enabled]);\n\n if (!enabled || !menuMount) return null;\n\n const closePopover = () => {\n const trigger = document.querySelector<HTMLButtonElement>(\n '.App-toolbar__extra-tools-trigger',\n );\n trigger?.click();\n };\n\n return createPortal(\n <>\n {stamps.map((stamp) => {\n const { displayLabel, shortcut } = splitTitleAndShortcut(\n stamp.toolbarTitle,\n stamp.toolbarLabel,\n );\n return (\n <StampMenuItem\n key={stamp.kind}\n icon={stamp.toolbarIcon}\n label={displayLabel}\n ariaLabel={stamp.toolbarTitle}\n shortcut={shortcut}\n active={activeStampKind === stamp.kind}\n onClick={() => {\n onToggle(stamp.kind);\n closePopover();\n }}\n dataTestId={stamp.toolbarTestId}\n />\n );\n })}\n <div\n aria-hidden=\"true\"\n style={{\n height: 1,\n background: 'var(--default-border-color, rgba(0,0,0,0.08))',\n margin: '6px 4px',\n }}\n />\n </>,\n menuMount,\n );\n}\n\n/**\n * Tách \"(X)\" cuối toolbarTitle thành shortcut hiển thị riêng ở góc phải\n * (giống các tool gốc Excalidraw: Frame F, Laser K, ...). Nếu title không\n * có pattern \"(...)\", fallback dùng toolbarLabel.\n */\nfunction splitTitleAndShortcut(\n title: string,\n fallbackShortcut: string,\n): { displayLabel: string; shortcut: string } {\n const match = title.match(/^(.*?)\\s*\\(([^()]+)\\)\\s*$/);\n if (match) {\n return { displayLabel: match[1].trim(), shortcut: match[2].trim() };\n }\n return { displayLabel: title, shortcut: fallbackShortcut };\n}\n\ninterface StampMenuItemProps {\n icon: React.ReactNode;\n label: string;\n ariaLabel: string;\n shortcut: string;\n active: boolean;\n onClick: () => void;\n dataTestId?: string;\n}\n\nfunction StampMenuItem({\n icon,\n label,\n ariaLabel,\n shortcut,\n active,\n onClick,\n dataTestId,\n}: StampMenuItemProps) {\n const className = [\n 'dropdown-menu-item',\n 'dropdown-menu-item-base',\n active ? 'dropdown-menu-item--selected' : '',\n ]\n .filter(Boolean)\n .join(' ');\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={ariaLabel}\n aria-label={ariaLabel}\n aria-pressed={active}\n data-testid={dataTestId}\n className={className}\n >\n <div className=\"dropdown-menu-item__icon\" aria-hidden=\"true\">\n {icon}\n </div>\n <div className=\"dropdown-menu-item__text\">{label}</div>\n {shortcut ? (\n <div className=\"dropdown-menu-item__shortcut\">{shortcut}</div>\n ) : null}\n </button>\n );\n}\n","import { useEffect } from 'react';\nimport { DEFAULT_STAMPS } from './registry';\nimport type { StampType } from './types';\n\ninterface Options {\n enabled: boolean;\n /** Toggle stamp theo kind khi user bấm shortcut tương ứng. */\n onToggle: (kind: string) => void;\n /** Registry. Mặc định DEFAULT_STAMPS. */\n stamps?: ReadonlyArray<StampType>;\n}\n\nfunction isEditableTarget(t: EventTarget | null): boolean {\n if (!t || !(t instanceof HTMLElement)) return false;\n if (t.isContentEditable) return true;\n const tag = t.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';\n}\n\n/**\n * Bind keyboard shortcut cho mỗi stamp trong registry. Capture phase +\n * stopPropagation để chặn trước Excalidraw's bubble-phase handlers (Excalidraw\n * dùng `L` cho Line tool, nếu không chặn → bấm L lại chuyển tool thay vì\n * toggle LaTeX panel).\n */\nexport function useShortcuts({\n enabled,\n onToggle,\n stamps = DEFAULT_STAMPS,\n}: Options): void {\n useEffect(() => {\n if (!enabled) return;\n const keyToKind = new Map<string, string>();\n for (const s of stamps) keyToKind.set(s.shortcutKey, s.kind);\n\n const handler = (e: KeyboardEvent) => {\n if (e.metaKey || e.ctrlKey || e.altKey) return;\n if (isEditableTarget(e.target)) return;\n const key = e.key.toLowerCase();\n const kind = keyToKind.get(key);\n if (!kind) return;\n e.preventDefault();\n e.stopPropagation();\n onToggle(kind);\n };\n window.addEventListener('keydown', handler, { capture: true });\n return () => window.removeEventListener('keydown', handler, { capture: true });\n }, [enabled, onToggle, stamps]);\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\ninterface Props {\n enabled: boolean;\n onPick: (file: File) => void;\n}\n\nconst WRAPPER_ID = 'pdf-import-portal-wrapper';\nconst POPOVER_SELECTOR =\n '.App-toolbar__extra-tools-dropdown .dropdown-menu-container';\n\n/**\n * Button \"Chèn PDF\" portal vào More tools dropdown của Excalidraw, ngay\n * dưới các stamp buttons. Click → mở native file picker (hidden input).\n *\n * Tách riêng khỏi ToolbarInjector vì PDF không phải stamp (không có Host,\n * không re-edit). Cùng pattern observer như ToolbarInjector để bắt\n * popover mount/unmount.\n */\nexport function PdfImporterButton({ enabled, onPick }: Props) {\n const [mount, setMount] = useState<HTMLElement | null>(null);\n const mountRef = useRef<HTMLElement | null>(null);\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n mountRef.current = null;\n setMount(null);\n document.getElementById(WRAPPER_ID)?.remove();\n return;\n }\n\n let cancelled = false;\n let observer: MutationObserver | null = null;\n let rafId: number | null = null;\n let observedRoot: Element | null = null;\n\n const apply = (next: HTMLElement | null) => {\n if (cancelled || mountRef.current === next) return;\n mountRef.current = next;\n queueMicrotask(() => {\n if (!cancelled) setMount(next);\n });\n };\n\n const findMenu = () => {\n if (cancelled) return;\n const container = document.querySelector<HTMLElement>(POPOVER_SELECTOR);\n if (!container) {\n apply(null);\n return;\n }\n let wrapper = container.querySelector<HTMLDivElement>('#' + WRAPPER_ID);\n if (!wrapper) {\n wrapper = document.createElement('div');\n wrapper.id = WRAPPER_ID;\n wrapper.setAttribute('data-pdf-import', 'true');\n wrapper.style.display = 'contents';\n // Append cuối để PDF button nằm sau stamps + divider.\n container.appendChild(wrapper);\n }\n apply(wrapper);\n };\n\n const attachObserver = () => {\n if (cancelled) return;\n const excalidraw = document.querySelector<HTMLElement>('.excalidraw');\n const nextRoot: Element = excalidraw ?? document.body;\n if (observedRoot === nextRoot) return;\n observer?.disconnect();\n observedRoot = nextRoot;\n observer = new MutationObserver(onMutation);\n observer.observe(nextRoot, { childList: true, subtree: true });\n };\n\n const onMutation = () => {\n if (rafId != null) return;\n rafId = requestAnimationFrame(() => {\n rafId = null;\n if (cancelled) return;\n if (observedRoot !== document.querySelector('.excalidraw')) {\n attachObserver();\n }\n findMenu();\n });\n };\n\n findMenu();\n attachObserver();\n\n return () => {\n cancelled = true;\n if (rafId != null) cancelAnimationFrame(rafId);\n observer?.disconnect();\n document.getElementById(WRAPPER_ID)?.remove();\n };\n }, [enabled]);\n\n const closePopover = () => {\n const trigger = document.querySelector<HTMLButtonElement>(\n '.App-toolbar__extra-tools-trigger',\n );\n trigger?.click();\n };\n\n const handleClick = () => {\n inputRef.current?.click();\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) onPick(file);\n // Reset để chọn lại cùng file lần sau vẫn fire onChange.\n e.target.value = '';\n closePopover();\n };\n\n if (!enabled || !mount) {\n // Vẫn render hidden input để parent có thể gọi qua ref nếu muốn — nhưng\n // không cần. Giữ null khi chưa mount để tránh DOM thừa.\n return (\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"application/pdf,.pdf\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n );\n }\n\n return (\n <>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"application/pdf,.pdf\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n {createPortal(\n <button\n type=\"button\"\n onClick={handleClick}\n title=\"Chèn PDF (P)\"\n aria-label=\"Chèn PDF\"\n data-testid=\"pdf-import-button\"\n className=\"dropdown-menu-item dropdown-menu-item-base\"\n >\n <div className=\"dropdown-menu-item__icon\" aria-hidden=\"true\">\n <PdfIcon />\n </div>\n <div className=\"dropdown-menu-item__text\">Chèn PDF</div>\n <div className=\"dropdown-menu-item__shortcut\">P</div>\n </button>,\n mount,\n )}\n </>\n );\n}\n\nfunction PdfIcon() {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 3v5h5\" />\n <text x=\"7.5\" y=\"17\" fontSize=\"6\" fontFamily=\"sans-serif\" fontWeight=\"700\" stroke=\"none\" fill=\"currentColor\">\n PDF\n </text>\n </svg>\n );\n}\n","/**\n * Parse chuỗi range trang dạng \"1,3,5-10\" → array số 1-based đã sort + dedupe.\n *\n * - Tokens cách nhau bằng dấu phẩy hoặc khoảng trắng.\n * - Token có gạch \"-\" → range inclusive (5-10 = [5,6,7,8,9,10]).\n * - Khoảng trắng quanh số bị bỏ qua.\n * - Empty / chỉ space → [].\n *\n * Throws `Error` với message tiếng Việt khi:\n * - Token không phải số / không phải range hợp lệ.\n * - Số <= 0 hoặc > totalPages.\n * - Range đảo ngược (vd \"10-5\") — coi là lỗi user thay vì auto-reverse để\n * tránh nuốt typo.\n */\nexport function parsePageRange(input: string, totalPages: number): number[] {\n if (!Number.isInteger(totalPages) || totalPages <= 0) {\n throw new Error('Số trang phải là số nguyên dương.');\n }\n const trimmed = input.trim();\n if (trimmed === '') return [];\n\n const tokens = trimmed\n .split(/[,\\s]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n\n const set = new Set<number>();\n\n for (const token of tokens) {\n if (token.includes('-')) {\n const parts = token.split('-');\n if (parts.length !== 2) {\n throw new Error(`Khoảng trang không hợp lệ: \"${token}\".`);\n }\n const start = parseStrictInt(parts[0]);\n const end = parseStrictInt(parts[1]);\n if (start === null || end === null) {\n throw new Error(`Khoảng trang không hợp lệ: \"${token}\".`);\n }\n if (start > end) {\n throw new Error(`Khoảng trang ngược: \"${token}\" (đầu > cuối).`);\n }\n if (start < 1 || end > totalPages) {\n throw new Error(\n `Khoảng trang vượt giới hạn: \"${token}\". PDF có ${totalPages} trang.`,\n );\n }\n for (let i = start; i <= end; i++) set.add(i);\n } else {\n const n = parseStrictInt(token);\n if (n === null) {\n throw new Error(`Số trang không hợp lệ: \"${token}\".`);\n }\n if (n < 1 || n > totalPages) {\n throw new Error(\n `Số trang vượt giới hạn: ${n}. PDF có ${totalPages} trang.`,\n );\n }\n set.add(n);\n }\n }\n\n return Array.from(set).sort((a, b) => a - b);\n}\n\nfunction parseStrictInt(s: string): number | null {\n if (!/^-?\\d+$/.test(s)) return null;\n const n = Number(s);\n return Number.isInteger(n) ? n : null;\n}\n","/**\n * Rasterize PDF → PNG dataURLs cho từng trang.\n *\n * Worker config:\n * - pdfjs-dist 5.x cần `GlobalWorkerOptions.workerSrc` (URL tới worker .mjs).\n * - Mặc định trỏ CDN (jsdelivr). Consumer có thể override qua\n * `configurePdfWorker(src)` trước khi gọi rasterize lần đầu.\n * - Lý do CDN thay vì bundled worker: tsup không có cách clean để emit\n * worker chunk ra cùng dist/ với URL ổn định, và consumer (Next.js)\n * có thể self-host nếu cần offline.\n *\n * Lazy import pdfjs-dist để không phình bundle khi user không dùng PDF.\n */\nimport type { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\nlet workerSrcOverride: string | null = null;\nlet pdfjsCache: typeof import('pdfjs-dist') | null = null;\n\n/**\n * Override workerSrc trước khi rasterize. Gọi từ consumer khi cần self-host\n * worker file (vd offline mode, CSP cấm CDN).\n *\n * Mặc định nếu không gọi: dùng CDN jsdelivr theo version pdfjs-dist đã cài.\n */\nexport function configurePdfWorker(workerSrc: string): void {\n workerSrcOverride = workerSrc;\n if (pdfjsCache) {\n pdfjsCache.GlobalWorkerOptions.workerSrc = workerSrc;\n }\n}\n\nasync function loadPdfjs(): Promise<typeof import('pdfjs-dist')> {\n if (pdfjsCache) return pdfjsCache;\n const mod = await import('pdfjs-dist');\n const workerSrc =\n workerSrcOverride ??\n `https://cdn.jsdelivr.net/npm/pdfjs-dist@${mod.version}/build/pdf.worker.min.mjs`;\n mod.GlobalWorkerOptions.workerSrc = workerSrc;\n pdfjsCache = mod;\n return mod;\n}\n\nexport interface RasterizedPage {\n pageNumber: number;\n dataURL: string;\n width: number;\n height: number;\n mimeType: 'image/png';\n}\n\nexport interface RasterizeOptions {\n /** Scale render. Mặc định 2 (HiDPI sharp). */\n scale?: number;\n /** Danh sách trang 1-based. Mặc định: tất cả. */\n pages?: number[];\n /** Callback progress sau mỗi page. */\n onProgress?: (done: number, total: number) => void;\n /** AbortSignal để cancel giữa chừng. */\n signal?: AbortSignal;\n}\n\n/**\n * Load PDF chỉ để lấy `numPages` (vd hiển thị tổng số trang trên dialog).\n * Caller phải tự đóng document bằng `closePdfDocument(doc)` khi xong.\n */\nexport async function loadPdfDocument(source: File | Blob | ArrayBuffer): Promise<PDFDocumentProxy> {\n const pdfjs = await loadPdfjs();\n const data = source instanceof ArrayBuffer ? source : await source.arrayBuffer();\n const task = pdfjs.getDocument({ data: new Uint8Array(data) });\n return task.promise;\n}\n\nexport async function closePdfDocument(doc: PDFDocumentProxy): Promise<void> {\n try {\n await doc.cleanup();\n await doc.destroy();\n } catch {\n /* ignore — best-effort cleanup */\n }\n}\n\n/**\n * Render danh sách trang ra PNG dataURL.\n *\n * Lưu ý:\n * - Sử dụng `OffscreenCanvas` nếu có (browser hiện đại) để không touch DOM,\n * fallback `<canvas>` document.createElement.\n * - Mỗi page render xong sẽ release canvas (cho GC sớm với PDF nhiều trang).\n */\nexport async function rasterizePdf(\n doc: PDFDocumentProxy,\n options: RasterizeOptions = {},\n): Promise<RasterizedPage[]> {\n const scale = options.scale ?? 2;\n const total = doc.numPages;\n const pages = options.pages ?? Array.from({ length: total }, (_, i) => i + 1);\n const signal = options.signal;\n\n const result: RasterizedPage[] = [];\n for (let i = 0; i < pages.length; i++) {\n if (signal?.aborted) {\n throw new DOMException('Rasterize PDF bị huỷ.', 'AbortError');\n }\n const pageNum = pages[i];\n const page = await doc.getPage(pageNum);\n try {\n const rendered = await renderPageToPng(page, scale);\n result.push({ pageNumber: pageNum, mimeType: 'image/png', ...rendered });\n } finally {\n page.cleanup();\n }\n options.onProgress?.(i + 1, pages.length);\n }\n return result;\n}\n\nasync function renderPageToPng(\n page: PDFPageProxy,\n scale: number,\n): Promise<{ dataURL: string; width: number; height: number }> {\n const viewport = page.getViewport({ scale });\n const width = Math.ceil(viewport.width);\n const height = Math.ceil(viewport.height);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Không lấy được 2D context của canvas.');\n await page.render({ canvasContext: ctx, viewport, canvas }).promise;\n const dataURL = canvas.toDataURL('image/png');\n return { dataURL, width, height };\n}\n\n/**\n * Render thumbnail nhẹ cho 1 trang — JPEG 0.7 quality + scale nhỏ (mặc định\n * 0.3). Tối ưu cho preview grid: ~10KB/thumb thay vì ~500KB PNG full scale.\n */\nexport async function renderPageThumbnail(\n page: PDFPageProxy,\n scale = 0.3,\n quality = 0.7,\n): Promise<{ dataURL: string; width: number; height: number }> {\n const viewport = page.getViewport({ scale });\n const width = Math.ceil(viewport.width);\n const height = Math.ceil(viewport.height);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Không lấy được 2D context của canvas.');\n // Nền trắng vì JPEG không support alpha.\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, width, height);\n await page.render({ canvasContext: ctx, viewport, canvas }).promise;\n const dataURL = canvas.toDataURL('image/jpeg', quality);\n return { dataURL, width, height };\n}\n\n/**\n * Render thumbnails cho tất cả trang với concurrency. Callback `onEach` được\n * gọi sau mỗi trang xong (theo thứ tự completion, không phải pageNumber) để\n * UI có thể progressive update. Tôn trọng `signal` để cancel sớm.\n */\nexport async function renderAllThumbnails(\n doc: PDFDocumentProxy,\n onEach: (pageNumber: number, dataURL: string, width: number, height: number) => void,\n options: { scale?: number; quality?: number; concurrency?: number; signal?: AbortSignal } = {},\n): Promise<void> {\n const total = doc.numPages;\n const scale = options.scale ?? 0.3;\n const quality = options.quality ?? 0.7;\n const concurrency = Math.max(1, options.concurrency ?? 3);\n const signal = options.signal;\n let next = 1;\n\n async function worker() {\n while (true) {\n if (signal?.aborted) return;\n const pageNum = next++;\n if (pageNum > total) return;\n const page = await doc.getPage(pageNum);\n try {\n if (signal?.aborted) return;\n const { dataURL, width, height } = await renderPageThumbnail(page, scale, quality);\n if (signal?.aborted) return;\n onEach(pageNum, dataURL, width, height);\n } finally {\n page.cleanup();\n }\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(concurrency, total) }, () => worker()),\n );\n}\n","'use client';\n \n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { parsePageRange } from './parseRange';\nimport { renderAllThumbnails } from './rasterize';\n\ninterface Props {\n doc: PDFDocumentProxy;\n fileName: string;\n onConfirm: (pages: number[]) => void;\n onCancel: () => void;\n}\n\ninterface ThumbInfo {\n dataURL: string;\n width: number;\n height: number;\n}\n\n/**\n * Set<number> → chuỗi range compact dạng \"1-3,5,7-9\".\n * Dùng cho hiển thị + sync ngược về text input khi user click thumbnails.\n */\nfunction serializeSelection(pages: number[]): string {\n if (pages.length === 0) return '';\n const sorted = [...pages].sort((a, b) => a - b);\n const groups: string[] = [];\n let start = sorted[0];\n let prev = start;\n for (let i = 1; i < sorted.length; i++) {\n const n = sorted[i];\n if (n === prev + 1) {\n prev = n;\n } else {\n groups.push(start === prev ? `${start}` : `${start}-${prev}`);\n start = n;\n prev = n;\n }\n }\n groups.push(start === prev ? `${start}` : `${start}-${prev}`);\n return groups.join(',');\n}\n\n/**\n * Modal chọn trang PDF với thumbnail grid.\n *\n * Hai chiều sync:\n * - Gõ text input → parse → update selectedSet → highlight thumbnails.\n * - Click thumbnail → toggle pageNum trong selectedSet → re-serialize text.\n *\n * Source of truth: `selectedSet`. Text input là derived view (user-editable).\n * Khi user đang gõ (focus) → giữ raw `inputValue`, không overwrite. Chỉ\n * re-derive text khi click thumbnail HOẶC input mất focus với value valid.\n */\nexport function PageRangeDialog({ doc, fileName, onConfirm, onCancel }: Props) {\n const totalPages = doc.numPages;\n const defaultPages = useMemo(\n () => Array.from({ length: totalPages }, (_, i) => i + 1),\n [totalPages],\n );\n\n const [selectedSet, setSelectedSet] = useState<Set<number>>(\n () => new Set(defaultPages),\n );\n const [inputValue, setInputValue] = useState(serializeSelection(defaultPages));\n const [inputError, setInputError] = useState<string | null>(null);\n const [thumbs, setThumbs] = useState<Record<number, ThumbInfo>>({});\n const [thumbProgress, setThumbProgress] = useState(0);\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // ---- Render thumbnails khi mount ----\n useEffect(() => {\n const ctrl = new AbortController();\n void renderAllThumbnails(\n doc,\n (pageNum, dataURL, width, height) => {\n setThumbs((prev) => ({ ...prev, [pageNum]: { dataURL, width, height } }));\n setThumbProgress((prev) => prev + 1);\n },\n { scale: 0.3, quality: 0.7, concurrency: 3, signal: ctrl.signal },\n ).catch((err) => {\n if (ctrl.signal.aborted) return;\n console.warn('[PageRangeDialog] render thumbnails lỗi:', err);\n });\n return () => ctrl.abort();\n }, [doc]);\n\n // ---- Esc đóng dialog ----\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n onCancel();\n }\n };\n window.addEventListener('keydown', onKey, { capture: true });\n return () => window.removeEventListener('keydown', onKey, { capture: true });\n }, [onCancel]);\n\n // ---- Text input handlers ----\n const handleInputChange = (next: string) => {\n setInputValue(next);\n try {\n const pages = parsePageRange(next, totalPages);\n setInputError(null);\n setSelectedSet(new Set(pages));\n } catch (e) {\n setInputError((e as Error).message);\n }\n };\n\n // ---- Thumbnail click handler ----\n const toggleThumb = (pageNum: number) => {\n setSelectedSet((prev) => {\n const next = new Set(prev);\n if (next.has(pageNum)) next.delete(pageNum);\n else next.add(pageNum);\n const serialized = serializeSelection([...next]);\n setInputValue(serialized);\n setInputError(null);\n return next;\n });\n };\n\n // ---- Quick select helpers ----\n const selectAll = () => {\n setSelectedSet(new Set(defaultPages));\n setInputValue(serializeSelection(defaultPages));\n setInputError(null);\n };\n\n const clearAll = () => {\n setSelectedSet(new Set());\n setInputValue('');\n setInputError(null);\n };\n\n const canSubmit = inputError === null && selectedSet.size > 0;\n const sortedSelected = useMemo(\n () => [...selectedSet].sort((a, b) => a - b),\n [selectedSet],\n );\n\n const handleSubmit = () => {\n if (!canSubmit) return;\n onConfirm(sortedSelected);\n };\n\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"pdf-range-title\"\n style={{\n position: 'fixed',\n inset: 0,\n background: 'rgba(0,0,0,0.55)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget) onCancel();\n }}\n >\n <div\n style={{\n background: 'var(--popup-bg-color, #fff)',\n color: 'var(--text-primary-color, #1b1b1f)',\n borderRadius: 12,\n padding: '20px 22px',\n width: 'min(880px, 92vw)',\n maxHeight: '88vh',\n boxShadow: '0 12px 40px rgba(0,0,0,0.3)',\n fontFamily: 'inherit',\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div>\n <h2\n id=\"pdf-range-title\"\n style={{ margin: 0, fontSize: 16, fontWeight: 600, lineHeight: 1.3 }}\n >\n Chèn PDF\n </h2>\n <p style={{ margin: '4px 0 0', fontSize: 12, opacity: 0.7 }}>\n {fileName} — {totalPages} trang\n {thumbProgress < totalPages && (\n <> · đang tải preview {thumbProgress}/{totalPages}…</>\n )}\n </p>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>\n <div style={{ flex: 1 }}>\n <label\n style={{ display: 'block', fontSize: 12, marginBottom: 4, opacity: 0.75 }}\n >\n Trang cần chèn (vd: 1,3,5-10) — hoặc click thumbnail bên dưới\n </label>\n <input\n ref={inputRef}\n type=\"text\"\n value={inputValue}\n onChange={(e) => handleInputChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSubmit();\n }\n }}\n style={{\n width: '100%',\n boxSizing: 'border-box',\n padding: '8px 10px',\n fontSize: 14,\n borderRadius: 6,\n border: `1px solid ${inputError ? '#dc2626' : 'rgba(0,0,0,0.2)'}`,\n outline: 'none',\n background: 'var(--input-bg-color, #fff)',\n color: 'inherit',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n }}\n />\n </div>\n <div style={{ display: 'flex', gap: 6, paddingTop: 18 }}>\n <button\n type=\"button\"\n onClick={selectAll}\n style={quickBtnStyle}\n title=\"Chọn tất cả trang\"\n >\n Tất cả\n </button>\n <button\n type=\"button\"\n onClick={clearAll}\n style={quickBtnStyle}\n title=\"Bỏ chọn tất cả\"\n >\n Bỏ hết\n </button>\n </div>\n </div>\n\n <div style={{ minHeight: 18, fontSize: 12 }} data-testid=\"pdf-range-status\">\n {inputError ? (\n <span style={{ color: '#dc2626' }}>{inputError}</span>\n ) : (\n <span style={{ opacity: 0.75 }}>\n Đã chọn <strong>{selectedSet.size}</strong> / {totalPages} trang\n </span>\n )}\n </div>\n\n <div\n style={{\n flex: 1,\n minHeight: 240,\n maxHeight: '60vh',\n overflow: 'auto',\n padding: 8,\n background: 'rgba(0,0,0,0.04)',\n borderRadius: 8,\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',\n gap: 10,\n alignContent: 'start',\n }}\n >\n {Array.from({ length: totalPages }, (_, i) => i + 1).map((pageNum) => {\n const thumb = thumbs[pageNum];\n const selected = selectedSet.has(pageNum);\n return (\n <ThumbnailItem\n key={pageNum}\n pageNum={pageNum}\n thumb={thumb}\n selected={selected}\n onToggle={() => toggleThumb(pageNum)}\n />\n );\n })}\n </div>\n\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n paddingTop: 4,\n }}\n >\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n padding: '8px 14px',\n fontSize: 13,\n borderRadius: 6,\n border: '1px solid rgba(0,0,0,0.15)',\n background: 'transparent',\n color: 'inherit',\n cursor: 'pointer',\n }}\n >\n Huỷ\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n style={{\n padding: '8px 16px',\n fontSize: 13,\n borderRadius: 6,\n border: 'none',\n background: canSubmit ? '#4f46e5' : 'rgba(0,0,0,0.15)',\n color: '#fff',\n cursor: canSubmit ? 'pointer' : 'not-allowed',\n fontWeight: 500,\n }}\n >\n Chèn {selectedSet.size > 0 ? `${selectedSet.size} trang` : ''}\n </button>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n\nconst quickBtnStyle: React.CSSProperties = {\n padding: '7px 10px',\n fontSize: 12,\n borderRadius: 6,\n border: '1px solid rgba(0,0,0,0.15)',\n background: 'transparent',\n color: 'inherit',\n cursor: 'pointer',\n whiteSpace: 'nowrap',\n};\n\ninterface ThumbProps {\n pageNum: number;\n thumb: ThumbInfo | undefined;\n selected: boolean;\n onToggle: () => void;\n}\n\nfunction ThumbnailItem({ pageNum, thumb, selected, onToggle }: ThumbProps) {\n const aspect = thumb ? thumb.width / thumb.height : 0.77; // A4 portrait default\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n aria-pressed={selected}\n aria-label={`Trang ${pageNum}${selected ? ' (đã chọn)' : ''}`}\n title={`Trang ${pageNum}`}\n style={{\n position: 'relative',\n padding: 0,\n background: '#fff',\n border: `2px solid ${selected ? '#4f46e5' : 'rgba(0,0,0,0.12)'}`,\n borderRadius: 6,\n overflow: 'hidden',\n cursor: 'pointer',\n boxShadow: selected ? '0 0 0 3px rgba(79,70,229,0.18)' : 'none',\n transition: 'border-color 80ms ease, box-shadow 80ms ease',\n }}\n >\n <div\n style={{\n width: '100%',\n aspectRatio: aspect.toString(),\n background: '#f5f5f5',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {thumb ? (\n <img\n src={thumb.dataURL}\n alt=\"\"\n style={{ width: '100%', height: '100%', display: 'block', objectFit: 'contain' }}\n draggable={false}\n />\n ) : (\n <div style={{ fontSize: 11, opacity: 0.5 }}>…</div>\n )}\n </div>\n <div\n style={{\n position: 'absolute',\n bottom: 4,\n left: 4,\n fontSize: 10,\n fontWeight: 600,\n padding: '2px 6px',\n borderRadius: 4,\n background: selected ? '#4f46e5' : 'rgba(0,0,0,0.6)',\n color: '#fff',\n }}\n >\n {pageNum}\n </div>\n {selected && (\n <div\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n top: 4,\n right: 4,\n width: 18,\n height: 18,\n borderRadius: '50%',\n background: '#4f46e5',\n color: '#fff',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 11,\n fontWeight: 700,\n boxShadow: '0 1px 3px rgba(0,0,0,0.3)',\n }}\n >\n ✓\n </div>\n )}\n </button>\n );\n}\n","import { useCallback, useRef } from 'react';\nimport { findStampForCustomData } from './registry';\nimport type { StampType } from './types';\n\nconst DOUBLE_CLICK_MS = 400;\n\ninterface Opts {\n enabled: boolean;\n stamps: ReadonlyArray<StampType>;\n onOpen: (\n kind: string,\n editingElement: { id: string; customData: unknown },\n ) => void;\n}\n\n/**\n * Trả về handler cho Excalidraw `onPointerDown`. Phát hiện double-click vào\n * image element thuộc một stamp đã đăng ký → gọi `onOpen(kind, element)`.\n */\nexport function useStampDoubleClick({ enabled, stamps, onOpen }: Opts) {\n const lastClickRef = useRef<{ time: number; elementId: string | null }>({\n time: 0,\n elementId: null,\n });\n\n return useCallback(\n \n (_activeTool: any, pointerDownState: any) => {\n if (!enabled) return;\n const hitElement = pointerDownState?.hit?.element;\n if (!hitElement || hitElement.type !== 'image') return;\n const stamp = findStampForCustomData(hitElement.customData, stamps);\n if (!stamp) return;\n const now = Date.now();\n const isDouble =\n lastClickRef.current.elementId === hitElement.id &&\n now - lastClickRef.current.time < DOUBLE_CLICK_MS;\n lastClickRef.current = { time: now, elementId: hitElement.id };\n if (!isDouble) return;\n onOpen(stamp.kind, {\n id: hitElement.id,\n customData: hitElement.customData,\n });\n },\n [enabled, stamps, onOpen],\n );\n}\n","import { useEffect, useMemo } from 'react';\nimport type { StampType } from './types';\n\nconst ALLOWED_KEYS = new Set([\n 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight',\n 'Shift', 'Control', 'Alt', 'Meta', 'CapsLock',\n 'Home', 'End', 'PageUp', 'PageDown',\n]);\n\nfunction isEditable(el: EventTarget | null): boolean {\n if (!(el instanceof HTMLElement)) return false;\n if (el.isContentEditable) return true;\n const tag = el.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT';\n}\n\ninterface Opts {\n /** Active stamp kind. Null = no blocker. */\n activeStamp: string | null;\n /** Stamps đăng ký để allow shortcut keys của chúng đi qua. */\n stamps: ReadonlyArray<StampType>;\n}\n\n/**\n * Khi 1 stamp panel đang mở, block hoàn toàn các phím tắt Excalidraw\n * (1-9, V, R, D...) bằng cách prevent + stop tại capture phase. Cho phép qua:\n * Tab/Arrow/Modifier, Escape, và phím tắt đã đăng ký bởi stamps (V/G/L/D...).\n */\nexport function useStampShortcutBlocker({ activeStamp, stamps }: Opts) {\n const shortcutKeys = useMemo(\n () => new Set(stamps.map((s) => s.shortcutKey.toLowerCase())),\n [stamps],\n );\n\n useEffect(() => {\n if (!activeStamp) return;\n\n const blocker = (e: KeyboardEvent) => {\n if (isEditable(e.target)) return;\n if (e.ctrlKey || e.metaKey) return;\n if (ALLOWED_KEYS.has(e.key)) return;\n if (e.key === 'Escape') return;\n if (shortcutKeys.has(e.key.toLowerCase())) return;\n e.preventDefault();\n e.stopPropagation();\n };\n window.addEventListener('keydown', blocker, { capture: true });\n return () => window.removeEventListener('keydown', blocker, { capture: true });\n }, [activeStamp, shortcutKeys]);\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { StampHostHandle } from './types';\n\ninterface Opts {\n /** Active stamp. Null = no listener. */\n activeStamp: string | null;\n /** Ref tới Host imperative API (tryInsert / hasContent). */\n hostRef: RefObject<StampHostHandle | null>;\n /** Callback đóng panel. */\n onClose: () => void;\n}\n\n/**\n * Khi 1 stamp panel mở, lắng nghe pointer/mouse-down toàn document. Nếu\n * điểm click không nằm trong vùng `[data-stamp-area=\"true\"]`, gọi\n * `hostRef.tryInsert()` để auto-commit (nếu có nội dung) rồi `onClose()`.\n */\nexport function useStampClickOutside({ activeStamp, hostRef, onClose }: Opts) {\n useEffect(() => {\n if (!activeStamp) return;\n let lastFire = 0;\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement | null;\n if (!target) return;\n if (target.closest('[data-stamp-area=\"true\"]')) return;\n const now = Date.now();\n if (now - lastFire < 50) return;\n lastFire = now;\n hostRef.current?.tryInsert();\n onClose();\n };\n window.addEventListener('pointerdown', handler, { capture: true });\n window.addEventListener('mousedown', handler, { capture: true });\n return () => {\n window.removeEventListener('pointerdown', handler, { capture: true });\n window.removeEventListener('mousedown', handler, { capture: true });\n };\n }, [activeStamp, hostRef, onClose]);\n}\n","import { type MutableRefObject, useCallback, useRef, useState } from 'react';\n\n \ntype ExApi = any;\n\nexport interface UseExcalidrawApiOptions {\n onApi?: (api: ExApi) => void;\n}\n\nexport interface UseExcalidrawApiResult {\n api: ExApi | null;\n apiRef: MutableRefObject<ExApi | null>;\n isDark: boolean;\n isDarkRef: MutableRefObject<boolean>;\n /** Gắn vào Excalidraw prop `excalidrawAPI`. Defer setState qua microtask\n * để tránh React 19 \"update from inside an update function\" warning. */\n setApiFromExcalidraw: (api: ExApi) => void;\n /** Gọi từ onChange. Bail-out qua ref + defer setState. */\n syncThemeFromAppState: (appState: { theme?: string } | undefined) => void;\n}\n\nexport function useExcalidrawApi(\n opts: UseExcalidrawApiOptions = {},\n): UseExcalidrawApiResult {\n const { onApi } = opts;\n const [api, setApi] = useState<ExApi | null>(null);\n const apiRef = useRef<ExApi | null>(null);\n const [isDark, setIsDark] = useState(false);\n const isDarkRef = useRef(false);\n const onApiRef = useRef(onApi);\n onApiRef.current = onApi;\n\n const setApiFromExcalidraw = useCallback((a: ExApi) => {\n if (apiRef.current === a) return;\n apiRef.current = a;\n queueMicrotask(() => {\n setApi(a);\n onApiRef.current?.(a);\n });\n }, []);\n\n const syncThemeFromAppState = useCallback(\n (appState: { theme?: string } | undefined) => {\n const next = appState?.theme === 'dark';\n if (isDarkRef.current !== next) {\n isDarkRef.current = next;\n queueMicrotask(() => setIsDark(next));\n }\n },\n [],\n );\n\n return { api, apiRef, isDark, isDarkRef, setApiFromExcalidraw, syncThemeFromAppState };\n}\n","import { useCallback, useMemo, useState } from 'react';\nimport type { StampType } from '../stamps/shared/registry';\n\nexport interface EditingElement {\n id: string;\n customData: unknown;\n}\n\nexport interface UseActiveStampOptions {\n readOnly: boolean;\n stamps: ReadonlyArray<StampType>;\n}\n\nexport interface UseActiveStampResult {\n activeStamp: string | null;\n editingElement: EditingElement | null;\n stampByKind: Map<string, StampType>;\n activeStampDef: StampType | null;\n HostComponent: StampType['Host'] | null;\n openStamp: (kind: string, element?: EditingElement | null) => void;\n closeStamp: () => void;\n toggleStampByKind: (kind: string) => void;\n}\n\nexport function useActiveStamp(opts: UseActiveStampOptions): UseActiveStampResult {\n const { readOnly, stamps } = opts;\n const [activeStamp, setActiveStamp] = useState<string | null>(null);\n const [editingElement, setEditingElement] = useState<EditingElement | null>(null);\n\n const stampByKind = useMemo(() => {\n const m = new Map<string, StampType>();\n for (const s of stamps) m.set(s.kind, s);\n return m;\n }, [stamps]);\n\n const activeStampDef = activeStamp ? stampByKind.get(activeStamp) ?? null : null;\n const HostComponent = activeStampDef?.Host ?? null;\n\n const openStamp = useCallback(\n (kind: string, element: EditingElement | null = null) => {\n if (readOnly) return;\n if (!stampByKind.has(kind)) return;\n setEditingElement(element);\n setActiveStamp(kind);\n },\n [readOnly, stampByKind],\n );\n\n const closeStamp = useCallback(() => {\n setActiveStamp(null);\n setEditingElement(null);\n }, []);\n\n const toggleStampByKind = useCallback(\n (kind: string) => {\n setActiveStamp((cur) => {\n if (cur === kind) {\n setEditingElement(null);\n return null;\n }\n if (readOnly) return cur;\n if (!stampByKind.has(kind)) return cur;\n setEditingElement(null);\n return kind;\n });\n },\n [readOnly, stampByKind],\n );\n\n return {\n activeStamp,\n editingElement,\n stampByKind,\n activeStampDef,\n HostComponent,\n openStamp,\n closeStamp,\n toggleStampByKind,\n };\n}\n","import type { ExcalidrawElement } from '../types';\nimport { closePdfDocument, loadPdfDocument, rasterizePdf, type RasterizedPage } from './rasterize';\n\n// Excalidraw imperative API — không có public type chính xác.\n \ntype ExApi = any;\n\n/** Khoảng cách dọc giữa các trang PDF khi xếp dọc, ở scene units. */\nconst PAGE_GAP = 24;\n\n/** Scale render mặc định (HiDPI sharp). */\nconst DEFAULT_SCALE = 2;\n\nexport interface InsertRasterizedPagesOptions {\n /** Scale dùng khi rasterize (để chia pixel → scene units). */\n scale: number;\n /** Toạ độ scene gốc cho page đầu tiên. Bỏ qua → giữa viewport. */\n origin?: { x: number; y: number };\n}\n\nexport interface InsertRasterizedPagesResult {\n insertedElementIds: string[];\n fileIds: string[];\n}\n\n/**\n * Chèn array `RasterizedPage` đã có sẵn vào scene. Tách ra để Whiteboard\n * có thể: load doc → hỏi user range → rasterize → insert mà không phải gọi\n * insertPdfPages (load lại từ ArrayBuffer 2 lần).\n */\nexport function insertRasterizedPagesIntoScene(\n api: ExApi,\n rendered: RasterizedPage[],\n options: InsertRasterizedPagesOptions,\n): InsertRasterizedPagesResult {\n if (!api) throw new Error('Excalidraw API chưa sẵn sàng.');\n if (rendered.length === 0) return { insertedElementIds: [], fileIds: [] };\n\n const { scale } = options;\n const filesPayload = rendered.map((p) => ({\n id: generateFileId(),\n dataURL: p.dataURL,\n mimeType: p.mimeType,\n created: Date.now(),\n }));\n api.addFiles(filesPayload);\n\n const origin = options.origin ?? getViewportCenter(api);\n const sceneSizes = rendered.map((p) => pixelsToSceneSize(p.width, p.height, scale));\n const maxSceneWidth = Math.max(...sceneSizes.map((s) => s.width));\n const baseX = origin.x - maxSceneWidth / 2;\n let cursorY = origin.y - sceneSizes[0].height / 2;\n\n const newElements = rendered.map((_, i) => {\n const { width, height } = sceneSizes[i];\n const x = baseX + (maxSceneWidth - width) / 2;\n const y = cursorY;\n cursorY = y + height + PAGE_GAP;\n return buildPdfImageElement(filesPayload[i].id, x, y, width, height);\n });\n\n const existing = api.getSceneElements() as readonly ExcalidrawElement[];\n api.updateScene({\n elements: [...existing, ...newElements],\n appState: { selectedElementIds: {}, croppingElementId: null },\n });\n\n return {\n insertedElementIds: newElements.map((e) => e.id),\n fileIds: filesPayload.map((f) => f.id),\n };\n}\n\n/**\n * Excalidraw lưu width/height theo \"scene units\". File PDF rasterize ở scale 2\n * → pixel = 2 × scene unit. Chia lại để stamp hiển thị đúng kích thước\n * gốc của trang PDF (giấy A4 ≈ 595×842 scene units ở 72 DPI).\n */\nfunction pixelsToSceneSize(pxWidth: number, pxHeight: number, scale: number) {\n return { width: pxWidth / scale, height: pxHeight / scale };\n}\n\nexport interface InsertPdfPagesOptions {\n /** Trang cần chèn (1-based). Bỏ qua → chèn tất cả. */\n pages?: number[];\n /** Scale rasterize. Mặc định 2. */\n scale?: number;\n /** Toạ độ scene gốc cho page đầu tiên. Bỏ qua → giữa viewport. */\n origin?: { x: number; y: number };\n /** Progress callback. */\n onProgress?: (done: number, total: number) => void;\n /** AbortSignal. */\n signal?: AbortSignal;\n}\n\nexport interface InsertPdfPagesResult {\n insertedElementIds: string[];\n pages: RasterizedPage[];\n}\n\n/**\n * Tạo image element cho 1 trang đã rasterize. Trả về object đủ field cho\n * Excalidraw `updateScene`. Lấy `fileId` từ caller để có thể batch addFiles\n * trước khi update elements.\n */\nfunction buildPdfImageElement(\n fileId: string,\n x: number,\n y: number,\n width: number,\n height: number,\n) {\n return {\n type: 'image' as const,\n id: 'pdf_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8),\n x,\n y,\n width,\n height,\n fileId,\n angle: 0,\n strokeColor: 'transparent',\n backgroundColor: 'transparent',\n fillStyle: 'solid',\n strokeWidth: 1,\n strokeStyle: 'solid',\n roughness: 0,\n opacity: 100,\n groupIds: [],\n roundness: null,\n seed: Math.floor(Math.random() * 1e9),\n versionNonce: 0,\n version: 1,\n isDeleted: false,\n boundElements: null,\n updated: Date.now(),\n link: null,\n locked: false,\n status: 'saved',\n scale: [1, 1],\n };\n}\n\nfunction generateFileId(): string {\n return 'pdf_' + Date.now() + '_' + Math.random().toString(36).slice(2, 10);\n}\n\nfunction getViewportCenter(api: ExApi): { x: number; y: number } {\n const appState = api?.getAppState?.() ?? {\n scrollX: 0,\n scrollY: 0,\n width: 800,\n height: 600,\n zoom: { value: 1 },\n };\n const zoom = appState.zoom?.value ?? 1;\n return {\n x: appState.scrollX + (appState.width ?? 800) / 2 / zoom,\n y: appState.scrollY + (appState.height ?? 600) / 2 / zoom,\n };\n}\n\n/**\n * High-level: rasterize PDF + insert thành nhiều image element xếp dọc.\n *\n * Flow:\n * 1. loadPdfDocument(source) → PDFDocumentProxy\n * 2. rasterizePdf(doc, {pages, scale}) → RasterizedPage[]\n * 3. Tạo fileId cho từng page, gọi api.addFiles batch.\n * 4. Tính position: page 1 trung tâm viewport (hoặc origin), các page sau\n * xếp dưới, cách PAGE_GAP.\n * 5. api.updateScene({ elements: [...cũ, ...mới] })\n *\n * Không serialize PDF bytes — sau insert, các page là image element thuần,\n * không thể re-edit qua double-click (theo design quyết định).\n */\nexport async function insertPdfPages(\n api: ExApi,\n source: File | Blob | ArrayBuffer,\n options: InsertPdfPagesOptions = {},\n): Promise<InsertPdfPagesResult> {\n if (!api) throw new Error('Excalidraw API chưa sẵn sàng.');\n\n const scale = options.scale ?? DEFAULT_SCALE;\n const doc = await loadPdfDocument(source);\n let rendered: RasterizedPage[];\n try {\n rendered = await rasterizePdf(doc, {\n pages: options.pages,\n scale,\n onProgress: options.onProgress,\n signal: options.signal,\n });\n } finally {\n void closePdfDocument(doc);\n }\n\n const { insertedElementIds } = insertRasterizedPagesIntoScene(api, rendered, {\n scale,\n origin: options.origin,\n });\n return { insertedElementIds, pages: rendered };\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport {\n loadPdfDocument,\n closePdfDocument,\n rasterizePdf,\n} from '../pdf/rasterize';\nimport { insertRasterizedPagesIntoScene } from '../pdf/insertPdfPages';\n\n// Excalidraw imperative API — không có public type chính xác.\n \ntype ExApi = any;\n\nexport interface PdfPendingState {\n doc: PDFDocumentProxy;\n fileName: string;\n totalPages: number;\n}\n\nexport interface UsePdfImporterOptions {\n readOnly: boolean;\n api: ExApi | null;\n}\n\nexport interface UsePdfImporterResult {\n pdfPending: PdfPendingState | null;\n pdfBusy: boolean;\n handlePdfPick: (file: File) => Promise<void>;\n handlePdfConfirm: (pages: number[]) => Promise<void>;\n handlePdfCancel: () => void;\n}\n\nexport function usePdfImporter(opts: UsePdfImporterOptions): UsePdfImporterResult {\n const { readOnly, api } = opts;\n const [pdfPending, setPdfPending] = useState<PdfPendingState | null>(null);\n const [pdfBusy, setPdfBusy] = useState(false);\n\n const handlePdfPick = useCallback(\n async (file: File) => {\n if (readOnly || pdfBusy) return;\n setPdfBusy(true);\n try {\n const doc = await loadPdfDocument(file);\n setPdfPending({ doc, fileName: file.name, totalPages: doc.numPages });\n } catch (err) {\n console.warn('[whiteboard] Đọc PDF thất bại:', err);\n window.alert('Không đọc được PDF. File có thể đã hỏng hoặc bị mật khẩu bảo vệ.');\n } finally {\n setPdfBusy(false);\n }\n },\n [readOnly, pdfBusy],\n );\n\n const handlePdfPickRef = useRef(handlePdfPick);\n useLayoutEffect(() => {\n handlePdfPickRef.current = handlePdfPick;\n });\n\n const handlePdfConfirm = useCallback(\n async (pages: number[]) => {\n if (!pdfPending || !api) return;\n const { doc } = pdfPending;\n setPdfPending(null);\n setPdfBusy(true);\n const scale = 2;\n try {\n const rendered = await rasterizePdf(doc, { pages, scale });\n await closePdfDocument(doc);\n insertRasterizedPagesIntoScene(api, rendered, { scale });\n } catch (err) {\n console.warn('[whiteboard] Chèn PDF thất bại:', err);\n window.alert('Chèn PDF thất bại. Xem console để biết chi tiết.');\n } finally {\n setPdfBusy(false);\n }\n },\n [pdfPending, api],\n );\n\n const handlePdfCancel = useCallback(() => {\n if (pdfPending) {\n void closePdfDocument(pdfPending.doc);\n }\n setPdfPending(null);\n }, [pdfPending]);\n\n // Drop handler: catch application/pdf trước Excalidraw (nó reject PDF).\n useEffect(() => {\n if (readOnly) return;\n const root = document.querySelector<HTMLElement>('.excalidraw');\n if (!root) return;\n\n const onDragOver = (e: DragEvent) => {\n const items = e.dataTransfer?.items;\n if (!items) return;\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind === 'file' && items[i].type === 'application/pdf') {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';\n return;\n }\n }\n };\n\n const onDrop = (e: DragEvent) => {\n const files = e.dataTransfer?.files;\n if (!files || files.length === 0) return;\n const pdf = Array.from(files).find((f) => f.type === 'application/pdf');\n if (!pdf) return;\n e.preventDefault();\n e.stopPropagation();\n void handlePdfPickRef.current(pdf);\n };\n\n root.addEventListener('dragover', onDragOver, { capture: true });\n root.addEventListener('drop', onDrop, { capture: true });\n return () => {\n root.removeEventListener('dragover', onDragOver, { capture: true });\n root.removeEventListener('drop', onDrop, { capture: true });\n };\n }, [readOnly, api]);\n\n return { pdfPending, pdfBusy, handlePdfPick, handlePdfConfirm, handlePdfCancel };\n}\n","import type { AppState } from '@excalidraw/excalidraw/types';\nimport type { SyncableAppState } from './types';\n\nexport function pickSyncableAppState(s: AppState): SyncableAppState {\n return {\n viewBackgroundColor: s.viewBackgroundColor,\n zoom: s.zoom,\n scrollX: s.scrollX,\n scrollY: s.scrollY,\n gridSize: s.gridSize ?? null,\n theme: s.theme,\n };\n}\n","// Regenerate Excalidraw BinaryFiles for stamp elements after page reload.\n//\n// Why this exists: VideoRoom only persists the Excalidraw scene (elements +\n// appState) to sessionStorage; binary files (the SVG dataURLs for stamp\n// images) are NOT persisted. After reload, elements still reference a fileId\n// via customData, but the file payload is missing — Excalidraw renders the\n// image area as an empty placeholder.\n//\n// Strategy: tra registry để tìm StampType khớp customData.kind. Nếu stamp có\n// `restoreFileFromCustomData`, gọi trực tiếp với full element (stamp tự lấy\n// fileId + render). Ngược lại, fallback sang `renderSvgFromCustomData` (path\n// cũ: filter type=image + fileId + kiểm tra existing files).\n//\n// Excalidraw key trên fileId chứ không phải hash dataURL nên nếu kết quả\n// render có sai khác nhỏ (vd thứ tự element) cũng không ảnh hưởng.\n//\n// Theme: stamps được render với LIGHT palette (nét đậm). Excalidraw áp dụng\n// `filter: invert(...)` lên canvas trong dark mode → nét tự đảo sáng. KHÔNG\n// cần force regenerate khi user toggle theme.\n\nimport { DEFAULT_STAMPS, findStampForCustomData } from './registry';\nimport type { StampType } from './types';\n\ninterface ElementLike {\n id: string;\n type?: string;\n fileId?: string | null;\n customData?: unknown;\n}\n\ninterface AddFileRecord {\n id: string;\n dataURL: string;\n mimeType: string;\n created: number;\n}\n\nfunction svgToDataURL(svg: string): string {\n const utf8 = unescape(encodeURIComponent(svg));\n return 'data:image/svg+xml;base64,' + btoa(utf8);\n}\n\nasync function buildFileForStamp(\n fileId: string,\n customData: unknown,\n stamp: StampType,\n): Promise<AddFileRecord | null> {\n try {\n if (!stamp.matchesCustomData(customData)) return null;\n const svg = await stamp.renderSvgFromCustomData(customData);\n return { id: fileId, dataURL: svgToDataURL(svg), mimeType: 'image/svg+xml', created: Date.now() };\n } catch (err) {\n console.warn('Stamp restore failed for', fileId, '(' + stamp.kind + ')', err);\n return null;\n }\n}\n\n/**\n * Find stamp elements whose binary file is missing from Excalidraw, then\n * regenerate via registry dispatch. Idempotent: safe to call on every scene\n * update.\n *\n * Stamps that implement `restoreFileFromCustomData` are handled via the new\n * registry-driven path (stamp receives the full element and returns the file\n * record). Stamps that only implement `renderSvgFromCustomData` use the legacy\n * path (filter type=image + fileId, skip already-present files).\n *\n * @param api Excalidraw imperative API.\n * @param elements Tất cả elements trong scene.\n * @param stamps Registry. Default = DEFAULT_STAMPS.\n */\nexport async function restoreMissingStampFiles(\n \n api: any,\n elements: readonly ElementLike[],\n stamps: ReadonlyArray<StampType> = DEFAULT_STAMPS,\n): Promise<void> {\n if (!api) return;\n\n const filesToAdd: AddFileRecord[] = [];\n\n // --- New registry-driven path: stamp.restoreFileFromCustomData ---\n const newPathHandled = new Set<string>();\n for (const el of elements) {\n const stamp = findStampForCustomData(el.customData, stamps);\n if (!stamp?.restoreFileFromCustomData) continue;\n \n const restored = await stamp.restoreFileFromCustomData(el as any);\n if (!restored) continue;\n newPathHandled.add(el.id);\n filesToAdd.push({\n id: restored.fileId,\n dataURL: restored.dataURL,\n mimeType: restored.mimeType,\n created: Date.now(),\n });\n }\n\n // --- Legacy path: stamp.renderSvgFromCustomData (type=image + fileId filter) ---\n const existing = (typeof api.getFiles === 'function') ? api.getFiles() : {};\n const seen = new Set<string>();\n for (const el of elements) {\n if (newPathHandled.has(el.id)) continue;\n if (el.type !== 'image') continue;\n if (!el.fileId) continue;\n if (existing && existing[el.fileId]) continue;\n if (seen.has(el.fileId)) continue;\n const stamp = findStampForCustomData(el.customData, stamps);\n if (!stamp) continue;\n seen.add(el.fileId);\n const built = await buildFileForStamp(el.fileId, el.customData, stamp);\n if (built) filesToAdd.push(built);\n }\n\n if (filesToAdd.length > 0) {\n try { api.addFiles(filesToAdd); } catch (err) { console.warn('addFiles failed:', err); }\n }\n}\n","/**\n * Hardening helpers cho persistence layer:\n *\n * - validateStorageKey: chặn ký tự lạ trong storageKey (consumer-supplied) trước khi\n * ghép vào key prefix (`whiteboard:scene:<key>`) hoặc dùng làm index trong IndexedDB.\n * - safeParseScene: parse JSON với reviver loại bỏ `__proto__/constructor/prototype`\n * để chặn prototype pollution, check max nesting depth, whitelist top-level keys.\n *\n * Các helper này không phụ thuộc DOM nên test được trong jsdom hoặc node thuần.\n */\n\nconst STORAGE_KEY_RE = /^[a-zA-Z0-9_-]{1,128}$/;\n\n/**\n * Validate storageKey từ consumer.\n *\n * Format cho phép: chữ + số + underscore + dash, 1..128 ký tự.\n * Throw nếu không hợp lệ — caller bị buộc handle hoặc crash sớm.\n */\nexport function validateStorageKey(key: unknown): string {\n if (typeof key !== 'string' || !STORAGE_KEY_RE.test(key)) {\n const sample = key === undefined ? 'undefined' : String(key).slice(0, 32);\n throw new Error(\n `[whiteboard] Invalid storageKey: must match ${STORAGE_KEY_RE} (got: ${sample})`,\n );\n }\n return key;\n}\n\nconst DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Reviver dùng cho `JSON.parse`: drop bất kỳ key nào trong DANGEROUS_KEYS,\n * tránh prototype pollution khi parse dữ liệu không tin cậy từ localStorage.\n */\nfunction sanitizingReviver(_key: string, value: unknown): unknown {\n if (DANGEROUS_KEYS.has(_key)) return undefined;\n return value;\n}\n\n/** Max nesting depth cho scene tree (object/array). */\nexport const MAX_NESTED_DEPTH = 64;\n\nfunction depthExceeds(v: unknown, max: number, depth = 0): boolean {\n if (depth > max) return true;\n if (v === null || typeof v !== 'object') return false;\n const children = Array.isArray(v)\n ? v\n : Object.values(v as Record<string, unknown>);\n for (const child of children) {\n if (depthExceeds(child, max, depth + 1)) return true;\n }\n return false;\n}\n\nconst ALLOWED_TOP_LEVEL_KEYS = new Set(['version', 'elements', 'appState', 'savedAt']);\n\n/** Shape của scene đã được validate (chưa check version + element shape — caller lo). */\nexport interface ParsedScene {\n version?: unknown;\n elements: unknown[];\n appState: Record<string, unknown>;\n savedAt?: unknown;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/**\n * Parse + sanitize raw JSON string từ localStorage.\n *\n * 1. JSON.parse với reviver strip dangerous keys.\n * 2. Reject nếu nested depth vượt MAX_NESTED_DEPTH.\n * 3. Whitelist top-level keys (drop extras).\n * 4. `elements` phải là array, mỗi item là object có `id: string` + `type: string`.\n *\n * Trả về `null` nếu bất kỳ check nào fail (caller handle như \"no data\").\n */\nexport function safeParseScene(raw: string): ParsedScene | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw, sanitizingReviver);\n } catch {\n return null;\n }\n if (!isPlainObject(parsed)) return null;\n if (depthExceeds(parsed, MAX_NESTED_DEPTH)) return null;\n\n // Whitelist top-level keys.\n const safe: Record<string, unknown> = {};\n for (const k of Object.keys(parsed)) {\n if (ALLOWED_TOP_LEVEL_KEYS.has(k)) safe[k] = parsed[k];\n }\n\n if (!Array.isArray(safe.elements)) return null;\n for (const el of safe.elements as unknown[]) {\n if (!isPlainObject(el)) return null;\n if (typeof el.id !== 'string' || typeof el.type !== 'string') return null;\n }\n\n const appState = isPlainObject(safe.appState) ? safe.appState : {};\n\n return {\n version: safe.version,\n elements: safe.elements as unknown[],\n appState,\n savedAt: safe.savedAt,\n };\n}\n","import type { ExcalidrawElement, SyncableAppState } from '../../types';\nimport { safeParseScene, validateStorageKey } from './validation';\n\nconst PREFIX = 'whiteboard:scene:';\nconst SCHEMA_VERSION = 1 as const;\n\nexport interface StoredScene {\n version: typeof SCHEMA_VERSION;\n elements: readonly ExcalidrawElement[];\n appState: Partial<SyncableAppState>;\n savedAt: number;\n}\n\nfunction fullKey(key: string): string {\n return PREFIX + key;\n}\n\nexport function readScene(key: string): StoredScene | null {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return null;\n const raw = window.localStorage.getItem(fullKey(validKey));\n if (!raw) return null;\n const parsed = safeParseScene(raw);\n if (!parsed) {\n console.warn('[whiteboard] scene parse/validation failed, clear:', validKey);\n try {\n window.localStorage.removeItem(fullKey(validKey));\n } catch { /* ignore */ }\n return null;\n }\n if (parsed.version !== SCHEMA_VERSION) {\n // Cố ý KHÔNG xoá entry — version mismatch có thể là dữ liệu của client\n // mới hơn (user vừa downgrade). Giữ lại để client tương ứng đọc được sau.\n console.warn(\n `[whiteboard] scene version ${parsed.version} không khớp ${SCHEMA_VERSION}, bỏ qua.`,\n );\n return null;\n }\n return {\n version: SCHEMA_VERSION,\n elements: parsed.elements as readonly ExcalidrawElement[],\n appState: parsed.appState as Partial<SyncableAppState>,\n savedAt: typeof parsed.savedAt === 'number' ? parsed.savedAt : Date.now(),\n };\n}\n\nexport function writeScene(\n key: string,\n payload: { elements: readonly ExcalidrawElement[]; appState: Partial<SyncableAppState> },\n): void {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return;\n const record: StoredScene = {\n version: SCHEMA_VERSION,\n elements: payload.elements,\n appState: payload.appState,\n savedAt: Date.now(),\n };\n try {\n window.localStorage.setItem(fullKey(validKey), JSON.stringify(record));\n } catch (err) {\n console.warn('[whiteboard] scene write failed:', err);\n }\n}\n\nexport function clearScene(key: string): void {\n const validKey = validateStorageKey(key);\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(fullKey(validKey));\n } catch { /* ignore */ }\n}\n","import type { BinaryFiles } from '../../types';\nimport { validateStorageKey } from './validation';\n\nconst DB_NAME = 'whiteboard-files';\nconst DB_VERSION = 1;\nconst STORE = 'files';\n\ninterface FileRecord {\n id: string;\n storageKey: string;\n dataURL: string;\n mimeType: string;\n created: number;\n savedAt: number;\n}\n\nlet dbPromise: Promise<IDBDatabase> | null = null;\nlet idbDisabled = false;\n\nfunction openDb(): Promise<IDBDatabase> {\n if (idbDisabled) return Promise.reject(new Error('IndexedDB disabled'));\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n if (typeof indexedDB === 'undefined') {\n idbDisabled = true;\n reject(new Error('indexedDB undefined'));\n return;\n }\n const req = indexedDB.open(DB_NAME, DB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(STORE)) {\n const store = db.createObjectStore(STORE, { keyPath: 'id' });\n store.createIndex('storageKey', 'storageKey', { unique: false });\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => {\n idbDisabled = true;\n reject(req.error ?? new Error('IDB open failed'));\n };\n });\n return dbPromise;\n}\n\nasync function withStore<T>(\n mode: IDBTransactionMode,\n fn: (\n store: IDBObjectStore,\n setResult: (value: T) => void,\n fail: (error: unknown) => void,\n ) => void,\n fallback: T,\n): Promise<T> {\n let db: IDBDatabase;\n try {\n db = await openDb();\n } catch {\n return fallback;\n }\n return new Promise<T>((resolve, reject) => {\n const tx = db.transaction(STORE, mode);\n const store = tx.objectStore(STORE);\n let result = fallback;\n try {\n fn(\n store,\n (value) => {\n result = value;\n },\n reject,\n );\n } catch (err) {\n reject(err);\n return;\n }\n tx.oncomplete = () => resolve(result);\n tx.onerror = () => {\n console.warn('[whiteboard] IDB tx error:', tx.error);\n reject(tx.error ?? new Error('IDB tx error'));\n };\n tx.onabort = () => reject(tx.error ?? new Error('IDB tx aborted'));\n });\n}\n\nexport async function readFiles(storageKey: string): Promise<BinaryFiles> {\n const validKey = validateStorageKey(storageKey);\n try {\n return await withStore(\n 'readonly',\n (store, setResult, fail) => {\n const out: BinaryFiles = {};\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(out);\n return;\n }\n const record = cursor.value as FileRecord;\n \n (out as any)[record.id] = {\n dataURL: record.dataURL,\n mimeType: record.mimeType,\n created: record.created,\n };\n cursor.continue();\n };\n req.onerror = () => fail(req.error);\n },\n {},\n );\n } catch (err) {\n console.warn('[whiteboard] readFiles failed:', err);\n return {};\n }\n}\n\nexport async function writeFiles(storageKey: string, files: BinaryFiles): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n const entries = Object.entries(files);\n if (entries.length === 0) return;\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n let pending = entries.length;\n const finishOne = () => {\n pending -= 1;\n if (pending === 0) setResult(undefined);\n };\n\n const now = Date.now();\n for (const [id, f] of entries) {\n \n const ff = f as any;\n const getReq = store.get(id);\n getReq.onsuccess = () => {\n if (getReq.result) {\n finishOne();\n return;\n }\n const rec: FileRecord = {\n id,\n storageKey: validKey,\n dataURL: ff.dataURL,\n mimeType: ff.mimeType,\n created: ff.created ?? now,\n savedAt: now,\n };\n const putReq = store.put(rec);\n putReq.onsuccess = finishOne;\n putReq.onerror = () => fail(putReq.error);\n };\n getReq.onerror = () => fail(getReq.error);\n };\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] writeFiles failed:', err);\n }\n}\n\nexport async function pruneFiles(\n storageKey: string,\n keepIds: ReadonlySet<string>,\n): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(undefined);\n return;\n }\n const record = cursor.value as FileRecord;\n if (keepIds.has(record.id)) {\n cursor.continue();\n return;\n }\n const deleteReq = cursor.delete();\n deleteReq.onsuccess = () => cursor.continue();\n deleteReq.onerror = () => fail(deleteReq.error);\n };\n req.onerror = () => fail(req.error);\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] pruneFiles failed:', err);\n }\n}\n\nexport async function clearAll(storageKey: string): Promise<void> {\n const validKey = validateStorageKey(storageKey);\n try {\n await withStore<void>(\n 'readwrite',\n (store, setResult, fail) => {\n const req = store.index('storageKey').openCursor(IDBKeyRange.only(validKey));\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) {\n setResult(undefined);\n return;\n }\n const deleteReq = cursor.delete();\n deleteReq.onsuccess = () => cursor.continue();\n deleteReq.onerror = () => fail(deleteReq.error);\n };\n req.onerror = () => fail(req.error);\n },\n undefined,\n );\n } catch (err) {\n console.warn('[whiteboard] clearAll failed:', err);\n }\n}\n","'use client';\nimport { useEffect, useMemo, useRef } from 'react';\nimport type {\n ExcalidrawElement,\n BinaryFiles,\n ExcalidrawSceneSnapshot,\n SyncableAppState,\n} from '../types';\nimport { pickSyncableAppState } from '../serialize';\nimport { isStampElement, type StampType } from '../stamps/shared/registry';\nimport { restoreMissingStampFiles } from '../stamps/shared/restoreStampFiles';\nimport { readScene, writeScene } from '../core/persistence/sceneStore';\nimport { readFiles, writeFiles, pruneFiles } from '../core/persistence/fileStore';\n\nconst SYNC_THROTTLE_MS = 200;\nconst FILE_THROTTLE_MS = 1000;\nconst PRUNE_THROTTLE_MS = 2000;\nconst RESTORE_PASS_DELAY_MS = 400;\n\nexport interface UseScenePersistOptions {\n storageKey: string | null;\n initialScene?: ExcalidrawSceneSnapshot | null;\n initialFiles?: BinaryFiles;\n readOnly: boolean;\n onSceneChange?: (snapshot: ExcalidrawSceneSnapshot) => void;\n onFilesChange?: (files: BinaryFiles, newFileIds: string[]) => void;\n \n api: any;\n \n apiRef: React.MutableRefObject<any>;\n stamps: ReadonlyArray<StampType>;\n}\n\nexport interface UseScenePersistResult {\n effectiveInitialScene: ExcalidrawSceneSnapshot | null;\n \n onSceneTick: (elements: readonly ExcalidrawElement[], appState: any, files: BinaryFiles) => void;\n}\n\n// Bundle toàn bộ persist orchestration cho Whiteboard:\n// - effectiveInitialScene: precedence initialScene > localStorage > blank.\n// - onSceneTick: gọi từ Excalidraw onChange (sau theme-sync + crop intercept).\n// Track new fileIds, throttle scene/file/prune writes.\n// - Mount: load initialFiles (server) + IDB raster + restoreMissingStampFiles.\n// - Unmount: flush mọi pending write trước teardown.\nexport function useScenePersist(opts: UseScenePersistOptions): UseScenePersistResult {\n const {\n storageKey,\n initialScene,\n initialFiles,\n readOnly,\n onSceneChange,\n onFilesChange,\n api,\n apiRef,\n stamps,\n } = opts;\n\n const persistEnabled = typeof storageKey === 'string' && storageKey.length > 0;\n\n const knownFileIdsRef = useRef<Set<string>>(new Set());\n const lastSceneHashRef = useRef<string>('');\n const sceneThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const fileThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pruneThrottleRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestSceneRef = useRef<{\n elements: readonly ExcalidrawElement[];\n \n appState: any;\n } | null>(null);\n const pendingFilesRef = useRef<BinaryFiles>({});\n // Cached hashElementsVersion để flushScene chạy sync trong unmount cleanup\n // (cleanup không thể await dynamic import).\n \n const hashElementsVersionRef = useRef<((elements: readonly ExcalidrawElement[]) => any) | null>(null);\n\n const stampsRef = useRef(stamps);\n stampsRef.current = stamps;\n const persistKeyRef = useRef(storageKey);\n persistKeyRef.current = storageKey;\n const onSceneChangeRef = useRef(onSceneChange);\n onSceneChangeRef.current = onSceneChange;\n const onFilesChangeRef = useRef(onFilesChange);\n onFilesChangeRef.current = onFilesChange;\n const persistEnabledRef = useRef(persistEnabled);\n persistEnabledRef.current = persistEnabled;\n\n const persistedInitial = useMemo(\n () => (persistEnabled ? readScene(storageKey as string) : null),\n [persistEnabled, storageKey],\n );\n const effectiveInitialScene: ExcalidrawSceneSnapshot | null =\n initialScene !== undefined\n ? initialScene\n : persistedInitial\n ? {\n elements: persistedInitial.elements,\n appState: persistedInitial.appState as SyncableAppState,\n }\n : null;\n\n const flushSceneRef = useRef<() => void>(() => undefined);\n flushSceneRef.current = () => {\n try {\n const latestScene = latestSceneRef.current;\n if (!latestScene) return;\n const liveElements = latestScene.elements.filter((e) => !e.isDeleted) as readonly ExcalidrawElement[];\n const liveAppState = pickSyncableAppState(latestScene.appState);\n const hashFn = hashElementsVersionRef.current;\n // Chưa load module → bỏ qua hash dedupe, ghi luôn (correctness > perf khi unmount).\n const elementHash = hashFn ? hashFn(liveElements) : liveElements.map((e) => e.id).join('|');\n const sceneHash = `${elementHash}:${JSON.stringify(liveAppState)}`;\n if (sceneHash === lastSceneHashRef.current) return;\n lastSceneHashRef.current = sceneHash;\n onSceneChangeRef.current?.({ elements: liveElements, appState: liveAppState });\n if (persistEnabledRef.current) {\n writeScene(persistKeyRef.current as string, {\n elements: liveElements,\n appState: liveAppState,\n });\n }\n } catch (err) {\n console.warn('[whiteboard] flushScene thất bại:', err);\n }\n };\n\n const flushFilesRef = useRef<() => void>(() => undefined);\n flushFilesRef.current = () => {\n try {\n const pending = pendingFilesRef.current;\n pendingFilesRef.current = {};\n if (Object.keys(pending).length === 0) return;\n const currentElements = (apiRef.current?.getSceneElements?.()\n ?? latestSceneRef.current?.elements\n ?? []) as readonly ExcalidrawElement[];\n const stampIds = new Set<string>();\n for (const el of currentElements) {\n \n const fid = (el as any).fileId as string | undefined;\n if (fid && isStampElement(el)) stampIds.add(fid);\n }\n const raster: BinaryFiles = {};\n for (const [id, f] of Object.entries(pending)) {\n if (!stampIds.has(id)) raster[id] = f;\n }\n if (Object.keys(raster).length > 0) {\n void writeFiles(persistKeyRef.current as string, raster);\n }\n } catch (err) {\n console.warn('[whiteboard] flushFiles thất bại:', err);\n }\n };\n\n const flushPruneRef = useRef<() => void>(() => undefined);\n flushPruneRef.current = () => {\n try {\n const currentElements = (apiRef.current?.getSceneElements?.()\n ?? latestSceneRef.current?.elements\n ?? []) as readonly ExcalidrawElement[];\n const keep = new Set<string>();\n for (const el of currentElements) {\n \n const fid = (el as any).fileId as string | undefined;\n if (fid && !isStampElement(el)) keep.add(fid);\n }\n void pruneFiles(persistKeyRef.current as string, keep);\n } catch (err) {\n console.warn('[whiteboard] flushPrune thất bại:', err);\n }\n };\n\n const onSceneTick: UseScenePersistResult['onSceneTick'] = (elements, appState, files) => {\n if (readOnly) return;\n latestSceneRef.current = { elements, appState };\n\n const fileIds = Object.keys(files);\n const newIds = fileIds.filter((id) => !knownFileIdsRef.current.has(id));\n if (newIds.length > 0) {\n newIds.forEach((id) => knownFileIdsRef.current.add(id));\n onFilesChangeRef.current?.(files, newIds);\n }\n\n if (!sceneThrottleRef.current) {\n sceneThrottleRef.current = setTimeout(async () => {\n sceneThrottleRef.current = null;\n try {\n const mod = await import('@excalidraw/excalidraw');\n \n hashElementsVersionRef.current = (mod as any).hashElementsVersion;\n } catch (err) {\n console.warn('[whiteboard] import excalidraw để flush scene thất bại:', err);\n return;\n }\n flushSceneRef.current();\n }, SYNC_THROTTLE_MS);\n }\n\n if (persistEnabled && newIds.length > 0) {\n for (const id of newIds) {\n if (files[id]) pendingFilesRef.current[id] = files[id];\n }\n if (!fileThrottleRef.current) {\n fileThrottleRef.current = setTimeout(() => {\n fileThrottleRef.current = null;\n flushFilesRef.current();\n }, FILE_THROTTLE_MS);\n }\n }\n\n if (persistEnabled && !pruneThrottleRef.current) {\n pruneThrottleRef.current = setTimeout(() => {\n pruneThrottleRef.current = null;\n flushPruneRef.current();\n }, PRUNE_THROTTLE_MS);\n }\n };\n\n // Mount: load initialFiles (server) → addFiles 1 lần khi api ready.\n const initialFilesAddedRef = useRef(false);\n useEffect(() => {\n if (!api || initialFilesAddedRef.current) return;\n initialFilesAddedRef.current = true;\n if (!initialFiles) return;\n const entries = Object.entries(initialFiles);\n if (entries.length === 0) return;\n try {\n api.addFiles(\n entries.map(([id, f]) => ({\n id,\n \n dataURL: (f as any).dataURL,\n \n mimeType: (f as any).mimeType,\n \n created: (f as any).created ?? Date.now(),\n })),\n );\n entries.forEach(([id]) => knownFileIdsRef.current.add(id));\n } catch (err) {\n console.warn('[whiteboard] addFiles initialFiles thất bại:', err);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api]);\n\n // Mount: load persisted raster files từ IDB → addFiles.\n useEffect(() => {\n if (!api || !persistEnabled) return;\n let cancelled = false;\n void readFiles(storageKey as string).then(\n (files) => {\n // Recheck cancelled — IDB onsuccess có thể fire sau component unmount.\n if (cancelled) return;\n const entries = Object.entries(files);\n if (entries.length === 0) return;\n if (cancelled) return;\n try {\n api.addFiles(\n entries.map(([id, f]) => ({\n id,\n \n dataURL: (f as any).dataURL,\n \n mimeType: (f as any).mimeType,\n \n created: (f as any).created ?? Date.now(),\n })),\n );\n if (cancelled) return;\n entries.forEach(([id]) => knownFileIdsRef.current.add(id));\n } catch (err) {\n if (cancelled) return;\n console.warn('[whiteboard] addFiles từ IDB thất bại:', err);\n }\n },\n (err) => {\n if (cancelled) return;\n console.warn('[whiteboard] readFiles thất bại:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [api, persistEnabled, storageKey]);\n\n useEffect(() => {\n if (!api) return;\n let cancelled = false;\n const run = async () => {\n if (cancelled) return;\n try {\n const elements = api.getSceneElements();\n if (!elements || elements.length === 0) return;\n if (cancelled) return;\n // stamps đọc từ ref — props có thể đã đổi sau 400ms, closure stale.\n await restoreMissingStampFiles(api, elements, stampsRef.current);\n } catch (err) {\n if (cancelled) return;\n console.warn('Math stamp restore pass failed:', err);\n }\n };\n void run();\n const t = setTimeout(() => {\n void run();\n }, RESTORE_PASS_DELAY_MS);\n return () => {\n cancelled = true;\n clearTimeout(t);\n };\n }, [api, persistedInitial]);\n\n // Unmount cleanup: flush pending writes TRƯỚC khi clearTimeout để không\n // mất scene/file write cuối khi user navigate giữa throttle window.\n useEffect(\n () => () => {\n if (sceneThrottleRef.current) {\n clearTimeout(sceneThrottleRef.current);\n sceneThrottleRef.current = null;\n flushSceneRef.current();\n }\n if (fileThrottleRef.current) {\n clearTimeout(fileThrottleRef.current);\n fileThrottleRef.current = null;\n flushFilesRef.current();\n }\n if (pruneThrottleRef.current) {\n clearTimeout(pruneThrottleRef.current);\n pruneThrottleRef.current = null;\n flushPruneRef.current();\n }\n },\n [],\n );\n\n return { effectiveInitialScene, onSceneTick };\n}\n","'use client';\n\nimport { lazy, Suspense, useCallback, useEffect, useRef } from 'react';\nimport type {\n ExcalidrawElement,\n BinaryFiles,\n ExcalidrawSceneSnapshot,\n} from './types';\nimport {\n DEFAULT_STAMPS,\n findStampForCustomData,\n type StampType,\n} from './stamps/shared/registry';\nimport { ToolbarInjector } from './stamps/shared/ToolbarInjector';\nimport { useShortcuts } from './stamps/shared/useShortcuts';\nimport { PdfImporterButton } from './pdf/PdfImporterButton';\nimport { PageRangeDialog } from './pdf/PageRangeDialog';\nimport { useStampDoubleClick } from './stamps/shared/useStampDoubleClick';\nimport { useStampShortcutBlocker } from './stamps/shared/useStampShortcutBlocker';\nimport { useStampClickOutside } from './stamps/shared/useStampClickOutside';\nimport type { GenerateGeometryFigure, StampHostHandle } from './stamps/shared/types';\nimport type { GeometryDraftPreview } from './stamps/shared/draftTypes';\nimport { useExcalidrawApi } from './hooks/useExcalidrawApi';\nimport { useActiveStamp } from './hooks/useActiveStamp';\nimport { usePdfImporter } from './hooks/usePdfImporter';\nimport { useScenePersist } from './hooks/useScenePersist';\nimport '@excalidraw/excalidraw/index.css';\nimport './stamps/shared/stamp.css';\n\nconst Excalidraw = lazy(() =>\n import('./ExcalidrawWithMenus').then((m) => ({ default: m.ExcalidrawWithMenus })),\n);\n\nconst ExcalidrawLoadingFallback = () => (\n <div className=\"flex h-full items-center justify-center text-sm text-gray-500\">\n Đang tải bảng…\n </div>\n);\n\nexport interface WhiteboardProps {\n /**\n * Storage key cho persist client-side.\n * - Scene -> localStorage['whiteboard:scene:'+storageKey]\n * - Files raster -> IndexedDB 'whiteboard-files' index theo storageKey\n * - Default: 'default'\n * - Truyen `null` de tat persist (consumer drive state qua onApi).\n */\n storageKey?: string | null;\n\n /** View-only (Excalidraw viewModeEnabled). Default false. */\n readOnly?: boolean;\n\n /** Local edits -> consumer broadcast. Optional. */\n onSceneChange?: (snapshot: ExcalidrawSceneSnapshot) => void;\n onFilesChange?: (files: BinaryFiles, newFileIds: string[]) => void;\n\n /** Excalidraw imperative API. Consumer dung inject remote scene khi can. */\n \n onApi?: (api: any) => void;\n\n /** Excalidraw UI language. Defaults to 'vi-VN'. See @excalidraw/excalidraw locales. */\n langCode?: string;\n\n /**\n * Danh sách stamp đăng ký. Mỗi stamp khai báo phím tắt + toolbar button +\n * Host component (UI editing). Mặc định DEFAULT_STAMPS (= ALL_STAMPS,\n * gồm geometry + latex + geometry3d + graph2d).\n * Truyền `[...DEFAULT_STAMPS, customStamp]` để thêm stamp mới hoặc\n * `STABLE_STAMPS` để chỉ bật stamp ổn định.\n */\n stamps?: ReadonlyArray<StampType>;\n\n /**\n * Snapshot từ server. Precedence: `initialScene` > localStorage > blank.\n * - `undefined` (default) → đọc từ localStorage qua `storageKey`\n * - `null` → explicit blank, bỏ qua localStorage\n * - object → dùng làm initialData của Excalidraw, bỏ qua localStorage\n *\n * Dùng để load board từ server. Thường đi cùng `storageKey={null}` để\n * tránh localStorage stale override server data.\n */\n initialScene?: ExcalidrawSceneSnapshot | null;\n\n /**\n * Binary files (raster, base64) từ server. Add vào Excalidraw đúng 1 lần\n * khi api ready. Dùng kèm `initialScene` cho flow load-from-server.\n * Nếu cần inject files động về sau, dùng `onApi` rồi gọi `api.addFiles`.\n */\n initialFiles?: BinaryFiles;\n\n /**\n * Opt-in bridge for the geometry editor AI prompt. This callback should call\n * `generateFigure()` on a server boundary so API credentials never reach the browser.\n */\n generateGeometryFigure?: GenerateGeometryFigure;\n /**\n * Geometry-2d live draft. GV: package gọi callback này (debounced) với SVG hình\n * đang dựng + vị trí chèn; `null` khi clear. Consumer broadcast cho học sinh.\n */\n onGeometryDraft?: (draft: GeometryDraftPreview | null) => void;\n}\n\nexport function Whiteboard({\n storageKey = 'default',\n readOnly = false,\n onSceneChange,\n onFilesChange,\n onApi,\n langCode = 'vi-VN',\n stamps = DEFAULT_STAMPS,\n initialScene,\n initialFiles,\n generateGeometryFigure,\n onGeometryDraft,\n}: WhiteboardProps) {\n const { api, apiRef, isDark, setApiFromExcalidraw, syncThemeFromAppState } =\n useExcalidrawApi({ onApi });\n\n const {\n activeStamp,\n editingElement,\n HostComponent,\n openStamp,\n closeStamp,\n toggleStampByKind,\n } = useActiveStamp({ readOnly, stamps });\n\n const {\n pdfPending,\n pdfBusy,\n handlePdfPick,\n handlePdfConfirm,\n handlePdfCancel,\n } = usePdfImporter({ readOnly, api });\n\n const { effectiveInitialScene, onSceneTick } = useScenePersist({\n storageKey,\n initialScene,\n initialFiles,\n readOnly,\n onSceneChange,\n onFilesChange,\n api,\n apiRef,\n stamps,\n });\n\n const hostRef = useRef<StampHostHandle | null>(null);\n const handledCropIdRef = useRef<string | null>(null);\n const prevExcalidrawToolRef = useRef<string>('selection');\n\n // Capture local changes: theme sync → crop intercept (re-edit) → persist tick.\n const handleChange = useCallback(\n \n (elements: readonly ExcalidrawElement[], appState: any, files: BinaryFiles) => {\n syncThemeFromAppState(appState);\n\n if (readOnly) return;\n\n // Intercept Excalidraw crop-image flow cho stamps: khi user double-click\n // 1 stamp, Excalidraw set appState.croppingElementId. Ta dismiss crop mode +\n // mở Host editor tương ứng. handlePointerDown phát hiện double-click sớm\n // hơn — đây là fallback (đặc biệt khi click rơi vào selection handle).\n const cropId = appState?.croppingElementId as string | null | undefined;\n if (cropId && cropId !== handledCropIdRef.current && api) {\n const el = elements.find((e: ExcalidrawElement) => e.id === cropId);\n if (el) {\n const stamp = findStampForCustomData((el as { customData?: unknown }).customData, stamps);\n if (stamp) {\n handledCropIdRef.current = cropId;\n // Defer updateScene + openStamp ra khỏi commit-phase của Excalidraw —\n // chạy đồng bộ sẽ trigger React 19 warn \"update scheduled from inside\n // an update function\" (handleChange chạy trong updater).\n const elId = el.id;\n const elCustom = (el as { customData?: unknown }).customData;\n const stampKind = stamp.kind;\n queueMicrotask(() => {\n try {\n api.updateScene({\n appState: { croppingElementId: null, selectedElementIds: {} },\n });\n } catch { /* ignore */ }\n openStamp(stampKind, { id: elId, customData: elCustom });\n });\n return;\n }\n }\n }\n if (!cropId) {\n handledCropIdRef.current = null;\n }\n\n onSceneTick(elements, appState, files);\n },\n [readOnly, api, stamps, openStamp, syncThemeFromAppState, onSceneTick],\n );\n\n // Double-click detection for re-edit.\n const handlePointerDown = useStampDoubleClick({\n enabled: !readOnly,\n stamps,\n onOpen: openStamp,\n });\n\n // Keyboard shortcuts: đọc registry, mỗi stamp tự khai báo phím tắt.\n useShortcuts({\n enabled: !readOnly,\n onToggle: toggleStampByKind,\n stamps,\n });\n\n // Sync Excalidraw activeTool với activeStamp.\n useEffect(() => {\n if (!api) return;\n if (activeStamp) {\n try {\n const cur = api.getAppState?.()?.activeTool?.type ?? 'selection';\n if (cur && cur !== 'hand') prevExcalidrawToolRef.current = cur;\n api.setActiveTool?.({ type: 'hand' });\n } catch { /* ignore */ }\n } else {\n try {\n \n api.setActiveTool?.({ type: prevExcalidrawToolRef.current as any });\n } catch { /* ignore */ }\n }\n }, [activeStamp, api]);\n\n // Block Excalidraw shortcuts khi stamp panel đang mở.\n useStampShortcutBlocker({ activeStamp, stamps });\n\n // Esc đóng panel (capture phase để chạy TRƯỚC Excalidraw).\n useEffect(() => {\n if (!activeStamp) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n const ae = document.activeElement as HTMLElement | null;\n if (ae && (ae.tagName === 'TEXTAREA' || ae.isContentEditable)) {\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n closeStamp();\n };\n window.addEventListener('keydown', onKey, { capture: true });\n return () => window.removeEventListener('keydown', onKey, { capture: true });\n }, [activeStamp, closeStamp]);\n\n useStampClickOutside({ activeStamp, hostRef, onClose: closeStamp });\n\n return (\n <div className={`relative h-full w-full${isDark ? ' theme--dark' : ''}`}>\n <Suspense fallback={<ExcalidrawLoadingFallback />}>\n <Excalidraw\n excalidrawAPI={setApiFromExcalidraw}\n langCode={langCode}\n viewModeEnabled={readOnly}\n initialData={\n effectiveInitialScene\n ? {\n elements: effectiveInitialScene.elements,\n appState: {\n ...effectiveInitialScene.appState,\n gridSize: effectiveInitialScene.appState.gridSize ?? undefined,\n },\n }\n : { appState: { viewBackgroundColor: '#ffffff' } }\n }\n onChange={handleChange}\n onPointerDown={handlePointerDown}\n />\n </Suspense>\n\n <ToolbarInjector\n enabled={!readOnly}\n activeStampKind={activeStamp}\n onToggle={toggleStampByKind}\n stamps={stamps}\n />\n\n <PdfImporterButton enabled={!readOnly} onPick={handlePdfPick} />\n\n {pdfPending && (\n <PageRangeDialog\n doc={pdfPending.doc}\n fileName={pdfPending.fileName}\n onConfirm={handlePdfConfirm}\n onCancel={handlePdfCancel}\n />\n )}\n\n {pdfBusy && !pdfPending && (\n <div\n aria-live=\"polite\"\n role=\"status\"\n style={{\n position: 'fixed',\n bottom: 16,\n right: 16,\n padding: '8px 14px',\n background: 'rgba(0,0,0,0.75)',\n color: '#fff',\n borderRadius: 6,\n fontSize: 12,\n zIndex: 10000,\n }}\n >\n Đang xử lý PDF…\n </div>\n )}\n\n {HostComponent && (\n <HostComponent\n ref={hostRef}\n api={api}\n editingElement={editingElement}\n onClose={closeStamp}\n isDark={isDark}\n generateGeometryFigure={generateGeometryFigure}\n onGeometryDraft={onGeometryDraft}\n />\n )}\n </div>\n );\n}\n"]}
|