@casualoffice/sheets 0.18.0 → 0.20.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/{api-DJhuCjhn.d.cts → api-cyO4EA4_.d.cts} +1 -1
- package/dist/{api-DJhuCjhn.d.ts → api-cyO4EA4_.d.ts} +1 -1
- package/dist/{attachCollab-BmCRT4V_.d.ts → attachCollab-BT4fVzxP.d.ts} +1 -1
- package/dist/{attachCollab-DIUQCCrq.d.cts → attachCollab-DHjb5XYK.d.cts} +1 -1
- package/dist/chrome.cjs +60 -3
- package/dist/chrome.cjs.map +1 -1
- package/dist/chrome.d.cts +3 -3
- package/dist/chrome.d.ts +3 -3
- package/dist/chrome.js +60 -3
- package/dist/chrome.js.map +1 -1
- package/dist/collab.d.cts +2 -2
- package/dist/collab.d.ts +2 -2
- package/dist/embed/embed-runtime.js +205 -161
- package/dist/{extensions-DZnqTEN2.d.ts → extensions-Cni7mbEm.d.ts} +1 -1
- package/dist/{extensions-FFqdLpk_.d.cts → extensions-DMmPnIYB.d.cts} +1 -1
- package/dist/index.cjs +6424 -1559
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6409 -1530
- package/dist/index.js.map +1 -1
- package/dist/sheets.cjs +5426 -561
- package/dist/sheets.cjs.map +1 -1
- package/dist/sheets.d.cts +5 -5
- package/dist/sheets.d.ts +5 -5
- package/dist/sheets.js +5415 -536
- package/dist/sheets.js.map +1 -1
- package/package.json +8 -7
- package/src/charts/ChartContextMenu.tsx +264 -0
- package/src/charts/ChartLayer.tsx +333 -0
- package/src/charts/ChartOverlay.tsx +293 -0
- package/src/charts/ChartsPanel.tsx +232 -0
- package/src/charts/FormatChartDialog.tsx +419 -0
- package/src/charts/InsertChartDialog.tsx +478 -0
- package/src/charts/build-option.ts +476 -0
- package/src/charts/charts-context.tsx +205 -0
- package/src/charts/echarts-init.ts +58 -0
- package/src/charts/hit-test.ts +130 -0
- package/src/charts/insert-chart.ts +106 -0
- package/src/charts/naming.ts +38 -0
- package/src/charts/render-to-png.ts +117 -0
- package/src/charts/resources.ts +108 -0
- package/src/charts/types.ts +239 -0
- package/src/charts/univer-dom.ts +102 -0
- package/src/chrome/CommentsPanel.tsx +418 -0
- package/src/chrome/HistoryPanel.tsx +304 -0
- package/src/chrome/InsertPivotDialog.tsx +74 -2
- package/src/chrome/PanelHost.tsx +56 -0
- package/src/chrome/PanelRail.tsx +90 -0
- package/src/chrome/PivotFieldsPanel.tsx +1021 -0
- package/src/chrome/TablesPanel.tsx +283 -0
- package/src/chrome/Toolbar.tsx +7 -1
- package/src/chrome/panel-context.tsx +55 -0
- package/src/chrome/panel-registry.ts +48 -0
- package/src/chrome/panel-shell.tsx +151 -0
- package/src/pivots/apply.ts +139 -0
- package/src/pivots/compute.ts +604 -0
- package/src/pivots/fields-model.ts +267 -0
- package/src/pivots/types.ts +137 -0
- package/src/sheets/CasualSheets.tsx +61 -35
- package/src/sheets/api.ts +37 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/signing/SigningProvider.tsx","../src/signing/controller.ts","../src/signing/SigningPane.tsx","../src/signing/captures.tsx","../src/embed/protocol.ts","../src/embed/EmbedTransport.ts","../src/embed/EmbedHostTransport.ts","../src/sheets/CasualSheets.tsx","../src/sheets/mention-io.ts","../src/sheets/mention-source.ts","../src/sheets/api.ts","../src/sheets/scripting.ts","../src/sheets/read-only.ts","../src/sheets/read-only-predicate.ts","../src/sheets/emitter.ts","../src/univer/lazy-plugins.ts","../src/ai/AiPanelSurface.tsx","../src/sheets/mount.tsx","../src/ai/transport.ts","../src/sheets/CasualSheetsIframe.tsx"],"sourcesContent":["/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @casualoffice/sheets — Casual Sheets SDK\n *\n * Three surfaces:\n * - `./signing` — anchored cell signatures (drawn / typed / uploaded).\n * - `./embed` — iframe postMessage protocol for host integrations.\n * - `./sheets` — `CasualSheets` React wrapper around Univer Sheets.\n *\n * The `./styles` side-effect entry brings in the eager plugin CSS:\n *\n * import '@casualoffice/sheets/styles';\n */\n\nexport * from './signing';\nexport * from './embed';\nexport * from './sheets';\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SigningProvider — wraps a signing session in React context so\n * descendant components (SigningPane, capture surfaces, and the\n * editor's field-highlight decorations) all see the same snapshot.\n *\n * The pure state machine lives in `./controller.ts`; this file\n * just bridges it to React.\n */\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react';\n\nimport {\n createSigningController,\n type SigningController,\n type SigningSnapshot,\n} from './controller';\nimport type {\n CancelReason,\n SignatureCompletePayload,\n SignedFieldPayload,\n SigningSessionConfig,\n} from './types';\n\ninterface SigningContextValue {\n controller: SigningController;\n snapshot: SigningSnapshot;\n /** Convenience wrapper around controller.signField that also fires the host's onFieldSigned. */\n signField: (payload: SignedFieldPayload) => Promise<void>;\n /** Convenience wrapper around controller.complete + host's onComplete. */\n completeIfReady: () => Promise<void>;\n /** Convenience wrapper around controller.cancel + host's onCancel. */\n cancel: (reason: CancelReason) => void;\n /** Source-of-truth document bytes the editor renders. Captured at\n * signing-session open; persists for the lifetime of the session. */\n baseDocumentBytes: ArrayBuffer | null;\n}\n\nconst SigningContext = createContext<SigningContextValue | null>(null);\n\nexport interface SigningProviderProps {\n /** Active signing session config. When null, signing is off and\n * children render unchanged. */\n session: SigningSessionConfig | null;\n /** Current document bytes the editor is rendering. Captured into\n * the context so the eventual `complete` payload carries the\n * right base buffer. */\n documentBytes: ArrayBuffer | null;\n children: ReactNode;\n}\n\nexport function SigningProvider({ session, documentBytes, children }: SigningProviderProps) {\n if (!session) {\n return <>{children}</>;\n }\n return (\n <SigningProviderInner session={session} documentBytes={documentBytes}>\n {children}\n </SigningProviderInner>\n );\n}\n\nfunction SigningProviderInner({\n session,\n documentBytes,\n children,\n}: {\n session: SigningSessionConfig;\n documentBytes: ArrayBuffer | null;\n children: ReactNode;\n}) {\n // Controller is constructed once per session-config identity.\n // Hosts that swap sessions mid-tree must change the React `key`\n // on the provider — otherwise stale state would leak.\n const controller = useMemo(\n () => createSigningController(session.fields, session.mode),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [session.fields, session.mode],\n );\n\n const [snapshot, setSnapshot] = useState<SigningSnapshot>(() => controller.snapshot());\n\n useEffect(() => {\n const unsub = controller.subscribe(setSnapshot);\n return unsub;\n }, [controller]);\n\n const value = useMemo<SigningContextValue>(\n () => ({\n controller,\n snapshot,\n signField: async (payload) => {\n controller.signField(payload);\n await session.onFieldSigned?.(payload);\n },\n completeIfReady: async () => {\n if (!controller.snapshot().canComplete) return;\n const final = controller.complete();\n const completePayload: SignatureCompletePayload = {\n fieldIds: final.fields\n .map((f) => f.fieldId)\n .filter((id) => final.signed[id] !== undefined),\n bytes: documentBytes ?? new ArrayBuffer(0),\n fields: final.signed,\n };\n await session.onComplete?.(completePayload);\n },\n cancel: (reason) => {\n controller.cancel();\n session.onCancel?.({ reason });\n },\n baseDocumentBytes: documentBytes,\n }),\n [controller, snapshot, session, documentBytes],\n );\n\n return <SigningContext.Provider value={value}>{children}</SigningContext.Provider>;\n}\n\n/**\n * Hook for descendants of <SigningProvider>. Returns null when\n * no signing session is active — caller renders its non-signing\n * shape.\n */\nexport function useSigning(): SigningContextValue | null {\n return useContext(SigningContext);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Signing state machine — pure with respect to React so bun-test\n * can exercise it without a renderer. The React wrappers\n * (SigningProvider / SigningPane) sit on top of this.\n *\n * Single source of truth for \"which field is the signer on,\n * which fields are done, can we complete yet\" — the React layer\n * never recomputes these from scratch.\n */\n\nimport type { SignedFieldPayload, SignatureField, SignatureMode } from './types';\n\nexport interface SigningSnapshot {\n fields: SignatureField[];\n mode: SignatureMode;\n /** Fields completed in order they were signed. */\n signed: Record<string, SignedFieldPayload>;\n /** Index into `fields` of the field the signer should focus on\n * next. -1 once everything required is done. */\n activeFieldIndex: number;\n /** True once every required field has a payload. */\n canComplete: boolean;\n /** True once the controller has received a completion command. */\n isComplete: boolean;\n /** True if a cancel has been emitted. */\n isCancelled: boolean;\n}\n\nexport interface SigningController {\n snapshot(): SigningSnapshot;\n subscribe(listener: (s: SigningSnapshot) => void): () => void;\n /** Record a signed field. Throws if the field id is unknown. */\n signField(payload: SignedFieldPayload): void;\n /** Move focus to a specific field (concurrent mode let users\n * pick); in sequential mode the controller silently no-ops if\n * the requested field isn't the next required. */\n focusField(fieldId: string): void;\n /** Mark the session complete. Returns the snapshot at the\n * moment of completion; throws if not yet canComplete. */\n complete(): SigningSnapshot;\n /** Mark the session cancelled. Idempotent. */\n cancel(): void;\n}\n\nexport function createSigningController(\n fields: SignatureField[],\n mode: SignatureMode,\n): SigningController {\n if (fields.length === 0) {\n throw new Error('createSigningController: at least one field required');\n }\n const fieldIds = new Set(fields.map((f) => f.fieldId));\n if (fieldIds.size !== fields.length) {\n throw new Error('createSigningController: duplicate fieldId');\n }\n\n const signed: Record<string, SignedFieldPayload> = {};\n let activeFieldIndex = nextRequiredIndex(fields, signed);\n let isComplete = false;\n let isCancelled = false;\n const listeners = new Set<(s: SigningSnapshot) => void>();\n\n function emit() {\n const snap = snapshotInternal();\n for (const l of listeners) l(snap);\n }\n\n function snapshotInternal(): SigningSnapshot {\n return {\n fields,\n mode,\n signed: { ...signed },\n activeFieldIndex,\n canComplete: allRequiredSigned(fields, signed),\n isComplete,\n isCancelled,\n };\n }\n\n return {\n snapshot: snapshotInternal,\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n signField(payload) {\n if (isComplete || isCancelled) return;\n if (!fieldIds.has(payload.fieldId)) {\n throw new Error(`signField: unknown fieldId ${payload.fieldId}`);\n }\n signed[payload.fieldId] = payload;\n activeFieldIndex = nextRequiredIndex(fields, signed);\n emit();\n },\n focusField(fieldId) {\n if (isComplete || isCancelled) return;\n const idx = fields.findIndex((f) => f.fieldId === fieldId);\n if (idx < 0) return;\n if (mode === 'sequential') {\n // Sequential mode: only the next-required field is focusable.\n const next = nextRequiredIndex(fields, signed);\n if (idx !== next) return;\n }\n activeFieldIndex = idx;\n emit();\n },\n complete() {\n if (!allRequiredSigned(fields, signed)) {\n throw new Error('complete: required fields are still unsigned');\n }\n isComplete = true;\n activeFieldIndex = -1;\n emit();\n return snapshotInternal();\n },\n cancel() {\n if (isComplete || isCancelled) return;\n isCancelled = true;\n activeFieldIndex = -1;\n emit();\n },\n };\n}\n\n// ---------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------\n\nfunction allRequiredSigned(\n fields: SignatureField[],\n signed: Record<string, SignedFieldPayload>,\n): boolean {\n return fields.every((f) => !f.required || signed[f.fieldId] !== undefined);\n}\n\nfunction nextRequiredIndex(\n fields: SignatureField[],\n signed: Record<string, SignedFieldPayload>,\n): number {\n for (let i = 0; i < fields.length; i++) {\n if (fields[i].required && !signed[fields[i].fieldId]) return i;\n }\n // Either all required are done OR no required exists; pick the\n // first unsigned optional.\n for (let i = 0; i < fields.length; i++) {\n if (!signed[fields[i].fieldId]) return i;\n }\n return -1;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SigningPane — the floating sidebar that walks the signer through\n * fields. Lives inside <SigningProvider>; uses the controller via\n * `useSigning()`.\n *\n * Layout: a right-anchored panel showing\n * - Banner (optional, from session config)\n * - Field list with state markers (active / signed / pending)\n * - Method picker for the active field\n * - Capture surface (Drawn / Typed / Uploaded) depending on method\n * - Footer: Cancel + Complete\n *\n * The pane is presentation-only — every action routes through the\n * SigningProvider's helpers (signField, completeIfReady, cancel)\n * so the controller stays the single source of truth.\n */\n\nimport { useEffect, useState, type CSSProperties } from 'react';\n\nimport { useSigning } from './SigningProvider';\nimport type { SignatureField, SignatureMethod, SignedFieldPayload } from './types';\nimport {\n DrawnSignaturePad,\n TypedSignatureField,\n UploadedSignatureField,\n type CapturedSignature,\n} from './captures';\n\nexport interface SigningPaneProps {\n /** Optional banner override; falls back to session.banner. */\n banner?: string;\n /** Optional data-testid root. */\n testId?: string;\n}\n\nexport function SigningPane({ banner, testId = 'signing-pane' }: SigningPaneProps) {\n const ctx = useSigning();\n if (!ctx) return null;\n\n const { snapshot, signField, completeIfReady, cancel } = ctx;\n if (snapshot.isComplete || snapshot.isCancelled) return null;\n\n const active: SignatureField | null =\n snapshot.activeFieldIndex >= 0 ? snapshot.fields[snapshot.activeFieldIndex] : null;\n\n return (\n <aside style={paneStyle} role=\"region\" aria-label=\"Signing pane\" data-testid={testId}>\n {banner && (\n <div style={bannerStyle} data-testid={`${testId}-banner`}>\n {banner}\n </div>\n )}\n <div style={listStyle} data-testid={`${testId}-fields`}>\n {snapshot.fields.map((f, i) => {\n const isSigned = !!snapshot.signed[f.fieldId];\n const isActive = i === snapshot.activeFieldIndex;\n return (\n <div\n key={f.fieldId}\n style={listItemStyle(isActive, isSigned)}\n data-testid={`${testId}-field-${f.fieldId}`}\n data-state={isSigned ? 'signed' : isActive ? 'active' : 'pending'}\n >\n <span style={listIconStyle(isSigned)} aria-hidden=\"true\">\n {isSigned ? '✓' : i + 1}\n </span>\n <span style={listLabelStyle}>{f.label}</span>\n {!f.required && (\n <span style={optionalChipStyle} aria-label=\"Optional\">\n optional\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n {active && (\n <ActiveFieldEditor\n field={active}\n testId={testId}\n onCapture={async (cap, method) => {\n const payload: SignedFieldPayload = {\n fieldId: active.fieldId,\n method,\n bytes: cap.bytes,\n mime: cap.mime,\n signedAt: new Date().toISOString(),\n };\n await signField(payload);\n }}\n />\n )}\n\n {!active && snapshot.canComplete && (\n <div style={completeBlockStyle} data-testid={`${testId}-complete-block`}>\n All required signatures collected. Ready to finalise.\n </div>\n )}\n\n <footer style={footerStyle}>\n <button\n type=\"button\"\n onClick={() => cancel('signer_cancelled')}\n style={secondaryBtnStyle()}\n data-testid={`${testId}-cancel`}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void completeIfReady()}\n disabled={!snapshot.canComplete}\n style={primaryBtnStyle(!snapshot.canComplete)}\n data-testid={`${testId}-complete`}\n >\n Complete\n </button>\n </footer>\n </aside>\n );\n}\n\n// ---------------------------------------------------------------\n// Active field editor — method picker + capture surface\n// ---------------------------------------------------------------\n\nfunction ActiveFieldEditor({\n field,\n testId,\n onCapture,\n}: {\n field: SignatureField;\n testId: string;\n onCapture: (cap: CapturedSignature, method: SignatureMethod) => void | Promise<void>;\n}) {\n const [method, setMethod] = useState<SignatureMethod>(field.methods[0]);\n\n // Reset the method picker whenever the active field changes — a\n // method that was valid for the previous field may not be in this\n // field's list.\n useEffect(() => {\n setMethod(field.methods[0]);\n }, [field]);\n\n return (\n <div style={editorStyle} data-testid={`${testId}-editor`}>\n <div style={editorHeaderStyle}>\n <div style={editorLabelStyle}>{field.label}</div>\n {field.signer?.name && <div style={editorSignerStyle}>{field.signer.name}</div>}\n </div>\n {field.methods.length > 1 && (\n <div style={methodTabsStyle} role=\"tablist\" data-testid={`${testId}-methods`}>\n {field.methods.map((m) => (\n <button\n key={m}\n type=\"button\"\n role=\"tab\"\n aria-selected={method === m}\n onClick={() => setMethod(m)}\n style={methodTabStyle(method === m)}\n data-testid={`${testId}-method-${m}`}\n >\n {methodLabel(m)}\n </button>\n ))}\n </div>\n )}\n <div style={captureWrapStyle}>\n {method === 'drawn' && <DrawnSignaturePad onCapture={(c) => onCapture(c, 'drawn')} />}\n {method === 'typed' && (\n <TypedSignatureField\n defaultText={field.signer?.name ?? ''}\n onCapture={(c) => onCapture(c, 'typed')}\n />\n )}\n {method === 'uploaded' && (\n <UploadedSignatureField onCapture={(c) => onCapture(c, 'uploaded')} />\n )}\n </div>\n </div>\n );\n}\n\nfunction methodLabel(m: SignatureMethod): string {\n switch (m) {\n case 'drawn':\n return 'Draw';\n case 'typed':\n return 'Type';\n case 'uploaded':\n return 'Upload';\n }\n}\n\n// ---------------------------------------------------------------\n// Styles\n// ---------------------------------------------------------------\n\nconst paneStyle: CSSProperties = {\n position: 'fixed',\n top: 16,\n right: 16,\n bottom: 16,\n width: 360,\n maxWidth: '100vw',\n display: 'flex',\n flexDirection: 'column',\n gap: 14,\n padding: 16,\n background: 'var(--doc-surface, #fff)',\n border: '1px solid var(--doc-border, #cbd5e1)',\n borderRadius: 12,\n boxShadow: '0 1px 1px rgba(0, 0, 0, 0.04), 0 6px 24px rgba(15, 23, 42, 0.12)',\n fontFamily: 'inherit',\n zIndex: 9000,\n};\n\nconst bannerStyle: CSSProperties = {\n padding: '8px 10px',\n background: 'var(--doc-surface-2, #f1f5f9)',\n border: '1px solid var(--doc-border-light, #e2e8f0)',\n borderRadius: 6,\n fontSize: 12,\n color: 'var(--doc-text-muted, #475569)',\n};\n\nconst listStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n};\n\nfunction listItemStyle(active: boolean, signed: boolean): CSSProperties {\n return {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n borderRadius: 6,\n background: active ? 'var(--doc-surface-2, #f1f5f9)' : signed ? 'transparent' : 'transparent',\n border: active ? '1px solid var(--doc-border, #cbd5e1)' : '1px solid transparent',\n opacity: signed && !active ? 0.7 : 1,\n };\n}\n\nfunction listIconStyle(signed: boolean): CSSProperties {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 22,\n height: 22,\n borderRadius: '50%',\n background: signed ? 'var(--doc-accent, #2563eb)' : 'var(--doc-surface-2, #f1f5f9)',\n color: signed ? '#fff' : 'var(--doc-text-muted, #475569)',\n fontSize: 12,\n fontWeight: 600,\n flexShrink: 0,\n };\n}\n\nconst listLabelStyle: CSSProperties = {\n flex: 1,\n fontSize: 13,\n color: 'var(--doc-text, #0f172a)',\n fontWeight: 500,\n};\n\nconst optionalChipStyle: CSSProperties = {\n fontSize: 11,\n color: 'var(--doc-text-muted, #64748b)',\n padding: '2px 6px',\n background: 'var(--doc-surface-2, #f1f5f9)',\n borderRadius: 4,\n};\n\nconst editorStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n};\n\nconst editorHeaderStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n};\n\nconst editorLabelStyle: CSSProperties = {\n fontSize: 13,\n fontWeight: 600,\n color: 'var(--doc-text, #0f172a)',\n};\n\nconst editorSignerStyle: CSSProperties = {\n fontSize: 12,\n color: 'var(--doc-text-muted, #64748b)',\n};\n\nconst methodTabsStyle: CSSProperties = {\n display: 'flex',\n gap: 4,\n padding: 2,\n background: 'var(--doc-surface-2, #f1f5f9)',\n borderRadius: 6,\n};\n\nfunction methodTabStyle(selected: boolean): CSSProperties {\n return {\n flex: 1,\n padding: '6px 10px',\n background: selected ? 'var(--doc-surface, #fff)' : 'transparent',\n border: 'none',\n borderRadius: 4,\n fontSize: 12,\n fontWeight: 500,\n color: selected ? 'var(--doc-text, #0f172a)' : 'var(--doc-text-muted, #475569)',\n cursor: 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nconst captureWrapStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n};\n\nconst completeBlockStyle: CSSProperties = {\n padding: '10px 12px',\n background: 'rgba(34, 197, 94, 0.08)',\n border: '1px solid rgba(34, 197, 94, 0.28)',\n borderRadius: 6,\n fontSize: 12,\n color: 'rgb(20, 83, 45)',\n};\n\nconst footerStyle: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n marginTop: 'auto',\n paddingTop: 12,\n borderTop: '1px solid var(--doc-border-light, #e2e8f0)',\n};\n\nfunction primaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid transparent',\n background: disabled ? 'var(--doc-border, #cbd5e1)' : 'var(--doc-accent, #2563eb)',\n color: disabled ? 'var(--doc-text-muted, #64748b)' : '#fff',\n fontSize: 13,\n fontWeight: 600,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nfunction secondaryBtnStyle(): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid var(--doc-border, #cbd5e1)',\n background: 'transparent',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Three signature-capture surfaces: drawn (canvas), typed (input\n * rendered in a script font), uploaded (image file picker).\n *\n * Each one emits an `{ bytes, mime }` pair that the parent feeds\n * into SigningContext.signField. The components are presentation +\n * input only — they don't know about the controller or the field\n * they're capturing for.\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\nexport interface CapturedSignature {\n bytes: ArrayBuffer;\n mime: string;\n}\n\n// ---------------------------------------------------------------\n// Drawn — canvas\n// ---------------------------------------------------------------\n\nexport interface DrawnSignaturePadProps {\n /** Fired when the user clicks \"Use this signature\". */\n onCapture: (sig: CapturedSignature) => void;\n /** Optional clear-button label override. */\n clearLabel?: string;\n /** Optional save-button label override. */\n saveLabel?: string;\n /** Canvas pixel size. Default 480 × 160. */\n width?: number;\n height?: number;\n}\n\nexport function DrawnSignaturePad({\n onCapture,\n clearLabel = 'Clear',\n saveLabel = 'Use this signature',\n width = 480,\n height = 160,\n}: DrawnSignaturePadProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const drawingRef = useRef(false);\n const [hasInk, setHasInk] = useState(false);\n\n // Set up a clean canvas on mount. Background is transparent so\n // the stamped image composites cleanly over the document.\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.strokeStyle = '#0f172a';\n ctx.lineWidth = 2;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n }, []);\n\n const start = (e: React.PointerEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const { x, y } = pointerPos(e, canvas);\n ctx.beginPath();\n ctx.moveTo(x, y);\n drawingRef.current = true;\n canvas.setPointerCapture(e.pointerId);\n };\n\n const move = (e: React.PointerEvent<HTMLCanvasElement>) => {\n if (!drawingRef.current) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const { x, y } = pointerPos(e, canvas);\n ctx.lineTo(x, y);\n ctx.stroke();\n if (!hasInk) setHasInk(true);\n };\n\n const end = (e: React.PointerEvent<HTMLCanvasElement>) => {\n drawingRef.current = false;\n canvasRef.current?.releasePointerCapture(e.pointerId);\n };\n\n const clear = () => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n setHasInk(false);\n };\n\n const save = async () => {\n const canvas = canvasRef.current;\n if (!canvas || !hasInk) return;\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob((b) => resolve(b), 'image/png');\n });\n if (!blob) return;\n const bytes = await blob.arrayBuffer();\n onCapture({ bytes, mime: 'image/png' });\n clear();\n };\n\n return (\n <div style={padWrapStyle} data-testid=\"drawn-signature-pad\">\n <canvas\n ref={canvasRef}\n width={width}\n height={height}\n style={padCanvasStyle(width, height)}\n onPointerDown={start}\n onPointerMove={move}\n onPointerUp={end}\n onPointerLeave={end}\n data-testid=\"drawn-signature-canvas\"\n />\n <div style={padActionsStyle}>\n <button type=\"button\" onClick={clear} style={secondaryBtnStyle(false)}>\n {clearLabel}\n </button>\n <button\n type=\"button\"\n onClick={save}\n disabled={!hasInk}\n style={primaryBtnStyle(!hasInk)}\n data-testid=\"drawn-signature-save\"\n >\n {saveLabel}\n </button>\n </div>\n </div>\n );\n}\n\nfunction pointerPos(e: React.PointerEvent<HTMLCanvasElement>, canvas: HTMLCanvasElement) {\n const rect = canvas.getBoundingClientRect();\n const scaleX = canvas.width / rect.width;\n const scaleY = canvas.height / rect.height;\n return {\n x: (e.clientX - rect.left) * scaleX,\n y: (e.clientY - rect.top) * scaleY,\n };\n}\n\n// ---------------------------------------------------------------\n// Typed\n// ---------------------------------------------------------------\n\nexport interface TypedSignatureFieldProps {\n onCapture: (sig: CapturedSignature) => void;\n defaultText?: string;\n saveLabel?: string;\n}\n\nexport function TypedSignatureField({\n onCapture,\n defaultText = '',\n saveLabel = 'Use this signature',\n}: TypedSignatureFieldProps) {\n const [value, setValue] = useState(defaultText);\n const save = () => {\n const trimmed = value.trim();\n if (!trimmed) return;\n const bytes = new TextEncoder().encode(trimmed).buffer;\n onCapture({ bytes, mime: 'text/plain' });\n setValue('');\n };\n return (\n <div style={padWrapStyle} data-testid=\"typed-signature-field\">\n <input\n type=\"text\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Type your full name\"\n style={typedInputStyle}\n data-testid=\"typed-signature-input\"\n autoFocus\n />\n <div style={padActionsStyle}>\n <button\n type=\"button\"\n onClick={save}\n disabled={!value.trim()}\n style={primaryBtnStyle(!value.trim())}\n data-testid=\"typed-signature-save\"\n >\n {saveLabel}\n </button>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------\n// Uploaded\n// ---------------------------------------------------------------\n\nexport interface UploadedSignatureFieldProps {\n onCapture: (sig: CapturedSignature) => void;\n /** Accept attribute. Default image/*. */\n accept?: string;\n}\n\nexport function UploadedSignatureField({\n onCapture,\n accept = 'image/png,image/jpeg,image/svg+xml',\n}: UploadedSignatureFieldProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const [fileName, setFileName] = useState<string | null>(null);\n const onChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const bytes = await file.arrayBuffer();\n onCapture({ bytes, mime: file.type || 'application/octet-stream' });\n setFileName(file.name);\n if (inputRef.current) inputRef.current.value = '';\n };\n return (\n <div style={padWrapStyle} data-testid=\"uploaded-signature-field\">\n <label style={uploadLabelStyle}>\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n onChange={onChange}\n style={{ display: 'none' }}\n data-testid=\"uploaded-signature-input\"\n />\n <span>{fileName ?? 'Choose image…'}</span>\n </label>\n </div>\n );\n}\n\n// ---------------------------------------------------------------\n// Shared styles\n// ---------------------------------------------------------------\n\nconst padWrapStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 10,\n};\n\nconst padCanvasStyle = (w: number, h: number): CSSProperties => ({\n width: w,\n height: h,\n maxWidth: '100%',\n border: '1px dashed var(--doc-border, #cbd5e1)',\n borderRadius: 8,\n background: 'var(--doc-surface, #fff)',\n cursor: 'crosshair',\n touchAction: 'none',\n});\n\nconst padActionsStyle: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n};\n\nconst typedInputStyle: CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: '1px solid var(--doc-border, #cbd5e1)',\n borderRadius: 6,\n fontSize: 18,\n fontFamily: '\"Caveat\", \"Dancing Script\", \"Brush Script MT\", cursive',\n background: 'var(--doc-surface, #fff)',\n color: 'var(--doc-text, #0f172a)',\n};\n\nconst uploadLabelStyle: CSSProperties = {\n display: 'inline-flex',\n padding: '8px 14px',\n border: '1px dashed var(--doc-border, #cbd5e1)',\n borderRadius: 6,\n background: 'var(--doc-surface, #fff)',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n cursor: 'pointer',\n alignSelf: 'flex-start',\n};\n\nfunction primaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid transparent',\n background: disabled ? 'var(--doc-border, #cbd5e1)' : 'var(--doc-accent, #2563eb)',\n color: disabled ? 'var(--doc-text-muted, #64748b)' : '#fff',\n fontSize: 13,\n fontWeight: 600,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nfunction secondaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid var(--doc-border, #cbd5e1)',\n background: 'transparent',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n fontWeight: 500,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Iframe protocol — wire envelopes that match\n * `docs/internal/13-iframe-protocol.md`.\n *\n * Mirror updates to the doc whenever a new envelope shape lands.\n * The discriminator on `type` (always starts with `casual.`) and\n * the per-envelope `data` shape are the contract.\n */\n\nimport type {\n CancelReason,\n SignatureCompletePayload,\n SignatureField,\n SignatureMode,\n SignedFieldPayload,\n} from '../signing/types';\n\nexport type CasualApp = 'docs' | 'sheet';\n\n/** Common envelope shape — every postMessage on the wire matches this. */\nexport interface CasualEnvelope<T = unknown> {\n type: string;\n app: CasualApp;\n /** Per-request id for request/response correlation. Empty for fire-and-forget. */\n id?: string;\n /** Protocol version. Bumped only on breaking changes. */\n v: 1;\n data: T;\n}\n\n// ---------------------------------------------------------------\n// Handshake\n// ---------------------------------------------------------------\n\nexport interface EditorHelloData {\n capabilities: string[];\n version: string;\n commit: string;\n}\n\nexport interface HostHelloData {\n capabilities: string[];\n authToken?: string;\n}\n\n// ---------------------------------------------------------------\n// Load + save (editor → host requests; host → editor responses)\n// ---------------------------------------------------------------\n\nexport interface LoadRequestData {\n docId: string;\n}\n\nexport interface LoadResponseDataOk {\n ok: true;\n bytes: ArrayBuffer;\n etag?: string;\n fileName: string;\n readOnly?: boolean;\n}\n\nexport interface LoadResponseDataErr {\n ok: false;\n code: string;\n message?: string;\n}\n\nexport type LoadResponseData = LoadResponseDataOk | LoadResponseDataErr;\n\nexport interface SaveRequestData {\n docId: string;\n bytes: ArrayBuffer;\n baseEtag?: string;\n}\n\nexport interface SaveResponseDataOk {\n ok: true;\n etag: string;\n}\n\nexport interface SaveResponseDataErr {\n ok: false;\n code: string;\n etag?: string;\n message?: string;\n}\n\nexport type SaveResponseData = SaveResponseDataOk | SaveResponseDataErr;\n\n// ---------------------------------------------------------------\n// Save / exit notifications (editor → host, fire-and-forget)\n// ---------------------------------------------------------------\n//\n// The lightweight counterpart to the bytes-carrying load/save *request*\n// pair above. These mirror the SDK's React `onSave` / `onExit` hooks one\n// for one — the \"one shape, two surfaces\" save/exit contract — so a host\n// that frames the iframe gets the same persistence signals a host that\n// renders `<CasualSheets>` directly does. Fire-and-forget: the editor\n// never owns storage; the host decides what to do with the snapshot.\n//\n// `casual.save.request` (above) stays the WOPI-style path for hosts that\n// want xlsx bytes + etag round-trips; these notifications are the simpler\n// \"here's the current state, persist it however you like\" path.\n\n/** Editor → host: the user explicitly asked to save — Ctrl/Cmd+S inside\n * the iframe, or the host's `casual.command.save`. Carries the full\n * editor snapshot as JSON (sheet app: Univer's `IWorkbookData`). Mirror\n * of the React `onSave` hook. v0.9+. */\nexport interface SaveNotifyData {\n /** App-specific snapshot JSON. Sheet: `IWorkbookData`. */\n snapshot: unknown;\n /** What triggered the save: the in-editor shortcut or a host command. */\n reason: 'shortcut' | 'host';\n}\n\n/** Editor → host: the editor is unmounting / navigating away. Carries\n * the final snapshot so the host can persist on exit. Mirror of the\n * React `onExit` hook. v0.9+. */\nexport interface ExitData {\n /** App-specific snapshot JSON. Sheet: `IWorkbookData`. */\n snapshot: unknown;\n}\n\n// ---------------------------------------------------------------\n// Selection + telemetry + lock (editor → host notifications)\n// ---------------------------------------------------------------\n\nexport interface SelectionChangedData {\n docs?: { paraId: string; from: number; to: number; selectedText: string };\n sheet?: { sheet: string; from: string; to: string };\n}\n\nexport interface TelemetryEventData {\n kind: string;\n /** Arbitrary metric fields. */\n [k: string]: unknown;\n}\n\nexport interface LockLostData {\n reason: 'taken_by_other' | 'expired' | 'host_revoked';\n}\n\n// ---------------------------------------------------------------\n// Commands (host → editor)\n// ---------------------------------------------------------------\n\nexport interface CommandSetReadOnlyData {\n readOnly: boolean;\n}\n\nexport interface CommandSetThemeData {\n theme: 'light' | 'dark' | 'system';\n}\n\n/** Host → editor: enable/disable chrome features. Each key maps a toolbar\n * group / menu item / capability to a boolean; a `false` hides the control\n * AND blocks its command. Omitted keys default to enabled. Mirrors the\n * `features` prop on `<CasualSheets>`. */\nexport interface CommandSetFeaturesData {\n features: Record<string, boolean>;\n}\n\n/** Editor → host: a chrome control backed by a dialog the SDK doesn't render\n * itself (Format Cells, Insert Chart, Find & Replace, …) was activated. The\n * host renders its OWN dialog/popup and applies the result via\n * `executeCommand`. Fired only when the host opted into host-owned dialogs\n * by handling this event. */\nexport interface DialogRequestData {\n kind: string;\n context?: unknown;\n}\n\nexport interface CommandSetLocaleData {\n locale: string;\n}\n\n/** Host → editor: switch chrome density between the two consumer-facing\n * modes without re-mounting. `preview` hides toolbar / formula bar /\n * side panel / status bar / sheet tabs and runs read-only; `editor`\n * shows the full UI. Mirrors the `viewMode` prop on `<CasualSheetsIframe>`. */\nexport interface CommandSetViewModeData {\n viewMode: 'preview' | 'editor';\n}\n\n/** Host → editor: execute a formatting / navigation command against\n * the active selection in the embedded workbook. Hosts (like Casual\n * Drive) build their own toolbar above the iframe and dispatch these\n * commands instead of Univer's built-in ribbon, which the SDK can't\n * ship because the ribbon resolves IRPCChannelService at construction\n * and that service needs a worker the SDK doesn't bundle.\n *\n * v0.6 covered the toggle set; v0.7 adds the rich-format set (font,\n * size, colour, fill) + merge / unmerge. Arg-carrying commands read\n * the relevant field off `args` — every other command ignores it. */\nexport interface CommandExecuteData {\n command: // v0.6 — toggle / nav (no args)\n | 'undo'\n | 'redo'\n | 'bold'\n | 'italic'\n | 'underline'\n | 'strikethrough'\n | 'align-left'\n | 'align-center'\n | 'align-right'\n // v0.7 — rich format (args carry the value)\n | 'set-font-family'\n | 'set-font-size'\n | 'set-text-color'\n | 'reset-text-color'\n | 'set-bg-color'\n | 'reset-bg-color'\n | 'merge'\n | 'unmerge'\n // v0.8 — number formats + freeze + wrap\n | 'numfmt-currency'\n | 'numfmt-percent'\n | 'numfmt-add-decimal'\n | 'numfmt-subtract-decimal'\n | 'numfmt-custom'\n | 'wrap-toggle'\n | 'freeze-first-row'\n | 'freeze-first-column'\n | 'freeze-none';\n args?: {\n /** Used by `set-font-family`. */\n family?: string;\n /** Used by `set-font-size`. Integer point size. */\n size?: number;\n /** Used by `set-text-color` and `set-bg-color`. Hex like `#1a73e8`. */\n color?: string;\n /** Used by `numfmt-custom`. The Excel-style format string, e.g.\n * `\"#,##0.00\"`, `\"$#,##0\"`, `\"0.00%\"`, `\"d-mmm-yy\"`. v0.8+. */\n pattern?: string;\n };\n}\n\n/** Editor → host: emitted whenever the selection's active cell's\n * format flags change. Drive's toolbar mirrors this state in the\n * button \"pressed\" / value indicators so the surface always reflects\n * what the user would see in the cell. v0.7 widens the payload with\n * the rich-format read-back (fontFamily, fontSize, textColor, bgColor)\n * so the toolbar's font picker / size stepper / colour swatches stay\n * in sync without the host having to poll. */\nexport interface SelectionFormatStateData {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strikethrough: boolean;\n align: 'left' | 'center' | 'right' | null;\n /** Defined font family on the active cell, or null when the cell\n * inherits the workbook default. v0.7+. */\n fontFamily: string | null;\n /** Defined font size on the active cell, or null when the cell\n * inherits the workbook default. v0.7+. */\n fontSize: number | null;\n /** Hex text colour like `#1a73e8`, or null when default. v0.7+. */\n textColor: string | null;\n /** Hex background colour, or null when no fill is set. v0.7+. */\n bgColor: string | null;\n}\n\n// ---------------------------------------------------------------\n// Errors (editor → host fatal signals)\n// ---------------------------------------------------------------\n\n/** Editor → host: a fatal error during boot / load. Hosts surface this\n * via the wrapper's `onError` callback. */\nexport interface CasualErrorData {\n code: 'embed_not_served' | 'load_failed' | 'parse_failed' | 'boot_failed' | 'internal';\n message: string;\n}\n\n// ---------------------------------------------------------------\n// Signing (uniform with the SDK `signing` prop)\n// ---------------------------------------------------------------\n\nexport interface SignatureRequestData {\n fields: SignatureField[];\n mode: SignatureMode;\n banner?: string;\n}\n\nexport interface SignatureRequestAckData {\n ok: boolean;\n code?: string;\n}\n\nexport type SignatureFieldSignedData = SignedFieldPayload;\nexport type SignatureCompleteData = SignatureCompletePayload;\n\nexport interface SignatureCancelData {\n reason: CancelReason;\n}\n\n// ---------------------------------------------------------------\n// Type guards\n// ---------------------------------------------------------------\n\nexport function isCasualEnvelope(value: unknown): value is CasualEnvelope {\n if (!value || typeof value !== 'object') return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.type === 'string' &&\n v.type.startsWith('casual.') &&\n (v.app === 'docs' || v.app === 'sheet') &&\n v.v === 1 &&\n 'data' in v\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * EmbedTransport — postMessage bridge for the iframe-embedded\n * editor. Validates origin, dispatches envelopes to handlers,\n * sends responses back to the host. Pure TypeScript — no React.\n *\n * Wire shape defined in\n * `docs/internal/13-iframe-protocol.md` + `./protocol.ts`.\n *\n * Lifetime: constructed once when the /embed page mounts.\n * Destroyed when the page unloads. Concurrent calls into the same\n * handler are the host's responsibility (well-behaved hosts\n * serialise requests by id).\n */\n\nimport {\n isCasualEnvelope,\n type CasualApp,\n type CasualEnvelope,\n type EditorHelloData,\n type HostHelloData,\n type LoadResponseData,\n type LoadRequestData,\n type SaveRequestData,\n type SaveResponseData,\n type SaveNotifyData,\n type ExitData,\n type SelectionChangedData,\n type TelemetryEventData,\n type CommandSetReadOnlyData,\n type CommandSetThemeData,\n type CommandSetLocaleData,\n type CommandSetViewModeData,\n type CommandSetFeaturesData,\n type DialogRequestData,\n type CommandExecuteData,\n type SelectionFormatStateData,\n type CasualErrorData,\n type SignatureRequestData,\n type SignatureRequestAckData,\n type SignatureFieldSignedData,\n type SignatureCompleteData,\n type SignatureCancelData,\n} from './protocol';\n\nexport interface EmbedTransportOptions {\n app: CasualApp;\n /** Origin allowed to send messages. Required — no `*` default. */\n hostOrigin: string;\n /** Editor build identity, surfaced in the editor.hello handshake. */\n version: string;\n commit: string;\n /** Editor-side capabilities advertised at handshake. */\n capabilities: string[];\n /** Optional injection for `window.parent` — tests pass a stub. */\n parentWindow?: {\n postMessage: (msg: unknown, targetOrigin: string, transfer?: Transferable[]) => void;\n };\n /** Optional injection for the window receiving messages — tests pass a stub. */\n hostWindow?: Pick<Window, 'addEventListener' | 'removeEventListener'>;\n}\n\nexport interface EmbedTransportHandlers {\n /** Host → editor handshake. Editor responds with `editor.ready`. */\n onHostHello?: (data: HostHelloData) => void | Promise<void>;\n /** Host → editor: command.* messages. */\n onCommandSetReadOnly?: (data: CommandSetReadOnlyData) => void | Promise<void>;\n onCommandSetTheme?: (data: CommandSetThemeData) => void | Promise<void>;\n onCommandSetLocale?: (data: CommandSetLocaleData) => void | Promise<void>;\n onCommandSetFeatures?: (data: CommandSetFeaturesData) => void | Promise<void>;\n /** Host → editor: switch chrome density (preview ↔ editor). */\n onCommandSetViewMode?: (data: CommandSetViewModeData) => void | Promise<void>;\n /** Host → editor: execute a formatting / navigation command (bold,\n * italic, undo, …) against the active selection. v0.6+. */\n onCommandExecute?: (data: CommandExecuteData) => void | Promise<void>;\n onCommandFocus?: () => void | Promise<void>;\n onCommandSave?: () => void | Promise<void>;\n onCommandLoad?: () => void | Promise<void>;\n /** Host → editor signing session. Editor responds with `signature.request.ack`. */\n onSignatureRequest?: (\n data: SignatureRequestData,\n ) => SignatureRequestAckData | Promise<SignatureRequestAckData>;\n onSignatureCancel?: (data: SignatureCancelData) => void | Promise<void>;\n /** Host → editor: response to a prior load.request the editor issued. */\n onLoadResponse?: (id: string, data: LoadResponseData) => void;\n /** Host → editor: response to a prior save.request the editor issued. */\n onSaveResponse?: (id: string, data: SaveResponseData) => void;\n}\n\nexport class EmbedTransport {\n private readonly opts: Required<Omit<EmbedTransportOptions, 'parentWindow' | 'hostWindow'>> & {\n parentWindow: NonNullable<EmbedTransportOptions['parentWindow']>;\n hostWindow: NonNullable<EmbedTransportOptions['hostWindow']>;\n };\n private handlers: EmbedTransportHandlers = {};\n private destroyed = false;\n private pendingRequests = new Map<string, (env: CasualEnvelope) => void>();\n\n constructor(opts: EmbedTransportOptions) {\n this.opts = {\n ...opts,\n parentWindow:\n opts.parentWindow ??\n (typeof window !== 'undefined'\n ? (window.parent as unknown as NonNullable<EmbedTransportOptions['parentWindow']>)\n : { postMessage: () => undefined }),\n hostWindow:\n opts.hostWindow ??\n (typeof window !== 'undefined'\n ? window\n : ({\n addEventListener: () => undefined,\n removeEventListener: () => undefined,\n } as unknown as NonNullable<EmbedTransportOptions['hostWindow']>)),\n };\n this.boundMessage = this.boundMessage.bind(this);\n this.opts.hostWindow.addEventListener('message', this.boundMessage as EventListener);\n }\n\n /** Replaces the handler set. Idempotent — call multiple times. */\n on(handlers: EmbedTransportHandlers): void {\n this.handlers = { ...this.handlers, ...handlers };\n }\n\n /** Editor → Host: announce ourselves. Call once after handlers are wired. */\n sendHello(): void {\n const data: EditorHelloData = {\n capabilities: this.opts.capabilities,\n version: this.opts.version,\n commit: this.opts.commit,\n };\n this.post('casual.hello', data);\n }\n\n /** Editor → Host: editor is ready to receive commands. */\n sendReady(): void {\n this.post('casual.ready', {});\n }\n\n /** Editor → Host: ask the host to supply document bytes for `docId`. */\n async requestLoad(docId: string, timeoutMs = 30000): Promise<LoadResponseData> {\n return this.request<LoadResponseData>(\n 'casual.load.request',\n { docId } as LoadRequestData,\n timeoutMs,\n );\n }\n\n /** Editor → Host: ask the host to persist `bytes`. */\n async requestSave(req: SaveRequestData, timeoutMs = 30000): Promise<SaveResponseData> {\n return this.request<SaveResponseData>('casual.save.request', req, timeoutMs, [req.bytes]);\n }\n\n /** Editor → Host: the user asked to save (Ctrl/Cmd+S or a host save\n * command). Fire-and-forget snapshot notification — the lightweight\n * mirror of the React `onSave` hook. The host persists however it\n * likes; no response is awaited. */\n sendSaveNotify(data: SaveNotifyData): void {\n this.post('casual.save.notify', data);\n }\n\n /** Editor → Host: the editor is unmounting. Carries the final snapshot\n * so the host can persist on exit. Mirror of the React `onExit` hook. */\n sendExit(data: ExitData): void {\n this.post('casual.exit', data);\n }\n\n /** Editor → Host: selection moved. Fire-and-forget. */\n sendSelectionChanged(data: SelectionChangedData): void {\n this.post('casual.selection.changed', data);\n }\n\n /** Editor → Host: format flags on the active cell changed (bold,\n * italic, …). Drive's custom toolbar mirrors this state in its\n * \"pressed\" indicators. v0.6+. */\n sendSelectionFormatState(data: SelectionFormatStateData): void {\n this.post('casual.selection.format-state', data);\n }\n\n /** Editor → host: a host-owned dialog (Format Cells, Insert Chart, …) was\n * requested. The host renders its own UI and applies via executeCommand. */\n sendDialogRequest(data: DialogRequestData): void {\n this.post('casual.dialog.request', data);\n }\n\n /** Editor → Host: a noteworthy event. */\n sendTelemetry(data: TelemetryEventData): void {\n this.post('casual.telemetry.event', data);\n }\n\n /** Editor → Host: per-field progress during a signing session. */\n sendSignatureFieldSigned(data: SignatureFieldSignedData): void {\n // Bytes ride the transfer list.\n this.post('casual.signature.field.signed', data, [data.bytes]);\n }\n\n /** Editor → Host: signing session is finished. */\n sendSignatureComplete(data: SignatureCompleteData): void {\n this.post('casual.signature.complete', data, [data.bytes]);\n }\n\n /** Editor → Host: editor-side cancel of a signing session. */\n sendSignatureCancel(reason: SignatureCancelData['reason']): void {\n this.post('casual.signature.cancel', { reason });\n }\n\n /** Editor → Host: fatal boot / load error. Host surfaces via wrapper\n * `onError` callback. Fire-and-forget. */\n sendError(data: CasualErrorData): void {\n this.post('casual.error', data);\n }\n\n /** Tear down listeners. Idempotent. */\n destroy(): void {\n if (this.destroyed) return;\n this.opts.hostWindow.removeEventListener('message', this.boundMessage as EventListener);\n this.pendingRequests.clear();\n this.destroyed = true;\n }\n\n // ---------------------------------------------------------------\n // Internals\n // ---------------------------------------------------------------\n\n private boundMessage(ev: Event): void {\n // MessageEvent isn't always available on the typing side when\n // a stub window is injected; cast pragmatically.\n const msg = ev as unknown as MessageEvent;\n if (msg.origin && msg.origin !== this.opts.hostOrigin) return;\n if (!isCasualEnvelope(msg.data)) return;\n void this.dispatch(msg.data as CasualEnvelope);\n }\n\n private async dispatch(env: CasualEnvelope): Promise<void> {\n // Responses to outbound requests route through the correlation map.\n if (env.id && this.pendingRequests.has(env.id)) {\n const resolve = this.pendingRequests.get(env.id)!;\n this.pendingRequests.delete(env.id);\n resolve(env);\n return;\n }\n\n switch (env.type) {\n case 'casual.hello':\n await this.handlers.onHostHello?.(env.data as HostHelloData);\n this.sendReady();\n return;\n case 'casual.command.set.readonly':\n await this.handlers.onCommandSetReadOnly?.(env.data as CommandSetReadOnlyData);\n return;\n case 'casual.command.set.theme':\n await this.handlers.onCommandSetTheme?.(env.data as CommandSetThemeData);\n return;\n case 'casual.command.set.locale':\n await this.handlers.onCommandSetLocale?.(env.data as CommandSetLocaleData);\n return;\n case 'casual.command.set.features':\n await this.handlers.onCommandSetFeatures?.(env.data as CommandSetFeaturesData);\n return;\n case 'casual.command.set.viewmode':\n await this.handlers.onCommandSetViewMode?.(env.data as CommandSetViewModeData);\n return;\n case 'casual.command.execute':\n await this.handlers.onCommandExecute?.(env.data as CommandExecuteData);\n return;\n case 'casual.command.focus':\n await this.handlers.onCommandFocus?.();\n return;\n case 'casual.command.save':\n await this.handlers.onCommandSave?.();\n return;\n case 'casual.command.load':\n await this.handlers.onCommandLoad?.();\n return;\n case 'casual.signature.request': {\n const ack = (await this.handlers.onSignatureRequest?.(\n env.data as SignatureRequestData,\n )) ?? {\n ok: false,\n code: 'unhandled',\n };\n if (env.id) {\n this.postReply(env.id, 'casual.signature.request.ack', ack);\n }\n return;\n }\n case 'casual.signature.cancel':\n await this.handlers.onSignatureCancel?.(env.data as SignatureCancelData);\n return;\n default:\n // Unknown envelope — silently drop per the forward-compat\n // convention in the protocol doc.\n return;\n }\n }\n\n private post(type: string, data: unknown, transfer?: Transferable[]): void {\n const env: CasualEnvelope = { type, app: this.opts.app, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);\n } catch {\n // Cross-origin postMessage can throw if the parent went away;\n // silently swallow — the next user action will retry.\n }\n }\n\n private postReply(id: string, type: string, data: unknown): void {\n const env: CasualEnvelope = { type, app: this.opts.app, id, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin);\n } catch {\n // see post()\n }\n }\n\n private async request<T>(\n type: string,\n data: unknown,\n timeoutMs: number,\n transfer?: Transferable[],\n ): Promise<T> {\n const id = newRequestId();\n return new Promise<T>((resolve, reject) => {\n const timer =\n timeoutMs > 0\n ? setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Embed request ${type} timed out after ${timeoutMs}ms`));\n }, timeoutMs)\n : null;\n this.pendingRequests.set(id, (env) => {\n if (timer) clearTimeout(timer);\n resolve(env.data as T);\n });\n const env: CasualEnvelope = { type, app: this.opts.app, id, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);\n } catch (err) {\n if (timer) clearTimeout(timer);\n this.pendingRequests.delete(id);\n reject(err);\n }\n });\n }\n}\n\nfunction newRequestId(): string {\n // 8 hex chars is plenty — IDs only need to be unique within a\n // single editor session. Math.random is fine; the host can't\n // use these for security.\n return Math.random().toString(16).slice(2, 10);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * EmbedHostTransport — the parent side of the embed iframe bridge for\n * the sheet SDK. Mirror of @casualoffice/docs's host transport.\n *\n * Wire shape: `docs/SDK_SIGNING_EMBED.md` (cross-link in the doc repo at\n * `docs/internal/13-iframe-protocol.md`) + `16-sdk-iframe-architecture.md`.\n *\n * Lifetime: constructed once when the wrapper mounts the iframe.\n * `destroy()` removes the event listener; safe to call multiple times.\n */\n\nimport {\n isCasualEnvelope,\n type CasualApp,\n type CasualEnvelope,\n type CasualErrorData,\n type CommandSetReadOnlyData,\n type CommandSetThemeData,\n type CommandSetLocaleData,\n type CommandSetViewModeData,\n type CommandSetFeaturesData,\n type DialogRequestData,\n type CommandExecuteData,\n type SelectionFormatStateData,\n type EditorHelloData,\n type HostHelloData,\n type LoadRequestData,\n type LoadResponseData,\n type SaveRequestData,\n type SaveResponseData,\n type SaveNotifyData,\n type ExitData,\n type SelectionChangedData,\n type SignatureCancelData,\n type SignatureCompleteData,\n type SignatureFieldSignedData,\n type SignatureRequestData,\n type TelemetryEventData,\n} from './protocol';\n\nexport interface EmbedHostTransportOptions {\n app: CasualApp;\n /** The iframe's `contentWindow`. */\n iframeWindow: Window;\n /** Origin allowed to send + receive messages. Same-origin internal\n * embed is `window.location.origin`. */\n embedOrigin: string;\n /** Optional injection — tests pass a stub. */\n hostWindow?: Pick<Window, 'addEventListener' | 'removeEventListener'>;\n}\n\nexport interface EmbedHostHandlers {\n onEditorReady?: (data: EditorHelloData) => void;\n /** Editor requests bytes for `docId`. */\n onLoadRequest?: (data: LoadRequestData) => Promise<LoadResponseData> | LoadResponseData;\n /** Editor requests a save (WOPI-style, carries xlsx bytes). */\n onSaveRequest?: (data: SaveRequestData) => Promise<SaveResponseData> | SaveResponseData;\n /** Editor fired its lightweight save notification (Ctrl/Cmd+S or a\n * host save command). Carries the full snapshot JSON; fire-and-forget.\n * Mirror of the React `onSave` hook. */\n onSaveNotify?: (data: SaveNotifyData) => void;\n /** Editor is unmounting; carries the final snapshot. Mirror of the\n * React `onExit` hook. */\n onExit?: (data: ExitData) => void;\n onSelectionChanged?: (data: SelectionChangedData) => void;\n onSelectionFormatState?: (data: SelectionFormatStateData) => void;\n /** A host-owned dialog (Format Cells, Insert Chart, …) was requested from the\n * editor's chrome. Render your own dialog and apply via executeCommand. */\n onDialogRequest?: (data: DialogRequestData) => void;\n onTelemetry?: (data: TelemetryEventData) => void;\n onSignatureFieldSigned?: (data: SignatureFieldSignedData) => void;\n onSignatureComplete?: (data: SignatureCompleteData) => void;\n onSignatureCancel?: (data: SignatureCancelData) => void;\n onError?: (data: CasualErrorData) => void;\n}\n\ntype IframePostMessage = (msg: unknown, targetOrigin: string, transfer?: Transferable[]) => void;\n\nexport class EmbedHostTransport {\n private readonly opts: EmbedHostTransportOptions;\n private handlers: EmbedHostHandlers = {};\n private readonly boundOnMessage: (ev: MessageEvent) => void;\n private destroyed = false;\n\n constructor(opts: EmbedHostTransportOptions) {\n this.opts = opts;\n this.boundOnMessage = this.onMessage.bind(this);\n const target = opts.hostWindow ?? window;\n target.addEventListener('message', this.boundOnMessage);\n }\n\n on(handlers: EmbedHostHandlers): void {\n this.handlers = { ...this.handlers, ...handlers };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n const target = this.opts.hostWindow ?? window;\n target.removeEventListener('message', this.boundOnMessage);\n }\n\n sendHostHello(data: HostHelloData): void {\n this.post('casual.hello', data);\n }\n\n sendSetViewMode(data: CommandSetViewModeData): void {\n this.post('casual.command.set.viewmode', data);\n }\n\n sendSetReadOnly(data: CommandSetReadOnlyData): void {\n this.post('casual.command.set.readonly', data);\n }\n\n sendSetTheme(data: CommandSetThemeData): void {\n this.post('casual.command.set.theme', data);\n }\n\n sendSetLocale(data: CommandSetLocaleData): void {\n this.post('casual.command.set.locale', data);\n }\n\n /** Host → editor: enable/disable chrome features (hide control + block command). */\n sendSetFeatures(data: CommandSetFeaturesData): void {\n this.post('casual.command.set.features', data);\n }\n\n sendCommandSave(): void {\n this.post('casual.command.save', null);\n }\n\n sendCommandFocus(): void {\n this.post('casual.command.focus', null);\n }\n\n /** Host → Editor: run a formatting / navigation command (bold,\n * italic, undo, …) against the active selection. v0.6+. */\n sendCommandExecute(data: CommandExecuteData): void {\n this.post('casual.command.execute', data);\n }\n\n sendSignatureRequest(id: string, data: SignatureRequestData): void {\n this.post('casual.signature.request', data, id);\n }\n\n sendSignatureCancel(data: SignatureCancelData): void {\n this.post('casual.signature.cancel', data);\n }\n\n private onMessage(ev: MessageEvent): void {\n if (this.destroyed) return;\n if (ev.origin !== this.opts.embedOrigin) return;\n if (ev.source !== this.opts.iframeWindow) return;\n if (!isCasualEnvelope(ev.data)) return;\n if (ev.data.app !== this.opts.app) return;\n\n void this.dispatch(ev.data);\n }\n\n private async dispatch(env: CasualEnvelope): Promise<void> {\n switch (env.type) {\n case 'casual.ready':\n this.handlers.onEditorReady?.(env.data as EditorHelloData);\n return;\n case 'casual.load.request': {\n if (!this.handlers.onLoadRequest) return;\n const id = env.id ?? '';\n try {\n const resp = await this.handlers.onLoadRequest(env.data as LoadRequestData);\n const transfer: Transferable[] = resp.ok ? [resp.bytes] : [];\n this.post('casual.load.response', resp, id, transfer);\n } catch (err) {\n this.post(\n 'casual.load.response',\n {\n ok: false as const,\n code: 'host_error',\n message: err instanceof Error ? err.message : String(err),\n },\n id,\n );\n }\n return;\n }\n case 'casual.save.request': {\n if (!this.handlers.onSaveRequest) return;\n const id = env.id ?? '';\n try {\n const resp = await this.handlers.onSaveRequest(env.data as SaveRequestData);\n this.post('casual.save.response', resp, id);\n } catch (err) {\n this.post(\n 'casual.save.response',\n {\n ok: false as const,\n code: 'host_error',\n message: err instanceof Error ? err.message : String(err),\n },\n id,\n );\n }\n return;\n }\n case 'casual.save.notify':\n this.handlers.onSaveNotify?.(env.data as SaveNotifyData);\n return;\n case 'casual.exit':\n this.handlers.onExit?.(env.data as ExitData);\n return;\n case 'casual.selection.changed':\n this.handlers.onSelectionChanged?.(env.data as SelectionChangedData);\n return;\n case 'casual.selection.format-state':\n this.handlers.onSelectionFormatState?.(env.data as SelectionFormatStateData);\n return;\n case 'casual.dialog.request':\n this.handlers.onDialogRequest?.(env.data as DialogRequestData);\n return;\n case 'casual.telemetry.event':\n this.handlers.onTelemetry?.(env.data as TelemetryEventData);\n return;\n case 'casual.signature.field.signed':\n this.handlers.onSignatureFieldSigned?.(env.data as SignatureFieldSignedData);\n return;\n case 'casual.signature.complete':\n this.handlers.onSignatureComplete?.(env.data as SignatureCompleteData);\n return;\n case 'casual.signature.cancel':\n this.handlers.onSignatureCancel?.(env.data as SignatureCancelData);\n return;\n case 'casual.signature.request.ack':\n return;\n case 'casual.error':\n this.handlers.onError?.(env.data as CasualErrorData);\n return;\n default:\n return;\n }\n }\n\n private post(type: string, data: unknown, id?: string, transfer?: Transferable[]): void {\n const env: CasualEnvelope = {\n type,\n app: this.opts.app,\n v: 1,\n data,\n ...(id ? { id } : {}),\n };\n const send = this.opts.iframeWindow.postMessage.bind(\n this.opts.iframeWindow,\n ) as IframePostMessage;\n send(env, this.opts.embedOrigin, transfer);\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheets — minimal React wrapper around Univer Sheets.\n *\n * Boots Univer with the eager plugin set (render + formula engine +\n * UI + docs + sheets + sheets-ui + sheets-formula + numfmt), mounts a\n * single workbook unit from `initialData`, and hands the host the\n * `CasualSheetsAPI` imperative ref via `onReady` (raw FUniver facade\n * available at `api.univer`).\n *\n * Feature plugins (conditional formatting, data validation, drawings,\n * sort, filter, hyperlinks, tables, comments, find/replace) load lazily\n * by default (`lazyPlugins`): eagerly before mount for whatever the\n * snapshot already uses, idle-loaded otherwise. Pass `lazyPlugins={false}`\n * for the minimal editor.\n *\n * Formula compute runs on the main thread by default; pass `formula={{ worker }}`\n * to move it off-thread (the SDK then wires `UniverRPCMainThreadPlugin` to the\n * host's worker — see the `formula` prop).\n *\n * Intentionally NOT included (host can layer on top via FUniver):\n * - Snapshot swap (this component mounts a snapshot once; change\n * the React `key` to remount with a fresh snapshot).\n * - Paste-merge hooks, dev helpers, zoom-shortcut overrides,\n * facade extensions — all app concerns.\n *\n * Styles: host must import `@casualoffice/sheets/styles.css`\n * (or the per-plugin CSS) once at app boot. Tree-shaking strips the\n * styles from this entry if the host doesn't reach the styles export.\n */\n\nimport {\n lazy,\n Suspense,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n} from 'react';\nimport {\n ICommandService,\n IMentionIOService,\n LocaleType,\n LogLevel,\n ThemeService,\n Univer,\n UniverInstanceType,\n type ICommandInfo,\n type IExecutionOptions,\n type IWorkbookData,\n type ILocales,\n} from '@univerjs/core';\nimport { CasualMentionIOService } from './mention-io';\nimport { FUniver } from '@univerjs/core/facade';\nimport { defaultTheme } from '@univerjs/themes';\n\nimport { UniverRenderEnginePlugin } from '@univerjs/engine-render';\nimport { UniverFormulaEnginePlugin } from '@univerjs/engine-formula';\nimport { UniverUIPlugin } from '@univerjs/ui';\nimport { UniverDocsPlugin } from '@univerjs/docs';\nimport { UniverDocsUIPlugin } from '@univerjs/docs-ui';\nimport { UniverSheetsPlugin } from '@univerjs/sheets';\nimport { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';\nimport { UniverSheetsFormulaPlugin, CalculationMode } from '@univerjs/sheets-formula';\nimport { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui';\nimport { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt';\nimport { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui';\n// Type-only — erased at build, so `@univerjs/rpc` stays a runtime-optional peer\n// (loaded via dynamic import only when a formula worker is passed).\nimport type { UniverRPCMainThreadPlugin as RpcMainThreadPluginType } from '@univerjs/rpc';\n\nimport {\n createCasualSheetsAPI,\n type CasualSheetsAPI,\n type CasualSheetsAPIInternal,\n type DocumentMode,\n type RangeRef,\n} from './api';\n// Type-only — erased at build, so the collab entry (Yjs + Hocuspocus) stays out\n// of the `sheets` bundle. The runtime `attachCollab` is pulled in lazily via a\n// dynamic `import('@casualoffice/sheets/collab')` only when the `collab` prop is\n// set (see the collab effect), so bare-grid hosts never load it.\nimport type { AttachCollabOptions, CollabHandle } from '../collab/attachCollab';\nimport {\n eagerLoadForSnapshot,\n ensurePlugin,\n idleLoadAll,\n setUniverForLazyLoad,\n} from '../univer/lazy-plugins';\nimport type { ChromeExtensions } from '../chrome/extensions';\nimport type { DialogKind } from '../chrome/dialog-context';\nimport { AiPanelSurface, type SheetsAiConfig } from '../ai/AiPanelSurface';\n// Chrome is lazy-loaded from the `@casualoffice/sheets/chrome` subpath (NOT a\n// relative import — that would inline under this build's splitting:false). The\n// subpath is externalised in tsup, so the consumer's bundler code-splits it and\n// `chrome=\"none\"` hosts (the default + the apps/web reference host) never load\n// the chrome chunk.\nconst ChromeTop = lazy(() =>\n import('@casualoffice/sheets/chrome').then((m) => ({ default: m.ChromeTop })),\n);\nconst ChromeBottom = lazy(() =>\n import('@casualoffice/sheets/chrome').then((m) => ({ default: m.ChromeBottom })),\n);\n\nexport interface CasualSheetsProps {\n /** Workbook snapshot to mount. Read once on initial mount; change\n * the React `key` on this component to remount with a new\n * workbook. */\n initialData: IWorkbookData;\n /** Called after the workbook unit is created. Hands back the\n * `CasualSheetsAPI` imperative ref — the SDK's stable integration\n * surface (snapshot I/O, xlsx import, selection, command dispatch).\n * The raw FUniver facade is on `api.univer` as the escape hatch. */\n onReady?: (api: CasualSheetsAPI) => void;\n /** Debounced stream of workbook snapshots, emitted after edits\n * settle. This is the \"host persists it\" half of the Excalidraw\n * model — the editor stays storage-unaware and the host writes the\n * snapshot wherever it likes (localStorage, server, …). Driven by\n * Univer's mutation hook (`onMutationExecutedForCollab`), not UI\n * events, so it captures every edit including programmatic ones.\n * May fire for background/structural mutations too; treat each call\n * as \"current state, persist if you care\". */\n onChange?: (snapshot: IWorkbookData) => void;\n /** Debounce window for `onChange`, in ms. Default 400. */\n onChangeDebounceMs?: number;\n /** Explicit save — fired when the user presses Ctrl/Cmd+S inside the editor\n * (the browser's save dialog is suppressed). The host persists the snapshot.\n * Part of the \"host owns storage\" contract: the SDK never writes a store. */\n onSave?: (snapshot: IWorkbookData) => void;\n /** Fired once when the editor unmounts, with the final snapshot — the host's\n * last chance to persist before the workbook is disposed. */\n onExit?: (snapshot: IWorkbookData) => void;\n /** The active selection changed (canvas-driven), or `null` when there is none.\n * The prop half of the canonical `selectionChange` event (doc 38 §3); the\n * same event is available via `api.on('selectionChange', …)`. Wired to\n * Univer's `SelectionChanged` / `SelectionMoveEnd` facade events. */\n onSelectionChange?: (selection: RangeRef | null) => void;\n /** A boot/runtime error surfaced by the editor — the prop half of the\n * canonical `error` event (doc 38 §3). Also available via\n * `api.on('error', …)`. */\n onError?: (error: Error) => void;\n /** The unsaved-changes flag flipped: `true` after the first edit since the\n * last load/save, `false` on save / `setContent` / `import`. The prop half of\n * the canonical `dirtyChange` event (doc 38 §3); also `api.on('dirtyChange',\n * …)`. Lets a host drive a \"•/unsaved\" title dot without diffing snapshots. */\n onDirtyChange?: (dirty: boolean) => void;\n /** Lazy-load the feature plugins (conditional formatting, data\n * validation, hyperlinks, notes, tables, comments, drawings, sort,\n * filter, find/replace). Default `true`: plugins whose data is in\n * `initialData` load eagerly before mount (so nothing is dropped on\n * open), the rest idle-load after first paint. Set `false` for the\n * minimal editor (render + formula + numfmt only) — the embed-iframe\n * build does this to stay a single self-contained bundle. */\n lazyPlugins?: boolean;\n /** Escape hatch fired after the SDK registers its built-in plugins but BEFORE\n * the workbook unit is created — the host can `univer.registerPlugin(...)`\n * additional plugins here (e.g. an off-main formula worker via\n * `UniverRPCMainThreadPlugin`, crosshair-highlight, zen-editor). Anything\n * registered after `createUnit` would miss the unit's plugin-init pass, so\n * register-time extras must go through this hook. Power hosts (the reference\n * app) use it to share the SDK editor core while keeping their extra plugins;\n * most integrators never need it. NOT covered by semver — it hands you the\n * raw `Univer` instance. */\n onBeforeCreateUnit?: (univer: Univer) => void;\n /** Off-main formula compute. By default the formula engine runs on the MAIN\n * thread (fine for typical sheets, zero host setup). Provide a Web Worker (or\n * its URL) to move compute off-thread so paste / sort / fill on large\n * workbooks don't freeze the UI: the SDK then registers the formula plugins\n * with `notExecuteFormula` and wires `UniverRPCMainThreadPlugin` to your\n * worker. The host owns the worker (the SDK never bundles one — that's brittle\n * across bundlers) and must have `@univerjs/rpc` installed. The worker script\n * is the standard Univer formula worker (see the reference app's\n * `apps/web/src/univer/formula-worker.ts`). */\n formula?: {\n /** A constructed `Worker`, or a URL/string the RPC plugin loads. */\n worker?: Worker | string;\n };\n /** Locale identifier. Defaults to `LocaleType.EN_US`. */\n locale?: LocaleType;\n /** Locale string bundle. Optional — Univer's default English\n * strings load if omitted. */\n locales?: ILocales;\n /** Univer log level. Defaults to `LogLevel.WARN`. */\n logLevel?: LogLevel;\n /** Univer chrome toggles. Defaults: header / toolbar / footer off,\n * context menu on — matches Casual Sheets' embedded shape. */\n ui?: {\n header?: boolean;\n toolbar?: boolean;\n footer?: boolean;\n contextMenu?: boolean;\n };\n /** Override the Univer theme object (colour palette). Defaults to\n * Univer's `defaultTheme`. Distinct from `appearance` (light/dark). */\n theme?: typeof defaultTheme;\n /** Light or dark mode. Reactive — flipping it re-themes the live\n * editor via `ThemeService.setDarkMode` (canvas colours, notifications,\n * and Univer's own `univer-dark` class). Defaults to light.\n * Note: Univer's Workbench applies the `univer-dark` class to the\n * document root (`<html>`) itself, so dark mode is page-global by\n * Univer's design — a host that embeds the editor inside a light page\n * should scope the editor or accept the global dark CSS. */\n appearance?: 'light' | 'dark';\n /** Office chrome rendered around the grid:\n * - `'none'` (default): bare grid — the host supplies its own chrome.\n * - `'minimal'` / `'full'`: the built-in Office shell — a menu bar\n * (Edit/Insert/Format/Data/View), a formatting toolbar (font family/size,\n * bold/italic/underline/strike, text & fill colour, borders, h/v align,\n * wrap, merge, number formats, clear format, AutoSum), a formula bar with a\n * name box + function autocomplete, a worksheet tab strip (switch/add/\n * rename/delete), and a status bar (Average/Count/Numerical Count/Min/Max/\n * Sum + zoom). All driven through the facade, themed via `--cs-chrome-*`\n * (light/dark). `'minimal'` and `'full'` currently render the same shell;\n * `'full'` is where richer panels (find/replace, charts, …) will land. */\n chrome?: 'none' | 'minimal' | 'full';\n /** Enable/disable chrome features. Each key maps a toolbar group / menu item /\n * capability to a boolean; `false` hides the control AND blocks its command.\n * Omitted keys default to enabled. Only applies when `chrome` is shown. */\n features?: Record<string, boolean>;\n /** Legacy host hook for dialog-backed chrome controls. The SDK now ships\n * BUILT-IN dialogs (Format Cells, Find & Replace, …) that open by default, so\n * this is no longer required. It still works for back-compat: kinds the SDK\n * has no built-in for (Insert Chart, PivotTable, …) fall through to it, and a\n * host can force specific kinds to it via `hostOwnedDialogs`. Prefer\n * `extensions.dialogs` to supply a React override component. */\n onDialogRequest?: (kind: string, context?: unknown) => void;\n /** Kinds the host wants to handle via `onDialogRequest` even though the SDK has\n * a built-in (e.g. keep the SDK chrome but your own Format Cells). */\n hostOwnedDialogs?: DialogKind[];\n /** Host chrome extensions — the extensibility surface for `chrome=\"full\"`.\n * Append custom toolbar items / menu items / side panels, and register or\n * OVERRIDE dialogs by kind. Built-ins are the defaults; host entries\n * append/override. See `ChromeExtensions` for the exact shape. */\n extensions?: ChromeExtensions;\n /** Document interaction mode (SuperDoc-aligned vocabulary, shared with the\n * docs SDK):\n * - `'editing'` (default): fully editable.\n * - `'viewing'`: read-only — applies the command-veto + permission path\n * (`applyReadOnly`) to the mounted workbook.\n * Reactive: flipping it re-applies via `api.setDocumentMode`. Wins over the\n * deprecated `readOnly` prop when both are set. */\n documentMode?: DocumentMode;\n /** Real-time co-editing, declaratively. Pass `{ server, room, … }` to join a\n * room and the SDK wires Yjs/Hocuspocus itself once the editor is ready\n * (mirrors how the docs `CasualEditor` opts in via `backendUrl`); omit it for\n * a single-user editor. Options match `attachCollab` (`server`, `room`,\n * `password`, `token`, `role`, `share`, `onStatus`, `onSnapshot`).\n *\n * Lifecycle: attaches after `onReady`, detaches on unmount, and re-attaches\n * when `server` / `room` / `password` / `token` / `role` change. The\n * imperative `attachCollab(api, opts)` export stays available for advanced\n * hosts that drive the room lifecycle themselves (presence UI, preflight,\n * reconnect banners) — don't combine both on one editor. */\n collab?: AttachCollabOptions;\n /** AI assistant surface, declaratively. Pass `{ enabled: true, transport,\n * render }` to mount a supported AI task-pane beside the grid — mirrors how\n * the docs SDK exposes its DocOps panel behind a transport prop. The SDK\n * owns the prop contract, the `SheetsAiTransport` type, and the layout slot;\n * the panel body is supplied via `ai.render` (the reference app passes its\n * `<AiPanel>`) and drives its tool loop against `ai.transport`. Build a\n * transport with `createSheetsAiTransport()` (desktop-native → collab\n * single-round → browser-direct). Omit `ai` for an editor with no AI.\n *\n * Reactive: flipping `enabled` mounts/unmounts the pane once the editor is\n * ready. See `SheetsAiConfig`. */\n ai?: SheetsAiConfig;\n /** @deprecated Use `documentMode` instead. `true` maps to\n * `documentMode=\"viewing\"`. Ignored when `documentMode` is set. */\n readOnly?: boolean;\n /** Container style. Default fills the parent. */\n style?: CSSProperties;\n /** Container className for additional styling hooks. */\n className?: string;\n /** Optional test id for the host container. */\n testId?: string;\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n position: 'relative',\n};\n\nconst DEFAULT_UI = {\n header: false,\n toolbar: false,\n footer: false,\n contextMenu: true,\n};\n\nexport function CasualSheets({\n initialData,\n onReady,\n onChange,\n onChangeDebounceMs = 400,\n onSave,\n onExit,\n onSelectionChange,\n onError,\n onDirtyChange,\n lazyPlugins = true,\n onBeforeCreateUnit,\n formula,\n locale = LocaleType.EN_US,\n locales,\n logLevel = LogLevel.WARN,\n ui,\n theme = defaultTheme,\n appearance = 'light',\n chrome = 'none',\n features,\n onDialogRequest,\n hostOwnedDialogs,\n extensions,\n documentMode,\n collab,\n ai,\n readOnly,\n style,\n className,\n testId = 'casual-sheets',\n}: CasualSheetsProps) {\n // `documentMode` wins; the deprecated `readOnly` boolean only applies when\n // `documentMode` is unset. Absent both → editable.\n const effectiveMode: DocumentMode = documentMode ?? (readOnly ? 'viewing' : 'editing');\n const hostRef = useRef<HTMLDivElement>(null);\n // Keep the latest onChange callable without re-subscribing (the effect\n // mounts once). The mutation subscription is always wired (it also backs the\n // `dirtyChange` / `change` emitter); only the snapshot serialization inside it\n // is gated on an actual consumer.\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n // Latest save/exit callbacks, called via refs so they fire without re-running\n // the boot effect. onExit is read in cleanup; onSave on the Ctrl/Cmd+S handler.\n const onSaveRef = useRef(onSave);\n onSaveRef.current = onSave;\n const onExitRef = useRef(onExit);\n onExitRef.current = onExit;\n // Latest handlers for the canonical event props (doc 38 §3), read via refs so\n // they fire without re-running the boot effect. `hasX` (fixed at mount) gates\n // whether we bridge each prop to the unified emitter — a host that passes none\n // of them (and never calls `api.on`) pays for none of the extra wiring.\n const onSelectionChangeRef = useRef(onSelectionChange);\n onSelectionChangeRef.current = onSelectionChange;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onDirtyChangeRef = useRef(onDirtyChange);\n onDirtyChangeRef.current = onDirtyChange;\n const hasSelectionChange = useRef(!!onSelectionChange).current;\n const hasError = useRef(!!onError).current;\n const hasDirtyChange = useRef(!!onDirtyChange).current;\n // The live FUniver facade, captured at mount so the reactive appearance\n // effect can reach Univer's ThemeService without re-running boot.\n const apiRef = useRef<CasualSheetsAPI | null>(null);\n // The live API as state, so the built-in chrome (FormulaBar) re-renders and\n // subscribes once the editor is ready. Only set when chrome is shown — the\n // bare-grid path never triggers this re-render. A single post-mount setState\n // doesn't disturb the grid (Univer owns its canvas outside React).\n const [chromeApi, setChromeApi] = useState<CasualSheetsAPI | null>(null);\n // Declarative collab. `hasCollab` is fixed at mount (the boot effect runs\n // once): only then do we surface the ready api as state to drive the attach\n // effect, so single-user consumers never take the extra re-render. The latest\n // options live on a ref so callback/`share` changes don't force a re-attach —\n // the attach effect only re-runs on connection-identity changes.\n const hasCollab = useRef(!!collab).current;\n const collabRef = useRef(collab);\n collabRef.current = collab;\n const [collabApi, setCollabApi] = useState<CasualSheetsAPI | null>(null);\n // AI surface. Like chrome/collab, only surface the ready api as state when\n // the `ai` prop was present at mount — so editors with no AI never take the\n // extra re-render. The panel itself only mounts when `ai.enabled` is set.\n const hasAi = useRef(!!ai).current;\n const [aiApi, setAiApi] = useState<CasualSheetsAPI | null>(null);\n\n useEffect(() => {\n const container = hostRef.current;\n if (!container) return;\n\n const univer = new Univer({\n theme,\n locale,\n locales,\n logLevel,\n // Replace the default mention IO (hardwired to the current user) with our\n // host-pluggable source so comment @-mentions can list real collaborators.\n // No-op until a provider is installed via `setMentionProvider`.\n override: [[IMentionIOService, { useClass: CasualMentionIOService }]],\n });\n\n const uiOpts = { ...DEFAULT_UI, ...ui, container };\n\n // `formula.worker` → off-main compute. Default = main thread (fine for\n // typical sheets, zero host setup).\n const offMain = !!formula?.worker;\n\n let cancelled = false;\n let changeTimer: ReturnType<typeof setTimeout> | null = null;\n let changeSub: { dispose: () => void } | undefined;\n\n void (async () => {\n // Plugin registration runs here (not synchronously) so the OPTIONAL RPC\n // transport can be `await import`ed FIRST and registered in its correct\n // slot — right after the formula engine, before sheets. Registering it out\n // of order (or after createUnit) leaves the formula engine's worker channel\n // unwired → cells stay 0. Dynamic import keeps `@univerjs/rpc` a true\n // optional peer (only loaded when a worker is passed).\n let RPCMainThreadPlugin: typeof RpcMainThreadPluginType | null = null;\n if (offMain && formula?.worker) {\n RPCMainThreadPlugin = (await import('@univerjs/rpc')).UniverRPCMainThreadPlugin;\n if (cancelled) return;\n }\n\n univer.registerPlugin(UniverRenderEnginePlugin);\n univer.registerPlugin(\n UniverFormulaEnginePlugin,\n offMain ? { notExecuteFormula: true } : undefined,\n );\n if (RPCMainThreadPlugin && formula?.worker) {\n univer.registerPlugin(RPCMainThreadPlugin, { workerURL: formula.worker });\n }\n univer.registerPlugin(UniverUIPlugin, uiOpts);\n univer.registerPlugin(UniverDocsPlugin);\n univer.registerPlugin(UniverDocsUIPlugin);\n univer.registerPlugin(UniverSheetsPlugin, offMain ? { notExecuteFormula: true } : undefined);\n univer.registerPlugin(UniverSheetsUIPlugin);\n univer.registerPlugin(\n UniverSheetsFormulaPlugin,\n offMain\n ? { notExecuteFormula: true, initialFormulaComputing: CalculationMode.NO_CALCULATION }\n : undefined,\n );\n univer.registerPlugin(UniverSheetsFormulaUIPlugin);\n univer.registerPlugin(UniverSheetsNumfmtPlugin);\n univer.registerPlugin(UniverSheetsNumfmtUIPlugin);\n\n // Lazy-loader holder (the loader is @internal so a relative import shares\n // no cross-instance state) + host plugin escape hatch — both before\n // createUnit.\n if (lazyPlugins) setUniverForLazyLoad(univer);\n onBeforeCreateUnit?.(univer);\n\n // Eager-load any feature plugin whose data already lives in initialData\n // (CF rules, tables, hyperlinks, …) BEFORE createUnit — Univer's resource\n // manager silently drops keys for plugins that aren't registered when it\n // reads the snapshot. Skipped entirely when lazyPlugins is false.\n if (lazyPlugins) {\n await eagerLoadForSnapshot(univer, initialData);\n if (cancelled) return;\n // Drawing/image is the one feature whose trigger (Insert ▸ Image) opens\n // a FILE PICKER — which needs the user's click gesture. If the plugin\n // lazy-loads on click, the await loses the gesture and the picker never\n // opens (\"can't insert image\"); if it idle-loads, a quick click before\n // it's ready silently no-ops. So load it eagerly here (tracked by\n // ensurePlugin, so idleLoadAll won't double-register) — image works on\n // the first click, in-gesture. Other features open panels (no gesture).\n await ensurePlugin(univer, 'drawing');\n if (cancelled) return;\n }\n\n univer.createUnit(UniverInstanceType.UNIVER_SHEET, initialData);\n\n const api = createCasualSheetsAPI(FUniver.newAPI(univer));\n const apiInternal = api as CasualSheetsAPIInternal;\n apiRef.current = api;\n // Bridge the declarative event props (doc 38 §3) to the unified emitter, so\n // a prop and `api.on(name, …)` both receive the event. Only wire the bridge\n // when the prop was present at mount — direct `api.on(...)` still works\n // without it (the emitter fires to its own subscribers regardless). The\n // selection bridge is what makes the factory's `SelectionChanged` listener\n // do real work, so bare hosts that pass no `onSelectionChange` (and never\n // call `api.on`) never pay for `getSelection` on every selection move.\n if (hasSelectionChange) {\n apiInternal.on('selectionChange', (sel) => onSelectionChangeRef.current?.(sel));\n }\n if (hasError) {\n apiInternal.on('error', (err) => onErrorRef.current?.(err));\n }\n if (hasDirtyChange) {\n apiInternal.on('dirtyChange', (d) => onDirtyChangeRef.current?.(d));\n }\n // Hand the live API to the built-in chrome (FormulaBar subscribes to it).\n // Only when chrome is shown, so bare-grid consumers never re-render.\n if (!cancelled && chrome !== 'none') setChromeApi(api);\n // Hand the ready api to the declarative-collab effect (only when the\n // `collab` prop was present at mount — otherwise no extra re-render).\n if (!cancelled && hasCollab) setCollabApi(api);\n // Hand the ready api to the AI surface (only when `ai` was present at\n // mount — otherwise no extra re-render).\n if (!cancelled && hasAi) setAiApi(api);\n // Apply the initial appearance now that the editor exists (the reactive\n // effect below also runs on mount, but apiRef may not be set yet when it\n // first fires — this guarantees dark mode from the first paint).\n applyAppearance(api, container, appearance);\n // Apply the initial document mode. Deferred a frame for the read-only case:\n // sheets-ui sets WorkbookEditablePermission → true during unit setup AFTER\n // onReady, which would clobber a synchronous flip (the embed preview path\n // waits a rAF for the same reason). The command-veto layer is unaffected,\n // but the rAF keeps the permission layer in sync too.\n if (effectiveMode === 'viewing') {\n requestAnimationFrame(() => {\n if (!cancelled) api.setDocumentMode('viewing');\n });\n }\n onReady?.(api);\n // Fire the canonical `ready` event for `api.on('ready', …)` subscribers.\n // `ready` is sticky in the emitter, so a late subscription still fires.\n if (!cancelled) apiInternal.emit('ready', api);\n\n // Mutation stream → dirty flag + debounced `change` (prop + emitter).\n // Subscribed AFTER createUnit so the initial unit-creation mutations don't\n // fire a spurious first emit. Uses the mutation hook (CLAUDE.md hard rule),\n // never UI events. Always subscribed now (not just when `onChange` was\n // passed) because `dirtyChange` and `api.on('change', …)` also depend on\n // it; the raw callback is cheap (a dirty-flag flip + a debounce timer), and\n // the expensive snapshot serialization is gated on an actual consumer.\n {\n const injector = (api.univer as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const cmdSvc = injector?.get(ICommandService) as\n | {\n onMutationExecutedForCollab: (\n l: (info: ICommandInfo, options?: IExecutionOptions) => void,\n ) => { dispose: () => void };\n }\n | undefined;\n changeSub = cmdSvc?.onMutationExecutedForCollab(() => {\n // First edit since load/save → dirty (emits dirtyChange on transition).\n apiInternal.markDirty(true);\n if (changeTimer) clearTimeout(changeTimer);\n changeTimer = setTimeout(() => {\n // Only serialize when something actually consumes the snapshot.\n if (!onChangeRef.current && apiInternal.listenerCount('change') === 0) return;\n const snap = api.getContent();\n if (snap) {\n onChangeRef.current?.(snap);\n apiInternal.emit('change', snap);\n }\n }, onChangeDebounceMs);\n });\n // If we unmounted during the eager-load await, cleanup already ran with\n // changeSub still undefined — dispose this late subscription.\n if (cancelled) changeSub?.dispose();\n }\n\n // Idle-load the remaining feature plugins so Insert / Data / Format actions\n // are ready when the user reaches them.\n if (lazyPlugins) idleLoadAll(univer);\n })().catch((err: unknown) => {\n // Boot failure (plugin load, unit creation, …) → the canonical `error`\n // event. Prefer the emitter once the API exists (reaches both the `onError`\n // prop bridge and `api.on('error', …)`); before then fall back to the prop.\n if (cancelled) return;\n const e = err instanceof Error ? err : new Error(String(err));\n const cur = apiRef.current as CasualSheetsAPIInternal | null;\n if (cur) cur.emit('error', e);\n else onErrorRef.current?.(e);\n });\n\n return () => {\n cancelled = true;\n if (changeTimer) clearTimeout(changeTimer);\n changeSub?.dispose();\n // Last-chance persist: emit the final snapshot before the workbook is\n // disposed (disposal is deferred via microtask below, so it's still alive).\n if (onExitRef.current) {\n const snap = apiRef.current?.getContent();\n if (snap) onExitRef.current(snap);\n }\n apiRef.current = null;\n setChromeApi(null);\n setCollabApi(null);\n setAiApi(null);\n if (lazyPlugins) setUniverForLazyLoad(null);\n // Defer disposal off the React render phase — Univer owns its\n // own React root, and a synchronous unmount mid-render warns\n // and leaves the canvas detached.\n const toDispose = univer;\n queueMicrotask(() => toDispose.dispose());\n };\n // initialData is intentionally NOT in the dep array — the wrapper\n // mounts the snapshot once. Hosts that need to swap workbooks\n // change the React `key` to force a remount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Reactive appearance. Runs after the boot effect (apiRef populated on first\n // mount) and re-runs whenever `appearance` flips, re-theming the live editor.\n useEffect(() => {\n const api = apiRef.current;\n const container = hostRef.current;\n if (!api || !container) return;\n applyAppearance(api, container, appearance);\n }, [appearance]);\n\n // Reactive document mode. On first mount apiRef may not be populated yet (boot\n // is async) — that run bails and the boot effect applies the initial mode; this\n // effect then handles every subsequent `documentMode` / `readOnly` flip.\n useEffect(() => {\n apiRef.current?.setDocumentMode(effectiveMode);\n }, [effectiveMode]);\n\n // Declarative collab: attach once the api is ready, detach on unmount, and\n // re-attach when the connection identity changes. `attachCollab` (and its\n // Yjs/Hocuspocus transport) is loaded lazily via the externalised\n // `@casualoffice/sheets/collab` subpath — same code-split as `chrome`/`xlsx`\n // — so single-user hosts never pull it into their bundle. Options are read\n // from `collabRef` at attach time so callback/`share` changes don't re-attach.\n useEffect(() => {\n if (!collabApi || !collabRef.current) return;\n let handle: CollabHandle | null = null;\n let disposed = false;\n void import('@casualoffice/sheets/collab').then(({ attachCollab }) => {\n const opts = collabRef.current;\n if (disposed || !opts) return;\n handle = attachCollab(collabApi, opts);\n });\n return () => {\n disposed = true;\n handle?.detach();\n handle = null;\n };\n // Re-attach only on connection-identity changes (server/room/auth/role); the\n // options object identity and callbacks are read live from `collabRef`.\n }, [collabApi, collab?.server, collab?.room, collab?.password, collab?.token, collab?.role]);\n\n // Ctrl/Cmd+S anywhere in the editor → onSave (suppress the browser dialog).\n // Capture phase so we beat Univer's own key handling on the canvas.\n const onKeyDownCapture = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n if ((e.metaKey || e.ctrlKey) && (e.key === 's' || e.key === 'S')) {\n e.preventDefault();\n const api = apiRef.current;\n const snap = api?.getContent();\n if (snap) {\n onSaveRef.current?.(snap);\n // Canonical `save` event + clear the dirty flag (an explicit save means\n // the buffer is clean until the next edit).\n const apiInternal = api as CasualSheetsAPIInternal;\n apiInternal.emit('save', snap);\n apiInternal.markDirty(false);\n }\n }\n };\n\n // chrome=\"none\" (default) keeps the exact bare-grid shape existing consumers\n // rely on (embed-runtime, hosts that bring their own shell). Any other level\n // wraps the grid in a flex column with the built-in chrome above it; the grid\n // container (hostRef, where Univer mounts) fills the remaining space.\n if (chrome === 'none') {\n // No `ai` prop → the exact bare-grid shape existing consumers rely on.\n if (!hasAi) {\n return (\n <div\n ref={hostRef}\n onKeyDownCapture={onKeyDownCapture}\n style={{ ...DEFAULT_STYLE, ...style }}\n className={className}\n data-testid={testId}\n />\n );\n }\n // With `ai`, the grid + AI pane sit in a stable flex row (shape fixed at\n // mount by `hasAi`, so toggling `ai.enabled` never remounts the grid host —\n // it only adds/removes the aside sibling). The grid host still fills the\n // remaining space, so Univer's canvas sizing is unchanged.\n return (\n <div\n className={className}\n data-testid={testId}\n onKeyDownCapture={onKeyDownCapture}\n style={{ ...DEFAULT_STYLE, ...style, display: 'flex', flexDirection: 'row' }}\n >\n <div\n ref={hostRef}\n style={{ flex: '1 1 auto', minWidth: 0, minHeight: 0, position: 'relative' }}\n />\n <AiPanelSurface config={ai} api={aiApi} />\n </div>\n );\n }\n\n // The built-in chrome components read their colours from `--cs-chrome-*` CSS\n // vars. Phase 4: each var now resolves to a `@schnsrw/design-system` token\n // (loaded by the host via `tokens.css`), with the prior hardcoded value as a\n // FALLBACK so the chrome still renders standalone for hosts that don't ship the\n // design system. `data-theme` on the wrapper (below) swaps the DS tokens\n // light/dark; the fallbacks keep `appearance` working without the DS too.\n const dark = appearance === 'dark';\n const chromeVars = {\n '--cs-chrome-bg': `var(--color-surface-strip, ${dark ? '#2a2e35' : '#eef1f5'})`,\n '--cs-chrome-fg': `var(--color-text, ${dark ? '#e6e6e6' : '#201f1e'})`,\n '--cs-chrome-muted': `var(--color-text-secondary, ${dark ? '#b0b3ba' : '#605e5c'})`,\n '--cs-chrome-border': `var(--color-divider, ${dark ? '#24272d' : '#edeff3'})`,\n '--cs-chrome-input-bg': `var(--color-surface, ${dark ? '#1b1e23' : '#ffffff'})`,\n '--cs-chrome-hover': `var(--color-hover, ${dark ? 'rgba(255,255,255,0.06)' : 'rgba(15,23,42,0.045)'})`,\n '--cs-chrome-active': `var(--color-selected, ${dark ? 'rgba(34,211,238,0.20)' : 'rgba(14,116,144,0.11)'})`,\n '--cs-chrome-active-fg': `var(--color-accent, ${dark ? '#22d3ee' : '#0e7490'})`,\n } as CSSProperties;\n\n return (\n <div\n className={className}\n data-testid={testId}\n data-theme={dark ? 'dark' : 'light'}\n onKeyDownCapture={onKeyDownCapture}\n style={{\n ...DEFAULT_STYLE,\n ...chromeVars,\n ...style,\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {/* Bars appear once their lazy chunk loads (a tick after first paint); the\n grid host is OUTSIDE Suspense so Univer mounts immediately. */}\n <Suspense fallback={null}>\n <ChromeTop\n api={chromeApi}\n features={features}\n onDialogRequest={onDialogRequest}\n hostOwnedDialogs={hostOwnedDialogs}\n extensions={extensions}\n />\n </Suspense>\n {hasAi ? (\n // Grid + AI pane share a flex row so the built-in chrome (top/bottom\n // bars) still spans the full width. Shape fixed at mount by `hasAi`.\n <div style={{ flex: '1 1 auto', minHeight: 0, display: 'flex', flexDirection: 'row' }}>\n <div\n ref={hostRef}\n style={{ flex: '1 1 auto', minWidth: 0, minHeight: 0, position: 'relative' }}\n />\n <AiPanelSurface config={ai} api={aiApi} />\n </div>\n ) : (\n <div ref={hostRef} style={{ flex: '1 1 auto', minHeight: 0, position: 'relative' }} />\n )}\n <Suspense fallback={null}>\n <ChromeBottom api={chromeApi} />\n </Suspense>\n </div>\n );\n}\n\n/**\n * Apply light/dark to a live editor. `ThemeService.setDarkMode` is the source of\n * truth — it flips the canvas colours, the internals that subscribe to\n * `darkMode$` (notifications, message containers), AND Univer's Workbench toggles\n * the `univer-dark` class on the document root for its compiled dark CSS. We also\n * mirror the class onto the editor container as race-insurance (the Workbench\n * effect can land a frame after ours). Mirrors the app's ThemeBridge.\n */\nfunction applyAppearance(\n api: CasualSheetsAPI,\n container: HTMLElement,\n appearance: 'light' | 'dark',\n): void {\n const dark = appearance === 'dark';\n container.classList.toggle('univer-dark', dark);\n try {\n const injector = (api.univer as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const themeService = injector?.get(ThemeService) as\n | { setDarkMode(b: boolean): void; darkMode: boolean }\n | undefined;\n if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);\n } catch {\n /* ThemeService unavailable — the class toggle still themes visible chrome */\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `CasualMentionIOService` — the `IMentionIOService` override registered by\n * CasualSheets. Thin by design: it owns the only @univerjs *value* import\n * (`MentionType`) and delegates all logic to the pure, unit-tested\n * `resolveMentionList` in `mention-source.ts`.\n */\nimport { MentionType } from '@univerjs/core';\nimport type { IListMentionParam, IListMentionResponse, IMentionIOService } from '@univerjs/core';\nimport { resolveMentionList } from './mention-source';\n\nexport class CasualMentionIOService implements IMentionIOService {\n list(params: IListMentionParam): Promise<IListMentionResponse> {\n return resolveMentionList(params, MentionType.PERSON);\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pluggable @mention data source for cell comments — pure layer.\n *\n * Univer's comment editor (the in-cell thread-comment popup) gets @-mention\n * autocomplete from `docs-mention-ui`, which lists candidates via the core\n * `IMentionIOService`. The default `MentionIOLocalService` is hardwired to a\n * single candidate — the current user — which is useless: you can't @mention\n * the people you're editing with.\n *\n * We override it with `CasualMentionIOService` (see `mention-io.ts`), which\n * reads candidates from a host-settable provider. The provider is the\n * pluggable seam the brief calls for:\n * - embedded in another platform → the host sets it to its directory/users,\n * - standalone → the app sets it to the live presence peers (+ self).\n *\n * This module is the @univerjs-value-free core (only `import type`, which is\n * erased at runtime) so it's unit-testable under the `node:test` + tsx runner,\n * which can't load @univerjs *value* modules. The enum-coupled service class\n * lives in `mention-io.ts`.\n */\nimport type { IListMentionParam, IListMentionResponse, MentionType } from '@univerjs/core';\n\n/** One mentionable entity. `id` must be stable enough to resolve later. */\nexport type MentionCandidate = { id: string; label: string; icon?: string };\n\n/** Resolves mention candidates for the current `@`-search term. */\nexport type MentionProvider = (search: string) => MentionCandidate[] | Promise<MentionCandidate[]>;\n\nlet provider: MentionProvider | null = null;\n\n/**\n * Install (or clear, with `null`) the mention candidate provider. Last writer\n * wins — the host or the app sets this once. Safe to call before or after the\n * editor boots; the service reads it lazily on each `@`-trigger.\n */\nexport function setMentionProvider(fn: MentionProvider | null): void {\n provider = fn;\n}\n\n/** Current provider — exposed for tests / introspection. */\nexport function getMentionProvider(): MentionProvider | null {\n return provider;\n}\n\n/**\n * Case-insensitive substring filter applied to a candidate list. Strips the\n * leading `@` trigger — `docs-mention-ui` passes the search slice starting at\n * the `@` anchor (e.g. `\"@gr\"`), so the raw term includes it.\n */\nexport function filterMentionCandidates(\n candidates: MentionCandidate[],\n search: string,\n): MentionCandidate[] {\n const q = search.replace(/^@+/, '').trim().toLowerCase();\n if (!q) return candidates;\n return candidates.filter((c) => c.label.toLowerCase().includes(q));\n}\n\n/**\n * Resolve the active provider into the `IMentionIOService.list` response shape.\n * `personType` is the numeric `MentionType.PERSON` value, passed in by the\n * service class so this module needs no @univerjs value import. A failing\n * provider degrades to an empty list — it must never break the editor.\n */\nexport async function resolveMentionList(\n params: IListMentionParam,\n personType: MentionType,\n): Promise<IListMentionResponse> {\n const search = params.search ?? '';\n let candidates: MentionCandidate[] = [];\n if (provider) {\n try {\n candidates = await provider(search);\n } catch {\n candidates = [];\n }\n }\n const mentions = candidates.map((c) => ({\n objectType: personType,\n objectId: c.id,\n label: c.label,\n metadata: c.icon ? { icon: c.icon } : undefined,\n }));\n return {\n list: [{ type: personType, mentions, metadata: {}, title: 'PEOPLE' }],\n page: params.page,\n size: params.size,\n total: mentions.length,\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheetsAPI — the imperative ref handed to a host via `<CasualSheets onReady>`.\n *\n * This is the SDK's stable integration surface (Excalidraw's model: props +\n * imperative ref). Hosts drive the editor through these methods rather than\n * reaching into Univer directly; `api.univer` is the documented escape hatch and\n * is explicitly NOT covered by semver — everything else here is.\n *\n * Surface (canonical, doc 38 §4):\n * getContent / setContent / import / export / getSelection / focus /\n * on / off / executeCommand / executeCommands / undo / redo / onMutation /\n * setTheme / setDocumentMode / getDocumentMode / univer\n * (+ deprecated aliases getSnapshot / loadSnapshot; format-specific\n * importXlsx / exportXlsx retained)\n *\n * `importXlsx` / `exportXlsx` lazy-load the converters via\n * `import('@casualoffice/sheets/xlsx')` — a BARE subpath, not a relative\n * `import('../xlsx')`. The main tsup config is `splitting:false`, so a relative\n * dynamic import would be inlined and balloon the editor entry from ~24KB to\n * ~200KB of ExcelJS for hosts that never touch a file. The subpath is\n * externalised in tsup.config.ts so it stays a separate chunk the consumer\n * code-splits.\n *\n * `attachCollab` is NOT a method here — it ships as a standalone\n * `attachCollab(api, opts)` on the `@casualoffice/sheets/collab` subpath so the\n * editor stays collab-unaware (and collab-free in the bundle) until opted in.\n */\n\n// Side-effect import: registers the Sheets FUniver mixins\n// (getActiveWorkbook / createWorkbook / FWorkbook.save / FRange.getRange / …)\n// onto the core FUniver facade — both the runtime methods AND the TypeScript\n// type augmentation this file relies on. Without it, FUniver is the bare core\n// facade and these methods exist neither at type-check nor at runtime.\nimport '@univerjs/sheets/facade';\nimport { ICommandService, IUniverInstanceService, ThemeService } from '@univerjs/core';\nimport type { FUniver } from '@univerjs/core/facade';\nimport type { IRange, IWorkbookData } from '@univerjs/core';\nimport {\n attachMutationObserver,\n runSteps,\n type CommandRecord,\n type MutationEmitter,\n} from './scripting';\nimport { applyReadOnly } from './read-only';\nimport { createEmitter } from './emitter';\n\n// Re-export so hosts can type a recorded/scripted step off the main entry.\nexport type { CommandRecord } from './scripting';\n\n/**\n * Document interaction mode — the SuperDoc-aligned vocabulary shared with the\n * docs SDK so hosts drive both editors the same way:\n *\n * - `'editing'` — fully editable (the default).\n * - `'viewing'` — read-only: the same command-veto + permission path as\n * {@link applyReadOnly}.\n *\n * Sheets has no `'suggesting'` tier (that's a docs-only track-changes concept),\n * so the union is the two states.\n */\nexport type DocumentMode = 'editing' | 'viewing';\n\n/** The active selection, as a sheet-scoped range. */\nexport interface RangeRef {\n /** Workbook unit id the selection belongs to. */\n unitId: string;\n /** Worksheet (sub-unit) id the selection belongs to. */\n sheetId: string;\n /** `{ startRow, startColumn, endRow, endColumn }`. */\n range: IRange;\n}\n\n/**\n * The canonical cross-editor event map (doc 38 §3), shared in shape with the\n * docs SDK so a host wires both editors the same way. Every event is available\n * two ways: as an `on*` prop on `<CasualSheets>` AND via `api.on(name, handler)` /\n * `api.off(name, handler)` on this handle — same event, same payload.\n *\n * Payloads are the format's own content type where the doc leaves it to the\n * format (`change` / `save` carry an `IWorkbookData` snapshot, not raw bytes).\n */\nexport interface CasualSheetsEvents {\n /** Fired once the workbook unit is created and the API is live. Sticky: a\n * handler registered via `api.on('ready', …)` after the editor is already\n * ready is invoked immediately with the API. */\n ready: (api: CasualSheetsAPI) => void;\n /** Debounced workbook snapshot, emitted after edits settle. */\n change: (snapshot: IWorkbookData) => void;\n /** The active selection changed (canvas-driven). `null` when there is none. */\n selectionChange: (selection: RangeRef | null) => void;\n /** Explicit save (Ctrl/Cmd+S), carrying the current snapshot to persist. */\n save: (snapshot: IWorkbookData) => void;\n /** A boot/runtime error surfaced by the editor. */\n error: (error: Error) => void;\n /** The unsaved-changes flag flipped. `true` after the first edit since the\n * last load/save, `false` on save / `setContent` / `import`. */\n dirtyChange: (dirty: boolean) => void;\n}\n\nexport interface CasualSheetsAPI {\n /** Current workbook as an `IWorkbookData` snapshot — the canonical\n * cross-editor content accessor (doc 38 §4). `null` before the unit is\n * created (shouldn't happen after `onReady`, but typed defensively). */\n getContent(): IWorkbookData | null;\n /** Replace the workbook with a new snapshot — the canonical cross-editor\n * content setter (doc 38 §4). Disposes the current unit, mounts `data` as a\n * fresh one, and clears the dirty flag. */\n setContent(data: IWorkbookData): void;\n /**\n * @deprecated Use {@link getContent} instead. Kept as an alias for one minor.\n */\n getSnapshot(): IWorkbookData | null;\n /**\n * @deprecated Use {@link setContent} instead. Kept as an alias for one minor.\n */\n loadSnapshot(data: IWorkbookData): void;\n /** Parse an `.xlsx` and load it as the active workbook — the format-specific\n * file import (canonically aliased as {@link import}). Accepts a `File` /\n * `Blob` (e.g. from an `<input type=file>`), an `ArrayBuffer`, or a\n * `Uint8Array`. The ExcelJS parser is lazy-loaded as a separate chunk, so\n * hosts that never import a file don't pay for it. When a `File` is passed,\n * its name + on-disk size are recorded on the snapshot (surfaced by the\n * built-in Properties dialog). Resolves to the loaded snapshot. */\n importXlsx(input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData>;\n /** Serialize the current workbook to an `.xlsx` `Blob` — the format-specific\n * file export (canonically aliased as {@link export}). Covers the core\n * fidelity (values/formulas, styles, merges, number formats, borders,\n * hyperlinks, comments, data validation, tables, page setup, named ranges,\n * VBA passthrough) — everything carried on the snapshot. App-level extras\n * (chart/pivot/sparkline models) are a power-host concern and aren't included\n * here. The converter (ExcelJS) is lazy-loaded as a separate chunk. Rejects\n * if there is no active workbook. */\n exportXlsx(): Promise<Blob>;\n /** Canonical cross-editor file import (doc 38 §4) — an alias of\n * {@link importXlsx}. */\n import(input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData>;\n /** Canonical cross-editor file export (doc 38 §4) — an alias of\n * {@link exportXlsx}. */\n export(): Promise<Blob>;\n /** The active selection, or `null` when there is none. */\n getSelection(): RangeRef | null;\n /** Move keyboard focus to the active workbook so subsequent typing / shortcuts\n * land on the grid (doc 38 §4). No-op when there is no active workbook. */\n focus(): void;\n /** Subscribe to a canonical editor event (doc 38 §3). Returns an unsubscribe\n * function. `'ready'` is sticky — subscribing after the editor is already\n * ready invokes the handler immediately. */\n on<K extends keyof CasualSheetsEvents>(name: K, handler: CasualSheetsEvents[K]): () => void;\n /** Remove a previously-registered event handler (doc 38 §3). */\n off<K extends keyof CasualSheetsEvents>(name: K, handler: CasualSheetsEvents[K]): void;\n /** Dispatch a Univer command by id. Resolves to the command's boolean\n * result. */\n executeCommand(id: string, params?: object): Promise<boolean>;\n /** Replay a sequence of command/mutation steps in order — e.g. a recorded\n * macro, or a host-authored script. Best-effort: a step that throws is\n * skipped (the underlying state may have moved on). Resolves to the number\n * of steps that ran without throwing. */\n executeCommands(steps: CommandRecord[]): Promise<number>;\n /** Undo the last edit — the canonical cross-editor history control (doc 38\n * §4). Dispatches Univer's `univer.command.undo` on the active unit\n * (fire-and-forget: no-op when there is nothing to undo). */\n undo(): void;\n /** Redo the last undone edit — the canonical cross-editor history control\n * (doc 38 §4). Dispatches Univer's `univer.command.redo` (fire-and-forget:\n * no-op when there is nothing to redo). */\n redo(): void;\n /** Observe the replayable mutation stream so a host can record automations\n * or build an audit log. Wraps Univer's canonical collab hook\n * (`onMutationExecutedForCollab`): fires for `CommandType.MUTATION` only —\n * the deterministic, replayable state changes, not transient command/calc\n * noise. Pair with `executeCommands` for record→replay. Returns a disposer;\n * call it to stop observing. */\n onMutation(handler: (record: CommandRecord) => void): () => void;\n /** Imperative light/dark switch — the API equivalent of the reactive\n * `appearance` prop. Flips Univer's `ThemeService.setDarkMode` (canvas\n * colours + the `univer-dark` class Univer applies to the document root). */\n setTheme(appearance: 'light' | 'dark'): void;\n /** Switch the active workbook between `'editing'` (fully editable, the\n * default) and `'viewing'` (read-only). `'viewing'` applies the same\n * command-veto + `WorkbookEditablePermission` path as {@link applyReadOnly};\n * `'editing'` disposes it and restores the prior editable state. Idempotent —\n * re-applying the current mode is a no-op. No-op when there is no active\n * workbook. */\n setDocumentMode(mode: DocumentMode): void;\n /** The current document mode: `'viewing'` while read-only is applied via\n * {@link setDocumentMode}, else `'editing'`. */\n getDocumentMode(): DocumentMode;\n /** The FUniver facade — documented escape hatch, NOT covered by semver. */\n univer: FUniver;\n}\n\n/**\n * Internal view of the API used by the `<CasualSheets>` wrapper to drive the\n * unified emitter from seams the factory can't see on its own (`ready` timing,\n * the Ctrl/Cmd+S save, boot errors) and to flip the dirty flag from the\n * wrapper's mutation subscription. NOT part of the public, semver-covered\n * surface — hosts use {@link CasualSheetsAPI}.\n * @internal\n */\nexport interface CasualSheetsAPIInternal extends CasualSheetsAPI {\n /** Emit a canonical event to all `api.on(name, …)` subscribers. */\n emit<K extends keyof CasualSheetsEvents>(\n name: K,\n ...args: Parameters<CasualSheetsEvents[K]>\n ): void;\n /** Flip the unsaved-changes flag; emits `dirtyChange` only on transitions. */\n markDirty(dirty: boolean): void;\n /** Live subscriber count for an event — lets the wrapper skip work (e.g.\n * serializing a snapshot for `change`) when nothing is listening. */\n listenerCount<K extends keyof CasualSheetsEvents>(name: K): number;\n}\n\n/**\n * Build the imperative API over a live FUniver facade. The wrapper holds no\n * state of its own — every call reads the current active workbook, so it stays\n * correct across `setContent` swaps without the host re-acquiring the ref.\n *\n * Returns a {@link CasualSheetsAPIInternal}; the public return type narrows it\n * to {@link CasualSheetsAPI} for hosts, while the `<CasualSheets>` wrapper casts\n * back to reach `emit` / `markDirty`.\n */\nexport function createCasualSheetsAPI(univerAPI: FUniver): CasualSheetsAPI {\n // Extracted so importXlsx / setContent reuse the exact same swap semantics.\n const swapWorkbook = (data: IWorkbookData) => {\n const current = univerAPI.getActiveWorkbook();\n if (current) univerAPI.disposeUnit(current.getId());\n univerAPI.createWorkbook(data);\n };\n\n // Unified event emitter (doc 38 §3). Drives api.on/off; the factory wires the\n // Univer-derived events (`selectionChange`) itself, and the <CasualSheets>\n // wrapper drives the seams it owns (`ready`/`change`/`save`/`error`) via emit.\n const emitter = createEmitter<CasualSheetsEvents>();\n // `ready` is sticky: a late `api.on('ready', …)` fires immediately. We remember\n // the API instance passed to the first `emit('ready', …)`.\n let readyFired = false;\n let readyApi: CasualSheetsAPI | null = null;\n\n // Dirty tracking: flips true on the first buffered mutation after a load/save,\n // false on setContent/import/save. Emits `dirtyChange` on transitions only.\n let dirty = false;\n const markDirty = (next: boolean) => {\n if (next === dirty) return;\n dirty = next;\n emitter.emit('dirtyChange', next);\n };\n\n // Document-mode state: `'editing'` by default. When `'viewing'`, we hold the\n // disposer returned by applyReadOnly so switching back to `'editing'` restores\n // the prior editable state instead of reinventing the permission path.\n let documentMode: DocumentMode = 'editing';\n let readOnlyDisposer: (() => void) | null = null;\n\n const getContent = (): IWorkbookData | null => univerAPI.getActiveWorkbook()?.save() ?? null;\n\n const setContent = (data: IWorkbookData): void => {\n swapWorkbook(data);\n // A fresh snapshot is a clean buffer until the user edits it.\n markDirty(false);\n };\n\n const importXlsx = async (input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData> => {\n // Normalise to ArrayBuffer. Blob/File expose arrayBuffer(); a Uint8Array\n // view is sliced to its exact window so we don't hand the parser a larger\n // backing buffer.\n let buffer: ArrayBuffer;\n if (input instanceof ArrayBuffer) {\n buffer = input;\n } else if (input instanceof Uint8Array) {\n // `.slice` of a (possibly SharedArrayBuffer-backed) view; uploads are\n // never shared, so narrow to ArrayBuffer for the parser.\n buffer = input.buffer.slice(\n input.byteOffset,\n input.byteOffset + input.byteLength,\n ) as ArrayBuffer;\n } else {\n buffer = await input.arrayBuffer();\n }\n // Bare subpath import → separate chunk (see file header + tsup external).\n const { xlsxToWorkbookData } = await import('@casualoffice/sheets/xlsx');\n const data = await xlsxToWorkbookData(buffer);\n // A File carries the original name + size; surface them on the snapshot so\n // the built-in Properties dialog shows the real file (not the snapshot).\n if (typeof Blob !== 'undefined' && input instanceof Blob && 'name' in input) {\n const file = input as File;\n data.name = file.name.replace(/\\.(xlsx|xlsm)$/i, '') || data.name;\n data.custom = { ...data.custom, sourceBytes: file.size, sourceName: file.name };\n }\n swapWorkbook(data);\n markDirty(false);\n return data;\n };\n\n const exportXlsx = async (): Promise<Blob> => {\n const snap = univerAPI.getActiveWorkbook()?.save();\n if (!snap) throw new Error('exportXlsx: no active workbook to export');\n // Bare subpath import → separate chunk (see file header + tsup external).\n const { workbookDataToXlsx } = await import('@casualoffice/sheets/xlsx');\n return workbookDataToXlsx(snap as IWorkbookData);\n };\n\n const getSelection = (): RangeRef | null => {\n const wb = univerAPI.getActiveWorkbook();\n const range = wb?.getActiveRange();\n if (!wb || !range) return null;\n return {\n unitId: wb.getId(),\n sheetId: wb.getActiveSheet().getSheetId(),\n range: range.getRange(),\n };\n };\n\n const focus = (): void => {\n const wb = univerAPI.getActiveWorkbook();\n if (!wb) return;\n try {\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const instanceService = injector?.get(IUniverInstanceService) as\n | { focusUnit(id: string | null): void }\n | undefined;\n // The same focus path FWorkbook.undo/redo use before dispatching, so the\n // grid takes keyboard focus for subsequent typing / shortcuts.\n instanceService?.focusUnit(wb.getId());\n } catch {\n /* focus is best-effort — no facade/injector, or unit already gone */\n }\n };\n\n // Sticky `on`: a late `on('ready', …)` fires immediately with the live API.\n const on = <K extends keyof CasualSheetsEvents>(\n name: K,\n handler: CasualSheetsEvents[K],\n ): (() => void) => {\n const unsubscribe = emitter.on(name, handler);\n if (name === 'ready' && readyFired && readyApi) {\n (handler as CasualSheetsEvents['ready'])(readyApi);\n }\n return unsubscribe;\n };\n\n const emit = <K extends keyof CasualSheetsEvents>(\n name: K,\n ...args: Parameters<CasualSheetsEvents[K]>\n ): void => {\n if (name === 'ready') {\n readyFired = true;\n readyApi = args[0] as CasualSheetsAPI;\n }\n emitter.emit(name, ...args);\n };\n\n // Canvas-driven selection → `selectionChange`. Both the internal\n // `SelectionChanged` (programmatic + user) and `SelectionMoveEnd` (fires\n // reliably on drag-release) feed it, mirroring the chrome FormulaBar's picker\n // wiring. Guarded by listener count so bare hosts never pay for `getSelection`.\n const emitSelection = () => {\n if (emitter.listenerCount('selectionChange') === 0) return;\n emitter.emit('selectionChange', getSelection());\n };\n // `SelectionChanged` / `SelectionMoveEnd` are contributed by the sheets-ui\n // facade (`@univerjs/sheets-ui/facade`), which the HOST registers (apps/web's\n // `facade.ts`). We reach them by name through a loose cast rather than a static\n // import: the vendored fork maps `@univerjs/sheets-ui/facade` to raw `.ts`\n // source, so importing it here would drag ~36 pre-existing fork type errors\n // into this package's typecheck. When the facade is present the events fire;\n // otherwise this stays a harmless no-op and the other events are unaffected.\n const evented = univerAPI as unknown as {\n Event?: Record<string, string | undefined>;\n addEvent(event: string, cb: () => void): { dispose(): void };\n };\n try {\n const changed = evented.Event?.SelectionChanged;\n const moveEnd = evented.Event?.SelectionMoveEnd;\n if (changed) evented.addEvent(changed, emitSelection);\n if (moveEnd) evented.addEvent(moveEnd, emitSelection);\n } catch {\n /* facade not loaded — selection events unavailable; other events unaffected */\n }\n\n const api: CasualSheetsAPIInternal = {\n univer: univerAPI,\n\n getContent,\n setContent,\n // Deprecated aliases (doc 38 §4) — kept working for one minor.\n getSnapshot: getContent,\n loadSnapshot: setContent,\n\n importXlsx,\n exportXlsx,\n // Canonical cross-editor aliases (doc 38 §4).\n import: importXlsx,\n export: exportXlsx,\n\n getSelection,\n focus,\n\n on,\n off: emitter.off,\n emit,\n markDirty,\n listenerCount: emitter.listenerCount,\n\n executeCommand(id, params) {\n return univerAPI.executeCommand(id, params) as Promise<boolean>;\n },\n\n executeCommands(steps) {\n return runSteps((id, params) => univerAPI.executeCommand(id, params), steps);\n },\n\n // History controls (doc 38 §4). Dispatched through the same command path the\n // built-in chrome (Toolbar/MenuBar) and the app shell already use, so undo/\n // redo, collab replay, and dirty tracking all stay consistent. Void the\n // promise — the canonical handle types these as fire-and-forget.\n undo() {\n void univerAPI.executeCommand('univer.command.undo');\n },\n\n redo() {\n void univerAPI.executeCommand('univer.command.redo');\n },\n\n onMutation(handler) {\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const cmdSvc = injector?.get(ICommandService) as MutationEmitter | undefined;\n return attachMutationObserver(cmdSvc, handler);\n },\n\n setTheme(appearance) {\n const dark = appearance === 'dark';\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const themeService = injector?.get(ThemeService) as\n | { setDarkMode(b: boolean): void; darkMode: boolean }\n | undefined;\n if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);\n },\n\n setDocumentMode(mode) {\n if (mode === documentMode) return;\n if (mode === 'viewing') {\n const wb = univerAPI.getActiveWorkbook();\n if (!wb) return; // no workbook yet — stay 'editing', caller can retry\n readOnlyDisposer = applyReadOnly(univerAPI, wb.getId());\n documentMode = 'viewing';\n } else {\n readOnlyDisposer?.();\n readOnlyDisposer = null;\n documentMode = 'editing';\n }\n },\n\n getDocumentMode() {\n return documentMode;\n },\n };\n\n return api;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pure scripting primitives behind CasualSheetsAPI's `executeCommands` /\n * `onMutation`. Kept free of any `@univerjs/*` *value* imports so it's unit\n * testable under the bare `node --import tsx` runner (importing Univer core\n * values fails to resolve there) — same split as\n * `read-only-predicate.ts` (pure) vs `read-only.ts` (wiring).\n */\n\n/**\n * A single scriptable step — a Univer command/mutation id plus its params.\n * The unit a host records (via `onMutation`) and replays (via\n * `executeCommands`); the SDK generalization of the app's macro recorder.\n */\nexport interface CommandRecord {\n /** Univer command/mutation id, e.g. `sheet.mutation.set-range-values`. */\n id: string;\n /** The command's params object, passed straight back to `executeCommand`. */\n params?: object;\n}\n\n/**\n * Replay `steps` in order through `execute`. Best-effort: a step that throws is\n * skipped (the underlying state may have moved on). Resolves to the number of\n * steps that ran without throwing.\n */\nexport async function runSteps(\n execute: (id: string, params?: object) => Promise<unknown> | unknown,\n steps: CommandRecord[],\n): Promise<number> {\n let applied = 0;\n for (const s of steps) {\n try {\n await execute(s.id, s.params);\n applied += 1;\n } catch {\n /* skip a step that no longer applies to the current state */\n }\n }\n return applied;\n}\n\n/** Minimal shape of the command service's collab mutation hook. */\nexport interface MutationEmitter {\n onMutationExecutedForCollab: (l: (info: CommandRecord) => void) => { dispose: () => void };\n}\n\n/**\n * Forward the collab mutation stream to `handler` as `{ id, params }` records.\n * Returns a disposer; safe to call with an absent service (no-op disposer).\n */\nexport function attachMutationObserver(\n cmdSvc: MutationEmitter | undefined,\n handler: (record: CommandRecord) => void,\n): () => void {\n const sub = cmdSvc?.onMutationExecutedForCollab((info) =>\n handler({ id: info.id, params: info.params }),\n );\n return () => sub?.dispose();\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CustomCommandExecutionError, ICommandService, IPermissionService } from '@univerjs/core';\nimport type { FUniver } from '@univerjs/core/facade';\nimport { WorkbookEditablePermission } from '@univerjs/sheets';\nimport { isCommentOnlyBlocked, READONLY_BLOCK } from './read-only-predicate';\n\nexport { isCommentOnlyBlocked, isReadOnlyBlocked } from './read-only-predicate';\n\n/**\n * Make a workbook genuinely READ-ONLY.\n *\n * Two layers, because they cover different host setups:\n *\n * 1. **Command veto** (`beforeCommandExecuted` → throw\n * `CustomCommandExecutionError`) — cancels every mutating command. This is\n * the load-bearing layer for the iframe embed, whose minimal plugin set does\n * NOT enforce `WorkbookEditablePermission` (verified: the editor still\n * accepts edits with the permission flipped off).\n * 2. **Permission flip** (`WorkbookEditablePermission` → false) — on the full\n * `<CasualSheets>` host path this also greys out mutating menu items and\n * stops the editor opening; harmless where unenforced.\n *\n * Returns a disposer that removes the veto and restores the prior editable\n * state (for callers that toggle a live unit between preview/editor).\n */\nexport function applyReadOnly(\n univerApi: FUniver,\n unitId: string,\n onBlock?: (commandId: string) => void,\n): () => void {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n\n // Layer 1: veto mutating commands — the only layer the minimal embed enforces.\n const cmd = injector?.get(ICommandService) as\n | { beforeCommandExecuted(l: (info: { id: string }) => void): { dispose(): void } }\n | undefined;\n const vetoDisposable = cmd?.beforeCommandExecuted((info) => {\n if (READONLY_BLOCK.test(info.id)) {\n onBlock?.(info.id);\n throw new CustomCommandExecutionError(`read-only: blocked ${info.id}`);\n }\n });\n\n // Layer 2: permission flip (best-effort; load-bearing only on full hosts).\n const svc = injector?.get(IPermissionService) as\n | {\n addPermissionPoint(p: unknown): boolean;\n updatePermissionPoint(id: string, value: unknown): void;\n getPermissionPoint(id: string): { value: unknown } | undefined;\n }\n | undefined;\n\n // Constructing the point yields the deterministic id Univer derives for the\n // workbook-edit permission; we don't keep the instance otherwise.\n const id = new WorkbookEditablePermission(unitId).id;\n let prev: unknown;\n if (svc) {\n try {\n const existing = svc.getPermissionPoint(id);\n if (existing) {\n prev = existing.value;\n svc.updatePermissionPoint(id, false);\n } else {\n const point = new WorkbookEditablePermission(unitId);\n point.value = false;\n svc.addPermissionPoint(point);\n }\n } catch {\n /* best-effort — the veto above is the load-bearing layer */\n }\n }\n\n return () => {\n vetoDisposable?.dispose();\n try {\n svc?.updatePermissionPoint(id, prev === undefined ? true : prev);\n } catch {\n /* swallow */\n }\n };\n}\n\n/**\n * Make a workbook **comment-only** (share role `comment`): cells are read-only,\n * but threaded comments and their editor stay fully usable. This is the middle\n * tier between `view` (read-only, no comments) and `edit` (full), enforced at\n * the engine layer via the same command veto as {@link applyReadOnly} — minus\n * the comment commands.\n *\n * No `WorkbookEditablePermission` flip here: on a full host that point also\n * disables comment affordances, which would defeat the role. The command veto is\n * the load-bearing layer (and the only one the minimal embed enforces anyway).\n *\n * Returns a disposer that removes the veto.\n */\nexport function applyCommentOnly(\n univerApi: FUniver,\n onBlock?: (commandId: string) => void,\n): () => void {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n const cmd = injector?.get(ICommandService) as\n | { beforeCommandExecuted(l: (info: { id: string }) => void): { dispose(): void } }\n | undefined;\n const vetoDisposable = cmd?.beforeCommandExecuted((info) => {\n if (isCommentOnlyBlocked(info.id)) {\n onBlock?.(info.id);\n throw new CustomCommandExecutionError(`comment-only: blocked ${info.id}`);\n }\n });\n return () => vetoDisposable?.dispose();\n}\n\n/**\n * Read the current `WorkbookEditablePermission` value for a unit — `true`\n * (editable), `false` (read-only), or `undefined` if the point isn't\n * registered yet. Lets hosts/tests confirm {@link applyReadOnly} took.\n */\nexport function getEditable(univerApi: FUniver, unitId: string): boolean | undefined {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n const svc = injector?.get(IPermissionService) as\n | { getPermissionPoint(id: string): { value: unknown } | undefined }\n | undefined;\n if (!svc) return undefined;\n const id = new WorkbookEditablePermission(unitId).id;\n const point = svc.getPermissionPoint(id);\n return point ? (point.value as boolean) : undefined;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pure command-id predicates for the read-only / comment-only vetoes. Kept\n * Univer-free (no `@univerjs/*` imports) so the security boundary is unit-testable\n * under the bare `node --import tsx` runner — `read-only.ts` pulls in Univer\n * services and can't load there.\n */\n\n/**\n * Command ids that MUTATE a sheet — opening the cell editor, writing values,\n * styling, structural edits, clipboard paste. The read-only veto cancels any\n * command whose id matches. Navigation (selection, scroll, zoom, sheet switch),\n * copy, and undo/redo deliberately fall through so preview stays usable.\n */\nexport const READONLY_BLOCK =\n /(set-cell-edit-visible|set-activate-cell-edit|set-range-values|set-style|set-bold|set-italic|set-underline|set-strike|set-font|set-background|set-text|set-horizontal|set-vertical|set-wrap|set-rotation|set-border|set-number-format|insert-|delete-|remove-|clear-selection|cut-content|paste|move-range|move-rows|move-cols|merge|split|add-worksheet|set-worksheet-name|set-worksheet-row|set-worksheet-col|auto-fill|reorder|set-defined-name|set-tab-color|set-frozen-cancel)/;\n\n/**\n * Commands that must stay usable for the **comment** share-role even though the\n * cells are locked: the threaded-comment commands (add / reply / update /\n * resolve / delete) and the comment editor's rich-text doc edits. Some of these\n * (`delete-comment`) would otherwise be caught by {@link READONLY_BLOCK}'s\n * `delete-` token, so the comment-only veto allowlists them explicitly.\n */\nexport const COMMENT_ALLOW = /(thread-comment|rich-text-editing)/;\n\n/** True for any mutating command (the read-only veto target). */\nexport function isReadOnlyBlocked(commandId: string): boolean {\n return READONLY_BLOCK.test(commandId);\n}\n\n/**\n * The comment-only veto predicate (the security boundary): block cell/style/\n * structural mutations, but let threaded-comment + comment-editor commands\n * through.\n */\nexport function isCommentOnlyBlocked(commandId: string): boolean {\n return READONLY_BLOCK.test(commandId) && !COMMENT_ALLOW.test(commandId);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Minimal typed event emitter backing the SDK's canonical `.on()/.off()` surface\n * (doc 38 §3). Kept in its own Univer-free module so it can be unit-tested in the\n * plain node test runner (importing `./api` would pull the Univer runtime).\n */\n\n/** Base constraint for an event map — a record of handler signatures. */\nexport type EventFn = (...args: never[]) => void;\n\nexport interface Emitter<E extends Record<keyof E, EventFn>> {\n /** Subscribe. Returns an unsubscribe function. */\n on<K extends keyof E>(name: K, handler: E[K]): () => void;\n /** Remove a previously-registered handler. */\n off<K extends keyof E>(name: K, handler: E[K]): void;\n /** Dispatch to all current subscribers of `name`. */\n emit<K extends keyof E>(name: K, ...args: Parameters<E[K]>): void;\n /** Live subscriber count for `name`. */\n listenerCount<K extends keyof E>(name: K): number;\n}\n\n/**\n * Build a typed emitter. `emit` snapshots the handler set so a handler that\n * unsubscribes mid-dispatch doesn't skip its peers, and isolates handler throws\n * so a misbehaving host callback can never break the seam `emit` is called from\n * (e.g. Univer's mutation / selection callbacks).\n */\nexport function createEmitter<E extends Record<keyof E, EventFn>>(): Emitter<E> {\n const listeners = new Map<keyof E, Set<EventFn>>();\n return {\n on<K extends keyof E>(name: K, handler: E[K]): () => void {\n let set = listeners.get(name);\n if (!set) {\n set = new Set();\n listeners.set(name, set);\n }\n set.add(handler as EventFn);\n return () => {\n listeners.get(name)?.delete(handler as EventFn);\n };\n },\n off<K extends keyof E>(name: K, handler: E[K]): void {\n listeners.get(name)?.delete(handler as EventFn);\n },\n emit<K extends keyof E>(name: K, ...args: Parameters<E[K]>): void {\n const set = listeners.get(name);\n if (!set) return;\n for (const handler of [...set]) {\n try {\n (handler as (...a: Parameters<E[K]>) => void)(...args);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error(`[CasualSheets] \"${String(name)}\" event handler threw`, err);\n }\n }\n }\n },\n listenerCount<K extends keyof E>(name: K): number {\n return listeners.get(name)?.size ?? 0;\n },\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Univer, IWorkbookData } from '@univerjs/core';\n\n/**\n * Lazy plugin loading — pipeline Stage 4. The cheap plugins (render,\n * formula, sheets, sheets-ui, numfmt, docs) stay eager because every\n * workbook needs them. The heavy / feature-specific plugins (CF, DV,\n * hyperlink, table, note, thread-comment, drawing, sort, filter,\n * find-replace) load on demand:\n *\n * 1. Eagerly when a snapshot is about to mount and we detect the\n * plugin's resource key on it (e.g. `SHEET_CONDITIONAL_FORMATTING_PLUGIN`\n * in `data.resources`). This is the safety net: missing this would\n * silently drop plugin data on file open.\n * 2. Lazily when the user reaches for the feature — opens the Data\n * tab (sort/filter), hits Ctrl+F (find-replace), uses the Insert\n * tab (drawing), etc. The shell hooks `ensurePlugin(...)` into\n * these triggers and awaits before the action runs.\n *\n * Each loader returns the plugins-to-register in the correct order\n * (base before UI, same as `plugins.ts`). Registration order matters\n * in Univer; the loaders bundle a small group together to keep that\n * locality explicit.\n */\n\nexport type LazyPluginGroup =\n | 'cf'\n | 'dv'\n | 'hyperlink'\n | 'note'\n | 'table'\n | 'threadComment'\n | 'drawing'\n | 'sort'\n | 'filter'\n | 'findReplace';\n\ntype Loader = () => Promise<Array<[unknown, unknown?]>>;\n\nconst LOADERS: Record<LazyPluginGroup, Loader> = {\n cf: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-conditional-formatting'),\n import('@univerjs/sheets-conditional-formatting-ui'),\n ]);\n return [\n [base.UniverSheetsConditionalFormattingPlugin],\n [ui.UniverSheetsConditionalFormattingUIPlugin],\n ];\n },\n dv: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-data-validation'),\n import('@univerjs/sheets-data-validation-ui'),\n ]);\n return [[base.UniverSheetsDataValidationPlugin], [ui.UniverSheetsDataValidationUIPlugin]];\n },\n hyperlink: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-hyper-link'),\n import('@univerjs/sheets-hyper-link-ui'),\n ]);\n return [[base.UniverSheetsHyperLinkPlugin], [ui.UniverSheetsHyperLinkUIPlugin]];\n },\n note: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-note'),\n import('@univerjs/sheets-note-ui'),\n ]);\n return [[base.UniverSheetsNotePlugin], [ui.UniverSheetsNoteUIPlugin]];\n },\n table: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-table'),\n import('@univerjs/sheets-table-ui'),\n ]);\n return [[base.UniverSheetsTablePlugin], [ui.UniverSheetsTableUIPlugin]];\n },\n threadComment: async () => {\n const [tc, tcUi, sheetsTc, sheetsTcUi, mentionUi] = await Promise.all([\n import('@univerjs/thread-comment'),\n import('@univerjs/thread-comment-ui'),\n import('@univerjs/sheets-thread-comment'),\n import('@univerjs/sheets-thread-comment-ui'),\n // @-mention autocomplete for the comment editor. Lists candidates via the\n // core IMentionIOService, which CasualSheets overrides with the\n // host-pluggable CasualMentionIOService (see mention-source.ts). Riding\n // the comment group means it loads exactly when comments do.\n import('@univerjs/docs-mention-ui'),\n // Side-effect imports: install FWorksheet.getComments / FRange.\n // getComments / addCommentAsync on the facade prototype. Without\n // these the CommentsPanel's `getActiveSheet().getComments()` and\n // any facade-driven comment flow (e2e, future shell glue) see an\n // undefined method even though the plugin is registered — mirrors\n // the `drawing` group's facade imports above.\n import('@univerjs/sheets-thread-comment/facade'),\n ]);\n return [\n [tc.UniverThreadCommentPlugin],\n [tcUi.UniverThreadCommentUIPlugin],\n [sheetsTc.UniverSheetsThreadCommentPlugin],\n [sheetsTcUi.UniverSheetsThreadCommentUIPlugin],\n [mentionUi.UniverDocsMentionUIPlugin],\n ];\n },\n drawing: async () => {\n const [d, dUi, sd, sdUi] = await Promise.all([\n import('@univerjs/drawing'),\n import('@univerjs/drawing-ui'),\n import('@univerjs/sheets-drawing'),\n import('@univerjs/sheets-drawing-ui'),\n // Side-effect imports: install FWorksheet.insertImage / getImages /\n // updateImages on the facade prototype. Without these, code that\n // reaches in via the FUniver facade (e2e specs, future shell glue)\n // sees an undefined method even though the plugin is registered.\n import('@univerjs/sheets-drawing/facade'),\n import('@univerjs/sheets-drawing-ui/facade'),\n ]);\n return [\n [d.UniverDrawingPlugin],\n [dUi.UniverDrawingUIPlugin],\n [sd.UniverSheetsDrawingPlugin],\n [sdUi.UniverSheetsDrawingUIPlugin],\n ];\n },\n sort: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-sort'),\n import('@univerjs/sheets-sort-ui'),\n ]);\n return [[base.UniverSheetsSortPlugin], [ui.UniverSheetsSortUIPlugin]];\n },\n filter: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-filter'),\n import('@univerjs/sheets-filter-ui'),\n ]);\n return [[base.UniverSheetsFilterPlugin], [ui.UniverSheetsFilterUIPlugin]];\n },\n findReplace: async () => {\n const [base, sheets] = await Promise.all([\n import('@univerjs/find-replace'),\n import('@univerjs/sheets-find-replace'),\n ]);\n return [[base.UniverFindReplacePlugin], [sheets.UniverSheetsFindReplacePlugin]];\n },\n};\n\n/**\n * Map from a Univer `data.resources[].name` to the lazy group that owns\n * it. Used by `eagerLoadForSnapshot` to pre-register plugins whose\n * state already lives on the workbook so file-open never silently\n * drops a CF rule / table / drawing / etc.\n */\nconst RESOURCE_NAME_TO_GROUP: Record<string, LazyPluginGroup> = {\n SHEET_CONDITIONAL_FORMATTING_PLUGIN: 'cf',\n SHEET_DATA_VALIDATION_PLUGIN: 'dv',\n SHEET_HYPER_LINK_PLUGIN: 'hyperlink',\n SHEET_NOTE_PLUGIN: 'note',\n SHEET_TABLE_PLUGIN: 'table',\n SHEET_THREAD_COMMENT_BASE_PLUGIN: 'threadComment',\n SHEET_DRAWING_PLUGIN: 'drawing',\n SHEET_SORT_PLUGIN: 'sort',\n SHEET_FILTER_PLUGIN: 'filter',\n};\n\nconst loaded = new Set<LazyPluginGroup>();\nconst inflight = new Map<LazyPluginGroup, Promise<void>>();\n\n/**\n * Module-level reference to the live Univer instance, set by\n * `UniverSheet.tsx` immediately after `new Univer()`. Lets shell code\n * call `ensurePluginByName(group)` without plumbing the Univer\n * instance through React context (the FUniver facade doesn't expose\n * its host). Cleared on dispose so callers fail loudly if they hit\n * the lazy path after teardown.\n */\nlet currentUniver: Univer | null = null;\n\nexport function setUniverForLazyLoad(univer: Univer | null): void {\n currentUniver = univer;\n}\n\n/**\n * Idempotent: subsequent calls for the same group resolve immediately\n * if the plugin is already loaded; concurrent calls share the same\n * in-flight promise so we never double-register.\n */\nexport function ensurePlugin(univer: Univer, group: LazyPluginGroup): Promise<void> {\n if (loaded.has(group)) return Promise.resolve();\n const existing = inflight.get(group);\n if (existing) return existing;\n const loader = LOADERS[group];\n if (!loader) return Promise.resolve();\n const p = loader().then((plugins) => {\n for (const [PluginCtor, config] of plugins) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n univer.registerPlugin(PluginCtor as any, config);\n }\n loaded.add(group);\n inflight.delete(group);\n });\n inflight.set(group, p);\n return p;\n}\n\n/**\n * Shell-friendly variant of `ensurePlugin` that pulls the Univer\n * instance from the module-level holder set by `UniverSheet.tsx`. Use\n * this anywhere we only have the FUniver facade (toolbar callbacks,\n * panel handlers). Returns a resolved promise if the holder is empty —\n * the worst case is a no-op, never a throw.\n */\nexport function ensurePluginByName(group: LazyPluginGroup): Promise<void> {\n if (loaded.has(group)) return Promise.resolve();\n if (!currentUniver) return Promise.resolve();\n return ensurePlugin(currentUniver, group);\n}\n\n/**\n * Walk a snapshot for plugin-owned resources + side-channel hyperlinks\n * and eagerly load every group that's referenced. Returns a promise\n * the caller MUST await before `createUnit` — Univer's resource manager\n * silently discards keys for plugins that aren't yet registered.\n */\nexport async function eagerLoadForSnapshot(univer: Univer, snapshot: IWorkbookData): Promise<void> {\n const groups = new Set<LazyPluginGroup>();\n const resources = snapshot.resources ?? [];\n for (const r of resources) {\n const g = RESOURCE_NAME_TO_GROUP[r.name];\n if (g) groups.add(g);\n }\n // Hyperlinks live inline in cell.p (Stage 5) — the hyperlink plugin\n // still owns click handling / context-menu actions, so eager-load\n // when any cell has a HYPERLINK customRange.\n if (snapshotHasHyperlinks(snapshot)) groups.add('hyperlink');\n await Promise.all(Array.from(groups).map((g) => ensurePlugin(univer, g)));\n}\n\n/**\n * Idle-load every remaining lazy group AFTER Univer is mounted. The\n * bundle split (each group ships as its own chunk) is the persistent\n * boot-time win — the initial paint doesn't pay for them. This\n * idle-load just ensures they're all eventually registered so a user\n * clicking \"Insert > Table\" doesn't hit a no-op.\n *\n * Loads in parallel via `requestIdleCallback` so they don't compete\n * with the first paint, falling back to `setTimeout(0)` in browsers\n * without rIC (Safari).\n */\nexport function idleLoadAll(univer: Univer): void {\n const groups = Object.keys(LOADERS) as LazyPluginGroup[];\n schedule(() => {\n for (const g of groups) {\n void ensurePlugin(univer, g);\n }\n });\n}\n\nfunction schedule(fn: () => void): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ric = (globalThis as any).requestIdleCallback as\n | ((cb: () => void, opts?: { timeout: number }) => number)\n | undefined;\n if (ric) ric(fn, { timeout: 500 });\n else setTimeout(fn, 0);\n}\n\nfunction snapshotHasHyperlinks(snapshot: IWorkbookData): boolean {\n const sheetOrder = snapshot.sheetOrder ?? [];\n for (const sid of sheetOrder) {\n const sheet = snapshot.sheets?.[sid];\n if (!sheet?.cellData) continue;\n const cellData = sheet.cellData as Record<\n string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Record<string, { p?: any }>\n >;\n for (const r of Object.keys(cellData)) {\n const row = cellData[r];\n for (const c of Object.keys(row)) {\n const ranges = row[c]?.p?.body?.customRanges ?? [];\n if (ranges.some((cr: { rangeType?: number }) => cr.rangeType === 0)) return true;\n }\n }\n }\n return false;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * AI surface for the Sheets SDK.\n *\n * `<CasualSheets ai={…}>` opts a host into a supported AI task-pane surface,\n * mirroring how the docs `CasualEditor`/`DocxEditor` SDK exposes its DocOps\n * panel behind a `docopsTransport` prop. The SDK owns the prop contract, the\n * `SheetsAiTransport` type (see `./transport`), and the layout slot beside the\n * grid; the host supplies the panel body via `ai.render` and drives its tool\n * loop against the transport.\n *\n * MVP (slot + transport wiring). The reference implementation of the panel\n * body — chat UI, `SheetsBridge` (FUniver tool catalog), agent mode, MCP — is\n * still in the reference app at `apps/web/src/shell/AiPanel.tsx`; that panel is\n * entangled with app-only modules (`use-ui`, `Icon`, the `ai/` catalog + MCP\n * runtime), so it is NOT yet moved wholesale into the SDK.\n *\n * TODO(sheets#280): extract the `SheetsBridge` catalog + a self-contained\n * default panel body into the SDK so `ai.enabled` renders a working assistant\n * with no `render` slot required.\n */\n\nimport type { ReactNode } from 'react';\nimport type { CasualSheetsAPI } from '../sheets/api';\nimport type { SheetsAiTransport } from './transport';\n\n/** Lifecycle / progress signals a panel body reports back to the host. */\nexport type SheetsAiAction =\n | { type: 'open' }\n | { type: 'close' }\n | { type: 'message'; role: 'user' | 'assistant'; text: string }\n | { type: 'tool'; tool: string; status: 'running' | 'done' | 'error' }\n | { type: 'error'; message: string };\n\n/** Context handed to `ai.render` — everything a panel body needs to run. */\nexport interface SheetsAiRenderContext {\n /** The ready editor facade (`CasualSheetsAPI`). Never null inside `render`. */\n api: CasualSheetsAPI;\n /** The transport the host configured (if any). */\n transport?: SheetsAiTransport;\n /** Forward panel lifecycle/progress to the host's `ai.onAction`. */\n onAction?: (action: SheetsAiAction) => void;\n /** Request the surface be dismissed (emits an `onAction({type:'close'})`). */\n close: () => void;\n}\n\n/** The `ai` prop on `<CasualSheets>`. */\nexport interface SheetsAiConfig {\n /** Mount the AI surface beside the grid. Default `false` (no surface). */\n enabled?: boolean;\n /** LLM transport the panel body drives its tool loop against. Build one with\n * `createSheetsAiTransport()` or supply your own `SheetsAiTransport`. */\n transport?: SheetsAiTransport;\n /** Observe panel lifecycle + progress (open/close, messages, tool steps). */\n onAction?: (action: SheetsAiAction) => void;\n /** Render the panel body. Receives a `SheetsAiRenderContext` (ready `api` +\n * `transport` + `onAction` + `close`). Until the SDK ships a built-in body,\n * this slot is how the panel is mounted — the reference app passes its\n * `<AiPanel>` here. When omitted, `enabled` mounts an empty pane. */\n render?: (ctx: SheetsAiRenderContext) => ReactNode;\n}\n\nconst asideStyle: React.CSSProperties = {\n flex: '0 0 auto',\n width: 340,\n maxWidth: '100%',\n height: '100%',\n minHeight: 0,\n display: 'flex',\n flexDirection: 'column',\n borderLeft: '1px solid var(--color-divider, #e5e7eb)',\n background: 'var(--color-surface, #ffffff)',\n overflow: 'hidden',\n};\n\n/**\n * Renders the configured AI surface beside the grid. Returns `null` until the\n * editor is ready (`api` populated) or when disabled — so bare-grid consumers\n * pay nothing. The host's `render` slot owns the panel body; if absent, an\n * empty (but present) pane is mounted so layout is stable.\n */\nexport function AiPanelSurface({\n config,\n api,\n}: {\n config: SheetsAiConfig | undefined;\n api: CasualSheetsAPI | null;\n}): ReactNode {\n if (!config?.enabled || !api) return null;\n\n const ctx: SheetsAiRenderContext = {\n api,\n transport: config.transport,\n onAction: config.onAction,\n close: () => config.onAction?.({ type: 'close' }),\n };\n\n return (\n <aside data-testid=\"casual-sheets-ai\" style={asideStyle}>\n {config.render?.(ctx) ?? null}\n </aside>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * mountCasualSheets — the framework-agnostic imperative mount (doc 38 §1).\n *\n * React hosts render `<CasualSheets {...config} />`; vanilla / non-React hosts\n * call `mountCasualSheets(container, config)` and get back the same\n * `CasualSheetsAPI` the component hands to `onReady`, plus a `destroy()` that\n * unmounts the React root. This is the sheets peer of the docs SDK's\n * `renderAsync(input, container, options)` — one programmatic entry point that\n * returns the full imperative handle, so a host never has to stand up its own\n * React root to drive the editor.\n *\n * (`mountEmbedded` in `../embed-runtime` is a DIFFERENT, iframe-only entry: it\n * boots the postMessage embed runtime and returns `void`. This one mounts the\n * live editor into a DOM node the host already controls and returns the API.)\n *\n * The config is exactly `CasualSheetsProps` — the same declarative object the\n * component takes — so the two mount styles stay key-for-key identical (doc 38\n * §1). `react` / `react-dom` are peer deps the host already provides.\n */\n\nimport { createElement } from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\nimport { CasualSheets, type CasualSheetsProps } from './CasualSheets';\nimport type { CasualSheetsAPI } from './api';\n\n/** The handle returned by {@link mountCasualSheets}. */\nexport interface MountedCasualSheets {\n /** The imperative editor API — identical to the ref handed to `onReady`\n * (snapshot I/O, xlsx import/export, selection, command dispatch, undo/redo,\n * the `.on()/.off()` emitter, document mode, `api.univer` escape hatch). */\n readonly api: CasualSheetsAPI;\n /** Unmount the React root and dispose the editor. The imperative-mount peer\n * of a React unmount (doc 38 §4 `destroy`). Idempotent. */\n destroy(): void;\n}\n\n/**\n * Mount `<CasualSheets>` into a DOM node without a host React tree, and resolve\n * once the editor is ready with its {@link CasualSheetsAPI} + a `destroy()`.\n *\n * Any `onReady` / `onError` you pass in `options` still fires — this composes\n * with them rather than replacing them. The returned promise resolves on the\n * first `ready`; if boot fails before ready, it rejects with the boot error\n * (so callers awaiting the mount never hang). Errors after ready reach your\n * `onError` (prop or `api.on('error', …)`), not the promise.\n */\nexport function mountCasualSheets(\n container: HTMLElement,\n options: CasualSheetsProps,\n): Promise<MountedCasualSheets> {\n const root: Root = createRoot(container);\n let destroyed = false;\n const destroy = () => {\n if (destroyed) return;\n destroyed = true;\n // Defer off any in-flight render commit (Univer owns its own React root and\n // warns on a synchronous unmount mid-render), mirroring the component's\n // microtask-deferred disposal.\n queueMicrotask(() => root.unmount());\n };\n\n return new Promise<MountedCasualSheets>((resolve, reject) => {\n let settled = false;\n const onReady = (api: CasualSheetsAPI) => {\n // Preserve the host's own onReady first, then settle the mount promise.\n options.onReady?.(api);\n if (settled) return;\n settled = true;\n resolve({ api, destroy });\n };\n const onError = (err: Error) => {\n options.onError?.(err);\n // A boot error before `ready` would otherwise leave the promise pending.\n if (settled) return;\n settled = true;\n reject(err);\n };\n try {\n root.render(createElement(CasualSheets, { ...options, onReady, onError }));\n } catch (err) {\n destroy();\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SDK-owned LLM transport contract for the Sheets AI surface.\n *\n * This is the canonical `SheetsAiTransport` type that the `ai` prop on\n * `<CasualSheets>` accepts. It mirrors the reference app's transport\n * (`apps/web/src/ai/transport.ts`) but lives in the SDK so integrators can\n * type their transport straight off `@casualoffice/sheets` and reuse the\n * shipped implementations:\n * - `DirectAiTransport` — browser fetch straight to Anthropic (BYO key)\n * - `CollabAiTransport` — WebSocket to the collab server `/api/ai`; the\n * server holds the key and runs ONE LLM round per\n * `call()` (single-round), routing `tool_call`\n * frames back to this client's `toolExecutor`\n * - `DesktopAiTransport` — native llama.cpp model in the Casual Office\n * desktop shell via the `docops_llm_call` Tauri\n * command (no key, no server)\n *\n * The panel drives the tool loop (`drivesLoop = false` on every transport):\n * each `call()` performs one round and returns an Anthropic-shaped\n * `{ content, stop_reason }` payload.\n */\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport type SheetsAiToolExecutor = (\n toolName: string,\n args: Record<string, unknown>,\n) => Promise<unknown>;\n\nexport interface SheetsAiLlmPayload {\n model: string;\n system: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n messages: any[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tools: any[];\n max_tokens: number;\n apiKey?: string;\n toolExecutor?: SheetsAiToolExecutor;\n onText?: (text: string) => void;\n signal?: AbortSignal;\n maxToolRounds?: number;\n}\n\nexport interface SheetsAiLlmResult {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data: any;\n status: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n updatedHistory?: any[];\n capHit?: boolean;\n}\n\nexport interface SheetsAiTransport {\n call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult>;\n readonly requiresApiKey: boolean;\n readonly drivesLoop: boolean;\n}\n\n// ── DirectAiTransport ──────────────────────────────────────────────────────\n\nexport class DirectAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = true;\n readonly drivesLoop = false;\n\n async call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n if (!payload.apiKey) {\n return { data: { error: { message: 'No API key configured.' } }, status: 401 };\n }\n\n const useStream = !!payload.onText;\n\n const resp = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': payload.apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model: payload.model,\n max_tokens: payload.max_tokens,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n ...(useStream ? { stream: true } : {}),\n }),\n signal: payload.signal,\n });\n\n if (!useStream || !resp.body) {\n return { data: await resp.json(), status: resp.status };\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buf = '';\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const content: any[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let msgDelta: any = {};\n\n try {\n outer: while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split('\\n');\n buf = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') break outer;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ev: any;\n try {\n ev = JSON.parse(raw);\n } catch {\n continue;\n }\n\n if (ev.type === 'content_block_start' && ev.content_block?.type === 'text') {\n content.push({ type: 'text', text: '' });\n } else if (ev.type === 'content_block_start' && ev.content_block?.type === 'tool_use') {\n content.push({\n type: 'tool_use',\n id: ev.content_block.id,\n name: ev.content_block.name,\n input: {},\n });\n } else if (ev.type === 'content_block_delta') {\n const last = content[content.length - 1];\n if (ev.delta?.type === 'text_delta' && last?.type === 'text') {\n last.text += ev.delta.text ?? '';\n payload.onText?.(ev.delta.text ?? '');\n } else if (ev.delta?.type === 'input_json_delta' && last?.type === 'tool_use') {\n last._inputStr = (last._inputStr ?? '') + (ev.delta.partial_json ?? '');\n }\n } else if (ev.type === 'content_block_stop') {\n const last = content[content.length - 1];\n if (last?.type === 'tool_use' && last._inputStr) {\n try {\n last.input = JSON.parse(last._inputStr);\n } catch {\n /* leave empty */\n }\n delete last._inputStr;\n }\n } else if (ev.type === 'message_delta') {\n msgDelta = ev.delta ?? {};\n }\n }\n }\n } catch (err) {\n return { data: { error: { message: String(err) } }, status: 500 };\n }\n\n return {\n data: { content, stop_reason: msgDelta.stop_reason ?? 'end_turn' },\n status: resp.status,\n };\n }\n}\n\n// ── CollabAiTransport ──────────────────────────────────────────────────────\n\n/**\n * Routes AI orchestration through the collab server's `/api/ai` WebSocket.\n * The server holds the Anthropic key; `singleRound: true` means the server\n * runs ONE LLM round per `call()` and routes any `tool_call` frames back to\n * this client, which executes them via the payload's `toolExecutor`. The\n * panel/agent drives the multi-round loop from there (so `drivesLoop = false`).\n */\nexport class CollabAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = false;\n readonly drivesLoop = false;\n\n constructor(private readonly aiWsUrl: string) {}\n\n call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n return new Promise((resolve, reject) => {\n if (payload.signal?.aborted) {\n reject(Object.assign(new Error('AbortError'), { name: 'AbortError' }));\n return;\n }\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(this.aiWsUrl);\n } catch (err) {\n reject(new Error(`Failed to open AI WebSocket: ${String(err)}`));\n return;\n }\n\n let settled = false;\n\n const settle = (v: SheetsAiLlmResult | null, err?: Error) => {\n if (settled) return;\n settled = true;\n payload.signal?.removeEventListener('abort', onAbort);\n if (err) reject(err);\n else resolve(v!);\n };\n\n const onAbort = () => {\n try {\n ws.close(1000, 'aborted');\n } catch {\n /* ignore */\n }\n settle(null, Object.assign(new Error('AbortError'), { name: 'AbortError' }));\n };\n payload.signal?.addEventListener('abort', onAbort);\n\n ws.addEventListener('open', () => {\n ws.send(\n JSON.stringify({\n type: 'chat',\n model: payload.model,\n max_tokens: payload.max_tokens,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n singleRound: true,\n ...(payload.apiKey ? { apiKey: payload.apiKey } : {}),\n }),\n );\n });\n\n ws.addEventListener('message', ({ data }: MessageEvent<string>) => {\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(data) as Record<string, unknown>;\n } catch {\n settle(null, new Error('AI WS: received non-JSON frame'));\n ws.close();\n return;\n }\n\n if (msg.type === 'round') {\n // Single-round reply: the panel/agent drives the loop from here.\n settle({\n data: {\n content: msg.content ?? [],\n stop_reason: (msg.stop_reason as string) ?? 'end_turn',\n },\n status: 200,\n });\n } else if (msg.type === 'text') {\n payload.onText?.(msg.text as string);\n } else if (msg.type === 'tool_call') {\n const id = msg.id as string;\n const toolName = msg.toolName as string;\n const args = (msg.args ?? {}) as Record<string, unknown>;\n\n if (!payload.toolExecutor) {\n ws.send(\n JSON.stringify({\n type: 'tool_result',\n id,\n error: 'no toolExecutor configured on this client',\n }),\n );\n return;\n }\n\n payload\n .toolExecutor(toolName, args)\n .then((result) => {\n ws.send(JSON.stringify({ type: 'tool_result', id, result }));\n })\n .catch((err) => {\n ws.send(\n JSON.stringify({\n type: 'tool_result',\n id,\n error: err instanceof Error ? err.message : String(err),\n }),\n );\n });\n } else if (msg.type === 'done') {\n settle({\n data: { ok: true },\n status: 200,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n updatedHistory: msg.history as any[],\n capHit: msg.capHit === true,\n });\n } else if (msg.type === 'error') {\n settle({\n data: { error: { message: msg.message as string } },\n status: 500,\n });\n }\n });\n\n ws.addEventListener('error', () => {\n settle(null, new Error('AI WebSocket connection failed'));\n });\n\n ws.addEventListener('close', ({ code, reason }: CloseEvent) => {\n if (!settled) {\n if (code === 1000 || reason === 'aborted') return;\n settle(null, new Error(`AI WebSocket closed unexpectedly (${code})`));\n }\n });\n });\n }\n}\n\n// ── DesktopAiTransport ─────────────────────────────────────────────────────\n\n/**\n * Routes AI calls to the native model loaded in the Casual Office desktop\n * shell (the llama.cpp worker) through the shared `docops_llm_call` Tauri\n * command — the same backend the document editor uses. No API key, no collab\n * server. Each `call()` performs one LLM round.\n */\nexport class DesktopAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = false;\n readonly drivesLoop = false;\n\n async call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n const invoke = tauriInvoke();\n if (!invoke) {\n return {\n data: { error: { message: 'Native AI is only available in the desktop app.' } },\n status: 500,\n };\n }\n try {\n // The Rust command is docops_llm_call(args: DocopsLlmArgs), so the\n // payload MUST be nested under `args`. Inner fields are camelCase.\n const data = await invoke('docops_llm_call', {\n args: {\n model: payload.model,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n maxTokens: payload.max_tokens,\n apiKey: payload.apiKey ?? '',\n },\n });\n return { data, status: 200 };\n } catch (err) {\n return { data: { error: { message: String(err) } }, status: 500 };\n }\n }\n}\n\n// ── Environment helpers ──────────────────────────────────────────────────────\n\n/** Tauri `invoke` when running inside the Casual Office desktop shell, else null. */\nfunction tauriInvoke(): ((cmd: string, args?: unknown) => Promise<unknown>) | null {\n const inv = (\n window as unknown as {\n __TAURI__?: { core?: { invoke?: (c: string, a?: unknown) => Promise<unknown> } };\n }\n ).__TAURI__?.core?.invoke;\n return typeof inv === 'function' ? inv : null;\n}\n\n/**\n * Derives the AI WebSocket URL: an explicit override wins, else the\n * `__COLLAB_WS_URL__` window global (same base as Yjs, `/yjs` → `/api/ai`),\n * else same-origin `/api/ai`.\n */\nfunction resolveAiWsUrl(explicit?: string): string {\n const base =\n explicit ??\n (window as unknown as { __COLLAB_WS_URL__?: string }).__COLLAB_WS_URL__ ??\n `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/yjs`;\n return base.replace(/\\/yjs$/, '').replace(/\\/+$/, '') + '/api/ai';\n}\n\n// ── Factory ──────────────────────────────────────────────────────────────────\n\nexport interface CreateSheetsAiTransportOptions {\n /** Explicit collab WS base URL (e.g. `wss://host/yjs`). Falls back to the\n * `__COLLAB_WS_URL__` window global, then same-origin. */\n collabWsUrl?: string;\n /** Force the browser-direct Anthropic transport (bring-your-own key) even\n * when a collab server is configured. */\n forceDirect?: boolean;\n}\n\n/**\n * Picks the transport for the current environment:\n * - `DesktopAiTransport` inside the desktop shell (native model),\n * - `CollabAiTransport` when a collab WS URL is available (server holds key),\n * - `DirectAiTransport` otherwise (user provides an Anthropic key).\n */\nexport function createSheetsAiTransport(\n opts: CreateSheetsAiTransportOptions = {},\n): SheetsAiTransport {\n if (!opts.forceDirect && tauriInvoke()) {\n return new DesktopAiTransport();\n }\n const hasCollab =\n !!opts.collabWsUrl || !!(window as unknown as { __COLLAB_WS_URL__?: string }).__COLLAB_WS_URL__;\n if (!opts.forceDirect && hasCollab) {\n return new CollabAiTransport(resolveAiWsUrl(opts.collabWsUrl));\n }\n return new DirectAiTransport();\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheetsIframe — the iframe-mounting variant of `<CasualSheets>`.\n * Sheet sibling of `@casualoffice/docs`'s `<CasualEditorIframe>`;\n * see doc 16 in the parent repo.\n *\n * Differs from CasualEditorIframe in one place: the embed URL params\n * carry `app=sheet` and the embed-runtime inside the iframe knows to\n * convert raw xlsx bytes into an `IWorkbookData` snapshot via\n * `xlsxToWorkbookData` before mounting `<CasualSheets>`.\n *\n * Public surface intentionally identical to CasualSheets. v0.6 will\n * rename CasualSheetsIframe → CasualSheets and the existing direct-\n * mount component → CasualSheetsDirect.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n type CSSProperties,\n type MutableRefObject,\n} from 'react';\n\nimport { EmbedHostTransport } from '../embed/EmbedHostTransport';\nimport type {\n CasualErrorData,\n CommandExecuteData,\n LoadResponseData,\n SaveResponseData,\n SelectionChangedData,\n SelectionFormatStateData,\n TelemetryEventData,\n} from '../embed/protocol';\n\n/** What the host-side load/save handlers consume + return. The wrapper\n * binds these to the host's FileSource via simple adapters. */\nexport interface HostFileBridge {\n open(docId: string): Promise<{ bytes: ArrayBuffer; name: string; etag?: string }>;\n save?(docId: string, bytes: ArrayBuffer, opts?: { etag?: string }): Promise<{ etag: string }>;\n}\n\nexport interface CasualSheetsIframeRef {\n setViewMode(mode: 'preview' | 'editor'): void;\n iframe(): HTMLIFrameElement | null;\n /** Dispatch a formatting / navigation command (bold, italic, undo, …)\n * against the iframe's active selection. `args` carries command payloads\n * (e.g. font family/size, colour) — forwarded over the protocol. v0.6+. */\n executeCommand(command: CommandExecuteData['command'], args?: CommandExecuteData['args']): void;\n}\n\nexport interface CasualSheetsIframeProps {\n /** Host-side bytes bridge. The wrapper round-trips load / save to the\n * iframe through postMessage; bytes never live in the iframe's origin\n * except in-memory while the workbook is open. */\n fileSource: HostFileBridge;\n docId: string;\n /** Default `editor`. Live changes push casual.command.set.viewmode. */\n viewMode?: 'preview' | 'editor';\n /** Default `/embed/sheets`. Consumer copies the SDK's\n * `dist/embed/{embed.html, embed-runtime.js, embed-runtime.css}`\n * to this path. */\n embedBasePath?: string;\n onSelectionChanged?: (data: SelectionChangedData) => void;\n /** Fires when the active cell's format flags change (bold, italic,\n * …). Drive's custom toolbar reflects this state in the button\n * \"pressed\" indicators. v0.6+. */\n onSelectionFormatState?: (data: SelectionFormatStateData) => void;\n onTelemetry?: (data: TelemetryEventData) => void;\n onError?: (data: CasualErrorData) => void;\n style?: CSSProperties;\n className?: string;\n testId?: string;\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 'none',\n display: 'block',\n};\n\nexport const CasualSheetsIframe = forwardRef<CasualSheetsIframeRef, CasualSheetsIframeProps>(\n function CasualSheetsIframe(props, ref) {\n const {\n fileSource,\n docId,\n viewMode = 'editor',\n embedBasePath = '/embed/sheets',\n onSelectionChanged,\n onSelectionFormatState,\n onTelemetry,\n onError,\n style,\n className,\n testId = 'casual-sheets-iframe',\n } = props;\n\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const transportRef = useRef<EmbedHostTransport | null>(null);\n const fileSourceRef = useRef(fileSource);\n fileSourceRef.current = fileSource;\n\n const onLoad = useCallback(async (req: { docId: string }): Promise<LoadResponseData> => {\n try {\n const { bytes, name, etag } = await fileSourceRef.current.open(req.docId);\n return {\n ok: true,\n bytes,\n fileName: name,\n ...(etag !== undefined ? { etag } : {}),\n };\n } catch (err) {\n return {\n ok: false,\n code: 'open_failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }, []);\n\n const onSave = useCallback(\n async (req: {\n docId: string;\n bytes: ArrayBuffer;\n baseEtag?: string;\n }): Promise<SaveResponseData> => {\n try {\n if (!fileSourceRef.current.save) {\n return {\n ok: false,\n code: 'save_unsupported',\n message: 'host fileSource does not implement save',\n };\n }\n const opts = req.baseEtag !== undefined ? { etag: req.baseEtag } : undefined;\n const { etag } = await fileSourceRef.current.save(req.docId, req.bytes, opts);\n return { ok: true, etag };\n } catch (err) {\n return {\n ok: false,\n code: 'save_failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n },\n [],\n );\n\n const onIframeLoad = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe?.contentWindow) return;\n transportRef.current?.destroy();\n const transport = new EmbedHostTransport({\n app: 'sheet',\n iframeWindow: iframe.contentWindow,\n embedOrigin: window.location.origin,\n });\n transport.on({\n onLoadRequest: onLoad,\n onSaveRequest: onSave,\n ...(onSelectionChanged ? { onSelectionChanged } : {}),\n ...(onSelectionFormatState ? { onSelectionFormatState } : {}),\n ...(onTelemetry ? { onTelemetry } : {}),\n ...(onError ? { onError } : {}),\n onEditorReady: () => {\n transport.sendHostHello({ capabilities: ['load', 'save'] });\n transport.sendSetViewMode({ viewMode });\n },\n });\n transportRef.current = transport;\n }, [\n onLoad,\n onSave,\n onSelectionChanged,\n onSelectionFormatState,\n onTelemetry,\n onError,\n viewMode,\n ]);\n\n useEffect(() => {\n transportRef.current?.sendSetViewMode({ viewMode });\n }, [viewMode]);\n\n useEffect(() => {\n return () => {\n transportRef.current?.destroy();\n transportRef.current = null;\n };\n }, []);\n\n if (ref) {\n const apiRef = ref as MutableRefObject<CasualSheetsIframeRef | null>;\n apiRef.current = {\n setViewMode: (mode) => transportRef.current?.sendSetViewMode({ viewMode: mode }),\n iframe: () => iframeRef.current,\n executeCommand: (command, args) =>\n transportRef.current?.sendCommandExecute({ command, args }),\n };\n }\n\n const url =\n `${embedBasePath}/embed.html` +\n `?app=sheet` +\n `&docId=${encodeURIComponent(docId)}` +\n `&viewMode=${viewMode}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={url}\n onLoad={onIframeLoad}\n title=\"Casual Sheets\"\n sandbox=\"allow-scripts allow-same-origin allow-downloads allow-modals\"\n style={{ ...DEFAULT_STYLE, ...style }}\n className={className}\n data-testid={testId}\n />\n );\n },\n);\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime","secondaryBtnStyle","primaryBtnStyle","env","import_react","import_core","import_facade","import_sheets","import_core","import_core","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","DEFAULT_STYLE","CasualSheetsIframe"]}
|
|
1
|
+
{"version":3,"sources":["../src/chrome/Icon.tsx","../src/chrome/panel-shell.tsx","../src/charts/types.ts","../src/charts/resources.ts","../src/charts/charts-context.tsx","../src/charts/insert-chart.ts","../src/charts/naming.ts","../src/chrome/Dialog.tsx","../src/charts/InsertChartDialog.tsx","../src/charts/ChartsPanel.tsx","../src/charts/univer-dom.ts","../src/charts/echarts-init.ts","../src/charts/build-option.ts","../src/charts/hit-test.ts","../src/charts/ChartOverlay.tsx","../src/charts/FormatChartDialog.tsx","../src/charts/ChartContextMenu.tsx","../src/charts/ChartLayer.tsx","../src/index.ts","../src/signing/SigningProvider.tsx","../src/signing/controller.ts","../src/signing/SigningPane.tsx","../src/signing/captures.tsx","../src/embed/protocol.ts","../src/embed/EmbedTransport.ts","../src/embed/EmbedHostTransport.ts","../src/sheets/CasualSheets.tsx","../src/sheets/mention-io.ts","../src/sheets/mention-source.ts","../src/sheets/api.ts","../src/sheets/scripting.ts","../src/sheets/read-only.ts","../src/sheets/read-only-predicate.ts","../src/sheets/emitter.ts","../src/univer/lazy-plugins.ts","../src/ai/AiPanelSurface.tsx","../src/chrome/panel-context.tsx","../src/chrome/PanelRail.tsx","../src/chrome/panel-registry.ts","../src/chrome/TablesPanel.tsx","../src/chrome/PivotFieldsPanel.tsx","../src/pivots/types.ts","../src/pivots/compute.ts","../src/pivots/apply.ts","../src/chrome/CommentsPanel.tsx","../src/chrome/HistoryPanel.tsx","../src/chrome/PanelHost.tsx","../src/sheets/mount.tsx","../src/ai/transport.ts","../src/sheets/CasualSheetsIframe.tsx"],"sourcesContent":["/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Icon — a Material Symbols Outlined glyph for the chrome.\n *\n * Names are Material Symbols ids (https://fonts.google.com/icons), e.g.\n * `format_bold`. Requires the Material Symbols font (loaded via\n * `ensureChromeFonts`); if it isn't present the ligature text shows instead,\n * which is harmless. Icon-only buttons must carry their own `aria-label`.\n */\n\nimport type { CSSProperties } from 'react';\n\nexport interface IconProps {\n name: string;\n size?: number;\n style?: CSSProperties;\n}\n\nexport function Icon({ name, size = 20, style }: IconProps) {\n return (\n <span\n className=\"material-symbols-outlined\"\n aria-hidden\n style={{\n fontFamily: \"'Material Symbols Outlined'\",\n fontWeight: 'normal',\n fontStyle: 'normal',\n fontSize: size,\n lineHeight: 1,\n letterSpacing: 'normal',\n textTransform: 'none',\n display: 'inline-block',\n whiteSpace: 'nowrap',\n wordWrap: 'normal',\n direction: 'ltr',\n // Hint the variable-font axes so weight/optical-size are consistent.\n fontVariationSettings: \"'opsz' 20, 'wght' 400, 'FILL' 0, 'GRAD' 0\",\n ...style,\n }}\n >\n {name}\n </span>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Shared chrome for the side panels — a consistent, polished header (icon +\n * title + optional count/actions + hover-capable close) and small building\n * blocks, so every panel (Tables / Charts / Pivot / Comments / History) looks\n * the same. Styling maps to the design-system tokens the host loads\n * (`--color-*`), falling back to the chrome vars, then a hardcoded default —\n * so it looks right standalone and themed inside a host.\n */\nimport { useState, type CSSProperties, type ReactNode } from 'react';\n\nimport { Icon } from './Icon';\n\nconst MUTED = 'var(--color-text-secondary, var(--cs-chrome-muted, #605e5c))';\nconst DIVIDER = 'var(--color-divider, var(--cs-chrome-border, #edeff3))';\n\nconst headerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '10px 14px',\n flex: '0 0 auto',\n background: 'var(--color-surface, var(--cs-chrome-input-bg, #ffffff))',\n borderBottom: `1px solid ${DIVIDER}`,\n};\n\nconst titleStyle: CSSProperties = {\n fontWeight: 600,\n fontSize: 14,\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\n\nconst countStyle: CSSProperties = {\n fontSize: 11,\n fontWeight: 600,\n minWidth: 18,\n height: 18,\n padding: '0 5px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 9,\n background: 'var(--color-hover, rgba(15,23,42,0.06))',\n color: MUTED,\n};\n\n/** A ghost icon button with a real hover state (inline styles can't do :hover). */\nexport function IconButton({\n name,\n label,\n onClick,\n size = 18,\n}: {\n name: string;\n label: string;\n onClick: () => void;\n size?: number;\n}) {\n const [hover, setHover] = useState(false);\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n onClick={onClick}\n onMouseEnter={() => setHover(true)}\n onMouseLeave={() => setHover(false)}\n style={{\n flex: '0 0 auto',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 26,\n height: 26,\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n color: hover ? 'var(--color-text, var(--cs-chrome-fg, #201f1e))' : MUTED,\n background: hover ? 'var(--color-hover, rgba(15,23,42,0.06))' : 'transparent',\n }}\n >\n <Icon name={name} size={size} />\n </button>\n );\n}\n\nexport function PanelHeader({\n icon,\n title,\n count,\n onClose,\n actions,\n}: {\n icon: string;\n title: string;\n count?: number;\n onClose: () => void;\n /** Optional trailing actions (e.g. an add button) shown before the close. */\n actions?: ReactNode;\n}) {\n return (\n <header style={headerStyle}>\n <Icon name={icon} size={18} style={{ color: MUTED, flex: '0 0 auto' }} />\n <span style={titleStyle}>{title}</span>\n {count != null && count > 0 && <span style={countStyle}>{count}</span>}\n {actions}\n <IconButton name=\"close\" label={`Close ${title} panel`} onClick={onClose} />\n </header>\n );\n}\n\n/** Centered empty-state block for panels with no content yet. */\nexport function PanelEmpty({\n icon,\n title,\n children,\n testId,\n}: {\n icon: string;\n title: string;\n children?: ReactNode;\n testId?: string;\n}) {\n return (\n <div\n data-testid={testId}\n style={{\n textAlign: 'center',\n padding: '32px 20px',\n color: MUTED,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 6,\n }}\n >\n <Icon name={icon} size={40} style={{ opacity: 0.35 }} />\n <div style={{ fontWeight: 600, fontSize: 14, color: 'var(--color-text, inherit)' }}>{title}</div>\n {children && <div style={{ fontSize: 13, lineHeight: 1.5 }}>{children}</div>}\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Chart model the in-memory store (`charts-context`) carries per\n * inserted chart. P0 is minimal — just enough to render a column\n * chart bound to a cell range. P1 adds the resource persistence\n * round-trip; P2 wires Univer's drawing model for move/resize; P3\n * expands `type` into the catalog of supported chart types.\n *\n * Position lives in cell coordinates rather than pixels — that's\n * how Excel anchors charts (top-left anchored to cell A, bottom-\n * right to cell B). We can compute pixels on the fly via\n * `range.getCellRect()` so the chart moves with the rows/columns\n * when they shift.\n */\n/**\n * Chart subtypes, grouped by family. Matches the most-used subset of\n * Excel's \"Insert Chart\" catalog:\n *\n * - Column (vertical bars): clustered / stacked / 100 %-stacked.\n * - Bar (horizontal bars): clustered / stacked / 100 %-stacked.\n * - Line: line / stacked line.\n * - Area: area / stacked area.\n * - Pie: pie / doughnut.\n * - Scatter.\n *\n * The legacy `'bar'` literal that P0/P1 used for \"vertical column\n * chart\" is migrated to `'column'` on read (see `resources.ts`).\n */\nexport type ChartType =\n | 'column'\n | 'column-stacked'\n | 'column-stacked-100'\n | 'bar'\n | 'bar-stacked'\n | 'bar-stacked-100'\n | 'line'\n | 'line-stacked'\n | 'area'\n | 'area-stacked'\n | 'pie'\n | 'doughnut'\n | 'scatter';\n\n/** Top-level family — what shows in the left column of the Insert dialog. */\nexport type ChartFamily = 'column' | 'bar' | 'line' | 'area' | 'pie' | 'scatter';\n\nexport const CHART_FAMILY_OF: Record<ChartType, ChartFamily> = {\n column: 'column',\n 'column-stacked': 'column',\n 'column-stacked-100': 'column',\n bar: 'bar',\n 'bar-stacked': 'bar',\n 'bar-stacked-100': 'bar',\n line: 'line',\n 'line-stacked': 'line',\n area: 'area',\n 'area-stacked': 'area',\n pie: 'pie',\n doughnut: 'pie',\n scatter: 'scatter',\n};\n\n/** Human-readable label shown in the panel + dialog. */\nexport const CHART_TYPE_LABEL: Record<ChartType, string> = {\n column: 'Clustered Column',\n 'column-stacked': 'Stacked Column',\n 'column-stacked-100': '100% Stacked Column',\n bar: 'Clustered Bar',\n 'bar-stacked': 'Stacked Bar',\n 'bar-stacked-100': '100% Stacked Bar',\n line: 'Line',\n 'line-stacked': 'Stacked Line',\n area: 'Area',\n 'area-stacked': 'Stacked Area',\n pie: 'Pie',\n doughnut: 'Doughnut',\n scatter: 'Scatter',\n};\n\nexport type ChartModel = {\n id: string;\n /** Sheet the chart lives on. Matches `FWorksheet.getSheetId()`. */\n sheetId: string;\n /** Source data range — first row treated as header (column names),\n * first column as category axis labels. */\n source: { startRow: number; endRow: number; startColumn: number; endColumn: number };\n /** Chart position, in 0-indexed cell coordinates. */\n pos: { startRow: number; endRow: number; startColumn: number; endColumn: number };\n type: ChartType;\n /** Auto-generated \"Chart N\" name; the user can rename via the panel\n * or the right-click menu. Doubles as the chart title shown above\n * the plot when `format.showTitle` is true. */\n title?: string;\n /** Excel's \"Format Chart Area\" options — none required; absent\n * values fall back to the defaults documented in `defaultFormat`. */\n format?: ChartFormat;\n};\n\n/** Equivalent of Excel's \"Format Chart Area\" pane in scope. */\nexport type ChartFormat = {\n /** Render the chart title above the plot. Defaults to `true` when\n * the chart has a `title`, `false` otherwise. */\n showTitle?: boolean;\n /** Legend placement. `'none'` hides the legend entirely. */\n legend?: 'top' | 'right' | 'bottom' | 'left' | 'none';\n /** Optional axis titles. Ignored for pie / doughnut. */\n xAxisTitle?: string;\n yAxisTitle?: string;\n /** Show major gridlines on the value axis. */\n gridlines?: boolean;\n /** Show numeric labels on bars / lines / slices. */\n dataLabels?: boolean;\n /** Color palette applied to the series. Mirrors Excel's \"Change\n * Colors\" picker — pick the first N from the chosen palette. */\n palette?: ChartPalette;\n /** Overlay a linear-regression trendline on every numeric series.\n * Only meaningful for line / scatter / area / bar / column charts;\n * ignored for pie. ECharts renders this via `markLine` from the\n * computed regression endpoints. */\n trendline?: boolean;\n /** Per-series colour overrides, keyed by series name (the header\n * row in the source range). Missing entries fall back to the\n * active `palette`. Stored on the resource so the override\n * survives reload + xlsx round-trip via the chart's `format`\n * payload. */\n seriesColors?: Record<string, string>;\n /** Combo charts: per-series render-kind override, keyed by series\n * name. Lets a column/bar/line/area chart mix bar + line series\n * (Excel's \"Combo\" chart type). Missing entries fall back to the\n * chart's base `type`. Only `'bar'` and `'line'` are offered; pie /\n * doughnut / scatter / 100%-stacked ignore this. */\n seriesTypes?: Record<string, 'bar' | 'line'>;\n /** Dual axis: when a series name maps to `true`, that series is\n * plotted against a secondary value axis (Excel's \"Secondary Axis\"\n * checkbox in the Format Data Series pane). The chart then renders\n * with two value axes — primary on the left, secondary on the\n * right. Only meaningful for the bar / column / line / area\n * families; ignored by pie / doughnut / scatter / 100%-stacked\n * (a shared 0–100% scale defeats the purpose). */\n secondaryAxis?: Record<string, boolean>;\n};\n\nexport type ChartPalette = 'office' | 'mono' | 'vivid' | 'pastel';\n\n/** Resolved (filled-in) format used by build-option. Apply over the\n * user's partial via `mergeFormat`. */\nexport type ResolvedChartFormat = Required<Omit<ChartFormat, 'xAxisTitle' | 'yAxisTitle'>> & {\n xAxisTitle?: string;\n yAxisTitle?: string;\n};\n\nexport function defaultFormat(model: Pick<ChartModel, 'title'>): ResolvedChartFormat {\n return {\n showTitle: Boolean(model.title),\n legend: 'bottom',\n gridlines: true,\n dataLabels: false,\n palette: 'office',\n trendline: false,\n seriesColors: {},\n seriesTypes: {},\n secondaryAxis: {},\n };\n}\n\nexport function mergeFormat(model: Pick<ChartModel, 'title' | 'format'>): ResolvedChartFormat {\n const base = defaultFormat(model);\n const f = model.format ?? {};\n return {\n showTitle: f.showTitle ?? base.showTitle,\n legend: f.legend ?? base.legend,\n gridlines: f.gridlines ?? base.gridlines,\n dataLabels: f.dataLabels ?? base.dataLabels,\n palette: f.palette ?? base.palette,\n trendline: f.trendline ?? base.trendline,\n seriesColors: f.seriesColors ?? base.seriesColors,\n seriesTypes: f.seriesTypes ?? base.seriesTypes,\n secondaryAxis: f.secondaryAxis ?? base.secondaryAxis,\n xAxisTitle: f.xAxisTitle,\n yAxisTitle: f.yAxisTitle,\n };\n}\n\n/** Palette colours, applied in order to the series. Picked to match\n * Excel's default colour sets so the look stays familiar. */\nexport const PALETTES: Record<ChartPalette, string[]> = {\n office: ['#5B9BD5', '#ED7D31', '#A5A5A5', '#FFC000', '#4472C4', '#70AD47', '#264478', '#9E480E'],\n mono: ['#1F77B4', '#3F8FBC', '#5FA7C5', '#7FBFCD', '#9FD7D6', '#BFEFDE', '#5A8DAA', '#3D6E89'],\n vivid: ['#E63946', '#F1A208', '#06A77D', '#005F73', '#9B5DE5', '#F15BB5', '#00BBF9', '#00F5D4'],\n pastel: ['#A3CEF1', '#FFD6A5', '#CAFFBF', '#FFADAD', '#BDB2FF', '#FDFFB6', '#FFC6FF', '#9BF6FF'],\n};\n\nexport const PALETTE_LABELS: Record<ChartPalette, string> = {\n office: 'Office',\n mono: 'Monochromatic',\n vivid: 'Vivid',\n pastel: 'Pastel',\n};\n\nexport const LEGEND_POSITIONS: { id: NonNullable<ChartFormat['legend']>; label: string }[] = [\n { id: 'bottom', label: 'Bottom' },\n { id: 'top', label: 'Top' },\n { id: 'right', label: 'Right' },\n { id: 'left', label: 'Left' },\n { id: 'none', label: 'None' },\n];\n\nexport function newChartId(): string {\n return `ch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n}\n\n/**\n * Plugin-resource name we use when stashing chart models in\n * `IWorkbookData.resources`. Mirrors `OUTLINE_RESOURCE_NAME` — survives\n * xlsx via the hidden `__casual_sheets_resources__` sheet and survives\n * collab via Univer's snapshot-load path.\n */\nexport const CHARTS_RESOURCE_NAME = '__casual_sheets_charts__';\n\n/** Versioned envelope so a future schema change can be detected. */\nexport type ChartsResourceV1 = {\n v: 1;\n charts: ChartModel[];\n};\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { IWorkbookData } from '@univerjs/core';\nimport {\n CHARTS_RESOURCE_NAME,\n type ChartModel,\n type ChartsResourceV1,\n type ChartType,\n} from './types';\n\n/**\n * Round-trip helpers for the charts plugin resource. The resource lives on\n * `IWorkbookData.resources` and is carried through xlsx via the hidden\n * `__casual_sheets_resources__` sheet we already use for outline groups,\n * and through collab via Univer's snapshot-load path.\n */\n\nconst VALID_TYPES: ChartType[] = [\n 'column',\n 'column-stacked',\n 'column-stacked-100',\n 'bar',\n 'bar-stacked',\n 'bar-stacked-100',\n 'line',\n 'line-stacked',\n 'area',\n 'area-stacked',\n 'pie',\n 'doughnut',\n 'scatter',\n];\n\n/**\n * The pre-P3 store used `'bar'` for what we now (correctly) call\n * `'column'` — vertical bars. Migrate on read so existing workbooks\n * keep rendering after the rename.\n */\nfunction migrateType(raw: unknown): ChartType | null {\n if (typeof raw !== 'string') return null;\n // Existing 'bar' string is ambiguous between old \"vertical column\"\n // and new \"horizontal bar\". P0/P1/P2 saved 'bar' meaning column;\n // we have no horizontal-bar charts in the wild yet, so 'bar' from\n // before P3 means column.\n if (raw === 'bar') return 'column';\n return VALID_TYPES.includes(raw as ChartType) ? (raw as ChartType) : null;\n}\n\nfunction isValidChart(c: unknown): c is ChartModel {\n if (!c || typeof c !== 'object') return false;\n const r = c as Record<string, unknown>;\n if (typeof r.id !== 'string' || typeof r.sheetId !== 'string') return false;\n const migrated = migrateType(r.type);\n if (!migrated) return false;\n r.type = migrated; // mutate so the rest of the app sees the new value\n const src = r.source as Record<string, unknown> | undefined;\n const pos = r.pos as Record<string, unknown> | undefined;\n if (!src || !pos) return false;\n for (const k of ['startRow', 'endRow', 'startColumn', 'endColumn'] as const) {\n if (typeof src[k] !== 'number' || typeof pos[k] !== 'number') return false;\n }\n // `format` is optional and freely shaped — defer validation to\n // `mergeFormat`, which fills missing fields with defaults. Anything\n // we don't recognise is ignored at render time.\n if (r.format != null && typeof r.format !== 'object') return false;\n return true;\n}\n\n/** Read chart models out of a snapshot. Tolerant of older / missing payloads. */\nexport function readChartsFromSnapshot(data: IWorkbookData | undefined): ChartModel[] {\n if (!data?.resources?.length) return [];\n const entry = data.resources.find((r) => r.name === CHARTS_RESOURCE_NAME);\n if (!entry?.data) return [];\n try {\n const parsed = JSON.parse(entry.data) as Partial<ChartsResourceV1>;\n if (parsed?.v !== 1 || !Array.isArray(parsed.charts)) return [];\n return parsed.charts.filter(isValidChart);\n } catch {\n /* corrupt payload — drop silently, the workbook still opens fine */\n return [];\n }\n}\n\n/** Merge chart models INTO `data.resources` for export. Mutates in place. */\nexport function writeChartsIntoSnapshot(data: IWorkbookData, charts: ChartModel[]): void {\n const existing = data.resources ?? [];\n const filtered = existing.filter((r) => r.name !== CHARTS_RESOURCE_NAME);\n if (charts.length === 0) {\n data.resources = filtered;\n return;\n }\n const payload: ChartsResourceV1 = { v: 1, charts };\n data.resources = [...filtered, { name: CHARTS_RESOURCE_NAME, data: JSON.stringify(payload) }];\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport type { CasualSheetsAPI } from '../sheets/api';\nimport { readChartsFromSnapshot, writeChartsIntoSnapshot } from './resources';\nimport type { ChartModel } from './types';\n\n/**\n * Chart store mirrored into `IWorkbookData.resources['__casual_sheets_charts__']`\n * at save time and re-hydrated when the active workbook changes. The store\n * keeps charts keyed by id (`ChartModel.id`); removal by id, updates by\n * replace — every change produces a new model object so React effect deps\n * work for downstream consumers (ChartLayer, ChartOverlay).\n *\n * SDK port: the app read/wrote the store through the hidden xlsx pre-pass +\n * `useWorkbook()` revision tracking. Here the store is loaded on mount and\n * persisted on every local change through the SDK's `api.getContent()` /\n * `api.setContent()` (which serialize/replace the active `IWorkbookData`).\n * `api` is also re-exported via `useCharts()` so downstream chart components\n * reach the FUniver facade through `api.univer` instead of a React hook.\n */\ntype ChartsCtxValue = {\n /** The SDK editor handle — chart components reach the FUniver facade via\n * `api.univer` (never a React `useUniverAPI` hook, which doesn't exist in\n * the SDK). */\n api: CasualSheetsAPI;\n charts: ChartModel[];\n /** Id of the chart with the selection frame + handles drawn. At most\n * one chart is selected at a time (Excel single-select; multi-select\n * via Ctrl+click is not implemented yet). */\n selectedId: string | null;\n insert: (chart: ChartModel) => void;\n remove: (id: string) => void;\n update: (id: string, patch: Partial<ChartModel>) => void;\n select: (id: string | null) => void;\n /** Replace the entire chart list. Used by CollabDriver to apply\n * remote chart-state updates from the Yjs sync map. App code should\n * prefer `insert / remove / update` — `__replaceAll` bypasses the\n * collab broadcast tag, so consecutive calls from outside the\n * collab driver can clobber each other. */\n __replaceAll: (next: ChartModel[], opts?: { fromCollab?: boolean }) => void;\n /** Subscribe to LOCAL chart-list changes (insert / remove / update,\n * excluding remote echoes from `__replaceAll({ fromCollab: true })`).\n * CollabDriver uses this to push our edits into the Yjs map without\n * echoing them back. Returns an unsubscribe. */\n __subscribeLocal: (cb: (charts: ChartModel[]) => void) => () => void;\n};\n\nexport const ChartsContext = createContext<ChartsCtxValue | null>(null);\n\nexport function useCharts(): ChartsCtxValue {\n const ctx = useContext(ChartsContext);\n if (!ctx) throw new Error('useCharts must be used inside <ChartsProvider>');\n return ctx;\n}\n\nexport function ChartsProvider({ api, children }: { api: CasualSheetsAPI; children: ReactNode }) {\n const [charts, setCharts] = useState<ChartModel[]>(() =>\n readChartsFromSnapshot(api.getContent() ?? undefined),\n );\n const [selectedId, setSelectedId] = useState<string | null>(null);\n // Local change subscribers (used by CollabDriver to push to Yjs).\n // Stored on a ref so the subscribe API is stable across renders.\n const subsRef = useRef<Set<(c: ChartModel[]) => void>>(new Set());\n const notifyLocal = useCallback((next: ChartModel[]) => {\n for (const cb of subsRef.current) cb(next);\n }, []);\n\n // Persist the chart list into the active workbook snapshot on every local\n // change. Mirrors the app's write-into-resources pre-pass, but driven\n // through the SDK content accessors. Guarded by `persistingRef` so the\n // `setContent` round-trip we trigger here doesn't bounce back through the\n // `change` re-hydrate below as a phantom remote update.\n const persistingRef = useRef(false);\n const persist = useCallback(\n (next: ChartModel[]) => {\n const snap = api.getContent();\n if (!snap) return;\n writeChartsIntoSnapshot(snap, next);\n persistingRef.current = true;\n try {\n api.setContent(snap);\n } finally {\n persistingRef.current = false;\n }\n },\n [api],\n );\n\n // Re-hydrate on external content swaps (Open / New / collab remote-snapshot).\n // The app keyed this off `useWorkbook().meta.revision`; the SDK surfaces the\n // same signal as the `change` event carrying a fresh `IWorkbookData`. Skip\n // the echo from our own `persist()` setContent so a local edit doesn't wipe\n // the selection / re-read what we just wrote.\n useEffect(() => {\n const off = api.on('change', (snapshot) => {\n if (persistingRef.current) return;\n setCharts(readChartsFromSnapshot(snapshot));\n setSelectedId(null);\n });\n return off;\n }, [api]);\n\n const insert = useCallback(\n (chart: ChartModel) => {\n setCharts((prev) => {\n const next = [...prev, chart];\n notifyLocal(next);\n persist(next);\n return next;\n });\n },\n [notifyLocal, persist],\n );\n\n const remove = useCallback(\n (id: string) => {\n setCharts((prev) => {\n const next = prev.filter((c) => c.id !== id);\n notifyLocal(next);\n persist(next);\n return next;\n });\n setSelectedId((cur) => (cur === id ? null : cur));\n },\n [notifyLocal, persist],\n );\n\n const update = useCallback(\n (id: string, patch: Partial<ChartModel>) => {\n setCharts((prev) => {\n const next = prev.map((c) => (c.id === id ? { ...c, ...patch } : c));\n notifyLocal(next);\n persist(next);\n return next;\n });\n },\n [notifyLocal, persist],\n );\n\n const select = useCallback((id: string | null) => {\n setSelectedId(id);\n }, []);\n\n const __replaceAll = useCallback(\n (next: ChartModel[], opts?: { fromCollab?: boolean }) => {\n setCharts(next);\n // Drop the selection if its chart no longer exists in the new list\n // (a peer deleted it).\n setSelectedId((cur) => (cur && next.some((c) => c.id === cur) ? cur : null));\n if (!opts?.fromCollab) {\n notifyLocal(next);\n persist(next);\n }\n },\n [notifyLocal, persist],\n );\n\n const __subscribeLocal = useCallback((cb: (charts: ChartModel[]) => void) => {\n subsRef.current.add(cb);\n return () => {\n subsRef.current.delete(cb);\n };\n }, []);\n\n const value = useMemo<ChartsCtxValue>(\n () => ({\n api,\n charts,\n selectedId,\n insert,\n remove,\n update,\n select,\n __replaceAll,\n __subscribeLocal,\n }),\n [api, charts, selectedId, insert, remove, update, select, __replaceAll, __subscribeLocal],\n );\n\n return <ChartsContext.Provider value={value}>{children}</ChartsContext.Provider>;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FUniver } from '@univerjs/core/facade';\nimport type { ChartType, ChartModel } from './types';\nimport { newChartId } from './types';\n\ntype Range = { startRow: number; endRow: number; startColumn: number; endColumn: number };\n\n/**\n * Build a ChartModel for `source` on the active sheet. The chart anchors\n * to a 10-row × 8-col block placed two rows below the source so it doesn't\n * cover its own data. Mirrors Excel's Insert > Chart defaults — source =\n * the dialog's selection, output = roughly the right size, dropped below.\n *\n * Returns null when there's no active workbook/sheet, or the range has\n * fewer than 2 rows × 2 cols (no header + data row, or no label + value\n * column).\n */\nexport function buildChartModelForRange(\n api: FUniver,\n source: Range,\n type: ChartType,\n): ChartModel | null {\n const wb = api.getActiveWorkbook();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws = wb?.getActiveSheet() as any;\n if (!wb || !ws) return null;\n\n const rows = source.endRow - source.startRow + 1;\n const cols = source.endColumn - source.startColumn + 1;\n if (rows < 2 || cols < 2) return null;\n\n const chartTop = source.endRow + 2;\n const chartLeft = source.startColumn;\n return {\n id: newChartId(),\n sheetId: ws.getSheetId(),\n source,\n pos: {\n startRow: chartTop,\n endRow: chartTop + 9,\n startColumn: chartLeft,\n endColumn: chartLeft + 7,\n },\n type,\n };\n}\n\n/**\n * Read the active selection on the active sheet. Returns null if no\n * workbook / sheet / selection is available — the menu item is enabled\n * unconditionally, so the caller still has to handle the empty case.\n */\nexport function getActiveSelectionRange(api: FUniver): Range | null {\n const wb = api.getActiveWorkbook();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws = wb?.getActiveSheet() as any;\n const range = ws?.getActiveRange();\n if (!wb || !ws || !range) return null;\n const r = range.getRange();\n return {\n startRow: r.startRow,\n endRow: r.endRow,\n startColumn: r.startColumn,\n endColumn: r.endColumn,\n };\n}\n\n/**\n * Format a cell range as an A1-style reference (e.g. `A1:C4`). Used by\n * the insert dialog to pre-fill its source-range input from the current\n * selection so the common case is two clicks.\n */\nexport function rangeToA1(range: Range): string {\n const tl = `${colIndexToA1(range.startColumn)}${range.startRow + 1}`;\n if (range.startRow === range.endRow && range.startColumn === range.endColumn) {\n return tl;\n }\n const br = `${colIndexToA1(range.endColumn)}${range.endRow + 1}`;\n return `${tl}:${br}`;\n}\n\nfunction colIndexToA1(c: number): string {\n let n = c + 1;\n let s = '';\n while (n > 0) {\n const rem = (n - 1) % 26;\n s = String.fromCharCode(65 + rem) + s;\n n = Math.floor((n - 1) / 26);\n }\n return s;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { ChartModel } from './types';\n\n/**\n * Excel auto-names charts as \"Chart 1\", \"Chart 2\", ..., picking the\n * lowest unused suffix even if intermediate charts have been deleted\n * (so deleting Chart 2 then inserting again gives you Chart 2, not\n * Chart 4). Match that.\n *\n * Operates on `ChartModel.title` — see the Chart Selection Pane for\n * inline rename.\n */\nexport function nextChartName(existing: ChartModel[]): string {\n const used = new Set<number>();\n for (const c of existing) {\n if (!c.title) continue;\n const m = /^Chart (\\d+)$/.exec(c.title);\n if (m) used.add(Number(m[1]));\n }\n let n = 1;\n while (used.has(n)) n++;\n return `Chart ${n}`;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Dialog — the SDK chrome's modal primitive for `<CasualSheets chrome>`.\n *\n * Ported from `apps/web/src/shell/Dialog.tsx`, but decoupled from the app: it\n * uses ONLY React + the chrome's `--cs-chrome-*` token approach (inline styles\n * with DS-token-backed CSS-var fallbacks, the same pattern as FindReplace), so\n * it renders standalone and themes light/dark via the `data-theme` wrapper\n * `<CasualSheets>` already sets. No app CSS classes, no app context.\n *\n * - Click-backdrop and Escape close it.\n * - Body scroll is locked while open.\n * - Focus is trapped (Tab/Shift+Tab cycle within the dialog) and restored to\n * the opener on close — the WAI-ARIA dialog pattern.\n * - Portaled to `document.body` so it escapes the chrome's stacking contexts\n * and the Univer canvas can't intercept clicks meant for the dialog.\n */\n\nimport { useEffect, useRef, type CSSProperties, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Icon } from './Icon';\n\nexport interface DialogProps {\n /** Heading shown in the dialog header. */\n title: string;\n /** Close request (backdrop click, Escape, the × button, or a footer action). */\n onClose: () => void;\n /** Optional footer node — typically Cancel / primary-action buttons. */\n footer?: ReactNode;\n children: ReactNode;\n /** Max width of the dialog card. Default 460. */\n width?: number;\n ['data-testid']?: string;\n}\n\nconst FOCUSABLE_SELECTOR =\n 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]';\n\nconst BACKDROP_STYLE: CSSProperties = {\n position: 'fixed',\n inset: 0,\n zIndex: 1200,\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'center',\n padding: '8vh 16px 16px',\n background: 'rgba(15, 23, 42, 0.35)',\n overflow: 'auto',\n};\n\nconst CARD_STYLE: CSSProperties = {\n width: '100%',\n background: 'var(--cs-chrome-input-bg, #ffffff)',\n color: 'var(--cs-chrome-fg, #201f1e)',\n borderRadius: 10,\n border: '1px solid var(--cs-chrome-border, #e6e9ee)',\n boxShadow: '0 18px 48px rgba(0, 0, 0, 0.28)',\n font: 'inherit',\n fontSize: 13,\n display: 'flex',\n flexDirection: 'column',\n maxHeight: '84vh',\n};\n\nconst HEADER_STYLE: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n padding: '12px 16px',\n borderBottom: '1px solid var(--cs-chrome-border, #edeff3)',\n};\n\nconst TITLE_STYLE: CSSProperties = {\n margin: 0,\n fontSize: 15,\n fontWeight: 600,\n color: 'var(--cs-chrome-fg, #201f1e)',\n};\n\nconst CLOSE_STYLE: CSSProperties = {\n width: 28,\n height: 28,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: 'none',\n borderRadius: 6,\n background: 'transparent',\n color: 'var(--cs-chrome-muted, #605e5c)',\n cursor: 'pointer',\n padding: 0,\n};\n\nconst BODY_STYLE: CSSProperties = {\n padding: 16,\n overflow: 'auto',\n};\n\nconst FOOTER_STYLE: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n gap: 8,\n padding: '12px 16px',\n borderTop: '1px solid var(--cs-chrome-border, #edeff3)',\n};\n\nexport function Dialog({ title, onClose, footer, children, width = 460, ...rest }: DialogProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const openerRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n // Remember who had focus before us so we can restore it on close.\n openerRef.current = (document.activeElement as HTMLElement) ?? null;\n\n // Lock body scroll; pad for the disappearing scrollbar so the grid doesn't\n // shift when the dialog opens.\n const prevOverflow = document.body.style.overflow;\n const prevPaddingRight = document.body.style.paddingRight;\n const scrollbarW = window.innerWidth - document.documentElement.clientWidth;\n document.body.style.overflow = 'hidden';\n if (scrollbarW > 0) document.body.style.paddingRight = `${scrollbarW}px`;\n\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onClose();\n return;\n }\n if (e.key !== 'Tab') return;\n const root = dialogRef.current;\n if (!root) return;\n const focusables = Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (el) => !el.hasAttribute('disabled') && el.offsetParent !== null,\n );\n if (focusables.length === 0) return;\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = document.activeElement as HTMLElement | null;\n if (e.shiftKey && (active === first || !root.contains(active))) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && (active === last || !root.contains(active))) {\n e.preventDefault();\n first.focus();\n }\n };\n document.addEventListener('keydown', onKey);\n\n const first = dialogRef.current?.querySelector<HTMLElement>(FOCUSABLE_SELECTOR);\n first?.focus();\n\n return () => {\n document.removeEventListener('keydown', onKey);\n document.body.style.overflow = prevOverflow;\n document.body.style.paddingRight = prevPaddingRight;\n const opener = openerRef.current;\n if (opener && document.contains(opener)) opener.focus();\n };\n }, [onClose]);\n\n return createPortal(\n <div\n style={BACKDROP_STYLE}\n data-testid=\"cs-dialog-backdrop\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n >\n <div\n style={{ ...CARD_STYLE, maxWidth: width }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n ref={dialogRef}\n data-testid={rest['data-testid']}\n >\n <div style={HEADER_STYLE}>\n <h2 style={TITLE_STYLE}>{title}</h2>\n <button\n type=\"button\"\n style={CLOSE_STYLE}\n data-testid=\"cs-dialog-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n <Icon name=\"close\" size={18} />\n </button>\n </div>\n <div style={BODY_STYLE}>{children}</div>\n {footer && <div style={FOOTER_STYLE}>{footer}</div>}\n </div>\n </div>,\n document.body,\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useRef, useState, type ReactElement } from 'react';\nimport { Dialog } from '../chrome/Dialog';\nimport type { FUniver } from '@univerjs/core/facade';\nimport { CHART_FAMILY_OF, CHART_TYPE_LABEL, type ChartFamily, type ChartType } from './types';\n\ntype Props = {\n api: FUniver;\n /** A1 reference to seed the source-range input. Pulled from the active\n * selection by the caller so the dialog opens already filled in. */\n defaultSourceA1: string;\n /** Pre-selected chart type. Defaults to `'column'` (Excel's\n * Insert > Chart default — Clustered Column). Set to the chart's\n * current type when used for \"Change chart type\". */\n initialType?: ChartType;\n /** Dialog title — defaults to \"Insert chart\". */\n title?: string;\n /** Primary action label — defaults to \"Insert\". */\n confirmLabel?: string;\n onCancel: () => void;\n onConfirm: (args: {\n source: { startRow: number; endRow: number; startColumn: number; endColumn: number };\n type: ChartType;\n }) => void;\n};\n\ntype FamilyDef = {\n id: ChartFamily;\n label: string;\n icon: string;\n subtypes: { id: ChartType; label: string }[];\n};\n\n/**\n * Excel chart catalog, family + subtype hierarchy. Order mirrors\n * Excel's Insert > Chart panel so muscle memory transfers.\n */\nconst FAMILIES: FamilyDef[] = [\n {\n id: 'column',\n label: 'Column',\n icon: 'bar_chart',\n subtypes: [\n { id: 'column', label: CHART_TYPE_LABEL.column },\n { id: 'column-stacked', label: CHART_TYPE_LABEL['column-stacked'] },\n { id: 'column-stacked-100', label: CHART_TYPE_LABEL['column-stacked-100'] },\n ],\n },\n {\n id: 'bar',\n label: 'Bar',\n icon: 'align_horizontal_left',\n subtypes: [\n { id: 'bar', label: CHART_TYPE_LABEL.bar },\n { id: 'bar-stacked', label: CHART_TYPE_LABEL['bar-stacked'] },\n { id: 'bar-stacked-100', label: CHART_TYPE_LABEL['bar-stacked-100'] },\n ],\n },\n {\n id: 'line',\n label: 'Line',\n icon: 'show_chart',\n subtypes: [\n { id: 'line', label: CHART_TYPE_LABEL.line },\n { id: 'line-stacked', label: CHART_TYPE_LABEL['line-stacked'] },\n ],\n },\n {\n id: 'area',\n label: 'Area',\n icon: 'area_chart',\n subtypes: [\n { id: 'area', label: CHART_TYPE_LABEL.area },\n { id: 'area-stacked', label: CHART_TYPE_LABEL['area-stacked'] },\n ],\n },\n {\n id: 'pie',\n label: 'Pie',\n icon: 'pie_chart',\n subtypes: [\n { id: 'pie', label: CHART_TYPE_LABEL.pie },\n { id: 'doughnut', label: CHART_TYPE_LABEL.doughnut },\n ],\n },\n {\n id: 'scatter',\n label: 'Scatter',\n icon: 'scatter_plot',\n subtypes: [{ id: 'scatter', label: CHART_TYPE_LABEL.scatter }],\n },\n];\n\n/**\n * Excel-style \"Insert chart\" dialog. Two-panel layout:\n *\n * - Left: family list (Column / Bar / Line / Area / Pie / Scatter).\n * Clicking switches the visible subtypes.\n * - Right top: subtype thumbnails with hover-to-preview labels.\n * - Right bottom: source-range input, pre-filled from the active\n * selection so the typical flow is two clicks.\n *\n * Range parsing leans on `sheet.getRange(a1)` — same A1 parser as the\n * Name Box — so anything the formula bar accepts works here too\n * (B5, A1:C4, B:B). Below 2 rows × 2 cols we refuse with an inline\n * hint instead of producing an empty chart.\n */\nexport function InsertChartDialog({\n api,\n defaultSourceA1,\n initialType = 'column',\n title = 'Insert chart',\n confirmLabel = 'Insert',\n onCancel,\n onConfirm,\n}: Props) {\n const [type, setType] = useState<ChartType>(initialType);\n const [family, setFamily] = useState<ChartFamily>(CHART_FAMILY_OF[initialType]);\n const [sourceA1, setSourceA1] = useState(defaultSourceA1);\n const [error, setError] = useState<string | null>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const activeSheet = useMemo(() => {\n const wb = api.getActiveWorkbook();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return wb?.getActiveSheet() as any;\n }, [api]);\n\n const currentFamily = FAMILIES.find((f) => f.id === family) ?? FAMILIES[0];\n\n const pickFamily = (id: ChartFamily) => {\n setFamily(id);\n const fam = FAMILIES.find((f) => f.id === id);\n if (fam && !fam.subtypes.some((s) => s.id === type)) {\n // Switched family — pick its first subtype.\n setType(fam.subtypes[0].id);\n }\n };\n\n const confirm = () => {\n const trimmed = sourceA1.trim();\n if (!trimmed) {\n setError('Pick a source range.');\n inputRef.current?.focus();\n return;\n }\n let range: { startRow: number; endRow: number; startColumn: number; endColumn: number } | null =\n null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const r = activeSheet?.getRange(trimmed) as any;\n const raw = r?.getRange?.();\n if (raw) {\n range = {\n startRow: raw.startRow,\n endRow: raw.endRow,\n startColumn: raw.startColumn,\n endColumn: raw.endColumn,\n };\n }\n } catch {\n /* fall through */\n }\n if (!range) {\n setError(\"That doesn't look like a valid range — try A1:C4.\");\n inputRef.current?.focus();\n return;\n }\n const rows = range.endRow - range.startRow + 1;\n const cols = range.endColumn - range.startColumn + 1;\n if (rows < 2 || cols < 2) {\n setError(\n 'Source needs at least a header row + a data row, and a label column + a value column.',\n );\n inputRef.current?.focus();\n return;\n }\n onConfirm({ source: range, type });\n };\n\n return (\n <Dialog\n title={title}\n onClose={onCancel}\n data-testid=\"insert-chart-dialog\"\n footer={\n <>\n <button\n type=\"button\"\n className=\"btn-secondary\"\n data-testid=\"insert-chart-cancel\"\n onClick={onCancel}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn-primary\"\n data-testid=\"insert-chart-confirm\"\n onClick={confirm}\n >\n {confirmLabel}\n </button>\n </>\n }\n >\n <div className=\"insert-chart\">\n <div className=\"insert-chart__catalog\">\n <ul\n className=\"insert-chart__families\"\n role=\"tablist\"\n aria-label=\"Chart family\"\n data-testid=\"insert-chart-families\"\n >\n {FAMILIES.map((f) => (\n <li key={f.id}>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={family === f.id}\n className={`insert-chart__family${family === f.id ? ' insert-chart__family--active' : ''}`}\n data-testid={`insert-chart-family-${f.id}`}\n onClick={() => pickFamily(f.id)}\n >\n <span className=\"material-symbols-outlined\" aria-hidden=\"true\">\n {f.icon}\n </span>\n <span>{f.label}</span>\n </button>\n </li>\n ))}\n </ul>\n <div className=\"insert-chart__subtypes\" role=\"radiogroup\" aria-label=\"Chart subtype\">\n {currentFamily.subtypes.map((s) => (\n <label\n key={s.id}\n className={`insert-chart__subtype${type === s.id ? ' insert-chart__subtype--active' : ''}`}\n data-testid={`insert-chart-type-${s.id}`}\n title={s.label}\n >\n <input\n type=\"radio\"\n name=\"chart-subtype\"\n value={s.id}\n checked={type === s.id}\n onChange={() => setType(s.id)}\n />\n <SubtypeThumbnail type={s.id} />\n <span className=\"insert-chart__subtype-label\">{s.label}</span>\n </label>\n ))}\n </div>\n </div>\n\n <fieldset className=\"insert-chart__group\">\n <legend className=\"insert-chart__legend\">Source data</legend>\n {/* Error elevates ABOVE the input so the user's eye lands\n on it before the field they're correcting. The previous\n \"small red text below the input\" layout was easy to\n miss (audit finding 1.2); a proper banner with icon +\n role=alert + aria-live=assertive makes it impossible\n to skip. Screen readers announce on appearance. */}\n {error && (\n <div\n className=\"insert-chart__error\"\n data-testid=\"insert-chart-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <span className=\"insert-chart__error-icon\" aria-hidden=\"true\">\n !\n </span>\n <span>{error}</span>\n </div>\n )}\n <input\n ref={inputRef}\n type=\"text\"\n className={`insert-chart__range${error ? ' insert-chart__range--error' : ''}`}\n data-testid=\"insert-chart-range\"\n value={sourceA1}\n spellCheck={false}\n aria-invalid={Boolean(error)}\n aria-describedby={error ? 'insert-chart-error-desc' : undefined}\n onChange={(e) => {\n setSourceA1(e.target.value);\n if (error) setError(null);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n confirm();\n }\n }}\n placeholder=\"A1:C4\"\n />\n <p className=\"insert-chart__hint\" id=\"insert-chart-error-desc\">\n First row is used as series labels and the first column as category labels — same\n convention as Excel's Insert > Chart.\n </p>\n </fieldset>\n </div>\n </Dialog>\n );\n}\n\n/**\n * Inline SVG thumbnail for each subtype. ECharts canvases would be\n * too heavy to mount one per option; small static SVGs read at a\n * glance and match the Excel preview tiles' role.\n */\nfunction SubtypeThumbnail({ type }: { type: ChartType }) {\n return (\n <svg\n className=\"insert-chart__thumb\"\n viewBox=\"0 0 60 40\"\n width={60}\n height={40}\n aria-hidden=\"true\"\n >\n {renderThumbBody(type)}\n </svg>\n );\n}\n\nfunction renderThumbBody(type: ChartType): ReactElement {\n const stroke = 'currentColor';\n switch (type) {\n case 'column':\n return (\n <g fill={stroke}>\n <rect x=\"6\" y=\"20\" width=\"6\" height=\"14\" />\n <rect x=\"16\" y=\"12\" width=\"6\" height=\"22\" />\n <rect x=\"26\" y=\"8\" width=\"6\" height=\"26\" />\n <rect x=\"36\" y=\"16\" width=\"6\" height=\"18\" />\n <rect x=\"46\" y=\"22\" width=\"6\" height=\"12\" />\n </g>\n );\n case 'column-stacked':\n return (\n <g>\n <rect x=\"10\" y=\"22\" width=\"10\" height=\"12\" fill={stroke} />\n <rect x=\"10\" y=\"12\" width=\"10\" height=\"10\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"26\" y=\"16\" width=\"10\" height=\"18\" fill={stroke} />\n <rect x=\"26\" y=\"8\" width=\"10\" height=\"8\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"42\" y=\"20\" width=\"10\" height=\"14\" fill={stroke} />\n <rect x=\"42\" y=\"10\" width=\"10\" height=\"10\" fill={stroke} opacity=\"0.6\" />\n </g>\n );\n case 'column-stacked-100':\n return (\n <g>\n <rect x=\"10\" y=\"20\" width=\"10\" height=\"14\" fill={stroke} />\n <rect x=\"10\" y=\"6\" width=\"10\" height=\"14\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"26\" y=\"14\" width=\"10\" height=\"20\" fill={stroke} />\n <rect x=\"26\" y=\"6\" width=\"10\" height=\"8\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"42\" y=\"24\" width=\"10\" height=\"10\" fill={stroke} />\n <rect x=\"42\" y=\"6\" width=\"10\" height=\"18\" fill={stroke} opacity=\"0.6\" />\n </g>\n );\n case 'bar':\n return (\n <g fill={stroke}>\n <rect x=\"6\" y=\"6\" width=\"22\" height=\"5\" />\n <rect x=\"6\" y=\"14\" width=\"36\" height=\"5\" />\n <rect x=\"6\" y=\"22\" width=\"48\" height=\"5\" />\n <rect x=\"6\" y=\"30\" width=\"28\" height=\"5\" />\n </g>\n );\n case 'bar-stacked':\n return (\n <g>\n <rect x=\"6\" y=\"10\" width=\"20\" height=\"6\" fill={stroke} />\n <rect x=\"26\" y=\"10\" width=\"16\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"6\" y=\"20\" width=\"14\" height=\"6\" fill={stroke} />\n <rect x=\"20\" y=\"20\" width=\"28\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"6\" y=\"30\" width=\"30\" height=\"6\" fill={stroke} />\n <rect x=\"36\" y=\"30\" width=\"14\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n </g>\n );\n case 'bar-stacked-100':\n return (\n <g>\n <rect x=\"6\" y=\"10\" width=\"28\" height=\"6\" fill={stroke} />\n <rect x=\"34\" y=\"10\" width=\"20\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"6\" y=\"20\" width=\"14\" height=\"6\" fill={stroke} />\n <rect x=\"20\" y=\"20\" width=\"34\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n <rect x=\"6\" y=\"30\" width=\"40\" height=\"6\" fill={stroke} />\n <rect x=\"46\" y=\"30\" width=\"8\" height=\"6\" fill={stroke} opacity=\"0.6\" />\n </g>\n );\n case 'line':\n return (\n <g fill=\"none\" stroke={stroke} strokeWidth=\"2\">\n <polyline points=\"6,30 18,18 30,24 42,10 54,16\" />\n <circle cx=\"6\" cy=\"30\" r=\"2\" fill={stroke} />\n <circle cx=\"18\" cy=\"18\" r=\"2\" fill={stroke} />\n <circle cx=\"30\" cy=\"24\" r=\"2\" fill={stroke} />\n <circle cx=\"42\" cy=\"10\" r=\"2\" fill={stroke} />\n <circle cx=\"54\" cy=\"16\" r=\"2\" fill={stroke} />\n </g>\n );\n case 'line-stacked':\n return (\n <g fill=\"none\" strokeWidth=\"2\">\n <polyline points=\"6,32 18,28 30,30 42,24 54,26\" stroke={stroke} />\n <polyline points=\"6,20 18,12 30,18 42,8 54,14\" stroke={stroke} opacity=\"0.6\" />\n </g>\n );\n case 'area':\n return (\n <g>\n <polygon points=\"6,34 6,24 18,14 30,18 42,8 54,12 54,34\" fill={stroke} opacity=\"0.4\" />\n <polyline\n points=\"6,24 18,14 30,18 42,8 54,12\"\n fill=\"none\"\n stroke={stroke}\n strokeWidth=\"2\"\n />\n </g>\n );\n case 'area-stacked':\n return (\n <g>\n <polygon points=\"6,34 6,24 18,18 30,22 42,16 54,20 54,34\" fill={stroke} opacity=\"0.6\" />\n <polygon\n points=\"6,24 18,18 30,22 42,16 54,20 54,12 42,6 30,12 18,8 6,14\"\n fill={stroke}\n opacity=\"0.3\"\n />\n </g>\n );\n case 'pie':\n return (\n <g>\n <circle cx=\"30\" cy=\"20\" r=\"14\" fill={stroke} opacity=\"0.4\" />\n <path d=\"M30 20 L30 6 A14 14 0 0 1 42 24 Z\" fill={stroke} />\n </g>\n );\n case 'doughnut':\n return (\n <g>\n <circle cx=\"30\" cy=\"20\" r=\"14\" fill={stroke} opacity=\"0.4\" />\n <path d=\"M30 20 L30 6 A14 14 0 0 1 42 24 Z\" fill={stroke} />\n <circle cx=\"30\" cy=\"20\" r=\"7\" fill=\"white\" />\n </g>\n );\n case 'scatter':\n return (\n <g fill={stroke}>\n <circle cx=\"10\" cy=\"30\" r=\"2\" />\n <circle cx=\"18\" cy=\"22\" r=\"2\" />\n <circle cx=\"24\" cy=\"26\" r=\"2\" />\n <circle cx=\"30\" cy=\"14\" r=\"2\" />\n <circle cx=\"36\" cy=\"20\" r=\"2\" />\n <circle cx=\"42\" cy=\"10\" r=\"2\" />\n <circle cx=\"48\" cy=\"16\" r=\"2\" />\n <circle cx=\"14\" cy=\"14\" r=\"2\" />\n <circle cx=\"50\" cy=\"28\" r=\"2\" />\n </g>\n );\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useState } from 'react';\nimport type { PanelComponentProps } from '../chrome/extensions';\nimport { Icon } from '../chrome/Icon';\nimport { PanelHeader, PanelEmpty, IconButton } from '../chrome/panel-shell';\n\nconst MUTED = 'var(--color-text-secondary, var(--cs-chrome-muted, #605e5c))';\nconst DIVIDER = 'var(--color-divider, var(--cs-chrome-border, #edeff3))';\nconst rowStyle = {\n border: `1px solid ${DIVIDER}`,\n borderRadius: 8,\n padding: 10,\n display: 'flex',\n flexDirection: 'column' as const,\n gap: 6,\n};\nconst nameBtnStyle = {\n flex: 1,\n textAlign: 'left' as const,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n font: 'inherit',\n fontWeight: 600,\n color: 'inherit',\n};\nconst ctaStyle = {\n border: `1px solid ${DIVIDER}`,\n borderRadius: 6,\n padding: '6px 12px',\n cursor: 'pointer',\n font: 'inherit',\n fontWeight: 600,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n background: 'var(--color-surface, var(--cs-chrome-input-bg, #fff))',\n color: 'var(--color-accent, var(--cs-chrome-active-fg, #0e7490))',\n};\nimport { useCharts } from './charts-context';\nimport { getActiveSelectionRange, rangeToA1, buildChartModelForRange } from './insert-chart';\nimport { nextChartName } from './naming';\nimport { InsertChartDialog } from './InsertChartDialog';\nimport { CHART_FAMILY_OF, CHART_TYPE_LABEL, type ChartFamily, type ChartModel } from './types';\n\n/**\n * Right-side Charts panel. Equivalent of Excel's Selection Pane scoped\n * to charts on the active sheet: list every chart, click the name to\n * rename, click the source-range badge to flash that range in the grid,\n * delete from the row, and \"Insert chart\" from the empty-state CTA.\n *\n * Only charts on the active sheet are shown — same scoping Excel uses\n * for its Selection Pane (it switches with the active sheet tab).\n *\n * SDK port: this is a chrome side-panel (`{ api, onClose }`). The app's\n * `useUI().toggleChartsPanel` becomes the panel host's `onClose`; the\n * FUniver facade is reached through `api.univer`. Chart data still comes\n * from `useCharts()` (mount `<ChartsProvider api={...}>` above the chrome).\n */\nconst FAMILY_ICONS: Record<ChartFamily, string> = {\n column: 'bar_chart',\n bar: 'align_horizontal_left',\n line: 'show_chart',\n area: 'area_chart',\n pie: 'pie_chart',\n scatter: 'scatter_plot',\n};\n\nexport function ChartsPanel({ api, onClose }: PanelComponentProps) {\n // FUniver facade — reached through the SDK handle.\n const univer = api.univer;\n const { charts, insert, remove, update } = useCharts();\n const [renaming, setRenaming] = useState<{ id: string; draft: string } | null>(null);\n const [showInsert, setShowInsert] = useState(false);\n const [insertDefault, setInsertDefault] = useState('A1');\n\n const activeSheetId = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws: any = univer?.getActiveWorkbook?.()?.getActiveSheet();\n return ws?.getSheetId?.() ?? null;\n }, [univer, charts]);\n\n const visible = useMemo<ChartModel[]>(\n () => (activeSheetId ? charts.filter((c) => c.sheetId === activeSheetId) : charts),\n [charts, activeSheetId],\n );\n const empty = visible.length === 0;\n\n const onRenameCommit = (id: string, prev: string) => {\n if (!renaming || renaming.id !== id) return;\n const draft = renaming.draft.trim();\n if (!draft || draft === prev) {\n setRenaming(null);\n return;\n }\n update(id, { title: draft });\n setRenaming(null);\n };\n\n const openInsert = () => {\n if (!univer) return;\n const sel = getActiveSelectionRange(univer);\n setInsertDefault(sel ? rangeToA1(sel) : 'A1');\n setShowInsert(true);\n };\n\n return (\n <div data-testid=\"charts-panel\" style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>\n <PanelHeader icon=\"bar_chart\" title=\"Charts\" count={visible.length} onClose={onClose} />\n <div style={{ flex: 1, overflow: 'auto', padding: 12 }}>\n {empty ? (\n <PanelEmpty icon=\"bar_chart\" title=\"No charts on this sheet\" testId=\"charts-panel-empty\">\n Select the data range you want to plot, then use <strong>Insert → Chart</strong> — or:\n <div style={{ marginTop: 12 }}>\n <button\n type=\"button\"\n data-testid=\"charts-panel-empty-cta\"\n disabled={!univer}\n onClick={openInsert}\n style={ctaStyle}\n >\n <Icon name=\"add\" size={16} /> Insert chart\n </button>\n </div>\n </PanelEmpty>\n ) : (\n <ul\n style={{\n listStyle: 'none',\n margin: 0,\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n }}\n >\n {visible.map((c) => {\n const isRenaming = renaming?.id === c.id;\n const displayName = c.title ?? 'Chart';\n return (\n <li key={c.id} data-testid={`charts-panel-row-${c.id}`} style={rowStyle}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span\n className=\"material-symbols-outlined\"\n aria-hidden=\"true\"\n style={{ fontSize: 18, color: MUTED, flex: '0 0 auto' }}\n >\n {FAMILY_ICONS[CHART_FAMILY_OF[c.type]]}\n </span>\n {isRenaming ? (\n <input\n autoFocus\n value={renaming.draft}\n onChange={(e) => setRenaming({ id: c.id, draft: e.target.value })}\n onBlur={() => onRenameCommit(c.id, displayName)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onRenameCommit(c.id, displayName);\n if (e.key === 'Escape') setRenaming(null);\n }}\n style={{ flex: 1, font: 'inherit', padding: '2px 4px' }}\n />\n ) : (\n <button\n type=\"button\"\n onClick={() => setRenaming({ id: c.id, draft: displayName })}\n title=\"Click to rename\"\n style={nameBtnStyle}\n >\n {displayName}\n </button>\n )}\n <IconButton\n name=\"delete\"\n label={`Delete ${displayName}`}\n onClick={() => remove(c.id)}\n size={16}\n />\n </div>\n <div style={{ display: 'flex', gap: 8, fontSize: 12, color: MUTED }}>\n <span>{CHART_TYPE_LABEL[c.type]}</span>\n <span title=\"Source range\">{rangeToA1(c.source)}</span>\n </div>\n </li>\n );\n })}\n <li style={{ listStyle: 'none', marginTop: 4 }}>\n <button\n type=\"button\"\n data-testid=\"charts-panel-add\"\n disabled={!univer}\n onClick={openInsert}\n style={ctaStyle}\n >\n <Icon name=\"add\" size={16} /> Insert chart\n </button>\n </li>\n </ul>\n )}\n </div>\n\n {showInsert && univer && (\n <InsertChartDialog\n api={univer}\n defaultSourceA1={insertDefault}\n onCancel={() => setShowInsert(false)}\n onConfirm={({ source, type }) => {\n const model = buildChartModelForRange(univer, source, type);\n if (model) {\n insert({ ...model, title: nextChartName(charts) });\n }\n setShowInsert(false);\n }}\n />\n )}\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Helpers for reaching into Univer's mounted DOM. Internal Univer DOM\n * identifiers are not part of the public API and have shifted between\n * minor versions — centralise the selectors here so a Univer upgrade\n * needs one fix instead of touching every overlay that anchors to the\n * canvas (PresenceLayer, ChartLayer, future drawing/comment overlays).\n *\n * Every helper falls back to a structural query and warns once if it\n * had to use the fallback, so a silent overlay-disappears regression\n * surfaces in the console instead of looking like a sync bug.\n */\n\nimport type { FUniver } from '@univerjs/core/facade';\n\nconst PRIMARY_CANVAS_SELECTOR = 'canvas[id^=\"univer-sheet-main-canvas_\"]';\n/** Univer mounts a hidden formula-editor canvas BEFORE the main grid\n * canvas. That one has no id, sits with width/height = 0, and is\n * useless to anchor overlays to. The fallback path must explicitly\n * skip it — picking it caused PresenceLayer / ChartLayer to render\n * cursors at the wrong position whenever the primary selector raced\n * the main-canvas mount. */\nlet fallbackWarned = false;\n\nexport function getUniverHost(): HTMLElement | null {\n return document.querySelector('[data-testid=\"univer-host\"]') as HTMLElement | null;\n}\n\nexport function getUniverMainCanvas(host: HTMLElement): HTMLCanvasElement | null {\n const primary = host.querySelector(PRIMARY_CANVAS_SELECTOR) as HTMLCanvasElement | null;\n if (primary) return primary;\n // Walk all canvases and pick the first one that LOOKS like the main\n // grid: has a non-empty id AND a non-zero rendered size. Editor\n // canvases have empty ids and 0x0 boxes until focused. We refuse to\n // return any of those — better to render no overlay than to anchor\n // it to a hidden offscreen canvas.\n const all = Array.from(host.querySelectorAll('canvas')) as HTMLCanvasElement[];\n for (const c of all) {\n if (!c.id) continue;\n const r = c.getBoundingClientRect();\n if (r.width < 50 || r.height < 50) continue;\n if (!fallbackWarned) {\n fallbackWarned = true;\n console.warn(\n '[univer-dom] primary canvas selector \"%s\" matched nothing — using fallback id \"%s\". Update PRIMARY_CANVAS_SELECTOR after a Univer upgrade.',\n PRIMARY_CANVAS_SELECTOR,\n c.id,\n );\n }\n return c;\n }\n return null;\n}\n\n/**\n * Pixel offset between the canvas top-left and the cell-content area's\n * top-left — i.e. the row-header gutter width and the column-header\n * gutter height. Every overlay that anchors to `getCellRect()`\n * coordinates must add these to land on the actual cells instead of\n * ~40 px up-and-left of them.\n *\n * We use Univer 0.22.x's documented defaults (row header = 46 px,\n * column header = 20 px) rather than reaching into the render\n * skeleton at runtime — the dynamic lookup via\n * `RenderUnit.with(SheetSkeletonManagerService)` instantiates the\n * service through redi, which transitively requires\n * `SheetScrollManagerService` that may not yet be registered on the\n * unit's injector when our rAF tick fires (race with Univer's\n * render-unit init). The crash surfaces as\n * \"QuantityCheckError: Expect 1 dependency item(s) for id\n * 'SheetScrollManagerService' but get 0\".\n *\n * Hardcoding the defaults trades ~40 px accuracy for any user who\n * customises header sizes (rare, undocumented in our app) for\n * zero-risk init. If you change Univer's default theme, update\n * these constants and the cursor/chart layers stay aligned.\n */\nexport type HeaderGutter = { rowHeaderWidth: number; columnHeaderHeight: number };\n\nconst DEFAULT_HEADER_GUTTER: HeaderGutter = {\n rowHeaderWidth: 46,\n columnHeaderHeight: 20,\n};\n\nexport function getHeaderGutter(_api: FUniver | null): HeaderGutter {\n return DEFAULT_HEADER_GUTTER;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { use } from 'echarts/core';\nimport { CanvasRenderer } from 'echarts/renderers';\nimport { BarChart, LineChart, PieChart, ScatterChart } from 'echarts/charts';\nimport {\n GridComponent,\n LegendComponent,\n TitleComponent,\n TooltipComponent,\n DatasetComponent,\n} from 'echarts/components';\n\n/**\n * Tree-shaken ECharts wiring. We pay only for the chart types + canvas\n * renderer we actually use. Pipeline Stage 4 already ships each lazy\n * group as its own chunk; this module is the chart-group entry point —\n * importing anything from `'echarts'` directly elsewhere would pull\n * the full library back in and undo the bundle savings.\n *\n * P0 ships Bar (the demo type). P3 layers Line / Pie / Scatter /\n * Area / Combo / Stacked variants on top — those use the same\n * Chart/Component registrations registered here, so future types\n * just import their chart constructor and add to `use([…])`.\n */\n// `use` here is ECharts' renderer/component registry, not a React hook —\n// silence rules-of-hooks for the module-level call.\n// eslint-disable-next-line react-hooks/rules-of-hooks\nuse([\n CanvasRenderer,\n BarChart,\n LineChart,\n PieChart,\n ScatterChart,\n GridComponent,\n LegendComponent,\n TitleComponent,\n TooltipComponent,\n DatasetComponent,\n]);\n\nexport { init } from 'echarts/core';\nexport type { EChartsType } from 'echarts/core';\nexport type { EChartsOption } from 'echarts';\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FUniver } from '@univerjs/core/facade';\nimport {\n PALETTES,\n mergeFormat,\n type ChartModel,\n type ChartType,\n type ResolvedChartFormat,\n} from './types';\nimport type { EChartsOption } from './echarts-init';\n\n/**\n * Read cells from the chart's source range and turn them into an\n * ECharts option. Convention (mirrors Excel's default chart-from-\n * selection):\n *\n * - Row 0 of the source range = header row → series names.\n * - Column 0 = category axis labels (x-axis for column / area / line,\n * y-axis for horizontal bar, dimension for pie).\n * - Remaining cells = numeric values, one series per column.\n *\n * Non-numeric cells coerce to `null` so the chart shows a gap instead\n * of NaN. If the source range collapses to one row / one column we\n * fall back to a \"No data\" placeholder so the overlay still paints\n * rather than crashing.\n *\n * Formatting (title visibility, legend position, axis titles,\n * gridlines, data labels, colour palette) is applied from\n * `mergeFormat(model)` — defaults match Excel's first-render.\n */\nexport function buildEChartsOption(api: FUniver, model: ChartModel): EChartsOption | null {\n const wb = api.getActiveWorkbook();\n if (!wb) return null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sheets = wb.getSheets() as any[];\n const ws = sheets.find((s) => s.getSheetId?.() === model.sheetId);\n if (!ws) return null;\n\n const { startRow, endRow, startColumn, endColumn } = model.source;\n const rows = endRow - startRow + 1;\n const cols = endColumn - startColumn + 1;\n if (rows < 2 || cols < 2) {\n return { title: { text: 'No data', left: 'center', top: 'center' } };\n }\n\n const headers: string[] = [];\n for (let c = 1; c < cols; c++) {\n const v = ws.getRange(startRow, startColumn + c).getValue();\n headers.push(v == null ? `Series ${c}` : String(v));\n }\n const categories: string[] = [];\n for (let r = 1; r < rows; r++) {\n const v = ws.getRange(startRow + r, startColumn).getValue();\n categories.push(v == null ? '' : String(v));\n }\n const seriesData: Array<Array<number | null>> = headers.map((_, sIdx) => {\n const data: Array<number | null> = [];\n for (let r = 1; r < rows; r++) {\n const v = ws.getRange(startRow + r, startColumn + 1 + sIdx).getValue();\n const n = typeof v === 'number' ? v : Number(v);\n data.push(Number.isFinite(n) ? n : null);\n }\n return data;\n });\n\n const format = mergeFormat(model);\n // If every category parses as a date, build the axis as a time axis\n // — ECharts gets nicer auto-formatted tick labels (Jan / Feb / Mar /\n // 2024) than the literal category strings. Pie/scatter/doughnut\n // ignore this (no category axis); buildOptionForType branches on it.\n const dates = detectDateCategories(categories);\n return buildOptionForType(\n model.type,\n headers,\n categories,\n seriesData,\n model.title,\n format,\n dates,\n );\n}\n\n/**\n * Returns a parallel array of ms timestamps if every category cell\n * looks like a date, otherwise null. Heuristic: parses with\n * `Date.parse` and accepts only results in the 1900–2100 range so we\n * don't false-positive on raw numbers like `2024` (which parses as\n * \"year 2024-01-01\") for what's actually a numeric category.\n */\nfunction detectDateCategories(categories: string[]): number[] | null {\n if (categories.length === 0) return null;\n const out: number[] = [];\n const min = Date.UTC(1900, 0, 1);\n const max = Date.UTC(2100, 0, 1);\n // Require at least one slash, dash, or letter so a column of bare\n // integers (e.g. `2024`, `2025`) doesn't get interpreted as years.\n const dateLike = /[-/]|\\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\b/i;\n for (const c of categories) {\n if (!c) return null;\n if (!dateLike.test(c)) return null;\n const t = Date.parse(c);\n if (!Number.isFinite(t) || t < min || t > max) return null;\n out.push(t);\n }\n return out;\n}\n\nfunction buildOptionForType(\n type: ChartType,\n headers: string[],\n categories: string[],\n rawSeries: Array<Array<number | null>>,\n title: string | undefined,\n format: ResolvedChartFormat,\n dateCategories: number[] | null = null,\n): EChartsOption {\n const titleNode =\n title && format.showTitle ? { text: title, left: 'center' as const } : undefined;\n const colors = PALETTES[format.palette];\n const legendNode = legendOption(format);\n const showAxes = format.legend !== 'none';\n void showAxes;\n\n if (type === 'pie' || type === 'doughnut') {\n const pieData = categories.map((label, i) => ({\n name: label,\n value: rawSeries[0]?.[i] ?? 0,\n }));\n return {\n color: colors,\n title: titleNode,\n tooltip: { trigger: 'item' },\n legend: legendNode,\n series: [\n {\n type: 'pie',\n radius: type === 'doughnut' ? ['40%', '70%'] : '60%',\n center: ['50%', titleNode ? '52%' : '48%'],\n data: pieData,\n label: format.dataLabels ? { formatter: '{b}: {c}' } : { formatter: '{b}' },\n },\n ],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n }\n\n if (type === 'scatter') {\n const xs = rawSeries[0] ?? [];\n const series = rawSeries.slice(1).map((ys, i) => ({\n name: headers[i + 1] ?? headers[0],\n type: 'scatter' as const,\n data: xs.map((x, idx) => [x, ys[idx]]).filter(([a, b]) => a != null && b != null),\n label: dataLabelConfig(format),\n }));\n return {\n color: colors,\n title: titleNode,\n tooltip: { trigger: 'item' },\n legend: legendNode,\n grid: chartGrid(format, titleNode != null),\n xAxis: {\n type: 'value',\n name: format.xAxisTitle ?? headers[0] ?? '',\n nameLocation: 'middle',\n nameGap: 24,\n splitLine: { show: format.gridlines },\n },\n yAxis: {\n type: 'value',\n name: format.yAxisTitle ?? '',\n nameLocation: 'middle',\n nameGap: 36,\n splitLine: { show: format.gridlines },\n },\n series:\n series.length > 0\n ? series\n : [\n {\n name: headers[0] ?? 'Series',\n type: 'scatter' as const,\n data: xs.map((x, idx) => [idx, x]).filter(([, b]) => b != null),\n label: dataLabelConfig(format),\n },\n ],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n }\n\n const isHorizontalBar = type === 'bar' || type === 'bar-stacked' || type === 'bar-stacked-100';\n const is100 = type === 'column-stacked-100' || type === 'bar-stacked-100';\n // Combo + dual-axis only make sense on a plain (non-100%, non-\n // horizontal) value-vs-category chart: column / line / area. A 100%-\n // stacked chart already pins both series to a shared 0–100% scale,\n // and horizontal bars swap the axes so a \"secondary value axis on\n // the right\" no longer reads as Excel does it. Gate the features\n // here so the rest of the branch can assume vertical, absolute axes.\n const allowComboAndDualAxis = !is100 && !isHorizontalBar;\n // Per-series secondary-axis flags, restricted to series that actually\n // exist in this chart. Empty unless the feature applies.\n const secondarySeries = allowComboAndDualAxis\n ? headers.filter((name) => format.secondaryAxis?.[name])\n : [];\n const hasSecondaryAxis = secondarySeries.length > 0;\n const isStacked =\n type === 'column-stacked' ||\n type === 'column-stacked-100' ||\n type === 'bar-stacked' ||\n type === 'bar-stacked-100' ||\n type === 'line-stacked' ||\n type === 'area-stacked';\n const isLine = type === 'line' || type === 'line-stacked';\n const isArea = type === 'area' || type === 'area-stacked';\n const echartsType: 'bar' | 'line' = isLine || isArea ? 'line' : 'bar';\n\n const sumPerCat = is100\n ? categories.map((_, i) => {\n let s = 0;\n for (const ys of rawSeries) {\n const v = ys[i];\n if (typeof v === 'number') s += v;\n }\n return s === 0 ? 1 : s;\n })\n : null;\n\n // Time axis only kicks in for horizontal-time charts (column / line /\n // area). Horizontal bars keep the categorical axis to avoid weird\n // sideways time scrolling.\n const useTimeAxis = dateCategories != null && !isHorizontalBar;\n\n const series = headers.map((name, sIdx) => {\n const raw = rawSeries[sIdx] ?? [];\n const dataRaw =\n is100 && sumPerCat\n ? raw.map((v, i) => (typeof v === 'number' ? (v / sumPerCat[i]) * 100 : null))\n : raw;\n // ECharts' time axis wants `[timestamp, value]` pairs. The\n // category axis takes plain values aligned with the axis labels.\n const data =\n useTimeAxis && dateCategories\n ? (dataRaw as Array<number | null>).map((v, i) => [dateCategories[i], v])\n : dataRaw;\n const trendlineMark = format.trendline\n ? buildTrendlineMark(dataRaw as Array<number | null>)\n : undefined;\n // Per-series colour override: if the user picked a specific\n // colour for this series in the Format Chart dialog, it wins over\n // the palette's default. Stored on `format.seriesColors[name]`.\n const overrideColor = format.seriesColors?.[name];\n // Combo: a per-series render-kind override turns this single series\n // into a bar or line regardless of the chart's base type. Only\n // honoured on the column / line / area families (see\n // `allowComboAndDualAxis`). Area's fill is preserved only when the\n // series stays a line; an explicit `bar` override drops the fill.\n const seriesKind = allowComboAndDualAxis ? format.seriesTypes?.[name] : undefined;\n const resolvedType: 'bar' | 'line' = seriesKind ?? echartsType;\n const seriesIsLine = resolvedType === 'line';\n const seriesIsArea = isArea && seriesIsLine && !seriesKind;\n // Dual axis: route this series to yAxisIndex 1 (the secondary,\n // right-hand value axis) when flagged. `yAxis` becomes a two-entry\n // array below; primary series keep the default index 0.\n const onSecondary = allowComboAndDualAxis && Boolean(format.secondaryAxis?.[name]);\n return {\n name,\n type: resolvedType,\n data,\n ...(hasSecondaryAxis ? { yAxisIndex: onSecondary ? 1 : 0 } : {}),\n ...(isStacked && !seriesKind ? { stack: 'all' as const } : {}),\n ...(seriesIsArea ? { areaStyle: {} } : {}),\n ...(seriesIsLine ? { smooth: false, symbol: 'circle' as const, symbolSize: 4 } : {}),\n ...(trendlineMark ? { markLine: trendlineMark } : {}),\n ...(overrideColor\n ? { itemStyle: { color: overrideColor }, lineStyle: { color: overrideColor } }\n : {}),\n label: dataLabelConfig(format, isHorizontalBar, seriesIsLine),\n };\n });\n\n const categoryAxis = useTimeAxis\n ? {\n type: 'time' as const,\n name: isHorizontalBar ? (format.yAxisTitle ?? '') : (format.xAxisTitle ?? ''),\n nameLocation: 'middle' as const,\n nameGap: 24,\n }\n : {\n type: 'category' as const,\n data: categories,\n name: isHorizontalBar ? (format.yAxisTitle ?? '') : (format.xAxisTitle ?? ''),\n nameLocation: 'middle' as const,\n nameGap: 24,\n };\n const valueAxis: Record<string, unknown> = {\n type: 'value' as const,\n name: isHorizontalBar ? (format.xAxisTitle ?? '') : (format.yAxisTitle ?? ''),\n nameLocation: 'middle',\n nameGap: 36,\n splitLine: { show: format.gridlines },\n };\n if (is100) {\n valueAxis.max = 100;\n valueAxis.axisLabel = { formatter: '{value}%' };\n }\n\n // Dual axis: build a second value axis aligned to the right. Its name\n // defaults to the secondary series' name(s) so the reader can tell\n // which line/bars it scales. `gridlines` is left off the secondary\n // axis to avoid two overlapping splitLine grids fighting each other.\n const secondaryValueAxis: Record<string, unknown> | null = hasSecondaryAxis\n ? {\n type: 'value' as const,\n name: secondarySeries.join(' / '),\n nameLocation: 'middle',\n nameGap: 40,\n position: 'right',\n splitLine: { show: false },\n }\n : null;\n\n // The value axis lives on Y for vertical charts. When a secondary\n // axis is requested we emit `yAxis: [primary, secondary]` and the\n // series above carry `yAxisIndex`. Horizontal bars + 100%-stacked\n // never reach here with `hasSecondaryAxis` (gated by\n // `allowComboAndDualAxis`), so the single-axis path stays unchanged\n // for them.\n const yAxisNode =\n !isHorizontalBar && secondaryValueAxis\n ? [valueAxis, secondaryValueAxis]\n : isHorizontalBar\n ? categoryAxis\n : valueAxis;\n\n return {\n color: colors,\n title: titleNode,\n tooltip: {\n trigger: 'axis',\n ...(is100 ? { valueFormatter: (v: unknown) => `${Math.round(Number(v))}%` } : {}),\n },\n legend: legendNode,\n grid: chartGrid(format, titleNode != null, hasSecondaryAxis),\n xAxis: isHorizontalBar ? valueAxis : categoryAxis,\n yAxis: yAxisNode,\n series,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n}\n\nfunction legendOption(format: ResolvedChartFormat): Record<string, unknown> | undefined {\n if (format.legend === 'none') return undefined;\n const pos: Record<string, unknown> = { type: 'scroll' };\n switch (format.legend) {\n case 'top':\n pos.top = 0;\n break;\n case 'bottom':\n pos.bottom = 0;\n break;\n case 'left':\n pos.left = 0;\n pos.orient = 'vertical';\n break;\n case 'right':\n pos.right = 0;\n pos.orient = 'vertical';\n break;\n }\n return pos;\n}\n\nfunction chartGrid(\n format: ResolvedChartFormat,\n hasTitle: boolean,\n hasSecondaryAxis = false,\n): Record<string, unknown> {\n // Make room for legend / title / axis-name labels by padding the\n // plot area. Without this the value axis name gets clipped by the\n // legend at the bottom.\n const grid: Record<string, unknown> = {\n left: 56,\n right: hasSecondaryAxis ? 56 : 24,\n top: hasTitle ? 40 : 16,\n bottom: 56,\n containLabel: true,\n };\n switch (format.legend) {\n case 'top':\n grid.top = hasTitle ? 60 : 32;\n break;\n case 'left':\n grid.left = 96;\n break;\n case 'right':\n // A right-side legend AND a secondary axis both compete for the\n // right margin; widen further so neither clips the other.\n grid.right = hasSecondaryAxis ? 128 : 96;\n break;\n case 'none':\n grid.bottom = 32;\n break;\n }\n return grid;\n}\n\nfunction dataLabelConfig(\n format: ResolvedChartFormat,\n isHorizontalBar?: boolean,\n isLineOrArea?: boolean,\n): Record<string, unknown> {\n if (!format.dataLabels) return { show: false };\n if (isLineOrArea) return { show: true, position: 'top' };\n if (isHorizontalBar) return { show: true, position: 'right' };\n return { show: true, position: 'top' };\n}\n\n/**\n * Linear regression trendline. Computes the best-fit line via simple\n * ordinary-least-squares on the series data points, then encodes it\n * as an ECharts `markLine` from (x_min, y_pred(x_min)) to (x_max,\n * y_pred(x_max)). Returns `undefined` if fewer than two valid\n * numeric points exist (a single point has no slope).\n */\nfunction buildTrendlineMark(data: Array<number | null>): Record<string, unknown> | undefined {\n const points: Array<{ x: number; y: number }> = [];\n for (let i = 0; i < data.length; i += 1) {\n const v = data[i];\n if (typeof v === 'number' && !Number.isNaN(v)) points.push({ x: i, y: v });\n }\n if (points.length < 2) return undefined;\n const n = points.length;\n let sumX = 0;\n let sumY = 0;\n let sumXY = 0;\n let sumXX = 0;\n for (const p of points) {\n sumX += p.x;\n sumY += p.y;\n sumXY += p.x * p.y;\n sumXX += p.x * p.x;\n }\n const denom = n * sumXX - sumX * sumX;\n if (denom === 0) return undefined;\n const slope = (n * sumXY - sumX * sumY) / denom;\n const intercept = (sumY - slope * sumX) / n;\n const xMin = points[0].x;\n const xMax = points[points.length - 1].x;\n const yAtMin = slope * xMin + intercept;\n const yAtMax = slope * xMax + intercept;\n return {\n silent: true,\n symbol: 'none',\n lineStyle: { type: 'dashed', width: 2, opacity: 0.75 },\n data: [\n [\n { xAxis: xMin, yAxis: yAtMin },\n { xAxis: xMax, yAxis: yAtMax },\n ],\n ],\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pixel ↔ cell conversion for chart drag / resize. The Univer facade\n * doesn't ship a `pixelToCell` for our coordinate space, so we walk\n * row heights / column widths via `getCellRect` until the cumulative\n * extent contains the target coordinate.\n *\n * Inputs are in canvas-local PRE-scroll coordinates — the same frame\n * `getCellRect` itself returns. Callers must add the viewport scroll\n * before invoking these.\n */\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Sheet = any;\n\nconst MAX_SCAN = 2048;\n\n/** Find the row whose [top, bottom) range contains `y`. Clamped to MAX_SCAN. */\nexport function rowAtY(sheet: Sheet, y: number, hintRow = 0): number {\n if (y < 0) return 0;\n // Walk forward from the hint. Charts only move a few cells per drag\n // frame, so the hint puts us within a handful of iterations.\n let r = Math.max(0, hintRow);\n for (let i = 0; i < MAX_SCAN; i++) {\n let rect: { top: number; bottom: number } | null = null;\n try {\n rect = sheet.getRange(r, 0).getCellRect();\n } catch {\n return Math.max(0, r - 1);\n }\n if (!rect) return Math.max(0, r - 1);\n if (rect.top > y) {\n // Overshot — walk back row by row.\n while (r > 0) {\n r--;\n try {\n const back = sheet.getRange(r, 0).getCellRect();\n if (back && back.top <= y && back.bottom > y) return r;\n if (back && back.top <= y) return r;\n } catch {\n return r;\n }\n }\n return 0;\n }\n if (rect.bottom > y) return r;\n r++;\n }\n return r;\n}\n\n/** Find the column whose [left, right) range contains `x`. Clamped to MAX_SCAN. */\nexport function colAtX(sheet: Sheet, x: number, hintCol = 0): number {\n if (x < 0) return 0;\n let c = Math.max(0, hintCol);\n for (let i = 0; i < MAX_SCAN; i++) {\n let rect: { left: number; right: number } | null = null;\n try {\n rect = sheet.getRange(0, c).getCellRect();\n } catch {\n return Math.max(0, c - 1);\n }\n if (!rect) return Math.max(0, c - 1);\n if (rect.left > x) {\n while (c > 0) {\n c--;\n try {\n const back = sheet.getRange(0, c).getCellRect();\n if (back && back.left <= x && back.right > x) return c;\n if (back && back.left <= x) return c;\n } catch {\n return c;\n }\n }\n return 0;\n }\n if (rect.right > x) return c;\n c++;\n }\n return c;\n}\n\n/**\n * Convert a chart's screen-local pixel rect to cell-coordinate position.\n * `screenRect` is the chart's host-local box (left/top/width/height).\n * `host`-local pixels are translated to canvas-local pre-scroll coords\n * using `canvasOffset` (canvas vs. host offset) and `scroll` (the\n * worksheet's current scroll offset). We then snap the resulting\n * top-left and bottom-right cells.\n */\nexport function rectToCellPos(\n sheet: Sheet,\n screenRect: { left: number; top: number; width: number; height: number },\n canvasOffset: { x: number; y: number },\n scroll: { x: number; y: number },\n hint?: { startRow: number; startColumn: number; endRow: number; endColumn: number },\n): { startRow: number; endRow: number; startColumn: number; endColumn: number } | null {\n const preLeft = screenRect.left - canvasOffset.x + scroll.x;\n const preTop = screenRect.top - canvasOffset.y + scroll.y;\n const preRight = preLeft + screenRect.width;\n const preBottom = preTop + screenRect.height;\n\n const startRow = rowAtY(sheet, preTop, hint?.startRow);\n const startColumn = colAtX(sheet, preLeft, hint?.startColumn);\n // For the bottom-right, snap to the cell BEFORE the bottom-right\n // pixel (so the chart includes that cell, matching Excel's \"anchor\n // to bottom-right cell\" semantics). Subtract 1 from preRight/Bottom\n // to land in the inclusive last cell.\n const endRow = Math.max(startRow, rowAtY(sheet, preBottom - 1, hint?.endRow ?? startRow));\n const endColumn = Math.max(\n startColumn,\n colAtX(sheet, preRight - 1, hint?.endColumn ?? startColumn),\n );\n return { startRow, endRow, startColumn, endColumn };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCharts } from './charts-context';\nimport { init, type EChartsType } from './echarts-init';\nimport { buildEChartsOption } from './build-option';\nimport { rectToCellPos } from './hit-test';\nimport type { ChartModel } from './types';\n\n/**\n * Single chart rendered on screen. Responsibilities:\n *\n * - Owns one ECharts instance, mounted into a dedicated div.\n * - Reads source data on mount + on every workbook value change,\n * redraws via `setOption(option, true)`.\n * - Selection: click selects (frame + 8 resize handles appear);\n * the parent (ChartLayer) handles click-outside-to-deselect.\n * - Drag-to-move: pointer-down on the body, drag, release → snap\n * the model.pos top-left to the nearest cell, keep the size.\n * - Drag-to-resize: pointer-down on any of the 8 handles, drag,\n * release → snap both anchor corners to cells.\n *\n * Excel parity notes:\n * - 4 corner handles (resize both axes) + 4 mid-edge handles\n * (resize one axis).\n * - Cursor changes to nwse/nesw/ns/ew depending on handle.\n * - Move/resize during drag is free-positioned via CSS; the cell\n * anchor only updates on pointer-up (so the model stays in cell\n * coordinates and round-trips cleanly through xlsx + collab).\n */\ntype Props = {\n model: ChartModel;\n /** Host-local CSS box. Parent computes from the cell rect + the\n * active sheet's scroll offset on every animation frame. */\n rect: { left: number; top: number; width: number; height: number };\n /** Canvas-vs-host offset + current scroll. Needed to convert the\n * chart's screen pixels back to canvas-local pre-scroll coords\n * when snapping to cells on drop. */\n canvasOffset: { x: number; y: number };\n scroll: { x: number; y: number };\n};\n\ntype Handle = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';\n\nconst CORNER_HANDLES: Handle[] = ['nw', 'ne', 'se', 'sw'];\nconst EDGE_HANDLES: Handle[] = ['n', 'e', 's', 'w'];\nconst ALL_HANDLES: Handle[] = [...CORNER_HANDLES, ...EDGE_HANDLES];\n\nconst HANDLE_CURSORS: Record<Handle, string> = {\n n: 'ns-resize',\n s: 'ns-resize',\n e: 'ew-resize',\n w: 'ew-resize',\n ne: 'nesw-resize',\n sw: 'nesw-resize',\n nw: 'nwse-resize',\n se: 'nwse-resize',\n};\n\nconst MIN_W = 80;\nconst MIN_H = 60;\n\nexport function ChartOverlay({ model, rect, canvasOffset, scroll }: Props) {\n const { api: sdkApi, selectedId, select, update } = useCharts();\n // FUniver facade — reached through the SDK handle.\n const api = sdkApi.univer;\n const hostRef = useRef<HTMLDivElement>(null);\n const echartRef = useRef<EChartsType | null>(null);\n const isSelected = selectedId === model.id;\n\n // `drag` is the ephemeral pixel-space delta applied while the user\n // is dragging the body or a handle. It's a CSS-only transform until\n // pointer-up, at which point we compute the new cell anchor and\n // commit via `update()`. Null when not dragging.\n const [drag, setDrag] = useState<null | {\n mode: 'move' | Handle;\n startMouse: { x: number; y: number };\n startRect: { left: number; top: number; width: number; height: number };\n current: { left: number; top: number; width: number; height: number };\n }>(null);\n\n // Init ECharts once + dispose on unmount. ECharts mutates its own\n // DOM children so it must own its container.\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const inst = init(host, undefined, { renderer: 'canvas' });\n echartRef.current = inst;\n return () => {\n inst.dispose();\n echartRef.current = null;\n };\n }, []);\n\n // Resize whenever the cell-rect-derived box (or the ephemeral drag\n // rect) changes. ECharts won't auto-resize on its own.\n useEffect(() => {\n echartRef.current?.resize();\n }, [rect.width, rect.height, drag?.current.width, drag?.current.height]);\n\n useEffect(() => {\n if (!api) return;\n const refresh = () => {\n const opt = buildEChartsOption(api, model);\n if (opt) {\n echartRef.current?.setOption(opt, true);\n // Expose the resolved ECharts option per chart id so e2e specs\n // (and manual debugging) can assert on the live config — e.g.\n // dual-axis charts emit a two-entry `yAxis`. Mirrors the\n // `window.__univerAPI` test hook; carries no secrets.\n const w = window as unknown as {\n __casualChartOptions?: Record<string, unknown>;\n };\n w.__casualChartOptions = w.__casualChartOptions ?? {};\n w.__casualChartOptions[model.id] = opt;\n }\n };\n refresh();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const evName = (api as any).Event?.SheetValueChanged;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (!evName || typeof (api as any).addEvent !== 'function') return;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const disp = (api as any).addEvent(evName, refresh) as { dispose?: () => void };\n return () => disp.dispose?.();\n }, [api, model]);\n\n // Pointer-up handler installed at the document level while a drag\n // is in flight. We can't put it on the overlay because the pointer\n // can escape during the move (and Excel doesn't lock pointers either).\n const commitDrag = useCallback(() => {\n if (!drag || !api) return;\n const wb = api.getActiveWorkbook();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sheets = wb?.getSheets() as any[] | undefined;\n const ws = sheets?.find((s) => s.getSheetId?.() === model.sheetId);\n if (!ws) {\n setDrag(null);\n return;\n }\n const newPos = rectToCellPos(ws, drag.current, canvasOffset, scroll, {\n startRow: model.pos.startRow,\n startColumn: model.pos.startColumn,\n endRow: model.pos.endRow,\n endColumn: model.pos.endColumn,\n });\n if (newPos) update(model.id, { pos: newPos });\n setDrag(null);\n }, [api, canvasOffset, drag, model, scroll, update]);\n\n useEffect(() => {\n if (!drag) return;\n const onMove = (e: PointerEvent) => {\n const dx = e.clientX - drag.startMouse.x;\n const dy = e.clientY - drag.startMouse.y;\n setDrag((cur) => {\n if (!cur) return cur;\n const next = computeDragRect(cur.mode, cur.startRect, dx, dy);\n return { ...cur, current: next };\n });\n };\n const onUp = () => commitDrag();\n document.addEventListener('pointermove', onMove);\n document.addEventListener('pointerup', onUp);\n document.addEventListener('pointercancel', onUp);\n return () => {\n document.removeEventListener('pointermove', onMove);\n document.removeEventListener('pointerup', onUp);\n document.removeEventListener('pointercancel', onUp);\n };\n }, [drag, commitDrag]);\n\n const onBodyPointerDown = (e: React.PointerEvent) => {\n if (e.button !== 0) return; // primary button only\n e.stopPropagation();\n select(model.id);\n // A bare click selects but doesn't start a drag — the drag effect\n // only commits on pointer-up if `drag.current` differs from\n // `drag.startRect`. So we always set drag and trust commit logic.\n setDrag({\n mode: 'move',\n startMouse: { x: e.clientX, y: e.clientY },\n startRect: { ...rect },\n current: { ...rect },\n });\n };\n\n const onHandlePointerDown = (handle: Handle) => (e: React.PointerEvent) => {\n if (e.button !== 0) return;\n e.stopPropagation();\n select(model.id);\n setDrag({\n mode: handle,\n startMouse: { x: e.clientX, y: e.clientY },\n startRect: { ...rect },\n current: { ...rect },\n });\n };\n\n const liveRect = drag?.current ?? rect;\n\n return (\n <div\n ref={hostRef}\n className={`chart-overlay${isSelected ? ' chart-overlay--selected' : ''}${drag ? ' chart-overlay--dragging' : ''}`}\n data-testid=\"chart-overlay\"\n data-chart-id={model.id}\n data-selected={isSelected ? 'true' : undefined}\n style={{\n position: 'absolute',\n left: `${liveRect.left}px`,\n top: `${liveRect.top}px`,\n width: `${liveRect.width}px`,\n height: `${liveRect.height}px`,\n cursor: drag?.mode === 'move' ? 'grabbing' : isSelected ? 'grab' : 'pointer',\n }}\n onPointerDown={onBodyPointerDown}\n onContextMenu={(e) => {\n e.preventDefault();\n select(model.id);\n // ChartLayer listens for this event and pops a context menu —\n // we just need to ensure the chart is selected first.\n const ce = new CustomEvent('casual-chart-contextmenu', {\n detail: { id: model.id, x: e.clientX, y: e.clientY },\n });\n document.dispatchEvent(ce);\n }}\n >\n {isSelected &&\n ALL_HANDLES.map((h) => (\n <div\n key={h}\n data-testid={`chart-handle-${h}`}\n className={`chart-overlay__handle chart-overlay__handle--${h}`}\n style={{ cursor: HANDLE_CURSORS[h] }}\n onPointerDown={onHandlePointerDown(h)}\n />\n ))}\n </div>\n );\n}\n\n/**\n * Apply a drag delta to the starting rect based on which handle (or\n * the body) is being dragged. Mode `'move'` slides the rect; the\n * handle modes resize from the matching edge / corner. We clamp\n * each dimension to a minimum so the chart can't collapse onto a\n * point (impossible to grab again).\n */\nfunction computeDragRect(\n mode: 'move' | Handle,\n start: { left: number; top: number; width: number; height: number },\n dx: number,\n dy: number,\n): { left: number; top: number; width: number; height: number } {\n if (mode === 'move') {\n return { left: start.left + dx, top: start.top + dy, width: start.width, height: start.height };\n }\n let { left, top, width, height } = start;\n const wantsLeft = mode === 'nw' || mode === 'w' || mode === 'sw';\n const wantsRight = mode === 'ne' || mode === 'e' || mode === 'se';\n const wantsTop = mode === 'nw' || mode === 'n' || mode === 'ne';\n const wantsBottom = mode === 'sw' || mode === 's' || mode === 'se';\n if (wantsLeft) {\n const newWidth = Math.max(MIN_W, start.width - dx);\n left = start.left + (start.width - newWidth);\n width = newWidth;\n } else if (wantsRight) {\n width = Math.max(MIN_W, start.width + dx);\n }\n if (wantsTop) {\n const newHeight = Math.max(MIN_H, start.height - dy);\n top = start.top + (start.height - newHeight);\n height = newHeight;\n } else if (wantsBottom) {\n height = Math.max(MIN_H, start.height + dy);\n }\n return { left, top, width, height };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState } from 'react';\nimport { Dialog } from '../chrome/Dialog';\nimport {\n CHART_FAMILY_OF,\n LEGEND_POSITIONS,\n PALETTES,\n PALETTE_LABELS,\n mergeFormat,\n type ChartFormat,\n type ChartModel,\n type ChartPalette,\n} from './types';\n\ntype Props = {\n model: ChartModel;\n /** Optional list of series names — when present, the dialog renders\n * a per-series colour-override picker below the palette section.\n * Pulled by the caller from the chart's source range. */\n seriesNames?: string[];\n onCancel: () => void;\n onConfirm: (next: ChartFormat) => void;\n};\n\n/**\n * Excel's \"Format Chart Area\" pane, compressed into a single dialog\n * tailored to what we currently render. Covers:\n *\n * - Chart title (text + show/hide).\n * - Legend position (Bottom / Top / Left / Right / None).\n * - X-axis title text + Y-axis title text (axis families only).\n * - Major gridlines on/off (axis families only).\n * - Data labels on/off.\n * - Colour palette (Office / Mono / Vivid / Pastel).\n *\n * The dialog confirms with a merged `ChartFormat`; ChartContextMenu\n * applies it to `model.format` via `update()`.\n *\n * The chart title text is `model.title` (auto-named \"Chart N\" on\n * insert). Editing it here also returns it so the caller can persist\n * the rename together with the format change.\n */\nexport function FormatChartDialog({ model, seriesNames, onCancel, onConfirm }: Props) {\n const merged = mergeFormat(model);\n const family = CHART_FAMILY_OF[model.type];\n const isAxisFamily = family !== 'pie';\n // Combo (mix bar + line) and a secondary value axis only make sense\n // on a vertical, absolute-scale chart: column / line / area. 100%-\n // stacked variants pin every series to a shared 0–100% scale, and\n // horizontal bars swap the axes so \"secondary axis on the right\"\n // stops reading like Excel — mirror the gate in `build-option.ts`.\n const is100 = model.type === 'column-stacked-100' || model.type === 'bar-stacked-100';\n const isHorizontalBar = family === 'bar';\n const supportsComboAndDualAxis =\n isAxisFamily && family !== 'scatter' && !is100 && !isHorizontalBar;\n const baseSeriesKind: 'bar' | 'line' = family === 'line' || family === 'area' ? 'line' : 'bar';\n const [title, setTitle] = useState(model.title ?? '');\n const [showTitle, setShowTitle] = useState(merged.showTitle);\n const [legend, setLegend] = useState(merged.legend);\n const [xAxisTitle, setXAxisTitle] = useState(merged.xAxisTitle ?? '');\n const [yAxisTitle, setYAxisTitle] = useState(merged.yAxisTitle ?? '');\n const [gridlines, setGridlines] = useState(merged.gridlines);\n const [dataLabels, setDataLabels] = useState(merged.dataLabels);\n const [palette, setPalette] = useState<ChartPalette>(merged.palette);\n const [trendline, setTrendline] = useState(merged.trendline);\n const [seriesColors, setSeriesColors] = useState<Record<string, string>>(\n merged.seriesColors ?? {},\n );\n const [seriesTypes, setSeriesTypes] = useState<Record<string, 'bar' | 'line'>>(\n merged.seriesTypes ?? {},\n );\n const [secondaryAxis, setSecondaryAxis] = useState<Record<string, boolean>>(\n merged.secondaryAxis ?? {},\n );\n\n const confirm = () => {\n // Strip empty / palette-matching overrides so the payload only\n // carries explicit user picks.\n const trimmedSeriesColors: Record<string, string> = {};\n for (const [name, color] of Object.entries(seriesColors)) {\n if (color && color.trim()) trimmedSeriesColors[name] = color;\n }\n // Only persist series-kind overrides that actually differ from the\n // chart's base kind, and secondary-axis flags that are `true`, so\n // the payload stays minimal (and toggling back to the default\n // cleanly removes the override).\n const trimmedSeriesTypes: Record<string, 'bar' | 'line'> = {};\n if (supportsComboAndDualAxis) {\n for (const [name, kind] of Object.entries(seriesTypes)) {\n if (kind && kind !== baseSeriesKind) trimmedSeriesTypes[name] = kind;\n }\n }\n const trimmedSecondaryAxis: Record<string, boolean> = {};\n if (supportsComboAndDualAxis) {\n for (const [name, on] of Object.entries(secondaryAxis)) {\n if (on) trimmedSecondaryAxis[name] = true;\n }\n }\n onConfirm({\n showTitle,\n legend,\n ...(xAxisTitle.trim() ? { xAxisTitle: xAxisTitle.trim() } : { xAxisTitle: undefined }),\n ...(yAxisTitle.trim() ? { yAxisTitle: yAxisTitle.trim() } : { yAxisTitle: undefined }),\n gridlines,\n dataLabels,\n palette,\n trendline,\n seriesColors: trimmedSeriesColors,\n seriesTypes: trimmedSeriesTypes,\n secondaryAxis: trimmedSecondaryAxis,\n // Title text is part of the chart's identity (`ChartModel.title`)\n // not its format. The caller reads the trimmed title via the\n // form input below and applies it alongside the format patch.\n });\n // Side-channel the title back via a custom event so the caller\n // doesn't need a separate prop just for one optional string.\n const trimmed = title.trim();\n if (trimmed !== (model.title ?? '')) {\n const ce = new CustomEvent('casual-chart-title-changed', {\n detail: { id: model.id, title: trimmed || undefined },\n });\n document.dispatchEvent(ce);\n }\n };\n\n return (\n <Dialog\n title=\"Format chart\"\n onClose={onCancel}\n data-testid=\"format-chart-dialog\"\n footer={\n <>\n <button\n type=\"button\"\n className=\"btn-secondary\"\n data-testid=\"format-chart-cancel\"\n onClick={onCancel}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn-primary\"\n data-testid=\"format-chart-apply\"\n onClick={confirm}\n >\n Apply\n </button>\n </>\n }\n >\n <div className=\"format-chart\">\n <Section legend=\"Title\">\n <div className=\"format-chart__row\">\n <label className=\"format-chart__checkbox\">\n <input\n type=\"checkbox\"\n checked={showTitle}\n data-testid=\"format-chart-show-title\"\n onChange={(e) => setShowTitle(e.target.checked)}\n />\n <span>Show title</span>\n </label>\n </div>\n <input\n type=\"text\"\n className=\"format-chart__input\"\n data-testid=\"format-chart-title-input\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Chart 1\"\n disabled={!showTitle}\n />\n </Section>\n\n <Section legend=\"Legend\">\n <div className=\"format-chart__segment\" role=\"radiogroup\" aria-label=\"Legend position\">\n {LEGEND_POSITIONS.map((p) => (\n <label\n key={p.id}\n className={`format-chart__seg-opt${legend === p.id ? ' format-chart__seg-opt--active' : ''}`}\n data-testid={`format-chart-legend-${p.id}`}\n >\n <input\n type=\"radio\"\n name=\"legend-pos\"\n value={p.id}\n checked={legend === p.id}\n onChange={() => setLegend(p.id)}\n />\n <span>{p.label}</span>\n </label>\n ))}\n </div>\n </Section>\n\n {isAxisFamily && (\n <Section legend=\"Axes\">\n <div className=\"format-chart__axis-row\">\n <label className=\"format-chart__field\">\n <span className=\"format-chart__field-label\">X-axis title</span>\n <input\n type=\"text\"\n className=\"format-chart__input\"\n data-testid=\"format-chart-x-axis-title\"\n value={xAxisTitle}\n onChange={(e) => setXAxisTitle(e.target.value)}\n placeholder=\"Auto\"\n />\n </label>\n <label className=\"format-chart__field\">\n <span className=\"format-chart__field-label\">Y-axis title</span>\n <input\n type=\"text\"\n className=\"format-chart__input\"\n data-testid=\"format-chart-y-axis-title\"\n value={yAxisTitle}\n onChange={(e) => setYAxisTitle(e.target.value)}\n placeholder=\"Auto\"\n />\n </label>\n </div>\n <label className=\"format-chart__checkbox\">\n <input\n type=\"checkbox\"\n checked={gridlines}\n data-testid=\"format-chart-gridlines\"\n onChange={(e) => setGridlines(e.target.checked)}\n />\n <span>Show major gridlines</span>\n </label>\n </Section>\n )}\n\n <Section legend=\"Data labels\">\n <label className=\"format-chart__checkbox\">\n <input\n type=\"checkbox\"\n checked={dataLabels}\n data-testid=\"format-chart-data-labels\"\n onChange={(e) => setDataLabels(e.target.checked)}\n />\n <span>Show values on each point</span>\n </label>\n </Section>\n\n {/* Trendline only meaningful for axis-based charts. Pie /\n doughnut have no time axis, so the toggle is hidden. */}\n {isAxisFamily && (\n <Section legend=\"Trendline\">\n <label className=\"format-chart__checkbox\">\n <input\n type=\"checkbox\"\n checked={trendline}\n data-testid=\"format-chart-trendline\"\n onChange={(e) => setTrendline(e.target.checked)}\n />\n <span>Overlay linear-regression trendline on each series</span>\n </label>\n </Section>\n )}\n\n {/* Combo + dual axis — per-series render-kind (bar/line) and a\n secondary value axis. Only shown for column / line / area\n charts where it's meaningful, and when the caller supplied\n series names. */}\n {supportsComboAndDualAxis && seriesNames && seriesNames.length > 0 && (\n <Section legend=\"Series type & axis\">\n <p className=\"format-chart__hint\">\n Mix bars and lines, and plot a series against a secondary (right) axis.\n </p>\n <div className=\"format-chart__series-rows\">\n {seriesNames.map((name, idx) => {\n const kind = seriesTypes[name] ?? baseSeriesKind;\n const onSecondary = Boolean(secondaryAxis[name]);\n return (\n <div\n key={name}\n className=\"format-chart__series-row\"\n data-testid={`format-chart-combo-${idx}`}\n >\n <span className=\"format-chart__series-name\">{name}</span>\n <select\n className=\"format-chart__series-kind\"\n data-testid={`format-chart-series-kind-${idx}`}\n aria-label={`${name} chart type`}\n value={kind}\n onChange={(e) =>\n setSeriesTypes({\n ...seriesTypes,\n [name]: e.target.value as 'bar' | 'line',\n })\n }\n >\n <option value=\"bar\">Bars</option>\n <option value=\"line\">Line</option>\n </select>\n <label className=\"format-chart__checkbox format-chart__series-secondary\">\n <input\n type=\"checkbox\"\n data-testid={`format-chart-secondary-axis-${idx}`}\n checked={onSecondary}\n onChange={(e) =>\n setSecondaryAxis({ ...secondaryAxis, [name]: e.target.checked })\n }\n />\n <span>Secondary axis</span>\n </label>\n </div>\n );\n })}\n </div>\n </Section>\n )}\n\n <Section legend=\"Colors\">\n <div className=\"format-chart__palettes\" role=\"radiogroup\" aria-label=\"Color palette\">\n {(Object.keys(PALETTES) as ChartPalette[]).map((p) => (\n <label\n key={p}\n className={`format-chart__palette${palette === p ? ' format-chart__palette--active' : ''}`}\n data-testid={`format-chart-palette-${p}`}\n title={PALETTE_LABELS[p]}\n >\n <input\n type=\"radio\"\n name=\"palette\"\n value={p}\n checked={palette === p}\n onChange={() => setPalette(p)}\n />\n <div className=\"format-chart__palette-swatches\">\n {PALETTES[p].slice(0, 5).map((c) => (\n <span\n key={c}\n className=\"format-chart__palette-swatch\"\n style={{ backgroundColor: c }}\n />\n ))}\n </div>\n <span className=\"format-chart__palette-label\">{PALETTE_LABELS[p]}</span>\n </label>\n ))}\n </div>\n </Section>\n\n {/* Per-series colour overrides — only rendered when the caller\n supplied series names from the source range. Each row pairs\n a colour swatch (native picker) with a Reset button that\n removes the override and falls back to the palette. */}\n {seriesNames && seriesNames.length > 0 && (\n <Section legend=\"Series colors\">\n <div className=\"format-chart__series-rows\">\n {seriesNames.map((name, idx) => {\n const override = seriesColors[name] ?? '';\n const defaultColor = PALETTES[palette][idx % PALETTES[palette].length];\n return (\n <div\n key={name}\n className=\"format-chart__series-row\"\n data-testid={`format-chart-series-${idx}`}\n >\n <span className=\"format-chart__series-name\">{name}</span>\n <input\n type=\"color\"\n className=\"format-chart__series-color\"\n data-testid={`format-chart-series-color-${idx}`}\n value={override || defaultColor}\n onChange={(e) => setSeriesColors({ ...seriesColors, [name]: e.target.value })}\n />\n {override && (\n <button\n type=\"button\"\n className=\"format-chart__series-reset\"\n data-testid={`format-chart-series-reset-${idx}`}\n title=\"Reset to palette default\"\n onClick={() => {\n const next = { ...seriesColors };\n delete next[name];\n setSeriesColors(next);\n }}\n >\n Reset\n </button>\n )}\n </div>\n );\n })}\n </div>\n </Section>\n )}\n </div>\n </Dialog>\n );\n}\n\nfunction Section({ legend, children }: { legend: string; children: React.ReactNode }) {\n return (\n <fieldset className=\"format-chart__group\">\n <legend className=\"format-chart__legend\">{legend}</legend>\n {children}\n </fieldset>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport type { FUniver } from '@univerjs/core/facade';\nimport { Icon } from '../chrome/Icon';\nimport { useCharts } from './charts-context';\nimport { InsertChartDialog } from './InsertChartDialog';\nimport { FormatChartDialog } from './FormatChartDialog';\n\n/**\n * Right-click context menu for a selected chart. Mirrors Excel's\n * chart context menu, scoped to the actions we support today:\n *\n * - Change Chart Type → reopens the Insert dialog seeded with the\n * chart's current source range and type.\n * - Rename → in-place edit (focus jumps to the panel rename if it's\n * open, otherwise inline prompt — for v0.1.1 we just toggle a\n * small inline input here).\n * - Delete → drops the chart from the store.\n *\n * Closes on outside click or Escape.\n */\ntype Props = {\n chartId: string;\n x: number;\n y: number;\n onClose: () => void;\n};\n\nexport function ChartContextMenu({ chartId, x, y, onClose }: Props) {\n const { api: sdkApi, charts, remove, update } = useCharts();\n // FUniver facade — reached through the SDK handle.\n const api = sdkApi.univer;\n const chart = charts.find((c) => c.id === chartId);\n const menuRef = useRef<HTMLDivElement>(null);\n const [renaming, setRenaming] = useState<string | null>(null);\n const [showChangeType, setShowChangeType] = useState(false);\n const [showFormat, setShowFormat] = useState(false);\n const dialogOpen = showChangeType || showFormat;\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n if (dialogOpen) return; // dialog handles its own Escape\n onClose();\n }\n };\n const onDown = (e: MouseEvent) => {\n const t = e.target as HTMLElement | null;\n if (!menuRef.current) return;\n if (t && menuRef.current.contains(t)) return;\n if (t?.closest('.dialog-backdrop')) return;\n if (t?.closest('[data-testid=\"cs-dialog-backdrop\"]')) return;\n onClose();\n };\n document.addEventListener('keydown', onKey);\n document.addEventListener('mousedown', onDown, true);\n return () => {\n document.removeEventListener('keydown', onKey);\n document.removeEventListener('mousedown', onDown, true);\n };\n }, [onClose, dialogOpen]);\n\n // The Format dialog side-channels the title change because title\n // text lives on `ChartModel`, not `ChartFormat`. Catch it and apply.\n useEffect(() => {\n const onTitle = (e: Event) => {\n const ce = e as CustomEvent<{ id: string; title?: string }>;\n if (ce.detail.id !== chartId) return;\n update(chartId, { title: ce.detail.title });\n };\n document.addEventListener('casual-chart-title-changed', onTitle);\n return () => document.removeEventListener('casual-chart-title-changed', onTitle);\n }, [chartId, update]);\n\n if (!chart) return null;\n\n // Anchor the menu inside the viewport — flip when too close to the\n // right/bottom edges. Excel does the same.\n const W = 200;\n const H = 200; // conservative; menu auto-sizes anyway\n const left = Math.min(x, window.innerWidth - W - 8);\n const top = Math.min(y, window.innerHeight - H - 8);\n\n if (renaming !== null) {\n return (\n <div\n ref={menuRef}\n className=\"chart-context-menu chart-context-menu--renaming\"\n data-testid=\"chart-context-menu\"\n style={{ position: 'fixed', left, top, pointerEvents: 'auto' }}\n >\n <input\n autoFocus\n className=\"chart-context-menu__rename-input\"\n data-testid=\"chart-context-rename-input\"\n value={renaming}\n onChange={(e) => setRenaming(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n const v = renaming.trim();\n if (v) update(chartId, { title: v });\n onClose();\n }\n if (e.key === 'Escape') onClose();\n }}\n onBlur={() => {\n const v = renaming.trim();\n if (v && v !== chart.title) update(chartId, { title: v });\n onClose();\n }}\n />\n </div>\n );\n }\n\n return (\n <>\n <div\n ref={menuRef}\n className=\"chart-context-menu\"\n data-testid=\"chart-context-menu\"\n style={{ position: 'fixed', left, top, pointerEvents: 'auto' }}\n role=\"menu\"\n >\n <button\n type=\"button\"\n className=\"chart-context-menu__item\"\n data-testid=\"chart-context-change-type\"\n onClick={() => setShowChangeType(true)}\n >\n <Icon name=\"bar_chart\" />\n <span>Change chart type…</span>\n </button>\n <button\n type=\"button\"\n className=\"chart-context-menu__item\"\n data-testid=\"chart-context-format\"\n onClick={() => setShowFormat(true)}\n >\n <Icon name=\"tune\" />\n <span>Format chart…</span>\n </button>\n <button\n type=\"button\"\n className=\"chart-context-menu__item\"\n data-testid=\"chart-context-rename\"\n onClick={() => setRenaming(chart.title ?? 'Chart')}\n >\n <Icon name=\"edit\" />\n <span>Rename</span>\n </button>\n <div className=\"chart-context-menu__sep\" />\n <button\n type=\"button\"\n className=\"chart-context-menu__item chart-context-menu__item--danger\"\n data-testid=\"chart-context-delete\"\n onClick={() => {\n remove(chartId);\n onClose();\n }}\n >\n <Icon name=\"delete\" />\n <span>Delete chart</span>\n </button>\n </div>\n\n {showChangeType && api && (\n <InsertChartDialog\n api={api}\n defaultSourceA1={rangeToA1(chart.source)}\n initialType={chart.type}\n title=\"Change chart type\"\n confirmLabel=\"Apply\"\n onCancel={() => {\n setShowChangeType(false);\n onClose();\n }}\n onConfirm={({ source, type }) => {\n update(chartId, { source, type });\n setShowChangeType(false);\n onClose();\n }}\n />\n )}\n\n {showFormat && (\n <FormatChartDialog\n model={chart}\n seriesNames={readSeriesNames(api, chart)}\n onCancel={() => {\n setShowFormat(false);\n onClose();\n }}\n onConfirm={(next) => {\n update(chartId, { format: next });\n setShowFormat(false);\n onClose();\n }}\n />\n )}\n </>\n );\n}\n\nfunction rangeToA1(r: {\n startRow: number;\n endRow: number;\n startColumn: number;\n endColumn: number;\n}): string {\n const a = colA1(r.startColumn) + (r.startRow + 1);\n if (r.startRow === r.endRow && r.startColumn === r.endColumn) return a;\n return `${a}:${colA1(r.endColumn)}${r.endRow + 1}`;\n}\n\nfunction colA1(c: number): string {\n let n = c + 1;\n let s = '';\n while (n > 0) {\n const rem = (n - 1) % 26;\n s = String.fromCharCode(65 + rem) + s;\n n = Math.floor((n - 1) / 26);\n }\n return s;\n}\n\nfunction readSeriesNames(\n api: FUniver | null,\n chart: { sheetId: string; source: { startRow: number; startColumn: number; endColumn: number } },\n): string[] {\n if (!api) return [];\n try {\n const wb = api.getActiveWorkbook();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sheets = wb?.getSheets() as any[];\n const ws = sheets?.find((s) => s.getSheetId?.() === chart.sheetId);\n if (!ws) return [];\n const { startRow, startColumn, endColumn } = chart.source;\n const names: string[] = [];\n for (let c = 1; c <= endColumn - startColumn; c += 1) {\n const v = ws.getRange(startRow, startColumn + c).getValue();\n names.push(v == null ? `Series ${c}` : String(v));\n }\n return names;\n } catch (err) {\n console.debug('[chart-format] failed to read series names', err);\n return [];\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { getHeaderGutter, getUniverHost, getUniverMainCanvas } from './univer-dom';\nimport { useCharts } from './charts-context';\nimport { ChartOverlay } from './ChartOverlay';\nimport { ChartContextMenu } from './ChartContextMenu';\n\n/**\n * Renders every chart in the store. Same anchoring strategy as\n * PresenceLayer:\n *\n * - Find the univer-host + main grid canvas.\n * - Translate the chart's cell-coordinate pos into a host-local\n * CSS box: `getCellRect(corner)` gives canvas-local pre-scroll\n * coords; subtract `scrollX/scrollY` (tracked via Univer's\n * Scroll event), add the canvas-vs-host offset.\n * - Only render charts whose sheet matches the active sheet\n * (Excel hides charts on inactive sheets).\n * - Rerun the math every animation frame so the chart sticks\n * to its cell anchor through scroll + resize + zoom.\n *\n * Mounts into the univer-host via a portal so the overlay paints\n * on top of the canvas at the same z-stack as PresenceLayer.\n */\ntype RenderedChart = {\n id: string;\n rect: { left: number; top: number; width: number; height: number };\n};\n\ntype CtxMenuState = { id: string; x: number; y: number } | null;\n\nexport function ChartLayer() {\n const { api: sdkApi, charts, selectedId, select, remove } = useCharts();\n // FUniver facade — reached through the SDK handle (the app used a\n // `useUniverAPI()` hook that doesn't exist in the packaged SDK).\n const api = sdkApi.univer;\n const [rendered, setRendered] = useState<RenderedChart[]>([]);\n const [ctxMenu, setCtxMenu] = useState<CtxMenuState>(null);\n const [canvasOffset, setCanvasOffset] = useState({ x: 0, y: 0 });\n // rAF callback closes over `rendered` from when the effect ran. The effect\n // re-runs only on [api, charts] changes, so a sheet-switch (which leaves\n // both inputs untouched) would compare new computed rects against the\n // stale closure copy — `rectsEqual` could return true while React state\n // still holds the previous overlays. Mirror state into a ref so the\n // diff always sees the live value.\n const renderedRef = useRef<RenderedChart[]>(rendered);\n renderedRef.current = rendered;\n const hostRef = useRef<HTMLElement | null>(null);\n const scrollRef = useRef({ x: 0, y: 0 });\n\n useEffect(() => {\n hostRef.current = getUniverHost();\n }, []);\n\n // The chart's screen position is the cell's canvas-local rect minus\n // the viewport scroll offset. `Event.Scroll` would be the natural\n // hook, but it doesn't fire on programmatic scrolls (scrollToCell)\n // and the registration timing is fragile against lifecycle stages.\n // `getScrollState()` is the authoritative read — poll it every\n // animation frame and diff. Cheap (a few number reads) and correct.\n\n useEffect(() => {\n if (!api) return;\n let raf = 0;\n\n const recompute = () => {\n const host = hostRef.current ?? getUniverHost();\n if (!host) {\n if (renderedRef.current.length) setRendered([]);\n return;\n }\n const canvas = getUniverMainCanvas(host);\n if (!canvas) {\n if (renderedRef.current.length) setRendered([]);\n return;\n }\n const hostRect = host.getBoundingClientRect();\n const canvasRect = canvas.getBoundingClientRect();\n const dx = canvasRect.left - hostRect.left;\n const dy = canvasRect.top - hostRect.top;\n if (dx !== canvasOffset.x || dy !== canvasOffset.y) {\n setCanvasOffset({ x: dx, y: dy });\n }\n\n const wb = api.getActiveWorkbook();\n if (!wb) {\n if (renderedRef.current.length) setRendered([]);\n return;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const activeSheet = wb.getActiveSheet() as any;\n const activeSheetId = activeSheet?.getSheetId?.();\n\n // Read viewport scroll directly from the worksheet — each frame\n // is cheap (a handful of property reads) and dodges Univer's\n // flaky `Event.Scroll` dispatch (doesn't fire on `scrollToCell`,\n // and the listener registration races the render lifecycle).\n // Cell rects come back canvas-local + pre-scroll; we convert by\n // asking for the rect of the cell currently at viewport top-left\n // — that rect's `top/left` IS the scroll offset to subtract.\n // CRITICAL: `getScrollState()` itself can throw a redi\n // QuantityCheckError during the brief window between Univer mount\n // and full render-unit DI graph setup. The whole block —\n // including the getScrollState() call — must be inside try/catch.\n // Otherwise the rAF tick throws every frame until init completes.\n let sx = 0;\n let sy = 0;\n try {\n const scrollState = activeSheet?.getScrollState?.() as\n | {\n sheetViewStartRow?: number;\n sheetViewStartColumn?: number;\n offsetX?: number;\n offsetY?: number;\n }\n | undefined;\n if (scrollState) {\n const r = scrollState.sheetViewStartRow ?? 0;\n const c = scrollState.sheetViewStartColumn ?? 0;\n const topLeft = activeSheet.getRange(r, c).getCellRect();\n if (topLeft) {\n sx = topLeft.left + (scrollState.offsetX ?? 0);\n sy = topLeft.top + (scrollState.offsetY ?? 0);\n }\n }\n } catch {\n /* skeleton / scroll service not ready — leave scroll at 0 this frame */\n }\n // Stash the latest scroll for downstream consumers (ChartOverlay).\n // We no longer need a tick counter to gate recomputes — they fire\n // every frame now.\n scrollRef.current = { x: sx, y: sy };\n\n // Header gutter — see univer-dom.getHeaderGutter. Without this,\n // charts sit ~40 px above and left of their cell anchor.\n const gutter = getHeaderGutter(api);\n\n // Zoom — getCellRect returns logical content coords; Univer\n // applies zoom as a scene transform when drawing the canvas.\n // Multiply (content - scroll) by zoom so the overlay tracks\n // the canvas at any zoom level. See PresenceLayer for the\n // same pattern + rationale.\n let zoom = 1;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ws = activeSheet as any;\n const z =\n (ws?._worksheet?.getZoomRatio?.() as number | undefined) ??\n (ws?.getZoomRatio?.() as number | undefined);\n if (typeof z === 'number' && z > 0) zoom = z;\n } catch {\n /* zoom unreadable — leave at 1 */\n }\n\n const out: RenderedChart[] = [];\n for (const c of charts) {\n if (c.sheetId !== activeSheetId) continue;\n try {\n const tl = activeSheet.getRange(c.pos.startRow, c.pos.startColumn).getCellRect();\n const br = activeSheet.getRange(c.pos.endRow, c.pos.endColumn).getCellRect();\n if (!tl || !br) continue;\n const left = (Math.min(tl.left, br.left) - sx) * zoom + dx + gutter.rowHeaderWidth;\n const top = (Math.min(tl.top, br.top) - sy) * zoom + dy + gutter.columnHeaderHeight;\n const right = (Math.max(tl.right, br.right) - sx) * zoom + dx + gutter.rowHeaderWidth;\n const bottom =\n (Math.max(tl.bottom, br.bottom) - sy) * zoom + dy + gutter.columnHeaderHeight;\n // Clip — charts mostly off-canvas don't render (saves\n // ECharts a redraw); partially off is fine because the\n // overlay overflow:hidden on the layer below clips it.\n if (right < dx || bottom < dy) continue;\n if (left > dx + canvasRect.width || top > dy + canvasRect.height) continue;\n out.push({\n id: c.id,\n rect: { left, top, width: right - left, height: bottom - top },\n });\n } catch {\n /* getCellRect can throw mid-resize — drop this frame */\n }\n }\n if (rectsEqual(out, renderedRef.current)) return;\n setRendered(out);\n };\n\n const tick = () => {\n // Recompute every animation frame. The cost is dominated by a\n // handful of `getCellRect` calls per chart and one `getHeaderGutter`\n // lookup — easily under a millisecond for typical workbooks.\n // Throttling to every 4 frames was the source of charts visually\n // pinning to the viewport for ~50 ms at the start of any scroll\n // (same root cause as the remote-cursor scroll-pin bug —\n // see docs/COLLAB-FIXES.md #14).\n recompute();\n raf = requestAnimationFrame(tick);\n };\n raf = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(raf);\n // charts + api are the inputs; rendered is the output.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [api, charts]);\n\n // Delete key removes the selected chart. Excel uses Delete/Backspace\n // both — match that. We ignore the press if the focus is in a text\n // input (formula bar, cell editor, dialog inputs) so the user can\n // still delete characters there. Also Esc clears selection.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (!selectedId) return;\n const t = e.target as HTMLElement | null;\n const tag = t?.tagName;\n const inText = tag === 'INPUT' || tag === 'TEXTAREA' || (t?.isContentEditable ?? false);\n if (e.key === 'Escape') {\n select(null);\n return;\n }\n if (!inText && (e.key === 'Delete' || e.key === 'Backspace')) {\n e.preventDefault();\n remove(selectedId);\n }\n };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [selectedId, remove, select]);\n\n // Listen for the right-click event ChartOverlay dispatches. We can't\n // mount the context menu inside ChartOverlay because the menu needs\n // to escape the overlay's clipping + sit at viewport coords.\n useEffect(() => {\n const onCtx = (e: Event) => {\n const ce = e as CustomEvent<{ id: string; x: number; y: number }>;\n setCtxMenu(ce.detail);\n };\n document.addEventListener('casual-chart-contextmenu', onCtx);\n return () => document.removeEventListener('casual-chart-contextmenu', onCtx);\n }, []);\n\n // Click anywhere outside any chart deselects. Capture-phase so the\n // grid canvas doesn't consume the event first. Skip if the click\n // originated inside a chart overlay or the context menu.\n useEffect(() => {\n const onClick = (e: MouseEvent) => {\n const t = e.target as HTMLElement | null;\n if (!t) return;\n if (t.closest('.chart-overlay')) return;\n if (t.closest('.chart-context-menu')) return;\n if (selectedId) select(null);\n };\n document.addEventListener('mousedown', onClick, true);\n return () => document.removeEventListener('mousedown', onClick, true);\n }, [selectedId, select]);\n\n const host = hostRef.current ?? getUniverHost();\n if (rendered.length === 0 && !ctxMenu) return null;\n if (!host) return null;\n\n return createPortal(\n <div\n className=\"chart-layer\"\n data-testid=\"chart-layer\"\n // z-index matches presence-layer so chart overlays sit above\n // Univer's main grid canvas (which has its own stacking context).\n // pointerEvents: none keeps clicks on empty space passing through\n // to the canvas; .chart-overlay re-enables pointer events.\n style={{\n position: 'absolute',\n inset: 0,\n overflow: 'hidden',\n pointerEvents: 'none',\n zIndex: 60,\n }}\n >\n {rendered.map((r) => {\n const model = charts.find((c) => c.id === r.id);\n if (!model) return null;\n // ChartOverlay positions itself absolutely (left/top/w/h from\n // `r.rect`). Render it directly — the previous wrapper used\n // `inset: 0` which covered the ENTIRE host with pointer-events\n // and intercepted clicks meant for empty grid cells.\n return (\n <ChartOverlay\n key={r.id}\n model={model}\n rect={r.rect}\n canvasOffset={canvasOffset}\n scroll={scrollRef.current}\n />\n );\n })}\n {ctxMenu && (\n <ChartContextMenu\n chartId={ctxMenu.id}\n x={ctxMenu.x}\n y={ctxMenu.y}\n onClose={() => setCtxMenu(null)}\n />\n )}\n </div>,\n host,\n );\n}\n\nfunction rectsEqual(a: RenderedChart[], b: RenderedChart[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i += 1) {\n const x = a[i];\n const y = b[i];\n if (x.id !== y.id) return false;\n if (\n x.rect.left !== y.rect.left ||\n x.rect.top !== y.rect.top ||\n x.rect.width !== y.rect.width ||\n x.rect.height !== y.rect.height\n ) {\n return false;\n }\n }\n return true;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @casualoffice/sheets — Casual Sheets SDK\n *\n * Three surfaces:\n * - `./signing` — anchored cell signatures (drawn / typed / uploaded).\n * - `./embed` — iframe postMessage protocol for host integrations.\n * - `./sheets` — `CasualSheets` React wrapper around Univer Sheets.\n *\n * The `./styles` side-effect entry brings in the eager plugin CSS:\n *\n * import '@casualoffice/sheets/styles';\n */\n\nexport * from './signing';\nexport * from './embed';\nexport * from './sheets';\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SigningProvider — wraps a signing session in React context so\n * descendant components (SigningPane, capture surfaces, and the\n * editor's field-highlight decorations) all see the same snapshot.\n *\n * The pure state machine lives in `./controller.ts`; this file\n * just bridges it to React.\n */\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react';\n\nimport {\n createSigningController,\n type SigningController,\n type SigningSnapshot,\n} from './controller';\nimport type {\n CancelReason,\n SignatureCompletePayload,\n SignedFieldPayload,\n SigningSessionConfig,\n} from './types';\n\ninterface SigningContextValue {\n controller: SigningController;\n snapshot: SigningSnapshot;\n /** Convenience wrapper around controller.signField that also fires the host's onFieldSigned. */\n signField: (payload: SignedFieldPayload) => Promise<void>;\n /** Convenience wrapper around controller.complete + host's onComplete. */\n completeIfReady: () => Promise<void>;\n /** Convenience wrapper around controller.cancel + host's onCancel. */\n cancel: (reason: CancelReason) => void;\n /** Source-of-truth document bytes the editor renders. Captured at\n * signing-session open; persists for the lifetime of the session. */\n baseDocumentBytes: ArrayBuffer | null;\n}\n\nconst SigningContext = createContext<SigningContextValue | null>(null);\n\nexport interface SigningProviderProps {\n /** Active signing session config. When null, signing is off and\n * children render unchanged. */\n session: SigningSessionConfig | null;\n /** Current document bytes the editor is rendering. Captured into\n * the context so the eventual `complete` payload carries the\n * right base buffer. */\n documentBytes: ArrayBuffer | null;\n children: ReactNode;\n}\n\nexport function SigningProvider({ session, documentBytes, children }: SigningProviderProps) {\n if (!session) {\n return <>{children}</>;\n }\n return (\n <SigningProviderInner session={session} documentBytes={documentBytes}>\n {children}\n </SigningProviderInner>\n );\n}\n\nfunction SigningProviderInner({\n session,\n documentBytes,\n children,\n}: {\n session: SigningSessionConfig;\n documentBytes: ArrayBuffer | null;\n children: ReactNode;\n}) {\n // Controller is constructed once per session-config identity.\n // Hosts that swap sessions mid-tree must change the React `key`\n // on the provider — otherwise stale state would leak.\n const controller = useMemo(\n () => createSigningController(session.fields, session.mode),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [session.fields, session.mode],\n );\n\n const [snapshot, setSnapshot] = useState<SigningSnapshot>(() => controller.snapshot());\n\n useEffect(() => {\n const unsub = controller.subscribe(setSnapshot);\n return unsub;\n }, [controller]);\n\n const value = useMemo<SigningContextValue>(\n () => ({\n controller,\n snapshot,\n signField: async (payload) => {\n controller.signField(payload);\n await session.onFieldSigned?.(payload);\n },\n completeIfReady: async () => {\n if (!controller.snapshot().canComplete) return;\n const final = controller.complete();\n const completePayload: SignatureCompletePayload = {\n fieldIds: final.fields\n .map((f) => f.fieldId)\n .filter((id) => final.signed[id] !== undefined),\n bytes: documentBytes ?? new ArrayBuffer(0),\n fields: final.signed,\n };\n await session.onComplete?.(completePayload);\n },\n cancel: (reason) => {\n controller.cancel();\n session.onCancel?.({ reason });\n },\n baseDocumentBytes: documentBytes,\n }),\n [controller, snapshot, session, documentBytes],\n );\n\n return <SigningContext.Provider value={value}>{children}</SigningContext.Provider>;\n}\n\n/**\n * Hook for descendants of <SigningProvider>. Returns null when\n * no signing session is active — caller renders its non-signing\n * shape.\n */\nexport function useSigning(): SigningContextValue | null {\n return useContext(SigningContext);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Signing state machine — pure with respect to React so bun-test\n * can exercise it without a renderer. The React wrappers\n * (SigningProvider / SigningPane) sit on top of this.\n *\n * Single source of truth for \"which field is the signer on,\n * which fields are done, can we complete yet\" — the React layer\n * never recomputes these from scratch.\n */\n\nimport type { SignedFieldPayload, SignatureField, SignatureMode } from './types';\n\nexport interface SigningSnapshot {\n fields: SignatureField[];\n mode: SignatureMode;\n /** Fields completed in order they were signed. */\n signed: Record<string, SignedFieldPayload>;\n /** Index into `fields` of the field the signer should focus on\n * next. -1 once everything required is done. */\n activeFieldIndex: number;\n /** True once every required field has a payload. */\n canComplete: boolean;\n /** True once the controller has received a completion command. */\n isComplete: boolean;\n /** True if a cancel has been emitted. */\n isCancelled: boolean;\n}\n\nexport interface SigningController {\n snapshot(): SigningSnapshot;\n subscribe(listener: (s: SigningSnapshot) => void): () => void;\n /** Record a signed field. Throws if the field id is unknown. */\n signField(payload: SignedFieldPayload): void;\n /** Move focus to a specific field (concurrent mode let users\n * pick); in sequential mode the controller silently no-ops if\n * the requested field isn't the next required. */\n focusField(fieldId: string): void;\n /** Mark the session complete. Returns the snapshot at the\n * moment of completion; throws if not yet canComplete. */\n complete(): SigningSnapshot;\n /** Mark the session cancelled. Idempotent. */\n cancel(): void;\n}\n\nexport function createSigningController(\n fields: SignatureField[],\n mode: SignatureMode,\n): SigningController {\n if (fields.length === 0) {\n throw new Error('createSigningController: at least one field required');\n }\n const fieldIds = new Set(fields.map((f) => f.fieldId));\n if (fieldIds.size !== fields.length) {\n throw new Error('createSigningController: duplicate fieldId');\n }\n\n const signed: Record<string, SignedFieldPayload> = {};\n let activeFieldIndex = nextRequiredIndex(fields, signed);\n let isComplete = false;\n let isCancelled = false;\n const listeners = new Set<(s: SigningSnapshot) => void>();\n\n function emit() {\n const snap = snapshotInternal();\n for (const l of listeners) l(snap);\n }\n\n function snapshotInternal(): SigningSnapshot {\n return {\n fields,\n mode,\n signed: { ...signed },\n activeFieldIndex,\n canComplete: allRequiredSigned(fields, signed),\n isComplete,\n isCancelled,\n };\n }\n\n return {\n snapshot: snapshotInternal,\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n signField(payload) {\n if (isComplete || isCancelled) return;\n if (!fieldIds.has(payload.fieldId)) {\n throw new Error(`signField: unknown fieldId ${payload.fieldId}`);\n }\n signed[payload.fieldId] = payload;\n activeFieldIndex = nextRequiredIndex(fields, signed);\n emit();\n },\n focusField(fieldId) {\n if (isComplete || isCancelled) return;\n const idx = fields.findIndex((f) => f.fieldId === fieldId);\n if (idx < 0) return;\n if (mode === 'sequential') {\n // Sequential mode: only the next-required field is focusable.\n const next = nextRequiredIndex(fields, signed);\n if (idx !== next) return;\n }\n activeFieldIndex = idx;\n emit();\n },\n complete() {\n if (!allRequiredSigned(fields, signed)) {\n throw new Error('complete: required fields are still unsigned');\n }\n isComplete = true;\n activeFieldIndex = -1;\n emit();\n return snapshotInternal();\n },\n cancel() {\n if (isComplete || isCancelled) return;\n isCancelled = true;\n activeFieldIndex = -1;\n emit();\n },\n };\n}\n\n// ---------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------\n\nfunction allRequiredSigned(\n fields: SignatureField[],\n signed: Record<string, SignedFieldPayload>,\n): boolean {\n return fields.every((f) => !f.required || signed[f.fieldId] !== undefined);\n}\n\nfunction nextRequiredIndex(\n fields: SignatureField[],\n signed: Record<string, SignedFieldPayload>,\n): number {\n for (let i = 0; i < fields.length; i++) {\n if (fields[i].required && !signed[fields[i].fieldId]) return i;\n }\n // Either all required are done OR no required exists; pick the\n // first unsigned optional.\n for (let i = 0; i < fields.length; i++) {\n if (!signed[fields[i].fieldId]) return i;\n }\n return -1;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SigningPane — the floating sidebar that walks the signer through\n * fields. Lives inside <SigningProvider>; uses the controller via\n * `useSigning()`.\n *\n * Layout: a right-anchored panel showing\n * - Banner (optional, from session config)\n * - Field list with state markers (active / signed / pending)\n * - Method picker for the active field\n * - Capture surface (Drawn / Typed / Uploaded) depending on method\n * - Footer: Cancel + Complete\n *\n * The pane is presentation-only — every action routes through the\n * SigningProvider's helpers (signField, completeIfReady, cancel)\n * so the controller stays the single source of truth.\n */\n\nimport { useEffect, useState, type CSSProperties } from 'react';\n\nimport { useSigning } from './SigningProvider';\nimport type { SignatureField, SignatureMethod, SignedFieldPayload } from './types';\nimport {\n DrawnSignaturePad,\n TypedSignatureField,\n UploadedSignatureField,\n type CapturedSignature,\n} from './captures';\n\nexport interface SigningPaneProps {\n /** Optional banner override; falls back to session.banner. */\n banner?: string;\n /** Optional data-testid root. */\n testId?: string;\n}\n\nexport function SigningPane({ banner, testId = 'signing-pane' }: SigningPaneProps) {\n const ctx = useSigning();\n if (!ctx) return null;\n\n const { snapshot, signField, completeIfReady, cancel } = ctx;\n if (snapshot.isComplete || snapshot.isCancelled) return null;\n\n const active: SignatureField | null =\n snapshot.activeFieldIndex >= 0 ? snapshot.fields[snapshot.activeFieldIndex] : null;\n\n return (\n <aside style={paneStyle} role=\"region\" aria-label=\"Signing pane\" data-testid={testId}>\n {banner && (\n <div style={bannerStyle} data-testid={`${testId}-banner`}>\n {banner}\n </div>\n )}\n <div style={listStyle} data-testid={`${testId}-fields`}>\n {snapshot.fields.map((f, i) => {\n const isSigned = !!snapshot.signed[f.fieldId];\n const isActive = i === snapshot.activeFieldIndex;\n return (\n <div\n key={f.fieldId}\n style={listItemStyle(isActive, isSigned)}\n data-testid={`${testId}-field-${f.fieldId}`}\n data-state={isSigned ? 'signed' : isActive ? 'active' : 'pending'}\n >\n <span style={listIconStyle(isSigned)} aria-hidden=\"true\">\n {isSigned ? '✓' : i + 1}\n </span>\n <span style={listLabelStyle}>{f.label}</span>\n {!f.required && (\n <span style={optionalChipStyle} aria-label=\"Optional\">\n optional\n </span>\n )}\n </div>\n );\n })}\n </div>\n\n {active && (\n <ActiveFieldEditor\n field={active}\n testId={testId}\n onCapture={async (cap, method) => {\n const payload: SignedFieldPayload = {\n fieldId: active.fieldId,\n method,\n bytes: cap.bytes,\n mime: cap.mime,\n signedAt: new Date().toISOString(),\n };\n await signField(payload);\n }}\n />\n )}\n\n {!active && snapshot.canComplete && (\n <div style={completeBlockStyle} data-testid={`${testId}-complete-block`}>\n All required signatures collected. Ready to finalise.\n </div>\n )}\n\n <footer style={footerStyle}>\n <button\n type=\"button\"\n onClick={() => cancel('signer_cancelled')}\n style={secondaryBtnStyle()}\n data-testid={`${testId}-cancel`}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void completeIfReady()}\n disabled={!snapshot.canComplete}\n style={primaryBtnStyle(!snapshot.canComplete)}\n data-testid={`${testId}-complete`}\n >\n Complete\n </button>\n </footer>\n </aside>\n );\n}\n\n// ---------------------------------------------------------------\n// Active field editor — method picker + capture surface\n// ---------------------------------------------------------------\n\nfunction ActiveFieldEditor({\n field,\n testId,\n onCapture,\n}: {\n field: SignatureField;\n testId: string;\n onCapture: (cap: CapturedSignature, method: SignatureMethod) => void | Promise<void>;\n}) {\n const [method, setMethod] = useState<SignatureMethod>(field.methods[0]);\n\n // Reset the method picker whenever the active field changes — a\n // method that was valid for the previous field may not be in this\n // field's list.\n useEffect(() => {\n setMethod(field.methods[0]);\n }, [field]);\n\n return (\n <div style={editorStyle} data-testid={`${testId}-editor`}>\n <div style={editorHeaderStyle}>\n <div style={editorLabelStyle}>{field.label}</div>\n {field.signer?.name && <div style={editorSignerStyle}>{field.signer.name}</div>}\n </div>\n {field.methods.length > 1 && (\n <div style={methodTabsStyle} role=\"tablist\" data-testid={`${testId}-methods`}>\n {field.methods.map((m) => (\n <button\n key={m}\n type=\"button\"\n role=\"tab\"\n aria-selected={method === m}\n onClick={() => setMethod(m)}\n style={methodTabStyle(method === m)}\n data-testid={`${testId}-method-${m}`}\n >\n {methodLabel(m)}\n </button>\n ))}\n </div>\n )}\n <div style={captureWrapStyle}>\n {method === 'drawn' && <DrawnSignaturePad onCapture={(c) => onCapture(c, 'drawn')} />}\n {method === 'typed' && (\n <TypedSignatureField\n defaultText={field.signer?.name ?? ''}\n onCapture={(c) => onCapture(c, 'typed')}\n />\n )}\n {method === 'uploaded' && (\n <UploadedSignatureField onCapture={(c) => onCapture(c, 'uploaded')} />\n )}\n </div>\n </div>\n );\n}\n\nfunction methodLabel(m: SignatureMethod): string {\n switch (m) {\n case 'drawn':\n return 'Draw';\n case 'typed':\n return 'Type';\n case 'uploaded':\n return 'Upload';\n }\n}\n\n// ---------------------------------------------------------------\n// Styles\n// ---------------------------------------------------------------\n\nconst paneStyle: CSSProperties = {\n position: 'fixed',\n top: 16,\n right: 16,\n bottom: 16,\n width: 360,\n maxWidth: '100vw',\n display: 'flex',\n flexDirection: 'column',\n gap: 14,\n padding: 16,\n background: 'var(--doc-surface, #fff)',\n border: '1px solid var(--doc-border, #cbd5e1)',\n borderRadius: 12,\n boxShadow: '0 1px 1px rgba(0, 0, 0, 0.04), 0 6px 24px rgba(15, 23, 42, 0.12)',\n fontFamily: 'inherit',\n zIndex: 9000,\n};\n\nconst bannerStyle: CSSProperties = {\n padding: '8px 10px',\n background: 'var(--doc-surface-2, #f1f5f9)',\n border: '1px solid var(--doc-border-light, #e2e8f0)',\n borderRadius: 6,\n fontSize: 12,\n color: 'var(--doc-text-muted, #475569)',\n};\n\nconst listStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n};\n\nfunction listItemStyle(active: boolean, signed: boolean): CSSProperties {\n return {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n borderRadius: 6,\n background: active ? 'var(--doc-surface-2, #f1f5f9)' : signed ? 'transparent' : 'transparent',\n border: active ? '1px solid var(--doc-border, #cbd5e1)' : '1px solid transparent',\n opacity: signed && !active ? 0.7 : 1,\n };\n}\n\nfunction listIconStyle(signed: boolean): CSSProperties {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 22,\n height: 22,\n borderRadius: '50%',\n background: signed ? 'var(--doc-accent, #2563eb)' : 'var(--doc-surface-2, #f1f5f9)',\n color: signed ? '#fff' : 'var(--doc-text-muted, #475569)',\n fontSize: 12,\n fontWeight: 600,\n flexShrink: 0,\n };\n}\n\nconst listLabelStyle: CSSProperties = {\n flex: 1,\n fontSize: 13,\n color: 'var(--doc-text, #0f172a)',\n fontWeight: 500,\n};\n\nconst optionalChipStyle: CSSProperties = {\n fontSize: 11,\n color: 'var(--doc-text-muted, #64748b)',\n padding: '2px 6px',\n background: 'var(--doc-surface-2, #f1f5f9)',\n borderRadius: 4,\n};\n\nconst editorStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n};\n\nconst editorHeaderStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n};\n\nconst editorLabelStyle: CSSProperties = {\n fontSize: 13,\n fontWeight: 600,\n color: 'var(--doc-text, #0f172a)',\n};\n\nconst editorSignerStyle: CSSProperties = {\n fontSize: 12,\n color: 'var(--doc-text-muted, #64748b)',\n};\n\nconst methodTabsStyle: CSSProperties = {\n display: 'flex',\n gap: 4,\n padding: 2,\n background: 'var(--doc-surface-2, #f1f5f9)',\n borderRadius: 6,\n};\n\nfunction methodTabStyle(selected: boolean): CSSProperties {\n return {\n flex: 1,\n padding: '6px 10px',\n background: selected ? 'var(--doc-surface, #fff)' : 'transparent',\n border: 'none',\n borderRadius: 4,\n fontSize: 12,\n fontWeight: 500,\n color: selected ? 'var(--doc-text, #0f172a)' : 'var(--doc-text-muted, #475569)',\n cursor: 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nconst captureWrapStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n};\n\nconst completeBlockStyle: CSSProperties = {\n padding: '10px 12px',\n background: 'rgba(34, 197, 94, 0.08)',\n border: '1px solid rgba(34, 197, 94, 0.28)',\n borderRadius: 6,\n fontSize: 12,\n color: 'rgb(20, 83, 45)',\n};\n\nconst footerStyle: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n marginTop: 'auto',\n paddingTop: 12,\n borderTop: '1px solid var(--doc-border-light, #e2e8f0)',\n};\n\nfunction primaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid transparent',\n background: disabled ? 'var(--doc-border, #cbd5e1)' : 'var(--doc-accent, #2563eb)',\n color: disabled ? 'var(--doc-text-muted, #64748b)' : '#fff',\n fontSize: 13,\n fontWeight: 600,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nfunction secondaryBtnStyle(): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid var(--doc-border, #cbd5e1)',\n background: 'transparent',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Three signature-capture surfaces: drawn (canvas), typed (input\n * rendered in a script font), uploaded (image file picker).\n *\n * Each one emits an `{ bytes, mime }` pair that the parent feeds\n * into SigningContext.signField. The components are presentation +\n * input only — they don't know about the controller or the field\n * they're capturing for.\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\nexport interface CapturedSignature {\n bytes: ArrayBuffer;\n mime: string;\n}\n\n// ---------------------------------------------------------------\n// Drawn — canvas\n// ---------------------------------------------------------------\n\nexport interface DrawnSignaturePadProps {\n /** Fired when the user clicks \"Use this signature\". */\n onCapture: (sig: CapturedSignature) => void;\n /** Optional clear-button label override. */\n clearLabel?: string;\n /** Optional save-button label override. */\n saveLabel?: string;\n /** Canvas pixel size. Default 480 × 160. */\n width?: number;\n height?: number;\n}\n\nexport function DrawnSignaturePad({\n onCapture,\n clearLabel = 'Clear',\n saveLabel = 'Use this signature',\n width = 480,\n height = 160,\n}: DrawnSignaturePadProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const drawingRef = useRef(false);\n const [hasInk, setHasInk] = useState(false);\n\n // Set up a clean canvas on mount. Background is transparent so\n // the stamped image composites cleanly over the document.\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.strokeStyle = '#0f172a';\n ctx.lineWidth = 2;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n }, []);\n\n const start = (e: React.PointerEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const { x, y } = pointerPos(e, canvas);\n ctx.beginPath();\n ctx.moveTo(x, y);\n drawingRef.current = true;\n canvas.setPointerCapture(e.pointerId);\n };\n\n const move = (e: React.PointerEvent<HTMLCanvasElement>) => {\n if (!drawingRef.current) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const { x, y } = pointerPos(e, canvas);\n ctx.lineTo(x, y);\n ctx.stroke();\n if (!hasInk) setHasInk(true);\n };\n\n const end = (e: React.PointerEvent<HTMLCanvasElement>) => {\n drawingRef.current = false;\n canvasRef.current?.releasePointerCapture(e.pointerId);\n };\n\n const clear = () => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n setHasInk(false);\n };\n\n const save = async () => {\n const canvas = canvasRef.current;\n if (!canvas || !hasInk) return;\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob((b) => resolve(b), 'image/png');\n });\n if (!blob) return;\n const bytes = await blob.arrayBuffer();\n onCapture({ bytes, mime: 'image/png' });\n clear();\n };\n\n return (\n <div style={padWrapStyle} data-testid=\"drawn-signature-pad\">\n <canvas\n ref={canvasRef}\n width={width}\n height={height}\n style={padCanvasStyle(width, height)}\n onPointerDown={start}\n onPointerMove={move}\n onPointerUp={end}\n onPointerLeave={end}\n data-testid=\"drawn-signature-canvas\"\n />\n <div style={padActionsStyle}>\n <button type=\"button\" onClick={clear} style={secondaryBtnStyle(false)}>\n {clearLabel}\n </button>\n <button\n type=\"button\"\n onClick={save}\n disabled={!hasInk}\n style={primaryBtnStyle(!hasInk)}\n data-testid=\"drawn-signature-save\"\n >\n {saveLabel}\n </button>\n </div>\n </div>\n );\n}\n\nfunction pointerPos(e: React.PointerEvent<HTMLCanvasElement>, canvas: HTMLCanvasElement) {\n const rect = canvas.getBoundingClientRect();\n const scaleX = canvas.width / rect.width;\n const scaleY = canvas.height / rect.height;\n return {\n x: (e.clientX - rect.left) * scaleX,\n y: (e.clientY - rect.top) * scaleY,\n };\n}\n\n// ---------------------------------------------------------------\n// Typed\n// ---------------------------------------------------------------\n\nexport interface TypedSignatureFieldProps {\n onCapture: (sig: CapturedSignature) => void;\n defaultText?: string;\n saveLabel?: string;\n}\n\nexport function TypedSignatureField({\n onCapture,\n defaultText = '',\n saveLabel = 'Use this signature',\n}: TypedSignatureFieldProps) {\n const [value, setValue] = useState(defaultText);\n const save = () => {\n const trimmed = value.trim();\n if (!trimmed) return;\n const bytes = new TextEncoder().encode(trimmed).buffer;\n onCapture({ bytes, mime: 'text/plain' });\n setValue('');\n };\n return (\n <div style={padWrapStyle} data-testid=\"typed-signature-field\">\n <input\n type=\"text\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Type your full name\"\n style={typedInputStyle}\n data-testid=\"typed-signature-input\"\n autoFocus\n />\n <div style={padActionsStyle}>\n <button\n type=\"button\"\n onClick={save}\n disabled={!value.trim()}\n style={primaryBtnStyle(!value.trim())}\n data-testid=\"typed-signature-save\"\n >\n {saveLabel}\n </button>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------\n// Uploaded\n// ---------------------------------------------------------------\n\nexport interface UploadedSignatureFieldProps {\n onCapture: (sig: CapturedSignature) => void;\n /** Accept attribute. Default image/*. */\n accept?: string;\n}\n\nexport function UploadedSignatureField({\n onCapture,\n accept = 'image/png,image/jpeg,image/svg+xml',\n}: UploadedSignatureFieldProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const [fileName, setFileName] = useState<string | null>(null);\n const onChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const bytes = await file.arrayBuffer();\n onCapture({ bytes, mime: file.type || 'application/octet-stream' });\n setFileName(file.name);\n if (inputRef.current) inputRef.current.value = '';\n };\n return (\n <div style={padWrapStyle} data-testid=\"uploaded-signature-field\">\n <label style={uploadLabelStyle}>\n <input\n ref={inputRef}\n type=\"file\"\n accept={accept}\n onChange={onChange}\n style={{ display: 'none' }}\n data-testid=\"uploaded-signature-input\"\n />\n <span>{fileName ?? 'Choose image…'}</span>\n </label>\n </div>\n );\n}\n\n// ---------------------------------------------------------------\n// Shared styles\n// ---------------------------------------------------------------\n\nconst padWrapStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 10,\n};\n\nconst padCanvasStyle = (w: number, h: number): CSSProperties => ({\n width: w,\n height: h,\n maxWidth: '100%',\n border: '1px dashed var(--doc-border, #cbd5e1)',\n borderRadius: 8,\n background: 'var(--doc-surface, #fff)',\n cursor: 'crosshair',\n touchAction: 'none',\n});\n\nconst padActionsStyle: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 8,\n};\n\nconst typedInputStyle: CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n border: '1px solid var(--doc-border, #cbd5e1)',\n borderRadius: 6,\n fontSize: 18,\n fontFamily: '\"Caveat\", \"Dancing Script\", \"Brush Script MT\", cursive',\n background: 'var(--doc-surface, #fff)',\n color: 'var(--doc-text, #0f172a)',\n};\n\nconst uploadLabelStyle: CSSProperties = {\n display: 'inline-flex',\n padding: '8px 14px',\n border: '1px dashed var(--doc-border, #cbd5e1)',\n borderRadius: 6,\n background: 'var(--doc-surface, #fff)',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n cursor: 'pointer',\n alignSelf: 'flex-start',\n};\n\nfunction primaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid transparent',\n background: disabled ? 'var(--doc-border, #cbd5e1)' : 'var(--doc-accent, #2563eb)',\n color: disabled ? 'var(--doc-text-muted, #64748b)' : '#fff',\n fontSize: 13,\n fontWeight: 600,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n\nfunction secondaryBtnStyle(disabled: boolean): CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid var(--doc-border, #cbd5e1)',\n background: 'transparent',\n color: 'var(--doc-text, #0f172a)',\n fontSize: 13,\n fontWeight: 500,\n cursor: disabled ? 'not-allowed' : 'pointer',\n fontFamily: 'inherit',\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Iframe protocol — wire envelopes that match\n * `docs/internal/13-iframe-protocol.md`.\n *\n * Mirror updates to the doc whenever a new envelope shape lands.\n * The discriminator on `type` (always starts with `casual.`) and\n * the per-envelope `data` shape are the contract.\n */\n\nimport type {\n CancelReason,\n SignatureCompletePayload,\n SignatureField,\n SignatureMode,\n SignedFieldPayload,\n} from '../signing/types';\n\nexport type CasualApp = 'docs' | 'sheet';\n\n/** Common envelope shape — every postMessage on the wire matches this. */\nexport interface CasualEnvelope<T = unknown> {\n type: string;\n app: CasualApp;\n /** Per-request id for request/response correlation. Empty for fire-and-forget. */\n id?: string;\n /** Protocol version. Bumped only on breaking changes. */\n v: 1;\n data: T;\n}\n\n// ---------------------------------------------------------------\n// Handshake\n// ---------------------------------------------------------------\n\nexport interface EditorHelloData {\n capabilities: string[];\n version: string;\n commit: string;\n}\n\nexport interface HostHelloData {\n capabilities: string[];\n authToken?: string;\n}\n\n// ---------------------------------------------------------------\n// Load + save (editor → host requests; host → editor responses)\n// ---------------------------------------------------------------\n\nexport interface LoadRequestData {\n docId: string;\n}\n\nexport interface LoadResponseDataOk {\n ok: true;\n bytes: ArrayBuffer;\n etag?: string;\n fileName: string;\n readOnly?: boolean;\n}\n\nexport interface LoadResponseDataErr {\n ok: false;\n code: string;\n message?: string;\n}\n\nexport type LoadResponseData = LoadResponseDataOk | LoadResponseDataErr;\n\nexport interface SaveRequestData {\n docId: string;\n bytes: ArrayBuffer;\n baseEtag?: string;\n}\n\nexport interface SaveResponseDataOk {\n ok: true;\n etag: string;\n}\n\nexport interface SaveResponseDataErr {\n ok: false;\n code: string;\n etag?: string;\n message?: string;\n}\n\nexport type SaveResponseData = SaveResponseDataOk | SaveResponseDataErr;\n\n// ---------------------------------------------------------------\n// Save / exit notifications (editor → host, fire-and-forget)\n// ---------------------------------------------------------------\n//\n// The lightweight counterpart to the bytes-carrying load/save *request*\n// pair above. These mirror the SDK's React `onSave` / `onExit` hooks one\n// for one — the \"one shape, two surfaces\" save/exit contract — so a host\n// that frames the iframe gets the same persistence signals a host that\n// renders `<CasualSheets>` directly does. Fire-and-forget: the editor\n// never owns storage; the host decides what to do with the snapshot.\n//\n// `casual.save.request` (above) stays the WOPI-style path for hosts that\n// want xlsx bytes + etag round-trips; these notifications are the simpler\n// \"here's the current state, persist it however you like\" path.\n\n/** Editor → host: the user explicitly asked to save — Ctrl/Cmd+S inside\n * the iframe, or the host's `casual.command.save`. Carries the full\n * editor snapshot as JSON (sheet app: Univer's `IWorkbookData`). Mirror\n * of the React `onSave` hook. v0.9+. */\nexport interface SaveNotifyData {\n /** App-specific snapshot JSON. Sheet: `IWorkbookData`. */\n snapshot: unknown;\n /** What triggered the save: the in-editor shortcut or a host command. */\n reason: 'shortcut' | 'host';\n}\n\n/** Editor → host: the editor is unmounting / navigating away. Carries\n * the final snapshot so the host can persist on exit. Mirror of the\n * React `onExit` hook. v0.9+. */\nexport interface ExitData {\n /** App-specific snapshot JSON. Sheet: `IWorkbookData`. */\n snapshot: unknown;\n}\n\n// ---------------------------------------------------------------\n// Selection + telemetry + lock (editor → host notifications)\n// ---------------------------------------------------------------\n\nexport interface SelectionChangedData {\n docs?: { paraId: string; from: number; to: number; selectedText: string };\n sheet?: { sheet: string; from: string; to: string };\n}\n\nexport interface TelemetryEventData {\n kind: string;\n /** Arbitrary metric fields. */\n [k: string]: unknown;\n}\n\nexport interface LockLostData {\n reason: 'taken_by_other' | 'expired' | 'host_revoked';\n}\n\n// ---------------------------------------------------------------\n// Commands (host → editor)\n// ---------------------------------------------------------------\n\nexport interface CommandSetReadOnlyData {\n readOnly: boolean;\n}\n\nexport interface CommandSetThemeData {\n theme: 'light' | 'dark' | 'system';\n}\n\n/** Host → editor: enable/disable chrome features. Each key maps a toolbar\n * group / menu item / capability to a boolean; a `false` hides the control\n * AND blocks its command. Omitted keys default to enabled. Mirrors the\n * `features` prop on `<CasualSheets>`. */\nexport interface CommandSetFeaturesData {\n features: Record<string, boolean>;\n}\n\n/** Editor → host: a chrome control backed by a dialog the SDK doesn't render\n * itself (Format Cells, Insert Chart, Find & Replace, …) was activated. The\n * host renders its OWN dialog/popup and applies the result via\n * `executeCommand`. Fired only when the host opted into host-owned dialogs\n * by handling this event. */\nexport interface DialogRequestData {\n kind: string;\n context?: unknown;\n}\n\nexport interface CommandSetLocaleData {\n locale: string;\n}\n\n/** Host → editor: switch chrome density between the two consumer-facing\n * modes without re-mounting. `preview` hides toolbar / formula bar /\n * side panel / status bar / sheet tabs and runs read-only; `editor`\n * shows the full UI. Mirrors the `viewMode` prop on `<CasualSheetsIframe>`. */\nexport interface CommandSetViewModeData {\n viewMode: 'preview' | 'editor';\n}\n\n/** Host → editor: execute a formatting / navigation command against\n * the active selection in the embedded workbook. Hosts (like Casual\n * Drive) build their own toolbar above the iframe and dispatch these\n * commands instead of Univer's built-in ribbon, which the SDK can't\n * ship because the ribbon resolves IRPCChannelService at construction\n * and that service needs a worker the SDK doesn't bundle.\n *\n * v0.6 covered the toggle set; v0.7 adds the rich-format set (font,\n * size, colour, fill) + merge / unmerge. Arg-carrying commands read\n * the relevant field off `args` — every other command ignores it. */\nexport interface CommandExecuteData {\n command: // v0.6 — toggle / nav (no args)\n | 'undo'\n | 'redo'\n | 'bold'\n | 'italic'\n | 'underline'\n | 'strikethrough'\n | 'align-left'\n | 'align-center'\n | 'align-right'\n // v0.7 — rich format (args carry the value)\n | 'set-font-family'\n | 'set-font-size'\n | 'set-text-color'\n | 'reset-text-color'\n | 'set-bg-color'\n | 'reset-bg-color'\n | 'merge'\n | 'unmerge'\n // v0.8 — number formats + freeze + wrap\n | 'numfmt-currency'\n | 'numfmt-percent'\n | 'numfmt-add-decimal'\n | 'numfmt-subtract-decimal'\n | 'numfmt-custom'\n | 'wrap-toggle'\n | 'freeze-first-row'\n | 'freeze-first-column'\n | 'freeze-none';\n args?: {\n /** Used by `set-font-family`. */\n family?: string;\n /** Used by `set-font-size`. Integer point size. */\n size?: number;\n /** Used by `set-text-color` and `set-bg-color`. Hex like `#1a73e8`. */\n color?: string;\n /** Used by `numfmt-custom`. The Excel-style format string, e.g.\n * `\"#,##0.00\"`, `\"$#,##0\"`, `\"0.00%\"`, `\"d-mmm-yy\"`. v0.8+. */\n pattern?: string;\n };\n}\n\n/** Editor → host: emitted whenever the selection's active cell's\n * format flags change. Drive's toolbar mirrors this state in the\n * button \"pressed\" / value indicators so the surface always reflects\n * what the user would see in the cell. v0.7 widens the payload with\n * the rich-format read-back (fontFamily, fontSize, textColor, bgColor)\n * so the toolbar's font picker / size stepper / colour swatches stay\n * in sync without the host having to poll. */\nexport interface SelectionFormatStateData {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strikethrough: boolean;\n align: 'left' | 'center' | 'right' | null;\n /** Defined font family on the active cell, or null when the cell\n * inherits the workbook default. v0.7+. */\n fontFamily: string | null;\n /** Defined font size on the active cell, or null when the cell\n * inherits the workbook default. v0.7+. */\n fontSize: number | null;\n /** Hex text colour like `#1a73e8`, or null when default. v0.7+. */\n textColor: string | null;\n /** Hex background colour, or null when no fill is set. v0.7+. */\n bgColor: string | null;\n}\n\n// ---------------------------------------------------------------\n// Errors (editor → host fatal signals)\n// ---------------------------------------------------------------\n\n/** Editor → host: a fatal error during boot / load. Hosts surface this\n * via the wrapper's `onError` callback. */\nexport interface CasualErrorData {\n code: 'embed_not_served' | 'load_failed' | 'parse_failed' | 'boot_failed' | 'internal';\n message: string;\n}\n\n// ---------------------------------------------------------------\n// Signing (uniform with the SDK `signing` prop)\n// ---------------------------------------------------------------\n\nexport interface SignatureRequestData {\n fields: SignatureField[];\n mode: SignatureMode;\n banner?: string;\n}\n\nexport interface SignatureRequestAckData {\n ok: boolean;\n code?: string;\n}\n\nexport type SignatureFieldSignedData = SignedFieldPayload;\nexport type SignatureCompleteData = SignatureCompletePayload;\n\nexport interface SignatureCancelData {\n reason: CancelReason;\n}\n\n// ---------------------------------------------------------------\n// Type guards\n// ---------------------------------------------------------------\n\nexport function isCasualEnvelope(value: unknown): value is CasualEnvelope {\n if (!value || typeof value !== 'object') return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.type === 'string' &&\n v.type.startsWith('casual.') &&\n (v.app === 'docs' || v.app === 'sheet') &&\n v.v === 1 &&\n 'data' in v\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * EmbedTransport — postMessage bridge for the iframe-embedded\n * editor. Validates origin, dispatches envelopes to handlers,\n * sends responses back to the host. Pure TypeScript — no React.\n *\n * Wire shape defined in\n * `docs/internal/13-iframe-protocol.md` + `./protocol.ts`.\n *\n * Lifetime: constructed once when the /embed page mounts.\n * Destroyed when the page unloads. Concurrent calls into the same\n * handler are the host's responsibility (well-behaved hosts\n * serialise requests by id).\n */\n\nimport {\n isCasualEnvelope,\n type CasualApp,\n type CasualEnvelope,\n type EditorHelloData,\n type HostHelloData,\n type LoadResponseData,\n type LoadRequestData,\n type SaveRequestData,\n type SaveResponseData,\n type SaveNotifyData,\n type ExitData,\n type SelectionChangedData,\n type TelemetryEventData,\n type CommandSetReadOnlyData,\n type CommandSetThemeData,\n type CommandSetLocaleData,\n type CommandSetViewModeData,\n type CommandSetFeaturesData,\n type DialogRequestData,\n type CommandExecuteData,\n type SelectionFormatStateData,\n type CasualErrorData,\n type SignatureRequestData,\n type SignatureRequestAckData,\n type SignatureFieldSignedData,\n type SignatureCompleteData,\n type SignatureCancelData,\n} from './protocol';\n\nexport interface EmbedTransportOptions {\n app: CasualApp;\n /** Origin allowed to send messages. Required — no `*` default. */\n hostOrigin: string;\n /** Editor build identity, surfaced in the editor.hello handshake. */\n version: string;\n commit: string;\n /** Editor-side capabilities advertised at handshake. */\n capabilities: string[];\n /** Optional injection for `window.parent` — tests pass a stub. */\n parentWindow?: {\n postMessage: (msg: unknown, targetOrigin: string, transfer?: Transferable[]) => void;\n };\n /** Optional injection for the window receiving messages — tests pass a stub. */\n hostWindow?: Pick<Window, 'addEventListener' | 'removeEventListener'>;\n}\n\nexport interface EmbedTransportHandlers {\n /** Host → editor handshake. Editor responds with `editor.ready`. */\n onHostHello?: (data: HostHelloData) => void | Promise<void>;\n /** Host → editor: command.* messages. */\n onCommandSetReadOnly?: (data: CommandSetReadOnlyData) => void | Promise<void>;\n onCommandSetTheme?: (data: CommandSetThemeData) => void | Promise<void>;\n onCommandSetLocale?: (data: CommandSetLocaleData) => void | Promise<void>;\n onCommandSetFeatures?: (data: CommandSetFeaturesData) => void | Promise<void>;\n /** Host → editor: switch chrome density (preview ↔ editor). */\n onCommandSetViewMode?: (data: CommandSetViewModeData) => void | Promise<void>;\n /** Host → editor: execute a formatting / navigation command (bold,\n * italic, undo, …) against the active selection. v0.6+. */\n onCommandExecute?: (data: CommandExecuteData) => void | Promise<void>;\n onCommandFocus?: () => void | Promise<void>;\n onCommandSave?: () => void | Promise<void>;\n onCommandLoad?: () => void | Promise<void>;\n /** Host → editor signing session. Editor responds with `signature.request.ack`. */\n onSignatureRequest?: (\n data: SignatureRequestData,\n ) => SignatureRequestAckData | Promise<SignatureRequestAckData>;\n onSignatureCancel?: (data: SignatureCancelData) => void | Promise<void>;\n /** Host → editor: response to a prior load.request the editor issued. */\n onLoadResponse?: (id: string, data: LoadResponseData) => void;\n /** Host → editor: response to a prior save.request the editor issued. */\n onSaveResponse?: (id: string, data: SaveResponseData) => void;\n}\n\nexport class EmbedTransport {\n private readonly opts: Required<Omit<EmbedTransportOptions, 'parentWindow' | 'hostWindow'>> & {\n parentWindow: NonNullable<EmbedTransportOptions['parentWindow']>;\n hostWindow: NonNullable<EmbedTransportOptions['hostWindow']>;\n };\n private handlers: EmbedTransportHandlers = {};\n private destroyed = false;\n private pendingRequests = new Map<string, (env: CasualEnvelope) => void>();\n\n constructor(opts: EmbedTransportOptions) {\n this.opts = {\n ...opts,\n parentWindow:\n opts.parentWindow ??\n (typeof window !== 'undefined'\n ? (window.parent as unknown as NonNullable<EmbedTransportOptions['parentWindow']>)\n : { postMessage: () => undefined }),\n hostWindow:\n opts.hostWindow ??\n (typeof window !== 'undefined'\n ? window\n : ({\n addEventListener: () => undefined,\n removeEventListener: () => undefined,\n } as unknown as NonNullable<EmbedTransportOptions['hostWindow']>)),\n };\n this.boundMessage = this.boundMessage.bind(this);\n this.opts.hostWindow.addEventListener('message', this.boundMessage as EventListener);\n }\n\n /** Replaces the handler set. Idempotent — call multiple times. */\n on(handlers: EmbedTransportHandlers): void {\n this.handlers = { ...this.handlers, ...handlers };\n }\n\n /** Editor → Host: announce ourselves. Call once after handlers are wired. */\n sendHello(): void {\n const data: EditorHelloData = {\n capabilities: this.opts.capabilities,\n version: this.opts.version,\n commit: this.opts.commit,\n };\n this.post('casual.hello', data);\n }\n\n /** Editor → Host: editor is ready to receive commands. */\n sendReady(): void {\n this.post('casual.ready', {});\n }\n\n /** Editor → Host: ask the host to supply document bytes for `docId`. */\n async requestLoad(docId: string, timeoutMs = 30000): Promise<LoadResponseData> {\n return this.request<LoadResponseData>(\n 'casual.load.request',\n { docId } as LoadRequestData,\n timeoutMs,\n );\n }\n\n /** Editor → Host: ask the host to persist `bytes`. */\n async requestSave(req: SaveRequestData, timeoutMs = 30000): Promise<SaveResponseData> {\n return this.request<SaveResponseData>('casual.save.request', req, timeoutMs, [req.bytes]);\n }\n\n /** Editor → Host: the user asked to save (Ctrl/Cmd+S or a host save\n * command). Fire-and-forget snapshot notification — the lightweight\n * mirror of the React `onSave` hook. The host persists however it\n * likes; no response is awaited. */\n sendSaveNotify(data: SaveNotifyData): void {\n this.post('casual.save.notify', data);\n }\n\n /** Editor → Host: the editor is unmounting. Carries the final snapshot\n * so the host can persist on exit. Mirror of the React `onExit` hook. */\n sendExit(data: ExitData): void {\n this.post('casual.exit', data);\n }\n\n /** Editor → Host: selection moved. Fire-and-forget. */\n sendSelectionChanged(data: SelectionChangedData): void {\n this.post('casual.selection.changed', data);\n }\n\n /** Editor → Host: format flags on the active cell changed (bold,\n * italic, …). Drive's custom toolbar mirrors this state in its\n * \"pressed\" indicators. v0.6+. */\n sendSelectionFormatState(data: SelectionFormatStateData): void {\n this.post('casual.selection.format-state', data);\n }\n\n /** Editor → host: a host-owned dialog (Format Cells, Insert Chart, …) was\n * requested. The host renders its own UI and applies via executeCommand. */\n sendDialogRequest(data: DialogRequestData): void {\n this.post('casual.dialog.request', data);\n }\n\n /** Editor → Host: a noteworthy event. */\n sendTelemetry(data: TelemetryEventData): void {\n this.post('casual.telemetry.event', data);\n }\n\n /** Editor → Host: per-field progress during a signing session. */\n sendSignatureFieldSigned(data: SignatureFieldSignedData): void {\n // Bytes ride the transfer list.\n this.post('casual.signature.field.signed', data, [data.bytes]);\n }\n\n /** Editor → Host: signing session is finished. */\n sendSignatureComplete(data: SignatureCompleteData): void {\n this.post('casual.signature.complete', data, [data.bytes]);\n }\n\n /** Editor → Host: editor-side cancel of a signing session. */\n sendSignatureCancel(reason: SignatureCancelData['reason']): void {\n this.post('casual.signature.cancel', { reason });\n }\n\n /** Editor → Host: fatal boot / load error. Host surfaces via wrapper\n * `onError` callback. Fire-and-forget. */\n sendError(data: CasualErrorData): void {\n this.post('casual.error', data);\n }\n\n /** Tear down listeners. Idempotent. */\n destroy(): void {\n if (this.destroyed) return;\n this.opts.hostWindow.removeEventListener('message', this.boundMessage as EventListener);\n this.pendingRequests.clear();\n this.destroyed = true;\n }\n\n // ---------------------------------------------------------------\n // Internals\n // ---------------------------------------------------------------\n\n private boundMessage(ev: Event): void {\n // MessageEvent isn't always available on the typing side when\n // a stub window is injected; cast pragmatically.\n const msg = ev as unknown as MessageEvent;\n if (msg.origin && msg.origin !== this.opts.hostOrigin) return;\n if (!isCasualEnvelope(msg.data)) return;\n void this.dispatch(msg.data as CasualEnvelope);\n }\n\n private async dispatch(env: CasualEnvelope): Promise<void> {\n // Responses to outbound requests route through the correlation map.\n if (env.id && this.pendingRequests.has(env.id)) {\n const resolve = this.pendingRequests.get(env.id)!;\n this.pendingRequests.delete(env.id);\n resolve(env);\n return;\n }\n\n switch (env.type) {\n case 'casual.hello':\n await this.handlers.onHostHello?.(env.data as HostHelloData);\n this.sendReady();\n return;\n case 'casual.command.set.readonly':\n await this.handlers.onCommandSetReadOnly?.(env.data as CommandSetReadOnlyData);\n return;\n case 'casual.command.set.theme':\n await this.handlers.onCommandSetTheme?.(env.data as CommandSetThemeData);\n return;\n case 'casual.command.set.locale':\n await this.handlers.onCommandSetLocale?.(env.data as CommandSetLocaleData);\n return;\n case 'casual.command.set.features':\n await this.handlers.onCommandSetFeatures?.(env.data as CommandSetFeaturesData);\n return;\n case 'casual.command.set.viewmode':\n await this.handlers.onCommandSetViewMode?.(env.data as CommandSetViewModeData);\n return;\n case 'casual.command.execute':\n await this.handlers.onCommandExecute?.(env.data as CommandExecuteData);\n return;\n case 'casual.command.focus':\n await this.handlers.onCommandFocus?.();\n return;\n case 'casual.command.save':\n await this.handlers.onCommandSave?.();\n return;\n case 'casual.command.load':\n await this.handlers.onCommandLoad?.();\n return;\n case 'casual.signature.request': {\n const ack = (await this.handlers.onSignatureRequest?.(\n env.data as SignatureRequestData,\n )) ?? {\n ok: false,\n code: 'unhandled',\n };\n if (env.id) {\n this.postReply(env.id, 'casual.signature.request.ack', ack);\n }\n return;\n }\n case 'casual.signature.cancel':\n await this.handlers.onSignatureCancel?.(env.data as SignatureCancelData);\n return;\n default:\n // Unknown envelope — silently drop per the forward-compat\n // convention in the protocol doc.\n return;\n }\n }\n\n private post(type: string, data: unknown, transfer?: Transferable[]): void {\n const env: CasualEnvelope = { type, app: this.opts.app, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);\n } catch {\n // Cross-origin postMessage can throw if the parent went away;\n // silently swallow — the next user action will retry.\n }\n }\n\n private postReply(id: string, type: string, data: unknown): void {\n const env: CasualEnvelope = { type, app: this.opts.app, id, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin);\n } catch {\n // see post()\n }\n }\n\n private async request<T>(\n type: string,\n data: unknown,\n timeoutMs: number,\n transfer?: Transferable[],\n ): Promise<T> {\n const id = newRequestId();\n return new Promise<T>((resolve, reject) => {\n const timer =\n timeoutMs > 0\n ? setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Embed request ${type} timed out after ${timeoutMs}ms`));\n }, timeoutMs)\n : null;\n this.pendingRequests.set(id, (env) => {\n if (timer) clearTimeout(timer);\n resolve(env.data as T);\n });\n const env: CasualEnvelope = { type, app: this.opts.app, id, v: 1, data };\n try {\n this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);\n } catch (err) {\n if (timer) clearTimeout(timer);\n this.pendingRequests.delete(id);\n reject(err);\n }\n });\n }\n}\n\nfunction newRequestId(): string {\n // 8 hex chars is plenty — IDs only need to be unique within a\n // single editor session. Math.random is fine; the host can't\n // use these for security.\n return Math.random().toString(16).slice(2, 10);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * EmbedHostTransport — the parent side of the embed iframe bridge for\n * the sheet SDK. Mirror of @casualoffice/docs's host transport.\n *\n * Wire shape: `docs/SDK_SIGNING_EMBED.md` (cross-link in the doc repo at\n * `docs/internal/13-iframe-protocol.md`) + `16-sdk-iframe-architecture.md`.\n *\n * Lifetime: constructed once when the wrapper mounts the iframe.\n * `destroy()` removes the event listener; safe to call multiple times.\n */\n\nimport {\n isCasualEnvelope,\n type CasualApp,\n type CasualEnvelope,\n type CasualErrorData,\n type CommandSetReadOnlyData,\n type CommandSetThemeData,\n type CommandSetLocaleData,\n type CommandSetViewModeData,\n type CommandSetFeaturesData,\n type DialogRequestData,\n type CommandExecuteData,\n type SelectionFormatStateData,\n type EditorHelloData,\n type HostHelloData,\n type LoadRequestData,\n type LoadResponseData,\n type SaveRequestData,\n type SaveResponseData,\n type SaveNotifyData,\n type ExitData,\n type SelectionChangedData,\n type SignatureCancelData,\n type SignatureCompleteData,\n type SignatureFieldSignedData,\n type SignatureRequestData,\n type TelemetryEventData,\n} from './protocol';\n\nexport interface EmbedHostTransportOptions {\n app: CasualApp;\n /** The iframe's `contentWindow`. */\n iframeWindow: Window;\n /** Origin allowed to send + receive messages. Same-origin internal\n * embed is `window.location.origin`. */\n embedOrigin: string;\n /** Optional injection — tests pass a stub. */\n hostWindow?: Pick<Window, 'addEventListener' | 'removeEventListener'>;\n}\n\nexport interface EmbedHostHandlers {\n onEditorReady?: (data: EditorHelloData) => void;\n /** Editor requests bytes for `docId`. */\n onLoadRequest?: (data: LoadRequestData) => Promise<LoadResponseData> | LoadResponseData;\n /** Editor requests a save (WOPI-style, carries xlsx bytes). */\n onSaveRequest?: (data: SaveRequestData) => Promise<SaveResponseData> | SaveResponseData;\n /** Editor fired its lightweight save notification (Ctrl/Cmd+S or a\n * host save command). Carries the full snapshot JSON; fire-and-forget.\n * Mirror of the React `onSave` hook. */\n onSaveNotify?: (data: SaveNotifyData) => void;\n /** Editor is unmounting; carries the final snapshot. Mirror of the\n * React `onExit` hook. */\n onExit?: (data: ExitData) => void;\n onSelectionChanged?: (data: SelectionChangedData) => void;\n onSelectionFormatState?: (data: SelectionFormatStateData) => void;\n /** A host-owned dialog (Format Cells, Insert Chart, …) was requested from the\n * editor's chrome. Render your own dialog and apply via executeCommand. */\n onDialogRequest?: (data: DialogRequestData) => void;\n onTelemetry?: (data: TelemetryEventData) => void;\n onSignatureFieldSigned?: (data: SignatureFieldSignedData) => void;\n onSignatureComplete?: (data: SignatureCompleteData) => void;\n onSignatureCancel?: (data: SignatureCancelData) => void;\n onError?: (data: CasualErrorData) => void;\n}\n\ntype IframePostMessage = (msg: unknown, targetOrigin: string, transfer?: Transferable[]) => void;\n\nexport class EmbedHostTransport {\n private readonly opts: EmbedHostTransportOptions;\n private handlers: EmbedHostHandlers = {};\n private readonly boundOnMessage: (ev: MessageEvent) => void;\n private destroyed = false;\n\n constructor(opts: EmbedHostTransportOptions) {\n this.opts = opts;\n this.boundOnMessage = this.onMessage.bind(this);\n const target = opts.hostWindow ?? window;\n target.addEventListener('message', this.boundOnMessage);\n }\n\n on(handlers: EmbedHostHandlers): void {\n this.handlers = { ...this.handlers, ...handlers };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n const target = this.opts.hostWindow ?? window;\n target.removeEventListener('message', this.boundOnMessage);\n }\n\n sendHostHello(data: HostHelloData): void {\n this.post('casual.hello', data);\n }\n\n sendSetViewMode(data: CommandSetViewModeData): void {\n this.post('casual.command.set.viewmode', data);\n }\n\n sendSetReadOnly(data: CommandSetReadOnlyData): void {\n this.post('casual.command.set.readonly', data);\n }\n\n sendSetTheme(data: CommandSetThemeData): void {\n this.post('casual.command.set.theme', data);\n }\n\n sendSetLocale(data: CommandSetLocaleData): void {\n this.post('casual.command.set.locale', data);\n }\n\n /** Host → editor: enable/disable chrome features (hide control + block command). */\n sendSetFeatures(data: CommandSetFeaturesData): void {\n this.post('casual.command.set.features', data);\n }\n\n sendCommandSave(): void {\n this.post('casual.command.save', null);\n }\n\n sendCommandFocus(): void {\n this.post('casual.command.focus', null);\n }\n\n /** Host → Editor: run a formatting / navigation command (bold,\n * italic, undo, …) against the active selection. v0.6+. */\n sendCommandExecute(data: CommandExecuteData): void {\n this.post('casual.command.execute', data);\n }\n\n sendSignatureRequest(id: string, data: SignatureRequestData): void {\n this.post('casual.signature.request', data, id);\n }\n\n sendSignatureCancel(data: SignatureCancelData): void {\n this.post('casual.signature.cancel', data);\n }\n\n private onMessage(ev: MessageEvent): void {\n if (this.destroyed) return;\n if (ev.origin !== this.opts.embedOrigin) return;\n if (ev.source !== this.opts.iframeWindow) return;\n if (!isCasualEnvelope(ev.data)) return;\n if (ev.data.app !== this.opts.app) return;\n\n void this.dispatch(ev.data);\n }\n\n private async dispatch(env: CasualEnvelope): Promise<void> {\n switch (env.type) {\n case 'casual.ready':\n this.handlers.onEditorReady?.(env.data as EditorHelloData);\n return;\n case 'casual.load.request': {\n if (!this.handlers.onLoadRequest) return;\n const id = env.id ?? '';\n try {\n const resp = await this.handlers.onLoadRequest(env.data as LoadRequestData);\n const transfer: Transferable[] = resp.ok ? [resp.bytes] : [];\n this.post('casual.load.response', resp, id, transfer);\n } catch (err) {\n this.post(\n 'casual.load.response',\n {\n ok: false as const,\n code: 'host_error',\n message: err instanceof Error ? err.message : String(err),\n },\n id,\n );\n }\n return;\n }\n case 'casual.save.request': {\n if (!this.handlers.onSaveRequest) return;\n const id = env.id ?? '';\n try {\n const resp = await this.handlers.onSaveRequest(env.data as SaveRequestData);\n this.post('casual.save.response', resp, id);\n } catch (err) {\n this.post(\n 'casual.save.response',\n {\n ok: false as const,\n code: 'host_error',\n message: err instanceof Error ? err.message : String(err),\n },\n id,\n );\n }\n return;\n }\n case 'casual.save.notify':\n this.handlers.onSaveNotify?.(env.data as SaveNotifyData);\n return;\n case 'casual.exit':\n this.handlers.onExit?.(env.data as ExitData);\n return;\n case 'casual.selection.changed':\n this.handlers.onSelectionChanged?.(env.data as SelectionChangedData);\n return;\n case 'casual.selection.format-state':\n this.handlers.onSelectionFormatState?.(env.data as SelectionFormatStateData);\n return;\n case 'casual.dialog.request':\n this.handlers.onDialogRequest?.(env.data as DialogRequestData);\n return;\n case 'casual.telemetry.event':\n this.handlers.onTelemetry?.(env.data as TelemetryEventData);\n return;\n case 'casual.signature.field.signed':\n this.handlers.onSignatureFieldSigned?.(env.data as SignatureFieldSignedData);\n return;\n case 'casual.signature.complete':\n this.handlers.onSignatureComplete?.(env.data as SignatureCompleteData);\n return;\n case 'casual.signature.cancel':\n this.handlers.onSignatureCancel?.(env.data as SignatureCancelData);\n return;\n case 'casual.signature.request.ack':\n return;\n case 'casual.error':\n this.handlers.onError?.(env.data as CasualErrorData);\n return;\n default:\n return;\n }\n }\n\n private post(type: string, data: unknown, id?: string, transfer?: Transferable[]): void {\n const env: CasualEnvelope = {\n type,\n app: this.opts.app,\n v: 1,\n data,\n ...(id ? { id } : {}),\n };\n const send = this.opts.iframeWindow.postMessage.bind(\n this.opts.iframeWindow,\n ) as IframePostMessage;\n send(env, this.opts.embedOrigin, transfer);\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheets — minimal React wrapper around Univer Sheets.\n *\n * Boots Univer with the eager plugin set (render + formula engine +\n * UI + docs + sheets + sheets-ui + sheets-formula + numfmt), mounts a\n * single workbook unit from `initialData`, and hands the host the\n * `CasualSheetsAPI` imperative ref via `onReady` (raw FUniver facade\n * available at `api.univer`).\n *\n * Feature plugins (conditional formatting, data validation, drawings,\n * sort, filter, hyperlinks, tables, comments, find/replace) load lazily\n * by default (`lazyPlugins`): eagerly before mount for whatever the\n * snapshot already uses, idle-loaded otherwise. Pass `lazyPlugins={false}`\n * for the minimal editor.\n *\n * Formula compute runs on the main thread by default; pass `formula={{ worker }}`\n * to move it off-thread (the SDK then wires `UniverRPCMainThreadPlugin` to the\n * host's worker — see the `formula` prop).\n *\n * Intentionally NOT included (host can layer on top via FUniver):\n * - Snapshot swap (this component mounts a snapshot once; change\n * the React `key` to remount with a fresh snapshot).\n * - Paste-merge hooks, dev helpers, zoom-shortcut overrides,\n * facade extensions — all app concerns.\n *\n * Styles: host must import `@casualoffice/sheets/styles.css`\n * (or the per-plugin CSS) once at app boot. Tree-shaking strips the\n * styles from this entry if the host doesn't reach the styles export.\n */\n\nimport {\n lazy,\n Suspense,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n} from 'react';\nimport {\n ICommandService,\n IMentionIOService,\n LocaleType,\n LogLevel,\n ThemeService,\n Univer,\n UniverInstanceType,\n type ICommandInfo,\n type IExecutionOptions,\n type IWorkbookData,\n type ILocales,\n} from '@univerjs/core';\nimport { CasualMentionIOService } from './mention-io';\nimport { FUniver } from '@univerjs/core/facade';\nimport { defaultTheme } from '@univerjs/themes';\n\nimport { UniverRenderEnginePlugin } from '@univerjs/engine-render';\nimport { UniverFormulaEnginePlugin } from '@univerjs/engine-formula';\nimport { UniverUIPlugin } from '@univerjs/ui';\nimport { UniverDocsPlugin } from '@univerjs/docs';\nimport { UniverDocsUIPlugin } from '@univerjs/docs-ui';\nimport { UniverSheetsPlugin } from '@univerjs/sheets';\nimport { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';\nimport { UniverSheetsFormulaPlugin, CalculationMode } from '@univerjs/sheets-formula';\nimport { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui';\nimport { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt';\nimport { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui';\n// Type-only — erased at build, so `@univerjs/rpc` stays a runtime-optional peer\n// (loaded via dynamic import only when a formula worker is passed).\nimport type { UniverRPCMainThreadPlugin as RpcMainThreadPluginType } from '@univerjs/rpc';\n\nimport {\n createCasualSheetsAPI,\n type CasualSheetsAPI,\n type CasualSheetsAPIInternal,\n type DocumentMode,\n type RangeRef,\n} from './api';\n// Type-only — erased at build, so the collab entry (Yjs + Hocuspocus) stays out\n// of the `sheets` bundle. The runtime `attachCollab` is pulled in lazily via a\n// dynamic `import('@casualoffice/sheets/collab')` only when the `collab` prop is\n// set (see the collab effect), so bare-grid hosts never load it.\nimport type { AttachCollabOptions, CollabHandle } from '../collab/attachCollab';\nimport {\n eagerLoadForSnapshot,\n ensurePlugin,\n idleLoadAll,\n setUniverForLazyLoad,\n} from '../univer/lazy-plugins';\nimport type { ChromeExtensions } from '../chrome/extensions';\nimport type { DialogKind } from '../chrome/dialog-context';\nimport { AiPanelSurface, type SheetsAiConfig } from '../ai/AiPanelSurface';\nimport { PanelProvider } from '../chrome/panel-context';\nimport { PanelRail } from '../chrome/PanelRail';\nimport { PanelHost } from '../chrome/PanelHost';\n// Charts: the provider is echarts-free (resources/types only) so it imports\n// eagerly; the overlay pulls echarts, so it's lazy — echarts becomes its own\n// async chunk, loaded only when a chart actually renders.\nimport { ChartsProvider } from '../charts/charts-context';\nconst ChartLayer = lazy(() =>\n import('../charts/ChartLayer').then((m) => ({ default: m.ChartLayer })),\n);\n// Chrome is lazy-loaded from the `@casualoffice/sheets/chrome` subpath (NOT a\n// relative import — that would inline under this build's splitting:false). The\n// subpath is externalised in tsup, so the consumer's bundler code-splits it and\n// `chrome=\"none\"` hosts (the default + the apps/web reference host) never load\n// the chrome chunk.\nconst ChromeTop = lazy(() =>\n import('@casualoffice/sheets/chrome').then((m) => ({ default: m.ChromeTop })),\n);\nconst ChromeBottom = lazy(() =>\n import('@casualoffice/sheets/chrome').then((m) => ({ default: m.ChromeBottom })),\n);\n\nexport interface CasualSheetsProps {\n /** Workbook snapshot to mount. Read once on initial mount; change\n * the React `key` on this component to remount with a new\n * workbook. */\n initialData: IWorkbookData;\n /** Called after the workbook unit is created. Hands back the\n * `CasualSheetsAPI` imperative ref — the SDK's stable integration\n * surface (snapshot I/O, xlsx import, selection, command dispatch).\n * The raw FUniver facade is on `api.univer` as the escape hatch. */\n onReady?: (api: CasualSheetsAPI) => void;\n /** Debounced stream of workbook snapshots, emitted after edits\n * settle. This is the \"host persists it\" half of the Excalidraw\n * model — the editor stays storage-unaware and the host writes the\n * snapshot wherever it likes (localStorage, server, …). Driven by\n * Univer's mutation hook (`onMutationExecutedForCollab`), not UI\n * events, so it captures every edit including programmatic ones.\n * May fire for background/structural mutations too; treat each call\n * as \"current state, persist if you care\". */\n onChange?: (snapshot: IWorkbookData) => void;\n /** Debounce window for `onChange`, in ms. Default 400. */\n onChangeDebounceMs?: number;\n /** Explicit save — fired when the user presses Ctrl/Cmd+S inside the editor\n * (the browser's save dialog is suppressed). The host persists the snapshot.\n * Part of the \"host owns storage\" contract: the SDK never writes a store. */\n onSave?: (snapshot: IWorkbookData) => void;\n /** Fired once when the editor unmounts, with the final snapshot — the host's\n * last chance to persist before the workbook is disposed. */\n onExit?: (snapshot: IWorkbookData) => void;\n /** The active selection changed (canvas-driven), or `null` when there is none.\n * The prop half of the canonical `selectionChange` event (doc 38 §3); the\n * same event is available via `api.on('selectionChange', …)`. Wired to\n * Univer's `SelectionChanged` / `SelectionMoveEnd` facade events. */\n onSelectionChange?: (selection: RangeRef | null) => void;\n /** A boot/runtime error surfaced by the editor — the prop half of the\n * canonical `error` event (doc 38 §3). Also available via\n * `api.on('error', …)`. */\n onError?: (error: Error) => void;\n /** The unsaved-changes flag flipped: `true` after the first edit since the\n * last load/save, `false` on save / `setContent` / `import`. The prop half of\n * the canonical `dirtyChange` event (doc 38 §3); also `api.on('dirtyChange',\n * …)`. Lets a host drive a \"•/unsaved\" title dot without diffing snapshots. */\n onDirtyChange?: (dirty: boolean) => void;\n /** Lazy-load the feature plugins (conditional formatting, data\n * validation, hyperlinks, notes, tables, comments, drawings, sort,\n * filter, find/replace). Default `true`: plugins whose data is in\n * `initialData` load eagerly before mount (so nothing is dropped on\n * open), the rest idle-load after first paint. Set `false` for the\n * minimal editor (render + formula + numfmt only) — the embed-iframe\n * build does this to stay a single self-contained bundle. */\n lazyPlugins?: boolean;\n /** Escape hatch fired after the SDK registers its built-in plugins but BEFORE\n * the workbook unit is created — the host can `univer.registerPlugin(...)`\n * additional plugins here (e.g. an off-main formula worker via\n * `UniverRPCMainThreadPlugin`, crosshair-highlight, zen-editor). Anything\n * registered after `createUnit` would miss the unit's plugin-init pass, so\n * register-time extras must go through this hook. Power hosts (the reference\n * app) use it to share the SDK editor core while keeping their extra plugins;\n * most integrators never need it. NOT covered by semver — it hands you the\n * raw `Univer` instance. */\n onBeforeCreateUnit?: (univer: Univer) => void;\n /** Off-main formula compute. By default the formula engine runs on the MAIN\n * thread (fine for typical sheets, zero host setup). Provide a Web Worker (or\n * its URL) to move compute off-thread so paste / sort / fill on large\n * workbooks don't freeze the UI: the SDK then registers the formula plugins\n * with `notExecuteFormula` and wires `UniverRPCMainThreadPlugin` to your\n * worker. The host owns the worker (the SDK never bundles one — that's brittle\n * across bundlers) and must have `@univerjs/rpc` installed. The worker script\n * is the standard Univer formula worker (see the reference app's\n * `apps/web/src/univer/formula-worker.ts`). */\n formula?: {\n /** A constructed `Worker`, or a URL/string the RPC plugin loads. */\n worker?: Worker | string;\n };\n /** Locale identifier. Defaults to `LocaleType.EN_US`. */\n locale?: LocaleType;\n /** Locale string bundle. Optional — Univer's default English\n * strings load if omitted. */\n locales?: ILocales;\n /** Univer log level. Defaults to `LogLevel.WARN`. */\n logLevel?: LogLevel;\n /** Univer chrome toggles. Defaults: header / toolbar / footer off,\n * context menu on — matches Casual Sheets' embedded shape. */\n ui?: {\n header?: boolean;\n toolbar?: boolean;\n footer?: boolean;\n contextMenu?: boolean;\n };\n /** Override the Univer theme object (colour palette). Defaults to\n * Univer's `defaultTheme`. Distinct from `appearance` (light/dark). */\n theme?: typeof defaultTheme;\n /** Light or dark mode. Reactive — flipping it re-themes the live\n * editor via `ThemeService.setDarkMode` (canvas colours, notifications,\n * and Univer's own `univer-dark` class). Defaults to light.\n * Note: Univer's Workbench applies the `univer-dark` class to the\n * document root (`<html>`) itself, so dark mode is page-global by\n * Univer's design — a host that embeds the editor inside a light page\n * should scope the editor or accept the global dark CSS. */\n appearance?: 'light' | 'dark';\n /** Office chrome rendered around the grid:\n * - `'none'` (default): bare grid — the host supplies its own chrome.\n * - `'minimal'` / `'full'`: the built-in Office shell — a menu bar\n * (Edit/Insert/Format/Data/View), a formatting toolbar (font family/size,\n * bold/italic/underline/strike, text & fill colour, borders, h/v align,\n * wrap, merge, number formats, clear format, AutoSum), a formula bar with a\n * name box + function autocomplete, a worksheet tab strip (switch/add/\n * rename/delete), and a status bar (Average/Count/Numerical Count/Min/Max/\n * Sum + zoom). All driven through the facade, themed via `--cs-chrome-*`\n * (light/dark). `'minimal'` and `'full'` currently render the same shell;\n * `'full'` is where richer panels (find/replace, charts, …) will land. */\n chrome?: 'none' | 'minimal' | 'full';\n /** Enable/disable chrome features. Each key maps a toolbar group / menu item /\n * capability to a boolean; `false` hides the control AND blocks its command.\n * Omitted keys default to enabled. Only applies when `chrome` is shown. */\n features?: Record<string, boolean>;\n /** Legacy host hook for dialog-backed chrome controls. The SDK now ships\n * BUILT-IN dialogs (Format Cells, Find & Replace, …) that open by default, so\n * this is no longer required. It still works for back-compat: kinds the SDK\n * has no built-in for (Insert Chart, PivotTable, …) fall through to it, and a\n * host can force specific kinds to it via `hostOwnedDialogs`. Prefer\n * `extensions.dialogs` to supply a React override component. */\n onDialogRequest?: (kind: string, context?: unknown) => void;\n /** Kinds the host wants to handle via `onDialogRequest` even though the SDK has\n * a built-in (e.g. keep the SDK chrome but your own Format Cells). */\n hostOwnedDialogs?: DialogKind[];\n /** Host chrome extensions — the extensibility surface for `chrome=\"full\"`.\n * Append custom toolbar items / menu items / side panels, and register or\n * OVERRIDE dialogs by kind. Built-ins are the defaults; host entries\n * append/override. See `ChromeExtensions` for the exact shape. */\n extensions?: ChromeExtensions;\n /** Document interaction mode (SuperDoc-aligned vocabulary, shared with the\n * docs SDK):\n * - `'editing'` (default): fully editable.\n * - `'viewing'`: read-only — applies the command-veto + permission path\n * (`applyReadOnly`) to the mounted workbook.\n * Reactive: flipping it re-applies via `api.setDocumentMode`. Wins over the\n * deprecated `readOnly` prop when both are set. */\n documentMode?: DocumentMode;\n /** Real-time co-editing, declaratively. Pass `{ server, room, … }` to join a\n * room and the SDK wires Yjs/Hocuspocus itself once the editor is ready\n * (mirrors how the docs `CasualEditor` opts in via `backendUrl`); omit it for\n * a single-user editor. Options match `attachCollab` (`server`, `room`,\n * `password`, `token`, `role`, `share`, `onStatus`, `onSnapshot`).\n *\n * Lifecycle: attaches after `onReady`, detaches on unmount, and re-attaches\n * when `server` / `room` / `password` / `token` / `role` change. The\n * imperative `attachCollab(api, opts)` export stays available for advanced\n * hosts that drive the room lifecycle themselves (presence UI, preflight,\n * reconnect banners) — don't combine both on one editor. */\n collab?: AttachCollabOptions;\n /** AI assistant surface, declaratively. Pass `{ enabled: true, transport,\n * render }` to mount a supported AI task-pane beside the grid — mirrors how\n * the docs SDK exposes its DocOps panel behind a transport prop. The SDK\n * owns the prop contract, the `SheetsAiTransport` type, and the layout slot;\n * the panel body is supplied via `ai.render` (the reference app passes its\n * `<AiPanel>`) and drives its tool loop against `ai.transport`. Build a\n * transport with `createSheetsAiTransport()` (desktop-native → collab\n * single-round → browser-direct). Omit `ai` for an editor with no AI.\n *\n * Reactive: flipping `enabled` mounts/unmounts the pane once the editor is\n * ready. See `SheetsAiConfig`. */\n ai?: SheetsAiConfig;\n /** @deprecated Use `documentMode` instead. `true` maps to\n * `documentMode=\"viewing\"`. Ignored when `documentMode` is set. */\n readOnly?: boolean;\n /** Container style. Default fills the parent. */\n style?: CSSProperties;\n /** Container className for additional styling hooks. */\n className?: string;\n /** Optional test id for the host container. */\n testId?: string;\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n position: 'relative',\n};\n\nconst DEFAULT_UI = {\n header: false,\n toolbar: false,\n footer: false,\n contextMenu: true,\n};\n\nexport function CasualSheets({\n initialData,\n onReady,\n onChange,\n onChangeDebounceMs = 400,\n onSave,\n onExit,\n onSelectionChange,\n onError,\n onDirtyChange,\n lazyPlugins = true,\n onBeforeCreateUnit,\n formula,\n locale = LocaleType.EN_US,\n locales,\n logLevel = LogLevel.WARN,\n ui,\n theme = defaultTheme,\n appearance = 'light',\n chrome = 'none',\n features,\n onDialogRequest,\n hostOwnedDialogs,\n extensions,\n documentMode,\n collab,\n ai,\n readOnly,\n style,\n className,\n testId = 'casual-sheets',\n}: CasualSheetsProps) {\n // `documentMode` wins; the deprecated `readOnly` boolean only applies when\n // `documentMode` is unset. Absent both → editable.\n const effectiveMode: DocumentMode = documentMode ?? (readOnly ? 'viewing' : 'editing');\n const hostRef = useRef<HTMLDivElement>(null);\n // Keep the latest onChange callable without re-subscribing (the effect\n // mounts once). The mutation subscription is always wired (it also backs the\n // `dirtyChange` / `change` emitter); only the snapshot serialization inside it\n // is gated on an actual consumer.\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n // Latest save/exit callbacks, called via refs so they fire without re-running\n // the boot effect. onExit is read in cleanup; onSave on the Ctrl/Cmd+S handler.\n const onSaveRef = useRef(onSave);\n onSaveRef.current = onSave;\n const onExitRef = useRef(onExit);\n onExitRef.current = onExit;\n // Latest handlers for the canonical event props (doc 38 §3), read via refs so\n // they fire without re-running the boot effect. `hasX` (fixed at mount) gates\n // whether we bridge each prop to the unified emitter — a host that passes none\n // of them (and never calls `api.on`) pays for none of the extra wiring.\n const onSelectionChangeRef = useRef(onSelectionChange);\n onSelectionChangeRef.current = onSelectionChange;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onDirtyChangeRef = useRef(onDirtyChange);\n onDirtyChangeRef.current = onDirtyChange;\n const hasSelectionChange = useRef(!!onSelectionChange).current;\n const hasError = useRef(!!onError).current;\n const hasDirtyChange = useRef(!!onDirtyChange).current;\n // The live FUniver facade, captured at mount so the reactive appearance\n // effect can reach Univer's ThemeService without re-running boot.\n const apiRef = useRef<CasualSheetsAPI | null>(null);\n // The live API as state, so the built-in chrome (FormulaBar) re-renders and\n // subscribes once the editor is ready. Only set when chrome is shown — the\n // bare-grid path never triggers this re-render. A single post-mount setState\n // doesn't disturb the grid (Univer owns its canvas outside React).\n const [chromeApi, setChromeApi] = useState<CasualSheetsAPI | null>(null);\n // Declarative collab. `hasCollab` is fixed at mount (the boot effect runs\n // once): only then do we surface the ready api as state to drive the attach\n // effect, so single-user consumers never take the extra re-render. The latest\n // options live on a ref so callback/`share` changes don't force a re-attach —\n // the attach effect only re-runs on connection-identity changes.\n const hasCollab = useRef(!!collab).current;\n const collabRef = useRef(collab);\n collabRef.current = collab;\n const [collabApi, setCollabApi] = useState<CasualSheetsAPI | null>(null);\n // AI surface. Like chrome/collab, only surface the ready api as state when\n // the `ai` prop was present at mount — so editors with no AI never take the\n // extra re-render. The panel itself only mounts when `ai.enabled` is set.\n const hasAi = useRef(!!ai).current;\n const [aiApi, setAiApi] = useState<CasualSheetsAPI | null>(null);\n\n useEffect(() => {\n const container = hostRef.current;\n if (!container) return;\n\n const univer = new Univer({\n theme,\n locale,\n locales,\n logLevel,\n // Replace the default mention IO (hardwired to the current user) with our\n // host-pluggable source so comment @-mentions can list real collaborators.\n // No-op until a provider is installed via `setMentionProvider`.\n override: [[IMentionIOService, { useClass: CasualMentionIOService }]],\n });\n\n const uiOpts = { ...DEFAULT_UI, ...ui, container };\n\n // `formula.worker` → off-main compute. Default = main thread (fine for\n // typical sheets, zero host setup).\n const offMain = !!formula?.worker;\n\n let cancelled = false;\n let changeTimer: ReturnType<typeof setTimeout> | null = null;\n let changeSub: { dispose: () => void } | undefined;\n\n void (async () => {\n // Plugin registration runs here (not synchronously) so the OPTIONAL RPC\n // transport can be `await import`ed FIRST and registered in its correct\n // slot — right after the formula engine, before sheets. Registering it out\n // of order (or after createUnit) leaves the formula engine's worker channel\n // unwired → cells stay 0. Dynamic import keeps `@univerjs/rpc` a true\n // optional peer (only loaded when a worker is passed).\n let RPCMainThreadPlugin: typeof RpcMainThreadPluginType | null = null;\n if (offMain && formula?.worker) {\n RPCMainThreadPlugin = (await import('@univerjs/rpc')).UniverRPCMainThreadPlugin;\n if (cancelled) return;\n }\n\n univer.registerPlugin(UniverRenderEnginePlugin);\n univer.registerPlugin(\n UniverFormulaEnginePlugin,\n offMain ? { notExecuteFormula: true } : undefined,\n );\n if (RPCMainThreadPlugin && formula?.worker) {\n univer.registerPlugin(RPCMainThreadPlugin, { workerURL: formula.worker });\n }\n univer.registerPlugin(UniverUIPlugin, uiOpts);\n univer.registerPlugin(UniverDocsPlugin);\n univer.registerPlugin(UniverDocsUIPlugin);\n univer.registerPlugin(UniverSheetsPlugin, offMain ? { notExecuteFormula: true } : undefined);\n univer.registerPlugin(UniverSheetsUIPlugin);\n univer.registerPlugin(\n UniverSheetsFormulaPlugin,\n offMain\n ? { notExecuteFormula: true, initialFormulaComputing: CalculationMode.NO_CALCULATION }\n : undefined,\n );\n univer.registerPlugin(UniverSheetsFormulaUIPlugin);\n univer.registerPlugin(UniverSheetsNumfmtPlugin);\n univer.registerPlugin(UniverSheetsNumfmtUIPlugin);\n\n // Lazy-loader holder (the loader is @internal so a relative import shares\n // no cross-instance state) + host plugin escape hatch — both before\n // createUnit.\n if (lazyPlugins) setUniverForLazyLoad(univer);\n onBeforeCreateUnit?.(univer);\n\n // Eager-load any feature plugin whose data already lives in initialData\n // (CF rules, tables, hyperlinks, …) BEFORE createUnit — Univer's resource\n // manager silently drops keys for plugins that aren't registered when it\n // reads the snapshot. Skipped entirely when lazyPlugins is false.\n if (lazyPlugins) {\n await eagerLoadForSnapshot(univer, initialData);\n if (cancelled) return;\n // Drawing/image is the one feature whose trigger (Insert ▸ Image) opens\n // a FILE PICKER — which needs the user's click gesture. If the plugin\n // lazy-loads on click, the await loses the gesture and the picker never\n // opens (\"can't insert image\"); if it idle-loads, a quick click before\n // it's ready silently no-ops. So load it eagerly here (tracked by\n // ensurePlugin, so idleLoadAll won't double-register) — image works on\n // the first click, in-gesture. Other features open panels (no gesture).\n await ensurePlugin(univer, 'drawing');\n if (cancelled) return;\n }\n\n univer.createUnit(UniverInstanceType.UNIVER_SHEET, initialData);\n\n const api = createCasualSheetsAPI(FUniver.newAPI(univer), initialData.resources);\n const apiInternal = api as CasualSheetsAPIInternal;\n apiRef.current = api;\n // Bridge the declarative event props (doc 38 §3) to the unified emitter, so\n // a prop and `api.on(name, …)` both receive the event. Only wire the bridge\n // when the prop was present at mount — direct `api.on(...)` still works\n // without it (the emitter fires to its own subscribers regardless). The\n // selection bridge is what makes the factory's `SelectionChanged` listener\n // do real work, so bare hosts that pass no `onSelectionChange` (and never\n // call `api.on`) never pay for `getSelection` on every selection move.\n if (hasSelectionChange) {\n apiInternal.on('selectionChange', (sel) => onSelectionChangeRef.current?.(sel));\n }\n if (hasError) {\n apiInternal.on('error', (err) => onErrorRef.current?.(err));\n }\n if (hasDirtyChange) {\n apiInternal.on('dirtyChange', (d) => onDirtyChangeRef.current?.(d));\n }\n // Hand the live API to the built-in chrome (FormulaBar subscribes to it).\n // Only when chrome is shown, so bare-grid consumers never re-render.\n if (!cancelled && chrome !== 'none') setChromeApi(api);\n // Hand the ready api to the declarative-collab effect (only when the\n // `collab` prop was present at mount — otherwise no extra re-render).\n if (!cancelled && hasCollab) setCollabApi(api);\n // Hand the ready api to the AI surface (only when `ai` was present at\n // mount — otherwise no extra re-render).\n if (!cancelled && hasAi) setAiApi(api);\n // Apply the initial appearance now that the editor exists (the reactive\n // effect below also runs on mount, but apiRef may not be set yet when it\n // first fires — this guarantees dark mode from the first paint).\n applyAppearance(api, container, appearance);\n // Apply the initial document mode. Deferred a frame for the read-only case:\n // sheets-ui sets WorkbookEditablePermission → true during unit setup AFTER\n // onReady, which would clobber a synchronous flip (the embed preview path\n // waits a rAF for the same reason). The command-veto layer is unaffected,\n // but the rAF keeps the permission layer in sync too.\n if (effectiveMode === 'viewing') {\n requestAnimationFrame(() => {\n if (!cancelled) api.setDocumentMode('viewing');\n });\n }\n onReady?.(api);\n // Fire the canonical `ready` event for `api.on('ready', …)` subscribers.\n // `ready` is sticky in the emitter, so a late subscription still fires.\n if (!cancelled) apiInternal.emit('ready', api);\n\n // Mutation stream → dirty flag + debounced `change` (prop + emitter).\n // Subscribed AFTER createUnit so the initial unit-creation mutations don't\n // fire a spurious first emit. Uses the mutation hook (CLAUDE.md hard rule),\n // never UI events. Always subscribed now (not just when `onChange` was\n // passed) because `dirtyChange` and `api.on('change', …)` also depend on\n // it; the raw callback is cheap (a dirty-flag flip + a debounce timer), and\n // the expensive snapshot serialization is gated on an actual consumer.\n {\n const injector = (api.univer as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const cmdSvc = injector?.get(ICommandService) as\n | {\n onMutationExecutedForCollab: (\n l: (info: ICommandInfo, options?: IExecutionOptions) => void,\n ) => { dispose: () => void };\n }\n | undefined;\n changeSub = cmdSvc?.onMutationExecutedForCollab(() => {\n // First edit since load/save → dirty (emits dirtyChange on transition).\n apiInternal.markDirty(true);\n if (changeTimer) clearTimeout(changeTimer);\n changeTimer = setTimeout(() => {\n // Only serialize when something actually consumes the snapshot.\n if (!onChangeRef.current && apiInternal.listenerCount('change') === 0) return;\n const snap = api.getContent();\n if (snap) {\n onChangeRef.current?.(snap);\n apiInternal.emit('change', snap);\n }\n }, onChangeDebounceMs);\n });\n // If we unmounted during the eager-load await, cleanup already ran with\n // changeSub still undefined — dispose this late subscription.\n if (cancelled) changeSub?.dispose();\n }\n\n // Idle-load the remaining feature plugins so Insert / Data / Format actions\n // are ready when the user reaches them.\n if (lazyPlugins) idleLoadAll(univer);\n })().catch((err: unknown) => {\n // Boot failure (plugin load, unit creation, …) → the canonical `error`\n // event. Prefer the emitter once the API exists (reaches both the `onError`\n // prop bridge and `api.on('error', …)`); before then fall back to the prop.\n if (cancelled) return;\n const e = err instanceof Error ? err : new Error(String(err));\n const cur = apiRef.current as CasualSheetsAPIInternal | null;\n if (cur) cur.emit('error', e);\n else onErrorRef.current?.(e);\n });\n\n return () => {\n cancelled = true;\n if (changeTimer) clearTimeout(changeTimer);\n changeSub?.dispose();\n // Last-chance persist: emit the final snapshot before the workbook is\n // disposed (disposal is deferred via microtask below, so it's still alive).\n if (onExitRef.current) {\n const snap = apiRef.current?.getContent();\n if (snap) onExitRef.current(snap);\n }\n apiRef.current = null;\n setChromeApi(null);\n setCollabApi(null);\n setAiApi(null);\n if (lazyPlugins) setUniverForLazyLoad(null);\n // Defer disposal off the React render phase — Univer owns its\n // own React root, and a synchronous unmount mid-render warns\n // and leaves the canvas detached.\n const toDispose = univer;\n queueMicrotask(() => toDispose.dispose());\n };\n // initialData is intentionally NOT in the dep array — the wrapper\n // mounts the snapshot once. Hosts that need to swap workbooks\n // change the React `key` to force a remount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Reactive appearance. Runs after the boot effect (apiRef populated on first\n // mount) and re-runs whenever `appearance` flips, re-theming the live editor.\n useEffect(() => {\n const api = apiRef.current;\n const container = hostRef.current;\n if (!api || !container) return;\n applyAppearance(api, container, appearance);\n }, [appearance]);\n\n // Reactive document mode. On first mount apiRef may not be populated yet (boot\n // is async) — that run bails and the boot effect applies the initial mode; this\n // effect then handles every subsequent `documentMode` / `readOnly` flip.\n useEffect(() => {\n apiRef.current?.setDocumentMode(effectiveMode);\n }, [effectiveMode]);\n\n // Declarative collab: attach once the api is ready, detach on unmount, and\n // re-attach when the connection identity changes. `attachCollab` (and its\n // Yjs/Hocuspocus transport) is loaded lazily via the externalised\n // `@casualoffice/sheets/collab` subpath — same code-split as `chrome`/`xlsx`\n // — so single-user hosts never pull it into their bundle. Options are read\n // from `collabRef` at attach time so callback/`share` changes don't re-attach.\n useEffect(() => {\n if (!collabApi || !collabRef.current) return;\n let handle: CollabHandle | null = null;\n let disposed = false;\n void import('@casualoffice/sheets/collab').then(({ attachCollab }) => {\n const opts = collabRef.current;\n if (disposed || !opts) return;\n handle = attachCollab(collabApi, opts);\n });\n return () => {\n disposed = true;\n handle?.detach();\n handle = null;\n };\n // Re-attach only on connection-identity changes (server/room/auth/role); the\n // options object identity and callbacks are read live from `collabRef`.\n }, [collabApi, collab?.server, collab?.room, collab?.password, collab?.token, collab?.role]);\n\n // Ctrl/Cmd+S anywhere in the editor → onSave (suppress the browser dialog).\n // Capture phase so we beat Univer's own key handling on the canvas.\n const onKeyDownCapture = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n if ((e.metaKey || e.ctrlKey) && (e.key === 's' || e.key === 'S')) {\n e.preventDefault();\n const api = apiRef.current;\n const snap = api?.getContent();\n if (snap) {\n onSaveRef.current?.(snap);\n // Canonical `save` event + clear the dirty flag (an explicit save means\n // the buffer is clean until the next edit).\n const apiInternal = api as CasualSheetsAPIInternal;\n apiInternal.emit('save', snap);\n apiInternal.markDirty(false);\n }\n }\n };\n\n // chrome=\"none\" (default) keeps the exact bare-grid shape existing consumers\n // rely on (embed-runtime, hosts that bring their own shell). Any other level\n // wraps the grid in a flex column with the built-in chrome above it; the grid\n // container (hostRef, where Univer mounts) fills the remaining space.\n if (chrome === 'none') {\n // No `ai` prop → the exact bare-grid shape existing consumers rely on.\n if (!hasAi) {\n return (\n <div\n ref={hostRef}\n onKeyDownCapture={onKeyDownCapture}\n style={{ ...DEFAULT_STYLE, ...style }}\n className={className}\n data-testid={testId}\n />\n );\n }\n // With `ai`, the grid + AI pane sit in a stable flex row (shape fixed at\n // mount by `hasAi`, so toggling `ai.enabled` never remounts the grid host —\n // it only adds/removes the aside sibling). The grid host still fills the\n // remaining space, so Univer's canvas sizing is unchanged.\n return (\n <div\n className={className}\n data-testid={testId}\n onKeyDownCapture={onKeyDownCapture}\n style={{ ...DEFAULT_STYLE, ...style, display: 'flex', flexDirection: 'row' }}\n >\n <div\n ref={hostRef}\n style={{ flex: '1 1 auto', minWidth: 0, minHeight: 0, position: 'relative' }}\n />\n <AiPanelSurface config={ai} api={aiApi} />\n </div>\n );\n }\n\n // The built-in chrome components read their colours from `--cs-chrome-*` CSS\n // vars. Phase 4: each var now resolves to a `@schnsrw/design-system` token\n // (loaded by the host via `tokens.css`), with the prior hardcoded value as a\n // FALLBACK so the chrome still renders standalone for hosts that don't ship the\n // design system. `data-theme` on the wrapper (below) swaps the DS tokens\n // light/dark; the fallbacks keep `appearance` working without the DS too.\n const dark = appearance === 'dark';\n const chromeVars = {\n '--cs-chrome-bg': `var(--color-surface-strip, ${dark ? '#2a2e35' : '#eef1f5'})`,\n '--cs-chrome-fg': `var(--color-text, ${dark ? '#e6e6e6' : '#201f1e'})`,\n '--cs-chrome-muted': `var(--color-text-secondary, ${dark ? '#b0b3ba' : '#605e5c'})`,\n '--cs-chrome-border': `var(--color-divider, ${dark ? '#24272d' : '#edeff3'})`,\n '--cs-chrome-input-bg': `var(--color-surface, ${dark ? '#1b1e23' : '#ffffff'})`,\n '--cs-chrome-hover': `var(--color-hover, ${dark ? 'rgba(255,255,255,0.06)' : 'rgba(15,23,42,0.045)'})`,\n '--cs-chrome-active': `var(--color-selected, ${dark ? 'rgba(34,211,238,0.20)' : 'rgba(14,116,144,0.11)'})`,\n '--cs-chrome-active-fg': `var(--color-accent, ${dark ? '#22d3ee' : '#0e7490'})`,\n } as CSSProperties;\n\n return (\n <PanelProvider>\n <div\n className={className}\n data-testid={testId}\n data-theme={dark ? 'dark' : 'light'}\n onKeyDownCapture={onKeyDownCapture}\n style={{\n ...DEFAULT_STYLE,\n ...chromeVars,\n ...style,\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {/* Bars appear once their lazy chunk loads (a tick after first paint); the\n grid host is OUTSIDE Suspense so Univer mounts immediately. */}\n <Suspense fallback={null}>\n <ChromeTop\n api={chromeApi}\n features={features}\n onDialogRequest={onDialogRequest}\n hostOwnedDialogs={hostOwnedDialogs}\n extensions={extensions}\n />\n </Suspense>\n {/* Grid + side panels + rail share a flex row so the built-in chrome\n (top/bottom bars) still spans the full width. The row shape is stable\n (grid host never remounts); PanelHost/AI aside only add/remove\n siblings, and the rail is always present. */}\n <div style={{ flex: '1 1 auto', minHeight: 0, display: 'flex', flexDirection: 'row' }}>\n <div\n ref={hostRef}\n data-testid=\"univer-host\"\n style={{ flex: '1 1 auto', minWidth: 0, minHeight: 0, position: 'relative' }}\n />\n {/* Charts context + overlay live once the api is ready (it arrives\n after Univer boots into the grid host above, so it can't gate the\n host). ChartLayer portals onto the `univer-host` marker; the\n Charts panel (inside PanelHost) reads the same context. */}\n {chromeApi ? (\n <ChartsProvider api={chromeApi}>\n <Suspense fallback={null}>\n <ChartLayer />\n </Suspense>\n <PanelHost api={chromeApi} extensions={extensions} />\n </ChartsProvider>\n ) : (\n <PanelHost api={chromeApi} extensions={extensions} />\n )}\n {hasAi && <AiPanelSurface config={ai} api={aiApi} />}\n <PanelRail extensions={extensions} />\n </div>\n <Suspense fallback={null}>\n <ChromeBottom api={chromeApi} />\n </Suspense>\n </div>\n </PanelProvider>\n );\n}\n\n/**\n * Apply light/dark to a live editor. `ThemeService.setDarkMode` is the source of\n * truth — it flips the canvas colours, the internals that subscribe to\n * `darkMode$` (notifications, message containers), AND Univer's Workbench toggles\n * the `univer-dark` class on the document root for its compiled dark CSS. We also\n * mirror the class onto the editor container as race-insurance (the Workbench\n * effect can land a frame after ours). Mirrors the app's ThemeBridge.\n */\nfunction applyAppearance(\n api: CasualSheetsAPI,\n container: HTMLElement,\n appearance: 'light' | 'dark',\n): void {\n const dark = appearance === 'dark';\n container.classList.toggle('univer-dark', dark);\n try {\n const injector = (api.univer as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const themeService = injector?.get(ThemeService) as\n | { setDarkMode(b: boolean): void; darkMode: boolean }\n | undefined;\n if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);\n } catch {\n /* ThemeService unavailable — the class toggle still themes visible chrome */\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `CasualMentionIOService` — the `IMentionIOService` override registered by\n * CasualSheets. Thin by design: it owns the only @univerjs *value* import\n * (`MentionType`) and delegates all logic to the pure, unit-tested\n * `resolveMentionList` in `mention-source.ts`.\n */\nimport { MentionType } from '@univerjs/core';\nimport type { IListMentionParam, IListMentionResponse, IMentionIOService } from '@univerjs/core';\nimport { resolveMentionList } from './mention-source';\n\nexport class CasualMentionIOService implements IMentionIOService {\n list(params: IListMentionParam): Promise<IListMentionResponse> {\n return resolveMentionList(params, MentionType.PERSON);\n }\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pluggable @mention data source for cell comments — pure layer.\n *\n * Univer's comment editor (the in-cell thread-comment popup) gets @-mention\n * autocomplete from `docs-mention-ui`, which lists candidates via the core\n * `IMentionIOService`. The default `MentionIOLocalService` is hardwired to a\n * single candidate — the current user — which is useless: you can't @mention\n * the people you're editing with.\n *\n * We override it with `CasualMentionIOService` (see `mention-io.ts`), which\n * reads candidates from a host-settable provider. The provider is the\n * pluggable seam the brief calls for:\n * - embedded in another platform → the host sets it to its directory/users,\n * - standalone → the app sets it to the live presence peers (+ self).\n *\n * This module is the @univerjs-value-free core (only `import type`, which is\n * erased at runtime) so it's unit-testable under the `node:test` + tsx runner,\n * which can't load @univerjs *value* modules. The enum-coupled service class\n * lives in `mention-io.ts`.\n */\nimport type { IListMentionParam, IListMentionResponse, MentionType } from '@univerjs/core';\n\n/** One mentionable entity. `id` must be stable enough to resolve later. */\nexport type MentionCandidate = { id: string; label: string; icon?: string };\n\n/** Resolves mention candidates for the current `@`-search term. */\nexport type MentionProvider = (search: string) => MentionCandidate[] | Promise<MentionCandidate[]>;\n\nlet provider: MentionProvider | null = null;\n\n/**\n * Install (or clear, with `null`) the mention candidate provider. Last writer\n * wins — the host or the app sets this once. Safe to call before or after the\n * editor boots; the service reads it lazily on each `@`-trigger.\n */\nexport function setMentionProvider(fn: MentionProvider | null): void {\n provider = fn;\n}\n\n/** Current provider — exposed for tests / introspection. */\nexport function getMentionProvider(): MentionProvider | null {\n return provider;\n}\n\n/**\n * Case-insensitive substring filter applied to a candidate list. Strips the\n * leading `@` trigger — `docs-mention-ui` passes the search slice starting at\n * the `@` anchor (e.g. `\"@gr\"`), so the raw term includes it.\n */\nexport function filterMentionCandidates(\n candidates: MentionCandidate[],\n search: string,\n): MentionCandidate[] {\n const q = search.replace(/^@+/, '').trim().toLowerCase();\n if (!q) return candidates;\n return candidates.filter((c) => c.label.toLowerCase().includes(q));\n}\n\n/**\n * Resolve the active provider into the `IMentionIOService.list` response shape.\n * `personType` is the numeric `MentionType.PERSON` value, passed in by the\n * service class so this module needs no @univerjs value import. A failing\n * provider degrades to an empty list — it must never break the editor.\n */\nexport async function resolveMentionList(\n params: IListMentionParam,\n personType: MentionType,\n): Promise<IListMentionResponse> {\n const search = params.search ?? '';\n let candidates: MentionCandidate[] = [];\n if (provider) {\n try {\n candidates = await provider(search);\n } catch {\n candidates = [];\n }\n }\n const mentions = candidates.map((c) => ({\n objectType: personType,\n objectId: c.id,\n label: c.label,\n metadata: c.icon ? { icon: c.icon } : undefined,\n }));\n return {\n list: [{ type: personType, mentions, metadata: {}, title: 'PEOPLE' }],\n page: params.page,\n size: params.size,\n total: mentions.length,\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheetsAPI — the imperative ref handed to a host via `<CasualSheets onReady>`.\n *\n * This is the SDK's stable integration surface (Excalidraw's model: props +\n * imperative ref). Hosts drive the editor through these methods rather than\n * reaching into Univer directly; `api.univer` is the documented escape hatch and\n * is explicitly NOT covered by semver — everything else here is.\n *\n * Surface (canonical, doc 38 §4):\n * getContent / setContent / import / export / getSelection / focus /\n * on / off / executeCommand / executeCommands / undo / redo / onMutation /\n * setTheme / setDocumentMode / getDocumentMode / univer\n * (+ deprecated aliases getSnapshot / loadSnapshot; format-specific\n * importXlsx / exportXlsx retained)\n *\n * `importXlsx` / `exportXlsx` lazy-load the converters via\n * `import('@casualoffice/sheets/xlsx')` — a BARE subpath, not a relative\n * `import('../xlsx')`. The main tsup config is `splitting:false`, so a relative\n * dynamic import would be inlined and balloon the editor entry from ~24KB to\n * ~200KB of ExcelJS for hosts that never touch a file. The subpath is\n * externalised in tsup.config.ts so it stays a separate chunk the consumer\n * code-splits.\n *\n * `attachCollab` is NOT a method here — it ships as a standalone\n * `attachCollab(api, opts)` on the `@casualoffice/sheets/collab` subpath so the\n * editor stays collab-unaware (and collab-free in the bundle) until opted in.\n */\n\n// Side-effect import: registers the Sheets FUniver mixins\n// (getActiveWorkbook / createWorkbook / FWorkbook.save / FRange.getRange / …)\n// onto the core FUniver facade — both the runtime methods AND the TypeScript\n// type augmentation this file relies on. Without it, FUniver is the bare core\n// facade and these methods exist neither at type-check nor at runtime.\nimport '@univerjs/sheets/facade';\nimport { ICommandService, IUniverInstanceService, ThemeService } from '@univerjs/core';\nimport type { FUniver } from '@univerjs/core/facade';\nimport type { IRange, IWorkbookData } from '@univerjs/core';\nimport {\n attachMutationObserver,\n runSteps,\n type CommandRecord,\n type MutationEmitter,\n} from './scripting';\nimport { applyReadOnly } from './read-only';\nimport { createEmitter } from './emitter';\n\n// Re-export so hosts can type a recorded/scripted step off the main entry.\nexport type { CommandRecord } from './scripting';\n\n/**\n * Document interaction mode — the SuperDoc-aligned vocabulary shared with the\n * docs SDK so hosts drive both editors the same way:\n *\n * - `'editing'` — fully editable (the default).\n * - `'viewing'` — read-only: the same command-veto + permission path as\n * {@link applyReadOnly}.\n *\n * Sheets has no `'suggesting'` tier (that's a docs-only track-changes concept),\n * so the union is the two states.\n */\nexport type DocumentMode = 'editing' | 'viewing';\n\n/** The active selection, as a sheet-scoped range. */\nexport interface RangeRef {\n /** Workbook unit id the selection belongs to. */\n unitId: string;\n /** Worksheet (sub-unit) id the selection belongs to. */\n sheetId: string;\n /** `{ startRow, startColumn, endRow, endColumn }`. */\n range: IRange;\n}\n\n/**\n * The canonical cross-editor event map (doc 38 §3), shared in shape with the\n * docs SDK so a host wires both editors the same way. Every event is available\n * two ways: as an `on*` prop on `<CasualSheets>` AND via `api.on(name, handler)` /\n * `api.off(name, handler)` on this handle — same event, same payload.\n *\n * Payloads are the format's own content type where the doc leaves it to the\n * format (`change` / `save` carry an `IWorkbookData` snapshot, not raw bytes).\n */\nexport interface CasualSheetsEvents {\n /** Fired once the workbook unit is created and the API is live. Sticky: a\n * handler registered via `api.on('ready', …)` after the editor is already\n * ready is invoked immediately with the API. */\n ready: (api: CasualSheetsAPI) => void;\n /** Debounced workbook snapshot, emitted after edits settle. */\n change: (snapshot: IWorkbookData) => void;\n /** The active selection changed (canvas-driven). `null` when there is none. */\n selectionChange: (selection: RangeRef | null) => void;\n /** Explicit save (Ctrl/Cmd+S), carrying the current snapshot to persist. */\n save: (snapshot: IWorkbookData) => void;\n /** A boot/runtime error surfaced by the editor. */\n error: (error: Error) => void;\n /** The unsaved-changes flag flipped. `true` after the first edit since the\n * last load/save, `false` on save / `setContent` / `import`. */\n dirtyChange: (dirty: boolean) => void;\n}\n\nexport interface CasualSheetsAPI {\n /** Current workbook as an `IWorkbookData` snapshot — the canonical\n * cross-editor content accessor (doc 38 §4). `null` before the unit is\n * created (shouldn't happen after `onReady`, but typed defensively). */\n getContent(): IWorkbookData | null;\n /** Replace the workbook with a new snapshot — the canonical cross-editor\n * content setter (doc 38 §4). Disposes the current unit, mounts `data` as a\n * fresh one, and clears the dirty flag. */\n setContent(data: IWorkbookData): void;\n /**\n * @deprecated Use {@link getContent} instead. Kept as an alias for one minor.\n */\n getSnapshot(): IWorkbookData | null;\n /**\n * @deprecated Use {@link setContent} instead. Kept as an alias for one minor.\n */\n loadSnapshot(data: IWorkbookData): void;\n /** Parse an `.xlsx` and load it as the active workbook — the format-specific\n * file import (canonically aliased as {@link import}). Accepts a `File` /\n * `Blob` (e.g. from an `<input type=file>`), an `ArrayBuffer`, or a\n * `Uint8Array`. The ExcelJS parser is lazy-loaded as a separate chunk, so\n * hosts that never import a file don't pay for it. When a `File` is passed,\n * its name + on-disk size are recorded on the snapshot (surfaced by the\n * built-in Properties dialog). Resolves to the loaded snapshot. */\n importXlsx(input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData>;\n /** Serialize the current workbook to an `.xlsx` `Blob` — the format-specific\n * file export (canonically aliased as {@link export}). Covers the core\n * fidelity (values/formulas, styles, merges, number formats, borders,\n * hyperlinks, comments, data validation, tables, page setup, named ranges,\n * VBA passthrough) — everything carried on the snapshot. App-level extras\n * (chart/pivot/sparkline models) are a power-host concern and aren't included\n * here. The converter (ExcelJS) is lazy-loaded as a separate chunk. Rejects\n * if there is no active workbook. */\n exportXlsx(): Promise<Blob>;\n /** Canonical cross-editor file import (doc 38 §4) — an alias of\n * {@link importXlsx}. */\n import(input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData>;\n /** Canonical cross-editor file export (doc 38 §4) — an alias of\n * {@link exportXlsx}. */\n export(): Promise<Blob>;\n /** The active selection, or `null` when there is none. */\n getSelection(): RangeRef | null;\n /** Move keyboard focus to the active workbook so subsequent typing / shortcuts\n * land on the grid (doc 38 §4). No-op when there is no active workbook. */\n focus(): void;\n /** Subscribe to a canonical editor event (doc 38 §3). Returns an unsubscribe\n * function. `'ready'` is sticky — subscribing after the editor is already\n * ready invokes the handler immediately. */\n on<K extends keyof CasualSheetsEvents>(name: K, handler: CasualSheetsEvents[K]): () => void;\n /** Remove a previously-registered event handler (doc 38 §3). */\n off<K extends keyof CasualSheetsEvents>(name: K, handler: CasualSheetsEvents[K]): void;\n /** Dispatch a Univer command by id. Resolves to the command's boolean\n * result. */\n executeCommand(id: string, params?: object): Promise<boolean>;\n /** Replay a sequence of command/mutation steps in order — e.g. a recorded\n * macro, or a host-authored script. Best-effort: a step that throws is\n * skipped (the underlying state may have moved on). Resolves to the number\n * of steps that ran without throwing. */\n executeCommands(steps: CommandRecord[]): Promise<number>;\n /** Undo the last edit — the canonical cross-editor history control (doc 38\n * §4). Dispatches Univer's `univer.command.undo` on the active unit\n * (fire-and-forget: no-op when there is nothing to undo). */\n undo(): void;\n /** Redo the last undone edit — the canonical cross-editor history control\n * (doc 38 §4). Dispatches Univer's `univer.command.redo` (fire-and-forget:\n * no-op when there is nothing to redo). */\n redo(): void;\n /** Observe the replayable mutation stream so a host can record automations\n * or build an audit log. Wraps Univer's canonical collab hook\n * (`onMutationExecutedForCollab`): fires for `CommandType.MUTATION` only —\n * the deterministic, replayable state changes, not transient command/calc\n * noise. Pair with `executeCommands` for record→replay. Returns a disposer;\n * call it to stop observing. */\n onMutation(handler: (record: CommandRecord) => void): () => void;\n /** Imperative light/dark switch — the API equivalent of the reactive\n * `appearance` prop. Flips Univer's `ThemeService.setDarkMode` (canvas\n * colours + the `univer-dark` class Univer applies to the document root). */\n setTheme(appearance: 'light' | 'dark'): void;\n /** Switch the active workbook between `'editing'` (fully editable, the\n * default) and `'viewing'` (read-only). `'viewing'` applies the same\n * command-veto + `WorkbookEditablePermission` path as {@link applyReadOnly};\n * `'editing'` disposes it and restores the prior editable state. Idempotent —\n * re-applying the current mode is a no-op. No-op when there is no active\n * workbook. */\n setDocumentMode(mode: DocumentMode): void;\n /** The current document mode: `'viewing'` while read-only is applied via\n * {@link setDocumentMode}, else `'editing'`. */\n getDocumentMode(): DocumentMode;\n /** The FUniver facade — documented escape hatch, NOT covered by semver. */\n univer: FUniver;\n}\n\n/**\n * Internal view of the API used by the `<CasualSheets>` wrapper to drive the\n * unified emitter from seams the factory can't see on its own (`ready` timing,\n * the Ctrl/Cmd+S save, boot errors) and to flip the dirty flag from the\n * wrapper's mutation subscription. NOT part of the public, semver-covered\n * surface — hosts use {@link CasualSheetsAPI}.\n * @internal\n */\nexport interface CasualSheetsAPIInternal extends CasualSheetsAPI {\n /** Emit a canonical event to all `api.on(name, …)` subscribers. */\n emit<K extends keyof CasualSheetsEvents>(\n name: K,\n ...args: Parameters<CasualSheetsEvents[K]>\n ): void;\n /** Flip the unsaved-changes flag; emits `dirtyChange` only on transitions. */\n markDirty(dirty: boolean): void;\n /** Live subscriber count for an event — lets the wrapper skip work (e.g.\n * serializing a snapshot for `change`) when nothing is listening. */\n listenerCount<K extends keyof CasualSheetsEvents>(name: K): number;\n}\n\n/**\n * Build the imperative API over a live FUniver facade. The wrapper holds no\n * state of its own — every call reads the current active workbook, so it stays\n * correct across `setContent` swaps without the host re-acquiring the ref.\n *\n * Returns a {@link CasualSheetsAPIInternal}; the public return type narrows it\n * to {@link CasualSheetsAPI} for hosts, while the `<CasualSheets>` wrapper casts\n * back to reach `emit` / `markDirty`.\n */\nexport function createCasualSheetsAPI(\n univerAPI: FUniver,\n initialResources?: IWorkbookData['resources'],\n): CasualSheetsAPI {\n // SDK-owned snapshot resources (charts / pivots / sparklines panels persist\n // their models here). Univer's `.save()`/`.load()` silently drop any resource\n // it doesn't own, so getContent()/setContent() alone can't round-trip them.\n // We shadow them in an SDK-layer store: setContent captures them before the\n // workbook swap, getContent merges them back onto the Univer snapshot. This\n // keeps the panels' existing `IWorkbookData.resources` read/write working and\n // makes them survive save/reload + collab.\n const CUSTOM_RESOURCE_NAMES = new Set([\n '__casual_sheets_charts__',\n '__casual_sheets_pivots__',\n '__casual_sheets_sparklines__',\n ]);\n const customResources = new Map<string, string>();\n const captureCustom = (resources: IWorkbookData['resources']) => {\n customResources.clear();\n for (const r of resources ?? []) {\n if (CUSTOM_RESOURCE_NAMES.has(r.name) && r.data) customResources.set(r.name, r.data);\n }\n };\n // Seed from the mounted snapshot so pivots/charts saved in a loaded workbook\n // are visible before the first edit.\n captureCustom(initialResources);\n\n // Extracted so importXlsx / setContent reuse the exact same swap semantics.\n const swapWorkbook = (data: IWorkbookData) => {\n const current = univerAPI.getActiveWorkbook();\n if (current) univerAPI.disposeUnit(current.getId());\n univerAPI.createWorkbook(data);\n };\n\n // Unified event emitter (doc 38 §3). Drives api.on/off; the factory wires the\n // Univer-derived events (`selectionChange`) itself, and the <CasualSheets>\n // wrapper drives the seams it owns (`ready`/`change`/`save`/`error`) via emit.\n const emitter = createEmitter<CasualSheetsEvents>();\n // `ready` is sticky: a late `api.on('ready', …)` fires immediately. We remember\n // the API instance passed to the first `emit('ready', …)`.\n let readyFired = false;\n let readyApi: CasualSheetsAPI | null = null;\n\n // Dirty tracking: flips true on the first buffered mutation after a load/save,\n // false on setContent/import/save. Emits `dirtyChange` on transitions only.\n let dirty = false;\n const markDirty = (next: boolean) => {\n if (next === dirty) return;\n dirty = next;\n emitter.emit('dirtyChange', next);\n };\n\n // Document-mode state: `'editing'` by default. When `'viewing'`, we hold the\n // disposer returned by applyReadOnly so switching back to `'editing'` restores\n // the prior editable state instead of reinventing the permission path.\n let documentMode: DocumentMode = 'editing';\n let readOnlyDisposer: (() => void) | null = null;\n\n const getContent = (): IWorkbookData | null => {\n const snap = univerAPI.getActiveWorkbook()?.save() ?? null;\n if (!snap || customResources.size === 0) return snap;\n // Re-attach the SDK-owned resources Univer dropped on save.\n const resources = (snap.resources ?? []).filter((r) => !CUSTOM_RESOURCE_NAMES.has(r.name));\n for (const [name, data] of customResources) resources.push({ name, data });\n return { ...snap, resources };\n };\n\n const setContent = (data: IWorkbookData): void => {\n // Capture the SDK-owned resources before Univer drops them on the swap.\n captureCustom(data.resources);\n swapWorkbook(data);\n // A fresh snapshot is a clean buffer until the user edits it.\n markDirty(false);\n };\n\n const importXlsx = async (input: ArrayBuffer | Uint8Array | Blob): Promise<IWorkbookData> => {\n // Normalise to ArrayBuffer. Blob/File expose arrayBuffer(); a Uint8Array\n // view is sliced to its exact window so we don't hand the parser a larger\n // backing buffer.\n let buffer: ArrayBuffer;\n if (input instanceof ArrayBuffer) {\n buffer = input;\n } else if (input instanceof Uint8Array) {\n // `.slice` of a (possibly SharedArrayBuffer-backed) view; uploads are\n // never shared, so narrow to ArrayBuffer for the parser.\n buffer = input.buffer.slice(\n input.byteOffset,\n input.byteOffset + input.byteLength,\n ) as ArrayBuffer;\n } else {\n buffer = await input.arrayBuffer();\n }\n // Bare subpath import → separate chunk (see file header + tsup external).\n const { xlsxToWorkbookData } = await import('@casualoffice/sheets/xlsx');\n const data = await xlsxToWorkbookData(buffer);\n // A File carries the original name + size; surface them on the snapshot so\n // the built-in Properties dialog shows the real file (not the snapshot).\n if (typeof Blob !== 'undefined' && input instanceof Blob && 'name' in input) {\n const file = input as File;\n data.name = file.name.replace(/\\.(xlsx|xlsm)$/i, '') || data.name;\n data.custom = { ...data.custom, sourceBytes: file.size, sourceName: file.name };\n }\n swapWorkbook(data);\n markDirty(false);\n return data;\n };\n\n const exportXlsx = async (): Promise<Blob> => {\n const snap = univerAPI.getActiveWorkbook()?.save();\n if (!snap) throw new Error('exportXlsx: no active workbook to export');\n // Bare subpath import → separate chunk (see file header + tsup external).\n const { workbookDataToXlsx } = await import('@casualoffice/sheets/xlsx');\n return workbookDataToXlsx(snap as IWorkbookData);\n };\n\n const getSelection = (): RangeRef | null => {\n const wb = univerAPI.getActiveWorkbook();\n const range = wb?.getActiveRange();\n if (!wb || !range) return null;\n return {\n unitId: wb.getId(),\n sheetId: wb.getActiveSheet().getSheetId(),\n range: range.getRange(),\n };\n };\n\n const focus = (): void => {\n const wb = univerAPI.getActiveWorkbook();\n if (!wb) return;\n try {\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const instanceService = injector?.get(IUniverInstanceService) as\n | { focusUnit(id: string | null): void }\n | undefined;\n // The same focus path FWorkbook.undo/redo use before dispatching, so the\n // grid takes keyboard focus for subsequent typing / shortcuts.\n instanceService?.focusUnit(wb.getId());\n } catch {\n /* focus is best-effort — no facade/injector, or unit already gone */\n }\n };\n\n // Sticky `on`: a late `on('ready', …)` fires immediately with the live API.\n const on = <K extends keyof CasualSheetsEvents>(\n name: K,\n handler: CasualSheetsEvents[K],\n ): (() => void) => {\n const unsubscribe = emitter.on(name, handler);\n if (name === 'ready' && readyFired && readyApi) {\n (handler as CasualSheetsEvents['ready'])(readyApi);\n }\n return unsubscribe;\n };\n\n const emit = <K extends keyof CasualSheetsEvents>(\n name: K,\n ...args: Parameters<CasualSheetsEvents[K]>\n ): void => {\n if (name === 'ready') {\n readyFired = true;\n readyApi = args[0] as CasualSheetsAPI;\n }\n emitter.emit(name, ...args);\n };\n\n // Canvas-driven selection → `selectionChange`. Both the internal\n // `SelectionChanged` (programmatic + user) and `SelectionMoveEnd` (fires\n // reliably on drag-release) feed it, mirroring the chrome FormulaBar's picker\n // wiring. Guarded by listener count so bare hosts never pay for `getSelection`.\n const emitSelection = () => {\n if (emitter.listenerCount('selectionChange') === 0) return;\n emitter.emit('selectionChange', getSelection());\n };\n // `SelectionChanged` / `SelectionMoveEnd` are contributed by the sheets-ui\n // facade (`@univerjs/sheets-ui/facade`), which the HOST registers (apps/web's\n // `facade.ts`). We reach them by name through a loose cast rather than a static\n // import: the vendored fork maps `@univerjs/sheets-ui/facade` to raw `.ts`\n // source, so importing it here would drag ~36 pre-existing fork type errors\n // into this package's typecheck. When the facade is present the events fire;\n // otherwise this stays a harmless no-op and the other events are unaffected.\n const evented = univerAPI as unknown as {\n Event?: Record<string, string | undefined>;\n addEvent(event: string, cb: () => void): { dispose(): void };\n };\n try {\n const changed = evented.Event?.SelectionChanged;\n const moveEnd = evented.Event?.SelectionMoveEnd;\n if (changed) evented.addEvent(changed, emitSelection);\n if (moveEnd) evented.addEvent(moveEnd, emitSelection);\n } catch {\n /* facade not loaded — selection events unavailable; other events unaffected */\n }\n\n const api: CasualSheetsAPIInternal = {\n univer: univerAPI,\n\n getContent,\n setContent,\n // Deprecated aliases (doc 38 §4) — kept working for one minor.\n getSnapshot: getContent,\n loadSnapshot: setContent,\n\n importXlsx,\n exportXlsx,\n // Canonical cross-editor aliases (doc 38 §4).\n import: importXlsx,\n export: exportXlsx,\n\n getSelection,\n focus,\n\n on,\n off: emitter.off,\n emit,\n markDirty,\n listenerCount: emitter.listenerCount,\n\n executeCommand(id, params) {\n return univerAPI.executeCommand(id, params) as Promise<boolean>;\n },\n\n executeCommands(steps) {\n return runSteps((id, params) => univerAPI.executeCommand(id, params), steps);\n },\n\n // History controls (doc 38 §4). Dispatched through the same command path the\n // built-in chrome (Toolbar/MenuBar) and the app shell already use, so undo/\n // redo, collab replay, and dirty tracking all stay consistent. Void the\n // promise — the canonical handle types these as fire-and-forget.\n undo() {\n void univerAPI.executeCommand('univer.command.undo');\n },\n\n redo() {\n void univerAPI.executeCommand('univer.command.redo');\n },\n\n onMutation(handler) {\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const cmdSvc = injector?.get(ICommandService) as MutationEmitter | undefined;\n return attachMutationObserver(cmdSvc, handler);\n },\n\n setTheme(appearance) {\n const dark = appearance === 'dark';\n const injector = (univerAPI as unknown as { _injector?: { get(t: unknown): unknown } })\n ._injector;\n const themeService = injector?.get(ThemeService) as\n | { setDarkMode(b: boolean): void; darkMode: boolean }\n | undefined;\n if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);\n },\n\n setDocumentMode(mode) {\n if (mode === documentMode) return;\n if (mode === 'viewing') {\n const wb = univerAPI.getActiveWorkbook();\n if (!wb) return; // no workbook yet — stay 'editing', caller can retry\n readOnlyDisposer = applyReadOnly(univerAPI, wb.getId());\n documentMode = 'viewing';\n } else {\n readOnlyDisposer?.();\n readOnlyDisposer = null;\n documentMode = 'editing';\n }\n },\n\n getDocumentMode() {\n return documentMode;\n },\n };\n\n return api;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pure scripting primitives behind CasualSheetsAPI's `executeCommands` /\n * `onMutation`. Kept free of any `@univerjs/*` *value* imports so it's unit\n * testable under the bare `node --import tsx` runner (importing Univer core\n * values fails to resolve there) — same split as\n * `read-only-predicate.ts` (pure) vs `read-only.ts` (wiring).\n */\n\n/**\n * A single scriptable step — a Univer command/mutation id plus its params.\n * The unit a host records (via `onMutation`) and replays (via\n * `executeCommands`); the SDK generalization of the app's macro recorder.\n */\nexport interface CommandRecord {\n /** Univer command/mutation id, e.g. `sheet.mutation.set-range-values`. */\n id: string;\n /** The command's params object, passed straight back to `executeCommand`. */\n params?: object;\n}\n\n/**\n * Replay `steps` in order through `execute`. Best-effort: a step that throws is\n * skipped (the underlying state may have moved on). Resolves to the number of\n * steps that ran without throwing.\n */\nexport async function runSteps(\n execute: (id: string, params?: object) => Promise<unknown> | unknown,\n steps: CommandRecord[],\n): Promise<number> {\n let applied = 0;\n for (const s of steps) {\n try {\n await execute(s.id, s.params);\n applied += 1;\n } catch {\n /* skip a step that no longer applies to the current state */\n }\n }\n return applied;\n}\n\n/** Minimal shape of the command service's collab mutation hook. */\nexport interface MutationEmitter {\n onMutationExecutedForCollab: (l: (info: CommandRecord) => void) => { dispose: () => void };\n}\n\n/**\n * Forward the collab mutation stream to `handler` as `{ id, params }` records.\n * Returns a disposer; safe to call with an absent service (no-op disposer).\n */\nexport function attachMutationObserver(\n cmdSvc: MutationEmitter | undefined,\n handler: (record: CommandRecord) => void,\n): () => void {\n const sub = cmdSvc?.onMutationExecutedForCollab((info) =>\n handler({ id: info.id, params: info.params }),\n );\n return () => sub?.dispose();\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CustomCommandExecutionError, ICommandService, IPermissionService } from '@univerjs/core';\nimport type { FUniver } from '@univerjs/core/facade';\nimport { WorkbookEditablePermission } from '@univerjs/sheets';\nimport { isCommentOnlyBlocked, READONLY_BLOCK } from './read-only-predicate';\n\nexport { isCommentOnlyBlocked, isReadOnlyBlocked } from './read-only-predicate';\n\n/**\n * Make a workbook genuinely READ-ONLY.\n *\n * Two layers, because they cover different host setups:\n *\n * 1. **Command veto** (`beforeCommandExecuted` → throw\n * `CustomCommandExecutionError`) — cancels every mutating command. This is\n * the load-bearing layer for the iframe embed, whose minimal plugin set does\n * NOT enforce `WorkbookEditablePermission` (verified: the editor still\n * accepts edits with the permission flipped off).\n * 2. **Permission flip** (`WorkbookEditablePermission` → false) — on the full\n * `<CasualSheets>` host path this also greys out mutating menu items and\n * stops the editor opening; harmless where unenforced.\n *\n * Returns a disposer that removes the veto and restores the prior editable\n * state (for callers that toggle a live unit between preview/editor).\n */\nexport function applyReadOnly(\n univerApi: FUniver,\n unitId: string,\n onBlock?: (commandId: string) => void,\n): () => void {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n\n // Layer 1: veto mutating commands — the only layer the minimal embed enforces.\n const cmd = injector?.get(ICommandService) as\n | { beforeCommandExecuted(l: (info: { id: string }) => void): { dispose(): void } }\n | undefined;\n const vetoDisposable = cmd?.beforeCommandExecuted((info) => {\n if (READONLY_BLOCK.test(info.id)) {\n onBlock?.(info.id);\n throw new CustomCommandExecutionError(`read-only: blocked ${info.id}`);\n }\n });\n\n // Layer 2: permission flip (best-effort; load-bearing only on full hosts).\n const svc = injector?.get(IPermissionService) as\n | {\n addPermissionPoint(p: unknown): boolean;\n updatePermissionPoint(id: string, value: unknown): void;\n getPermissionPoint(id: string): { value: unknown } | undefined;\n }\n | undefined;\n\n // Constructing the point yields the deterministic id Univer derives for the\n // workbook-edit permission; we don't keep the instance otherwise.\n const id = new WorkbookEditablePermission(unitId).id;\n let prev: unknown;\n if (svc) {\n try {\n const existing = svc.getPermissionPoint(id);\n if (existing) {\n prev = existing.value;\n svc.updatePermissionPoint(id, false);\n } else {\n const point = new WorkbookEditablePermission(unitId);\n point.value = false;\n svc.addPermissionPoint(point);\n }\n } catch {\n /* best-effort — the veto above is the load-bearing layer */\n }\n }\n\n return () => {\n vetoDisposable?.dispose();\n try {\n svc?.updatePermissionPoint(id, prev === undefined ? true : prev);\n } catch {\n /* swallow */\n }\n };\n}\n\n/**\n * Make a workbook **comment-only** (share role `comment`): cells are read-only,\n * but threaded comments and their editor stay fully usable. This is the middle\n * tier between `view` (read-only, no comments) and `edit` (full), enforced at\n * the engine layer via the same command veto as {@link applyReadOnly} — minus\n * the comment commands.\n *\n * No `WorkbookEditablePermission` flip here: on a full host that point also\n * disables comment affordances, which would defeat the role. The command veto is\n * the load-bearing layer (and the only one the minimal embed enforces anyway).\n *\n * Returns a disposer that removes the veto.\n */\nexport function applyCommentOnly(\n univerApi: FUniver,\n onBlock?: (commandId: string) => void,\n): () => void {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n const cmd = injector?.get(ICommandService) as\n | { beforeCommandExecuted(l: (info: { id: string }) => void): { dispose(): void } }\n | undefined;\n const vetoDisposable = cmd?.beforeCommandExecuted((info) => {\n if (isCommentOnlyBlocked(info.id)) {\n onBlock?.(info.id);\n throw new CustomCommandExecutionError(`comment-only: blocked ${info.id}`);\n }\n });\n return () => vetoDisposable?.dispose();\n}\n\n/**\n * Read the current `WorkbookEditablePermission` value for a unit — `true`\n * (editable), `false` (read-only), or `undefined` if the point isn't\n * registered yet. Lets hosts/tests confirm {@link applyReadOnly} took.\n */\nexport function getEditable(univerApi: FUniver, unitId: string): boolean | undefined {\n const injector = (univerApi as unknown as { _injector?: { get(t: unknown): unknown } })._injector;\n const svc = injector?.get(IPermissionService) as\n | { getPermissionPoint(id: string): { value: unknown } | undefined }\n | undefined;\n if (!svc) return undefined;\n const id = new WorkbookEditablePermission(unitId).id;\n const point = svc.getPermissionPoint(id);\n return point ? (point.value as boolean) : undefined;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pure command-id predicates for the read-only / comment-only vetoes. Kept\n * Univer-free (no `@univerjs/*` imports) so the security boundary is unit-testable\n * under the bare `node --import tsx` runner — `read-only.ts` pulls in Univer\n * services and can't load there.\n */\n\n/**\n * Command ids that MUTATE a sheet — opening the cell editor, writing values,\n * styling, structural edits, clipboard paste. The read-only veto cancels any\n * command whose id matches. Navigation (selection, scroll, zoom, sheet switch),\n * copy, and undo/redo deliberately fall through so preview stays usable.\n */\nexport const READONLY_BLOCK =\n /(set-cell-edit-visible|set-activate-cell-edit|set-range-values|set-style|set-bold|set-italic|set-underline|set-strike|set-font|set-background|set-text|set-horizontal|set-vertical|set-wrap|set-rotation|set-border|set-number-format|insert-|delete-|remove-|clear-selection|cut-content|paste|move-range|move-rows|move-cols|merge|split|add-worksheet|set-worksheet-name|set-worksheet-row|set-worksheet-col|auto-fill|reorder|set-defined-name|set-tab-color|set-frozen-cancel)/;\n\n/**\n * Commands that must stay usable for the **comment** share-role even though the\n * cells are locked: the threaded-comment commands (add / reply / update /\n * resolve / delete) and the comment editor's rich-text doc edits. Some of these\n * (`delete-comment`) would otherwise be caught by {@link READONLY_BLOCK}'s\n * `delete-` token, so the comment-only veto allowlists them explicitly.\n */\nexport const COMMENT_ALLOW = /(thread-comment|rich-text-editing)/;\n\n/** True for any mutating command (the read-only veto target). */\nexport function isReadOnlyBlocked(commandId: string): boolean {\n return READONLY_BLOCK.test(commandId);\n}\n\n/**\n * The comment-only veto predicate (the security boundary): block cell/style/\n * structural mutations, but let threaded-comment + comment-editor commands\n * through.\n */\nexport function isCommentOnlyBlocked(commandId: string): boolean {\n return READONLY_BLOCK.test(commandId) && !COMMENT_ALLOW.test(commandId);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Minimal typed event emitter backing the SDK's canonical `.on()/.off()` surface\n * (doc 38 §3). Kept in its own Univer-free module so it can be unit-tested in the\n * plain node test runner (importing `./api` would pull the Univer runtime).\n */\n\n/** Base constraint for an event map — a record of handler signatures. */\nexport type EventFn = (...args: never[]) => void;\n\nexport interface Emitter<E extends Record<keyof E, EventFn>> {\n /** Subscribe. Returns an unsubscribe function. */\n on<K extends keyof E>(name: K, handler: E[K]): () => void;\n /** Remove a previously-registered handler. */\n off<K extends keyof E>(name: K, handler: E[K]): void;\n /** Dispatch to all current subscribers of `name`. */\n emit<K extends keyof E>(name: K, ...args: Parameters<E[K]>): void;\n /** Live subscriber count for `name`. */\n listenerCount<K extends keyof E>(name: K): number;\n}\n\n/**\n * Build a typed emitter. `emit` snapshots the handler set so a handler that\n * unsubscribes mid-dispatch doesn't skip its peers, and isolates handler throws\n * so a misbehaving host callback can never break the seam `emit` is called from\n * (e.g. Univer's mutation / selection callbacks).\n */\nexport function createEmitter<E extends Record<keyof E, EventFn>>(): Emitter<E> {\n const listeners = new Map<keyof E, Set<EventFn>>();\n return {\n on<K extends keyof E>(name: K, handler: E[K]): () => void {\n let set = listeners.get(name);\n if (!set) {\n set = new Set();\n listeners.set(name, set);\n }\n set.add(handler as EventFn);\n return () => {\n listeners.get(name)?.delete(handler as EventFn);\n };\n },\n off<K extends keyof E>(name: K, handler: E[K]): void {\n listeners.get(name)?.delete(handler as EventFn);\n },\n emit<K extends keyof E>(name: K, ...args: Parameters<E[K]>): void {\n const set = listeners.get(name);\n if (!set) return;\n for (const handler of [...set]) {\n try {\n (handler as (...a: Parameters<E[K]>) => void)(...args);\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.error(`[CasualSheets] \"${String(name)}\" event handler threw`, err);\n }\n }\n }\n },\n listenerCount<K extends keyof E>(name: K): number {\n return listeners.get(name)?.size ?? 0;\n },\n };\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Univer, IWorkbookData } from '@univerjs/core';\n\n/**\n * Lazy plugin loading — pipeline Stage 4. The cheap plugins (render,\n * formula, sheets, sheets-ui, numfmt, docs) stay eager because every\n * workbook needs them. The heavy / feature-specific plugins (CF, DV,\n * hyperlink, table, note, thread-comment, drawing, sort, filter,\n * find-replace) load on demand:\n *\n * 1. Eagerly when a snapshot is about to mount and we detect the\n * plugin's resource key on it (e.g. `SHEET_CONDITIONAL_FORMATTING_PLUGIN`\n * in `data.resources`). This is the safety net: missing this would\n * silently drop plugin data on file open.\n * 2. Lazily when the user reaches for the feature — opens the Data\n * tab (sort/filter), hits Ctrl+F (find-replace), uses the Insert\n * tab (drawing), etc. The shell hooks `ensurePlugin(...)` into\n * these triggers and awaits before the action runs.\n *\n * Each loader returns the plugins-to-register in the correct order\n * (base before UI, same as `plugins.ts`). Registration order matters\n * in Univer; the loaders bundle a small group together to keep that\n * locality explicit.\n */\n\nexport type LazyPluginGroup =\n | 'cf'\n | 'dv'\n | 'hyperlink'\n | 'note'\n | 'table'\n | 'threadComment'\n | 'drawing'\n | 'sort'\n | 'filter'\n | 'findReplace';\n\ntype Loader = () => Promise<Array<[unknown, unknown?]>>;\n\nconst LOADERS: Record<LazyPluginGroup, Loader> = {\n cf: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-conditional-formatting'),\n import('@univerjs/sheets-conditional-formatting-ui'),\n ]);\n return [\n [base.UniverSheetsConditionalFormattingPlugin],\n [ui.UniverSheetsConditionalFormattingUIPlugin],\n ];\n },\n dv: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-data-validation'),\n import('@univerjs/sheets-data-validation-ui'),\n ]);\n return [[base.UniverSheetsDataValidationPlugin], [ui.UniverSheetsDataValidationUIPlugin]];\n },\n hyperlink: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-hyper-link'),\n import('@univerjs/sheets-hyper-link-ui'),\n ]);\n return [[base.UniverSheetsHyperLinkPlugin], [ui.UniverSheetsHyperLinkUIPlugin]];\n },\n note: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-note'),\n import('@univerjs/sheets-note-ui'),\n ]);\n return [[base.UniverSheetsNotePlugin], [ui.UniverSheetsNoteUIPlugin]];\n },\n table: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-table'),\n import('@univerjs/sheets-table-ui'),\n ]);\n return [[base.UniverSheetsTablePlugin], [ui.UniverSheetsTableUIPlugin]];\n },\n threadComment: async () => {\n const [tc, tcUi, sheetsTc, sheetsTcUi, mentionUi] = await Promise.all([\n import('@univerjs/thread-comment'),\n import('@univerjs/thread-comment-ui'),\n import('@univerjs/sheets-thread-comment'),\n import('@univerjs/sheets-thread-comment-ui'),\n // @-mention autocomplete for the comment editor. Lists candidates via the\n // core IMentionIOService, which CasualSheets overrides with the\n // host-pluggable CasualMentionIOService (see mention-source.ts). Riding\n // the comment group means it loads exactly when comments do.\n import('@univerjs/docs-mention-ui'),\n // Side-effect imports: install FWorksheet.getComments / FRange.\n // getComments / addCommentAsync on the facade prototype. Without\n // these the CommentsPanel's `getActiveSheet().getComments()` and\n // any facade-driven comment flow (e2e, future shell glue) see an\n // undefined method even though the plugin is registered — mirrors\n // the `drawing` group's facade imports above.\n import('@univerjs/sheets-thread-comment/facade'),\n ]);\n return [\n [tc.UniverThreadCommentPlugin],\n [tcUi.UniverThreadCommentUIPlugin],\n [sheetsTc.UniverSheetsThreadCommentPlugin],\n [sheetsTcUi.UniverSheetsThreadCommentUIPlugin],\n [mentionUi.UniverDocsMentionUIPlugin],\n ];\n },\n drawing: async () => {\n const [d, dUi, sd, sdUi] = await Promise.all([\n import('@univerjs/drawing'),\n import('@univerjs/drawing-ui'),\n import('@univerjs/sheets-drawing'),\n import('@univerjs/sheets-drawing-ui'),\n // Side-effect imports: install FWorksheet.insertImage / getImages /\n // updateImages on the facade prototype. Without these, code that\n // reaches in via the FUniver facade (e2e specs, future shell glue)\n // sees an undefined method even though the plugin is registered.\n import('@univerjs/sheets-drawing/facade'),\n import('@univerjs/sheets-drawing-ui/facade'),\n ]);\n return [\n [d.UniverDrawingPlugin],\n [dUi.UniverDrawingUIPlugin],\n [sd.UniverSheetsDrawingPlugin],\n [sdUi.UniverSheetsDrawingUIPlugin],\n ];\n },\n sort: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-sort'),\n import('@univerjs/sheets-sort-ui'),\n ]);\n return [[base.UniverSheetsSortPlugin], [ui.UniverSheetsSortUIPlugin]];\n },\n filter: async () => {\n const [base, ui] = await Promise.all([\n import('@univerjs/sheets-filter'),\n import('@univerjs/sheets-filter-ui'),\n ]);\n return [[base.UniverSheetsFilterPlugin], [ui.UniverSheetsFilterUIPlugin]];\n },\n findReplace: async () => {\n const [base, sheets] = await Promise.all([\n import('@univerjs/find-replace'),\n import('@univerjs/sheets-find-replace'),\n ]);\n return [[base.UniverFindReplacePlugin], [sheets.UniverSheetsFindReplacePlugin]];\n },\n};\n\n/**\n * Map from a Univer `data.resources[].name` to the lazy group that owns\n * it. Used by `eagerLoadForSnapshot` to pre-register plugins whose\n * state already lives on the workbook so file-open never silently\n * drops a CF rule / table / drawing / etc.\n */\nconst RESOURCE_NAME_TO_GROUP: Record<string, LazyPluginGroup> = {\n SHEET_CONDITIONAL_FORMATTING_PLUGIN: 'cf',\n SHEET_DATA_VALIDATION_PLUGIN: 'dv',\n SHEET_HYPER_LINK_PLUGIN: 'hyperlink',\n SHEET_NOTE_PLUGIN: 'note',\n SHEET_TABLE_PLUGIN: 'table',\n SHEET_THREAD_COMMENT_BASE_PLUGIN: 'threadComment',\n SHEET_DRAWING_PLUGIN: 'drawing',\n SHEET_SORT_PLUGIN: 'sort',\n SHEET_FILTER_PLUGIN: 'filter',\n};\n\nconst loaded = new Set<LazyPluginGroup>();\nconst inflight = new Map<LazyPluginGroup, Promise<void>>();\n\n/**\n * Module-level reference to the live Univer instance, set by\n * `UniverSheet.tsx` immediately after `new Univer()`. Lets shell code\n * call `ensurePluginByName(group)` without plumbing the Univer\n * instance through React context (the FUniver facade doesn't expose\n * its host). Cleared on dispose so callers fail loudly if they hit\n * the lazy path after teardown.\n */\nlet currentUniver: Univer | null = null;\n\nexport function setUniverForLazyLoad(univer: Univer | null): void {\n currentUniver = univer;\n}\n\n/**\n * Idempotent: subsequent calls for the same group resolve immediately\n * if the plugin is already loaded; concurrent calls share the same\n * in-flight promise so we never double-register.\n */\nexport function ensurePlugin(univer: Univer, group: LazyPluginGroup): Promise<void> {\n if (loaded.has(group)) return Promise.resolve();\n const existing = inflight.get(group);\n if (existing) return existing;\n const loader = LOADERS[group];\n if (!loader) return Promise.resolve();\n const p = loader().then((plugins) => {\n for (const [PluginCtor, config] of plugins) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n univer.registerPlugin(PluginCtor as any, config);\n }\n loaded.add(group);\n inflight.delete(group);\n });\n inflight.set(group, p);\n return p;\n}\n\n/**\n * Shell-friendly variant of `ensurePlugin` that pulls the Univer\n * instance from the module-level holder set by `UniverSheet.tsx`. Use\n * this anywhere we only have the FUniver facade (toolbar callbacks,\n * panel handlers). Returns a resolved promise if the holder is empty —\n * the worst case is a no-op, never a throw.\n */\nexport function ensurePluginByName(group: LazyPluginGroup): Promise<void> {\n if (loaded.has(group)) return Promise.resolve();\n if (!currentUniver) return Promise.resolve();\n return ensurePlugin(currentUniver, group);\n}\n\n/**\n * Walk a snapshot for plugin-owned resources + side-channel hyperlinks\n * and eagerly load every group that's referenced. Returns a promise\n * the caller MUST await before `createUnit` — Univer's resource manager\n * silently discards keys for plugins that aren't yet registered.\n */\nexport async function eagerLoadForSnapshot(univer: Univer, snapshot: IWorkbookData): Promise<void> {\n const groups = new Set<LazyPluginGroup>();\n const resources = snapshot.resources ?? [];\n for (const r of resources) {\n const g = RESOURCE_NAME_TO_GROUP[r.name];\n if (g) groups.add(g);\n }\n // Hyperlinks live inline in cell.p (Stage 5) — the hyperlink plugin\n // still owns click handling / context-menu actions, so eager-load\n // when any cell has a HYPERLINK customRange.\n if (snapshotHasHyperlinks(snapshot)) groups.add('hyperlink');\n await Promise.all(Array.from(groups).map((g) => ensurePlugin(univer, g)));\n}\n\n/**\n * Idle-load every remaining lazy group AFTER Univer is mounted. The\n * bundle split (each group ships as its own chunk) is the persistent\n * boot-time win — the initial paint doesn't pay for them. This\n * idle-load just ensures they're all eventually registered so a user\n * clicking \"Insert > Table\" doesn't hit a no-op.\n *\n * Loads in parallel via `requestIdleCallback` so they don't compete\n * with the first paint, falling back to `setTimeout(0)` in browsers\n * without rIC (Safari).\n */\nexport function idleLoadAll(univer: Univer): void {\n const groups = Object.keys(LOADERS) as LazyPluginGroup[];\n schedule(() => {\n for (const g of groups) {\n void ensurePlugin(univer, g);\n }\n });\n}\n\nfunction schedule(fn: () => void): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ric = (globalThis as any).requestIdleCallback as\n | ((cb: () => void, opts?: { timeout: number }) => number)\n | undefined;\n if (ric) ric(fn, { timeout: 500 });\n else setTimeout(fn, 0);\n}\n\nfunction snapshotHasHyperlinks(snapshot: IWorkbookData): boolean {\n const sheetOrder = snapshot.sheetOrder ?? [];\n for (const sid of sheetOrder) {\n const sheet = snapshot.sheets?.[sid];\n if (!sheet?.cellData) continue;\n const cellData = sheet.cellData as Record<\n string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Record<string, { p?: any }>\n >;\n for (const r of Object.keys(cellData)) {\n const row = cellData[r];\n for (const c of Object.keys(row)) {\n const ranges = row[c]?.p?.body?.customRanges ?? [];\n if (ranges.some((cr: { rangeType?: number }) => cr.rangeType === 0)) return true;\n }\n }\n }\n return false;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * AI surface for the Sheets SDK.\n *\n * `<CasualSheets ai={…}>` opts a host into a supported AI task-pane surface,\n * mirroring how the docs `CasualEditor`/`DocxEditor` SDK exposes its DocOps\n * panel behind a `docopsTransport` prop. The SDK owns the prop contract, the\n * `SheetsAiTransport` type (see `./transport`), and the layout slot beside the\n * grid; the host supplies the panel body via `ai.render` and drives its tool\n * loop against the transport.\n *\n * MVP (slot + transport wiring). The reference implementation of the panel\n * body — chat UI, `SheetsBridge` (FUniver tool catalog), agent mode, MCP — is\n * still in the reference app at `apps/web/src/shell/AiPanel.tsx`; that panel is\n * entangled with app-only modules (`use-ui`, `Icon`, the `ai/` catalog + MCP\n * runtime), so it is NOT yet moved wholesale into the SDK.\n *\n * TODO(sheets#280): extract the `SheetsBridge` catalog + a self-contained\n * default panel body into the SDK so `ai.enabled` renders a working assistant\n * with no `render` slot required.\n */\n\nimport type { ReactNode } from 'react';\nimport type { CasualSheetsAPI } from '../sheets/api';\nimport type { SheetsAiTransport } from './transport';\n\n/** Lifecycle / progress signals a panel body reports back to the host. */\nexport type SheetsAiAction =\n | { type: 'open' }\n | { type: 'close' }\n | { type: 'message'; role: 'user' | 'assistant'; text: string }\n | { type: 'tool'; tool: string; status: 'running' | 'done' | 'error' }\n | { type: 'error'; message: string };\n\n/** Context handed to `ai.render` — everything a panel body needs to run. */\nexport interface SheetsAiRenderContext {\n /** The ready editor facade (`CasualSheetsAPI`). Never null inside `render`. */\n api: CasualSheetsAPI;\n /** The transport the host configured (if any). */\n transport?: SheetsAiTransport;\n /** Forward panel lifecycle/progress to the host's `ai.onAction`. */\n onAction?: (action: SheetsAiAction) => void;\n /** Request the surface be dismissed (emits an `onAction({type:'close'})`). */\n close: () => void;\n}\n\n/** The `ai` prop on `<CasualSheets>`. */\nexport interface SheetsAiConfig {\n /** Mount the AI surface beside the grid. Default `false` (no surface). */\n enabled?: boolean;\n /** LLM transport the panel body drives its tool loop against. Build one with\n * `createSheetsAiTransport()` or supply your own `SheetsAiTransport`. */\n transport?: SheetsAiTransport;\n /** Observe panel lifecycle + progress (open/close, messages, tool steps). */\n onAction?: (action: SheetsAiAction) => void;\n /** Render the panel body. Receives a `SheetsAiRenderContext` (ready `api` +\n * `transport` + `onAction` + `close`). Until the SDK ships a built-in body,\n * this slot is how the panel is mounted — the reference app passes its\n * `<AiPanel>` here. When omitted, `enabled` mounts an empty pane. */\n render?: (ctx: SheetsAiRenderContext) => ReactNode;\n}\n\nconst asideStyle: React.CSSProperties = {\n flex: '0 0 auto',\n width: 340,\n maxWidth: '100%',\n height: '100%',\n minHeight: 0,\n display: 'flex',\n flexDirection: 'column',\n borderLeft: '1px solid var(--color-divider, #e5e7eb)',\n background: 'var(--color-surface, #ffffff)',\n overflow: 'hidden',\n};\n\n/**\n * Renders the configured AI surface beside the grid. Returns `null` until the\n * editor is ready (`api` populated) or when disabled — so bare-grid consumers\n * pay nothing. The host's `render` slot owns the panel body; if absent, an\n * empty (but present) pane is mounted so layout is stable.\n */\nexport function AiPanelSurface({\n config,\n api,\n}: {\n config: SheetsAiConfig | undefined;\n api: CasualSheetsAPI | null;\n}): ReactNode {\n if (!config?.enabled || !api) return null;\n\n const ctx: SheetsAiRenderContext = {\n api,\n transport: config.transport,\n onAction: config.onAction,\n close: () => config.onAction?.({ type: 'close' }),\n };\n\n return (\n <aside data-testid=\"casual-sheets-ai\" style={asideStyle}>\n {config.render?.(ctx) ?? null}\n </aside>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Panel store for the SDK chrome's side-panel rail (Tables/Charts/Comments/…).\n *\n * A single `openPanelId` is the whole state — that IS the mutex: opening one\n * panel closes any other, exactly like the standalone app's PanelMutex, but\n * without the app-only `ui-context`. The rail toggles panels through here and\n * the panel host renders whichever id is open. Kept deliberately tiny so the\n * chrome stays a thin shell around Univer.\n */\nimport { createContext, useContext, useMemo, useState, type ReactNode } from 'react';\n\nexport interface PanelStore {\n /** The id of the currently-open panel, or null when the rail is all-closed. */\n openPanelId: string | null;\n /** Open `id`, replacing whatever was open (mutex). */\n open: (id: string) => void;\n /** Close the open panel. */\n close: () => void;\n /** Toggle `id`: open it if closed, close it if it's the open one. */\n toggle: (id: string) => void;\n}\n\nconst PanelContext = createContext<PanelStore | null>(null);\n\nexport function PanelProvider({ children }: { children: ReactNode }) {\n const [openPanelId, setOpenPanelId] = useState<string | null>(null);\n const store = useMemo<PanelStore>(\n () => ({\n openPanelId,\n open: (id) => setOpenPanelId(id),\n close: () => setOpenPanelId(null),\n toggle: (id) => setOpenPanelId((cur) => (cur === id ? null : id)),\n }),\n [openPanelId],\n );\n return <PanelContext.Provider value={store}>{children}</PanelContext.Provider>;\n}\n\n/** Read the panel store. Returns a no-op store when used outside a provider. */\nexport function usePanels(): PanelStore {\n return (\n useContext(PanelContext) ?? {\n openPanelId: null,\n open: () => {},\n close: () => {},\n toggle: () => {},\n }\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Right-edge vertical rail of panel-toggle buttons (mirrors the standalone\n * app's PanelRail, but registry-driven and self-contained in the SDK). Built-in\n * panels come first, then any host `extensions.panels`. Clicking a button\n * toggles that panel through the shared panel store; the open panel's body is\n * rendered to the left by PanelHost.\n */\nimport type { CSSProperties } from 'react';\n\nimport type { ChromeExtensions } from './extensions';\nimport { Icon } from './Icon';\nimport { usePanels } from './panel-context';\nimport { BUILT_IN_PANELS } from './panel-registry';\n\nconst railStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 2,\n padding: '6px 4px',\n flex: '0 0 auto',\n borderLeft: '1px solid var(--cs-chrome-border, #edeff3)',\n background: 'var(--cs-chrome-bg, #eef1f5)',\n};\n\nexport interface RailEntry {\n id: string;\n label: string;\n icon: string;\n}\n\n/** Merge built-in panels with host-supplied ones into a single rail list. */\nexport function railEntries(extensions?: ChromeExtensions): RailEntry[] {\n const built = BUILT_IN_PANELS.map((p) => ({ id: p.id, label: p.label, icon: p.icon }));\n const host = (extensions?.panels ?? []).map((p) => ({\n id: p.id,\n label: p.title,\n icon: p.railIcon,\n }));\n return [...built, ...host];\n}\n\nexport function PanelRail({ extensions }: { extensions?: ChromeExtensions }) {\n const panels = usePanels();\n const entries = railEntries(extensions);\n if (entries.length === 0) return null;\n\n return (\n <aside style={railStyle} data-testid=\"cs-panel-rail\" aria-label=\"Panels\" role=\"toolbar\">\n {entries.map((e) => {\n const pressed = panels.openPanelId === e.id;\n return (\n <button\n key={e.id}\n type=\"button\"\n data-testid={`cs-panel-rail-${e.id}`}\n aria-pressed={pressed}\n aria-label={pressed ? `Hide ${e.label}` : e.label}\n title={pressed ? `Hide ${e.label}` : e.label}\n onClick={() => panels.toggle(e.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 30,\n height: 30,\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n color: pressed\n ? 'var(--cs-chrome-active-fg, #0e7490)'\n : 'var(--cs-chrome-fg, #201f1e)',\n background: pressed\n ? 'var(--cs-chrome-active, rgba(14,116,144,0.11))'\n : 'transparent',\n }}\n >\n <Icon name={e.icon} size={18} />\n </button>\n );\n })}\n </aside>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Built-in side panels the SDK chrome ships (mirrors `BUILT_IN_DIALOGS`). Each\n * entry gets a rail button + a body rendered by the panel host. Hosts can add\n * more via `extensions.panels` (see extensions.ts) — those are merged after\n * these on the rail.\n */\nimport { lazy, type ComponentType } from 'react';\n\nimport type { PanelComponentProps } from './extensions';\nimport { TablesPanel } from './TablesPanel';\nimport { PivotFieldsPanel } from './PivotFieldsPanel';\nimport { CommentsPanel } from './CommentsPanel';\nimport { HistoryPanel } from './HistoryPanel';\n// Charts panel pulls echarts — lazy so it (and echarts) only load when the\n// panel is first opened. PanelHost renders panels inside a Suspense boundary.\nconst ChartsPanel = lazy(() =>\n import('../charts/ChartsPanel').then((m) => ({ default: m.ChartsPanel })),\n);\n\nexport interface BuiltInPanel {\n /** Stable id (rail `data-testid` `cs-panel-rail-<id>`, mutex key). */\n id: string;\n /** Rail button tooltip / aria-label. */\n label: string;\n /** Material Symbols icon name for the rail button. */\n icon: string;\n /** The panel body; receives `{ api, onClose }`. */\n component: ComponentType<PanelComponentProps>;\n}\n\nexport const BUILT_IN_PANELS: BuiltInPanel[] = [\n { id: 'tables', label: 'Tables', icon: 'table', component: TablesPanel },\n {\n id: 'pivot',\n label: 'PivotTable Fields',\n icon: 'pivot_table_chart',\n component: PivotFieldsPanel,\n },\n { id: 'charts', label: 'Charts', icon: 'analytics', component: ChartsPanel },\n { id: 'comments', label: 'Comments', icon: 'forum', component: CommentsPanel },\n { id: 'history', label: 'History', icon: 'history', component: HistoryPanel },\n];\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Tables side panel: lists the formatted tables on the active sheet with\n * inline rename, theme swatches, and delete. Ported from the standalone app's\n * TablesPanel — the app-only `useUI`/`useBusy` couplings are replaced by the\n * panel host's `onClose`, and the Univer facade is reached through `api.univer`.\n */\nimport { useEffect, useMemo, useState, type CSSProperties } from 'react';\n\nimport { ensurePluginByName } from '../univer';\nimport type { PanelComponentProps } from './extensions';\nimport { Icon } from './Icon';\nimport { PanelHeader, PanelEmpty } from './panel-shell';\n\n// Univer's six built-in table themes, surfaced as swatches.\nconst TABLE_THEMES = [\n { id: 'table-default-0', label: 'Indigo', swatch: '#6280F9' },\n { id: 'table-default-1', label: 'Teal', swatch: '#16BDCA' },\n { id: 'table-default-2', label: 'Green', swatch: '#31C48D' },\n { id: 'table-default-3', label: 'Purple', swatch: '#AC94FA' },\n { id: 'table-default-4', label: 'Pink', swatch: '#F17EBB' },\n { id: 'table-default-5', label: 'Red', swatch: '#F98080' },\n] as const;\ntype TableThemeId = (typeof TABLE_THEMES)[number]['id'];\n\ninterface TableRange {\n startRow: number;\n startColumn: number;\n endRow: number;\n endColumn: number;\n}\ninterface RawTable {\n id: string;\n name: string;\n subUnitId: string;\n range: TableRange;\n}\ninterface TableInfo extends RawTable {\n styleId: string;\n}\n\nfunction colLetters(col: number): string {\n let n = col + 1;\n let out = '';\n while (n > 0) {\n const r = (n - 1) % 26;\n out = String.fromCharCode(65 + r) + out;\n n = Math.floor((n - 1) / 26);\n }\n return out;\n}\nfunction toA1(r: TableRange): string {\n const start = `${colLetters(r.startColumn)}${r.startRow + 1}`;\n const end = `${colLetters(r.endColumn)}${r.endRow + 1}`;\n return start === end ? start : `${start}:${end}`;\n}\n\nconst REFRESH_CMDS = new Set([\n 'sheet.command.add-table',\n 'sheet.command.delete-table',\n 'sheet.command.set-table-config',\n 'sheet.mutation.add-table',\n 'sheet.mutation.set-table-config',\n 'sheet.mutation.delete-table',\n 'sheet.operation.set-worksheet-activate',\n 'doc.command-replace-snapshot',\n]);\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction readTables(univer: any, sheetId: string | null): TableInfo[] {\n try {\n const wb = univer.getActiveWorkbook?.();\n if (!wb) return [];\n const all: RawTable[] = wb.getTableList?.() ?? [];\n return all\n .filter((t) => (sheetId ? t.subUnitId === sheetId : true))\n .map((t) => ({ ...t, styleId: 'table-default-0' }));\n } catch {\n // Table plugin still registering — the CommandExecuted subscription\n // recomputes once it's ready.\n return [];\n }\n}\n\nconst header: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 12px',\n borderBottom: '1px solid var(--cs-chrome-border, #edeff3)',\n};\n\nexport function TablesPanel({ api, onClose }: PanelComponentProps) {\n const univer = (api as any).univer;\n const [tables, setTables] = useState<TableInfo[]>([]);\n const [renaming, setRenaming] = useState<{ id: string; draft: string } | null>(null);\n\n useEffect(() => {\n if (!univer) return;\n let cancelled = false;\n let disp: { dispose?: () => void } | undefined;\n const compute = () => {\n if (cancelled) return;\n const sheetId = univer.getActiveWorkbook?.()?.getActiveSheet?.()?.getSheetId?.() ?? null;\n setTables(readTables(univer, sheetId));\n };\n // The table plugin is lazy-loaded — `getTableList()` resolves SheetTableService\n // and throws if the plugin isn't registered yet, so ensure it before reading.\n void ensurePluginByName('table').then(() => {\n if (cancelled) return;\n compute();\n disp = univer.addEvent(univer.Event.CommandExecuted, (e: { id?: string }) => {\n if (e.id && REFRESH_CMDS.has(e.id)) compute();\n });\n });\n return () => {\n cancelled = true;\n disp?.dispose?.();\n };\n }, [univer]);\n\n const themesById = useMemo(() => {\n const m = new Map<string, (typeof TABLE_THEMES)[number]>();\n for (const t of TABLE_THEMES) m.set(t.id, t);\n return m;\n }, []);\n\n const empty = tables.length === 0;\n\n const onRenameCommit = async (id: string, currentName: string) => {\n if (!renaming || renaming.id !== id) return;\n const next = renaming.draft.trim();\n setRenaming(null);\n if (!next || next === currentName) return;\n const sheet = univer.getActiveWorkbook?.()?.getActiveSheet?.();\n if (!sheet) return;\n await ensurePluginByName('table');\n const ok = await Promise.resolve(sheet.setTableName?.(id, next));\n if (ok === false) console.warn(`[tables] rename rejected: \"${next}\"`);\n };\n\n const onPickTheme = async (id: string, themeId: TableThemeId) => {\n const wb = univer.getActiveWorkbook?.();\n if (!wb) return;\n await ensurePluginByName('table');\n univer.executeCommand('sheet.command.set-table-config', {\n unitId: wb.getId(),\n tableId: id,\n theme: themeId,\n });\n };\n\n const onDelete = async (id: string) => {\n const wb = univer.getActiveWorkbook?.();\n if (!wb) return;\n await ensurePluginByName('table');\n wb.removeTable?.(id);\n };\n\n return (\n <div\n data-testid=\"cs-tables-panel\"\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\n >\n <PanelHeader icon=\"table\" title=\"Tables\" count={tables.length} onClose={onClose} />\n\n <div style={{ flex: 1, overflow: 'auto', padding: 12 }}>\n {empty ? (\n <PanelEmpty icon=\"table_rows\" title=\"No tables on this sheet\" testId=\"cs-tables-panel-empty\">\n Select your data, then use <strong>Insert → Table</strong> from the menu.\n </PanelEmpty>\n ) : (\n <ul\n style={{\n listStyle: 'none',\n margin: 0,\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n }}\n >\n {tables.map((t) => {\n const isRenaming = renaming?.id === t.id;\n const theme = themesById.get(t.styleId);\n return (\n <li\n key={t.id}\n data-testid={`cs-tables-panel-row-${t.id}`}\n style={{\n border: '1px solid var(--cs-chrome-border, #edeff3)',\n borderRadius: 8,\n padding: 10,\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n {isRenaming ? (\n <input\n autoFocus\n value={renaming.draft}\n onChange={(e) => setRenaming({ id: t.id, draft: e.target.value })}\n onBlur={() => onRenameCommit(t.id, t.name)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onRenameCommit(t.id, t.name);\n if (e.key === 'Escape') setRenaming(null);\n }}\n style={{ flex: 1, font: 'inherit', padding: '2px 4px' }}\n />\n ) : (\n <button\n type=\"button\"\n onClick={() => setRenaming({ id: t.id, draft: t.name })}\n title=\"Click to rename\"\n style={{\n flex: 1,\n textAlign: 'left',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n font: 'inherit',\n fontWeight: 600,\n color: 'inherit',\n }}\n >\n {t.name}\n </button>\n )}\n <span style={{ opacity: 0.6, fontSize: 12 }}>{toA1(t.range)}</span>\n <button\n type=\"button\"\n aria-label={`Delete table ${t.name}`}\n title=\"Delete table\"\n onClick={() => onDelete(t.id)}\n style={{\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n }}\n >\n <Icon name=\"delete\" size={16} />\n </button>\n </div>\n <div role=\"group\" aria-label=\"Table theme\" style={{ display: 'flex', gap: 4 }}>\n {TABLE_THEMES.map((opt) => (\n <button\n key={opt.id}\n type=\"button\"\n title={opt.label}\n aria-label={opt.label}\n aria-pressed={theme?.id === opt.id}\n onClick={() => onPickTheme(t.id, opt.id)}\n style={{\n width: 18,\n height: 18,\n borderRadius: 4,\n cursor: 'pointer',\n background: opt.swatch,\n border:\n theme?.id === opt.id\n ? '2px solid var(--cs-chrome-active-fg, #0e7490)'\n : '1px solid rgba(0,0,0,0.15)',\n }}\n />\n ))}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * PivotTable Fields side panel — Excel's \"PivotTable Fields\" task pane, ported\n * from the standalone app's PivotFieldsPanel into the SDK chrome so embedders\n * (dochub) get it natively.\n *\n * Lists the source fields of a pivot and its four drop zones — Filters /\n * Columns / Rows / Values — and lets the user assign fields (drag, or the \"+\"\n * zone menu), remove/reorder chips, edit a value's aggregation + Show-Values-As,\n * a row field's date grouping, and a report filter's per-value checklist. The\n * pivot config is persisted on the workbook so it round-trips through xlsx and\n * collab.\n *\n * DECOUPLING from the app:\n * - `useUniverAPI()` → the injected `api` prop; `useUI().togglePivotPanel` →\n * the `onClose` prop.\n * - The app reads/writes pivot models through its `PivotsProvider` context\n * (apps/web/src/pivots/pivots-context.tsx), which does NOT exist in the SDK.\n * Instead — mirroring the SDK's InsertSparklineDialog — we read the pivot\n * models straight off the live workbook snapshot's\n * `resources['__casual_sheets_pivots__']` via `api.getContent()` and persist\n * edits back with `api.setContent()`. Same resource envelope the app's\n * pivots feature owns; it round-trips through xlsx + collab identically.\n * - The pure `fields-model` transforms + label tables + source reader are\n * INLINED here (structurally identical to apps/web/src/pivots/*) so the SDK\n * stays free of the app package.\n *\n * The pivot engine (`computePivot` / `applyPivot`, ported to ../pivots) runs on\n * every edit: `commit()` re-applies the model to the sheet so the laid-out\n * output grid recomputes live, then persists the model (with its new output\n * extent) into the workbook resource. Field assignment, drag-and-drop,\n * agg/showAs/grouping/filters all recompute the visible pivot immediately.\n */\n\nimport { useEffect, useMemo, useState, type CSSProperties, type ReactNode } from 'react';\nimport type { IWorkbookData } from '@univerjs/core';\n\nimport type { CasualSheetsAPI } from '../sheets/api';\nimport type { PanelComponentProps } from './extensions';\nimport { Icon } from './Icon';\nimport { PanelHeader } from './panel-shell';\nimport { applyPivot } from '../pivots/apply';\n\n/* ------------------------------------------------------------------ *\n * Pivot model — mirrors apps/web/src/pivots/types.ts (duplicated so the\n * SDK doesn't depend on the app package).\n * ------------------------------------------------------------------ */\n\ntype PivotAggregation = 'sum' | 'count' | 'average' | 'min' | 'max' | 'distinctCount';\nconst PIVOT_AGG_LABELS: Record<PivotAggregation, string> = {\n sum: 'Sum',\n count: 'Count',\n average: 'Average',\n min: 'Min',\n max: 'Max',\n distinctCount: 'Distinct Count',\n};\n\ntype DateGrouping = 'none' | 'year' | 'quarter' | 'month';\nconst PIVOT_DATE_GROUP_LABELS: Record<DateGrouping, string> = {\n none: 'No grouping',\n year: 'Years',\n quarter: 'Quarters',\n month: 'Months',\n};\n\ntype PivotShowAs = 'normal' | 'pctOfGrandTotal' | 'pctOfColumnTotal' | 'pctOfRowTotal';\nconst PIVOT_SHOW_AS_LABELS: Record<PivotShowAs, string> = {\n normal: 'Normal',\n pctOfGrandTotal: '% of Grand Total',\n pctOfColumnTotal: '% of Column Total',\n pctOfRowTotal: '% of Row Total',\n};\n\ntype PivotFieldRef = { column: number; grouping?: DateGrouping };\ntype PivotValueField = { column: number; agg: PivotAggregation; showAs?: PivotShowAs };\ntype PivotFilter = { column: number; allowedValues: string[] };\n\ninterface PivotModel {\n id: string;\n sourceSheetId: string;\n source: { startRow: number; endRow: number; startColumn: number; endColumn: number };\n targetSheetId: string;\n target: { row: number; column: number };\n rows: PivotFieldRef[];\n cols: PivotFieldRef[];\n values: PivotValueField[];\n filters?: PivotFilter[];\n lastOutputExtent?: { rows: number; cols: number };\n title?: string;\n}\n\n/** Resource key + envelope — mirrors `PIVOTS_RESOURCE_NAME` /\n * `PivotsResourceV1` in apps/web/src/pivots/types.ts. */\nconst PIVOTS_RESOURCE_NAME = '__casual_sheets_pivots__';\ninterface PivotsResourceV1 {\n v: 1;\n pivots: PivotModel[];\n}\n\n/* ------------------------------------------------------------------ *\n * Pure model transforms — mirrors apps/web/src/pivots/fields-model.ts.\n * ------------------------------------------------------------------ */\n\ntype ZoneId = 'filters' | 'rows' | 'cols' | 'values';\n\nconst ZONE_LABELS: Record<ZoneId, string> = {\n filters: 'Filters',\n cols: 'Columns',\n rows: 'Rows',\n values: 'Values',\n};\n\nconst AXES: Array<Exclude<ZoneId, 'values'>> = ['rows', 'cols', 'filters'];\n\ntype DragPayload = { from: 'list'; column: number } | { from: 'zone'; zone: ZoneId; index: number };\n\nfunction placedColumns(model: PivotModel): Set<number> {\n const s = new Set<number>();\n for (const r of model.rows) s.add(r.column);\n for (const c of model.cols) s.add(c.column);\n for (const v of model.values) s.add(v.column);\n for (const f of model.filters ?? []) s.add(f.column);\n return s;\n}\n\nfunction cloneZones(model: PivotModel) {\n return {\n rows: model.rows.map((r) => ({ ...r })),\n cols: model.cols.map((c) => ({ ...c })),\n values: model.values.map((v) => ({ ...v })),\n filters: (model.filters ?? []).map((f) => ({ ...f, allowedValues: [...f.allowedValues] })),\n };\n}\n\nfunction stripFromAxes(z: ReturnType<typeof cloneZones>, column: number): void {\n z.rows = z.rows.filter((r) => r.column !== column);\n z.cols = z.cols.filter((c) => c.column !== column);\n z.filters = z.filters.filter((f) => f.column !== column);\n}\n\nfunction addFieldToZone(\n model: PivotModel,\n column: number,\n zone: ZoneId,\n opts?: { defaultAgg?: PivotAggregation; allowedValues?: string[] },\n): PivotModel {\n const z = cloneZones(model);\n if (zone === 'values') {\n z.values.push({ column, agg: opts?.defaultAgg ?? 'sum', showAs: 'normal' });\n return { ...model, rows: z.rows, cols: z.cols, values: z.values, filters: z.filters };\n }\n stripFromAxes(z, column);\n if (zone === 'rows') z.rows.push({ column });\n else if (zone === 'cols') z.cols.push({ column });\n else z.filters.push({ column, allowedValues: opts?.allowedValues ?? [] });\n return { ...model, rows: z.rows, cols: z.cols, values: z.values, filters: z.filters };\n}\n\nfunction removeFieldFromZone(model: PivotModel, zone: ZoneId, index: number): PivotModel {\n const z = cloneZones(model);\n z[zone] = (z[zone] as unknown[]).filter((_, i) => i !== index) as never;\n return { ...model, rows: z.rows, cols: z.cols, values: z.values, filters: z.filters };\n}\n\nfunction moveWithinZone(model: PivotModel, zone: ZoneId, from: number, to: number): PivotModel {\n const z = cloneZones(model);\n const arr = z[zone] as unknown[];\n if (from < 0 || from >= arr.length || to < 0 || to >= arr.length || from === to) return model;\n const [moved] = arr.splice(from, 1);\n arr.splice(to, 0, moved);\n return { ...model, rows: z.rows, cols: z.cols, values: z.values, filters: z.filters };\n}\n\nfunction updateValueField(\n model: PivotModel,\n index: number,\n patch: Partial<Pick<PivotValueField, 'agg' | 'showAs'>>,\n): PivotModel {\n const values = model.values.map((v, i) => (i === index ? { ...v, ...patch } : v));\n return { ...model, values };\n}\n\nfunction updateRowGrouping(model: PivotModel, index: number, grouping: DateGrouping): PivotModel {\n const rows = model.rows.map((r, i) =>\n i === index ? { ...r, grouping: grouping === 'none' ? undefined : grouping } : r,\n );\n return { ...model, rows };\n}\n\nfunction hasValues(model: PivotModel): boolean {\n return model.values.length > 0;\n}\n\nfunction axisOf(model: PivotModel, column: number): Exclude<ZoneId, 'values'> | null {\n for (const ax of AXES) {\n const arr = ax === 'filters' ? (model.filters ?? []) : model[ax];\n if (arr.some((e) => e.column === column)) return ax;\n }\n return null;\n}\n\nfunction toggleFilterValue(\n model: PivotModel,\n filterIndex: number,\n value: string,\n checked: boolean,\n allValues: string[],\n): PivotModel {\n const filters = (model.filters ?? []).map((f) => ({ ...f, allowedValues: [...f.allowedValues] }));\n const f = filters[filterIndex];\n if (!f) return model;\n const current = new Set(f.allowedValues.length ? f.allowedValues : allValues);\n if (checked) current.add(value);\n else current.delete(value);\n f.allowedValues = allValues.filter((v) => current.has(v));\n return { ...model, filters };\n}\n\nfunction setFilterValues(model: PivotModel, filterIndex: number, values: string[]): PivotModel {\n const filters = (model.filters ?? []).map((f) => ({ ...f, allowedValues: [...f.allowedValues] }));\n if (!filters[filterIndex]) return model;\n filters[filterIndex].allowedValues = [...values];\n return { ...model, filters };\n}\n\nfunction filterAllowedCount(model: PivotModel, filterIndex: number, allCount: number): number {\n const f = (model.filters ?? [])[filterIndex];\n if (!f) return allCount;\n return f.allowedValues.length ? f.allowedValues.length : allCount;\n}\n\nfunction columnInZone(model: PivotModel, zone: ZoneId, index: number): number | null {\n const arr =\n zone === 'values' ? model.values : zone === 'filters' ? (model.filters ?? []) : model[zone];\n return arr[index]?.column ?? null;\n}\n\nfunction applyDrop(\n model: PivotModel,\n payload: DragPayload,\n targetZone: ZoneId,\n optsFor: (column: number) => { defaultAgg?: PivotAggregation; allowedValues?: string[] },\n): PivotModel {\n if (payload.from === 'list') {\n return addFieldToZone(model, payload.column, targetZone, optsFor(payload.column));\n }\n if (payload.zone === targetZone) return model;\n const column = columnInZone(model, payload.zone, payload.index);\n if (column == null) return model;\n if (payload.zone === 'values' && model.values.length <= 1) return model;\n const removed = removeFieldFromZone(model, payload.zone, payload.index);\n return addFieldToZone(removed, column, targetZone, optsFor(column));\n}\n\n/* ------------------------------------------------------------------ *\n * Snapshot resource read/write — the SDK-native persistence path\n * (mirrors InsertSparklineDialog): read models off `api.getContent()`,\n * write back through `api.setContent()`.\n * ------------------------------------------------------------------ */\n\nfunction readPivots(api: CasualSheetsAPI): PivotModel[] {\n const data = api.getContent();\n const entry = data?.resources?.find((r) => r.name === PIVOTS_RESOURCE_NAME);\n if (!entry?.data) return [];\n try {\n const parsed = JSON.parse(entry.data) as Partial<PivotsResourceV1>;\n if (parsed?.v !== 1 || !Array.isArray(parsed.pivots)) return [];\n return parsed.pivots;\n } catch {\n return [];\n }\n}\n\n/** Persist an edited pivot model back onto the workbook snapshot. Merges over\n * the existing entry and re-mounts via `setContent` — the same path the\n * sparkline dialog uses. */\nfunction persistPivot(api: CasualSheetsAPI, next: PivotModel): void {\n const data = api.getContent();\n if (!data) return;\n const resources = data.resources ? [...data.resources] : [];\n const idx = resources.findIndex((r) => r.name === PIVOTS_RESOURCE_NAME);\n let pivots: PivotModel[] = [];\n if (idx >= 0 && resources[idx]?.data) {\n try {\n const parsed = JSON.parse(resources[idx].data) as Partial<PivotsResourceV1>;\n if (parsed?.v === 1 && Array.isArray(parsed.pivots)) pivots = parsed.pivots;\n } catch {\n pivots = [];\n }\n }\n const merged = pivots.some((p) => p.id === next.id)\n ? pivots.map((p) => (p.id === next.id ? next : p))\n : [...pivots, next];\n const entry = { name: PIVOTS_RESOURCE_NAME, data: JSON.stringify({ v: 1, pivots: merged }) };\n if (idx >= 0) resources[idx] = entry;\n else resources.push(entry);\n const nextData: IWorkbookData = { ...data, resources };\n api.setContent(nextData);\n}\n\n/* ------------------------------------------------------------------ *\n * Source reader — headers + distinct values off the FUniver facade.\n * Mirrors readSource() in apps/web/src/pivots/PivotFieldsPanel.tsx.\n * ------------------------------------------------------------------ */\n\ninterface SourceView {\n headers: string[];\n distinct: (col: number) => string[];\n isNumeric: (col: number) => boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction readSource(api: CasualSheetsAPI, model: PivotModel | null): SourceView {\n const empty: SourceView = { headers: [], distinct: () => [], isNumeric: () => false };\n if (!model) return empty;\n const wb = api.univer.getActiveWorkbook?.();\n if (!wb) return empty;\n const ws = (wb.getSheets() as any[]).find((s) => s.getSheetId?.() === model.sourceSheetId);\n if (!ws) return empty;\n const { startRow, endRow, startColumn, endColumn } = model.source;\n const headers: string[] = [];\n for (let c = startColumn; c <= endColumn; c++) {\n const v = ws.getRange(startRow, c).getValue();\n headers.push(v == null || v === '' ? `Column ${c - startColumn + 1}` : String(v));\n }\n const colAt = (idx: number) => startColumn + idx;\n return {\n headers,\n distinct: (col) => {\n const seen = new Set<string>();\n for (let r = startRow + 1; r <= endRow; r++) {\n const v = ws.getRange(r, colAt(col)).getValue();\n seen.add(v == null ? '' : String(v));\n }\n return [...seen].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));\n },\n isNumeric: (col) => {\n for (let r = startRow + 1; r <= endRow; r++) {\n const v = ws.getRange(r, colAt(col)).getValue();\n if (v == null || v === '') continue;\n return typeof v === 'number';\n }\n return false;\n },\n };\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/* ------------------------------------------------------------------ *\n * Styles — inline, --cs-chrome-* CSS vars, no external classes.\n * ------------------------------------------------------------------ */\n\nconst border = '1px solid var(--cs-chrome-border, #edeff3)';\n\nconst headerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 12px',\n borderBottom: border,\n};\n\nconst iconBtn: CSSProperties = {\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n display: 'inline-flex',\n alignItems: 'center',\n padding: 2,\n};\n\nconst sectionTitle: CSSProperties = {\n margin: '0 0 6px',\n fontSize: 11,\n fontWeight: 700,\n textTransform: 'uppercase',\n letterSpacing: 0.4,\n opacity: 0.6,\n};\n\nconst fieldRow: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '5px 6px',\n borderRadius: 6,\n cursor: 'grab',\n userSelect: 'none',\n};\n\nconst chipStyle: CSSProperties = {\n border,\n borderRadius: 6,\n padding: '6px 8px',\n background: 'var(--cs-chrome-surface, #fbfbfd)',\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n};\n\nconst selectStyle: CSSProperties = {\n font: 'inherit',\n fontSize: 12,\n padding: '2px 4px',\n border,\n borderRadius: 4,\n background: 'transparent',\n color: 'inherit',\n flex: 1,\n};\n\n/* ------------------------------------------------------------------ *\n * Panel component.\n * ------------------------------------------------------------------ */\n\nexport function PivotFieldsPanel({ api, onClose }: PanelComponentProps) {\n const [pivots, setPivots] = useState<PivotModel[]>(() => readPivots(api));\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [menuFor, setMenuFor] = useState<number | null>(null);\n const [expandedFilter, setExpandedFilter] = useState<number | null>(null);\n\n // Re-read pivots whenever the workbook content settles (edit / import /\n // setContent / collab). Keeps the panel live without the app pivot store.\n useEffect(() => {\n const reload = () => setPivots(readPivots(api));\n reload();\n const offChange = api.on('change', reload);\n return () => offChange();\n }, [api]);\n\n // Keep a valid selection: default to the most-recent pivot; recover if the\n // selected one was deleted.\n useEffect(() => {\n if (pivots.length === 0) {\n if (selectedId !== null) setSelectedId(null);\n return;\n }\n if (!selectedId || !pivots.some((p) => p.id === selectedId)) {\n setSelectedId(pivots[pivots.length - 1].id);\n }\n }, [pivots, selectedId]);\n\n const model = useMemo(\n () => pivots.find((p) => p.id === selectedId) ?? null,\n [pivots, selectedId],\n );\n const source = useMemo(() => readSource(api, model), [api, model]);\n\n const placed = model ? placedColumns(model) : new Set<number>();\n\n // Optimistic local update + persist. We update `pivots` immediately so the UI\n // is responsive, then write through to the snapshot so it round-trips.\n const commit = (next: PivotModel) => {\n // Recompute the laid-out output grid on the sheet (pivot engine), then\n // persist the model with the fresh output extent so the next apply clears\n // the previous region before writing the new one.\n const extent = applyPivot(api.univer, next, next.lastOutputExtent ?? null);\n const model = extent ? { ...next, lastOutputExtent: extent } : next;\n setPivots((prev) => prev.map((p) => (p.id === model.id ? model : p)));\n persistPivot(api, model);\n };\n\n const optsFor = (col: number) => ({\n defaultAgg: source.isNumeric(col) ? ('sum' as const) : ('count' as const),\n allowedValues: source.distinct(col),\n });\n\n const onZoneDrop = (zone: ZoneId, raw: string) => {\n if (!model || !raw) return;\n let payload: DragPayload;\n try {\n payload = JSON.parse(raw) as DragPayload;\n } catch {\n return;\n }\n commit(applyDrop(model, payload, zone, optsFor));\n };\n\n const labelFor = (col: number) => source.headers[col] ?? `Column ${col + 1}`;\n\n return (\n <div\n data-testid=\"cs-pivot-fields-panel\"\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\n >\n <PanelHeader icon=\"pivot_table_chart\" title=\"PivotTable Fields\" onClose={onClose} />\n\n <div style={{ flex: 1, overflow: 'auto', padding: 12 }}>\n {!model ? (\n <div\n data-testid=\"cs-pivot-fields-empty\"\n style={{ textAlign: 'center', opacity: 0.75, padding: '24px 8px' }}\n >\n <Icon name=\"pivot_table_chart\" size={40} style={{ opacity: 0.4 }} />\n <div style={{ fontWeight: 600, marginTop: 8 }}>No PivotTable selected</div>\n <div style={{ fontSize: 13, marginTop: 4 }}>\n Insert a PivotTable, then configure its fields here.\n </div>\n </div>\n ) : (\n <>\n {pivots.length > 1 && (\n <label style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>\n <span style={{ fontSize: 12, opacity: 0.7 }}>PivotTable</span>\n <select\n data-testid=\"cs-pivot-fields-picker\"\n value={selectedId ?? ''}\n onChange={(e) => setSelectedId(e.target.value)}\n style={{ ...selectStyle, flex: 1 }}\n >\n {pivots.map((p, i) => (\n <option key={p.id} value={p.id}>\n {p.title ?? `PivotTable ${i + 1}`}\n </option>\n ))}\n </select>\n </label>\n )}\n\n {/* Source field list */}\n <section style={{ marginBottom: 14 }}>\n <h3 style={sectionTitle}>Choose fields</h3>\n <ul\n data-testid=\"cs-pivot-fields-list\"\n style={{ listStyle: 'none', margin: 0, padding: 0 }}\n >\n {source.headers.map((h, col) => {\n const ax = axisOf(model, col);\n const badge =\n ax === 'rows' ? 'R' : ax === 'cols' ? 'C' : ax === 'filters' ? '▽' : '';\n return (\n <li\n key={col}\n style={fieldRow}\n draggable\n data-testid={`cs-pivot-fields-field-${col}`}\n onDragStart={(e) => {\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData(\n 'text/plain',\n JSON.stringify({ from: 'list', column: col } satisfies DragPayload),\n );\n }}\n >\n <Icon name=\"drag_indicator\" size={16} style={{ opacity: 0.4 }} />\n <span\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n flexShrink: 0,\n background: placed.has(col)\n ? 'var(--cs-chrome-active-fg, #0e7490)'\n : 'transparent',\n border: placed.has(col)\n ? 'none'\n : '1px solid var(--cs-chrome-border, #c8ccd4)',\n }}\n />\n <span\n title={h}\n style={{\n flex: 1,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {h}\n </span>\n {badge && (\n <span\n style={{\n fontSize: 11,\n fontWeight: 700,\n opacity: 0.6,\n minWidth: 14,\n textAlign: 'center',\n }}\n >\n {badge}\n </span>\n )}\n <div style={{ position: 'relative' }}>\n <button\n type=\"button\"\n aria-label={`Add ${h} to a zone`}\n data-testid={`cs-pivot-fields-add-${col}`}\n onClick={() => setMenuFor((cur) => (cur === col ? null : col))}\n style={iconBtn}\n >\n <Icon name=\"add\" size={16} />\n </button>\n {menuFor === col && (\n <div\n role=\"menu\"\n data-testid={`cs-pivot-fields-add-menu-${col}`}\n style={{\n position: 'absolute',\n right: 0,\n top: '100%',\n zIndex: 10,\n minWidth: 150,\n background: 'var(--cs-chrome-bg, #fff)',\n border,\n borderRadius: 6,\n boxShadow: '0 4px 16px rgba(0,0,0,0.14)',\n padding: 4,\n }}\n >\n {(['filters', 'rows', 'cols', 'values'] as ZoneId[]).map((zone) => (\n <button\n key={zone}\n type=\"button\"\n role=\"menuitem\"\n data-testid={`cs-pivot-fields-add-${col}-${zone}`}\n onClick={() => {\n setMenuFor(null);\n commit(addFieldToZone(model, col, zone, optsFor(col)));\n }}\n style={{\n display: 'block',\n width: '100%',\n textAlign: 'left',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n font: 'inherit',\n color: 'inherit',\n padding: '6px 8px',\n borderRadius: 4,\n }}\n >\n Add to {ZONE_LABELS[zone]}\n </button>\n ))}\n </div>\n )}\n </div>\n </li>\n );\n })}\n {source.headers.length === 0 && (\n <li style={{ fontSize: 12, opacity: 0.6, padding: '6px 2px' }}>\n No source fields found.\n </li>\n )}\n </ul>\n </section>\n\n {/* Drop zones */}\n <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>\n <Zone zone=\"filters\" model={model} onDrop={onZoneDrop}>\n {(col, i) => {\n const all = source.distinct(col);\n const allowed = filterAllowedCount(model, i, all.length);\n const stored = model.filters?.[i]?.allowedValues ?? [];\n const isAllowed = (v: string) =>\n stored.length === 0 ? true : stored.includes(v);\n const expanded = expandedFilter === i;\n return (\n <Chip\n key={`f-${i}`}\n label={labelFor(col)}\n zone=\"filters\"\n index={i}\n count={(model.filters ?? []).length}\n onRemove={() => commit(removeFieldFromZone(model, 'filters', i))}\n onMove={(dir) => commit(moveWithinZone(model, 'filters', i, i + dir))}\n >\n <button\n type=\"button\"\n data-testid={`cs-pivot-fields-filter-toggle-${i}`}\n aria-expanded={expanded}\n onClick={() => setExpandedFilter(expanded ? null : i)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n fontSize: 12,\n padding: 0,\n }}\n >\n <Icon name={expanded ? 'expand_less' : 'expand_more'} size={16} />\n <span>\n {allowed} of {all.length} selected\n </span>\n </button>\n {expanded && (\n <div\n data-testid={`cs-pivot-fields-filter-values-${i}`}\n style={{\n maxHeight: 160,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n }}\n >\n <div style={{ display: 'flex', gap: 8, marginBottom: 4 }}>\n <button\n type=\"button\"\n data-testid={`cs-pivot-fields-filter-all-${i}`}\n onClick={() => commit(setFilterValues(model, i, all))}\n style={linkBtn}\n >\n Select all\n </button>\n <button\n type=\"button\"\n data-testid={`cs-pivot-fields-filter-clear-${i}`}\n onClick={() => commit(setFilterValues(model, i, []))}\n style={linkBtn}\n >\n Clear\n </button>\n </div>\n {all.map((v) => (\n <label\n key={v}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n fontSize: 12,\n }}\n >\n <input\n type=\"checkbox\"\n data-testid={`cs-pivot-fields-filter-${i}-${v || 'blank'}`}\n checked={isAllowed(v)}\n onChange={(e) =>\n commit(toggleFilterValue(model, i, v, e.target.checked, all))\n }\n />\n <span>{v === '' ? '(blank)' : v}</span>\n </label>\n ))}\n </div>\n )}\n </Chip>\n );\n }}\n </Zone>\n\n <Zone zone=\"cols\" model={model} onDrop={onZoneDrop}>\n {(col, i) => (\n <Chip\n key={`c-${i}`}\n label={labelFor(col)}\n zone=\"cols\"\n index={i}\n count={model.cols.length}\n onRemove={() => commit(removeFieldFromZone(model, 'cols', i))}\n onMove={(dir) => commit(moveWithinZone(model, 'cols', i, i + dir))}\n />\n )}\n </Zone>\n\n <Zone zone=\"rows\" model={model} onDrop={onZoneDrop}>\n {(col, i) => (\n <Chip\n key={`r-${i}`}\n label={labelFor(col)}\n zone=\"rows\"\n index={i}\n count={model.rows.length}\n onRemove={() => commit(removeFieldFromZone(model, 'rows', i))}\n onMove={(dir) => commit(moveWithinZone(model, 'rows', i, i + dir))}\n >\n <select\n aria-label=\"Group dates by\"\n data-testid={`cs-pivot-fields-rows-grouping-${i}`}\n value={model.rows[i]?.grouping ?? 'none'}\n onChange={(e) =>\n commit(updateRowGrouping(model, i, e.target.value as DateGrouping))\n }\n style={selectStyle}\n >\n {(Object.keys(PIVOT_DATE_GROUP_LABELS) as DateGrouping[]).map((g) => (\n <option key={g} value={g}>\n {PIVOT_DATE_GROUP_LABELS[g]}\n </option>\n ))}\n </select>\n </Chip>\n )}\n </Zone>\n\n <Zone zone=\"values\" model={model} onDrop={onZoneDrop}>\n {(col, i) => (\n <Chip\n key={`v-${i}`}\n label={`${PIVOT_AGG_LABELS[model.values[i].agg]} of ${labelFor(col)}`}\n zone=\"values\"\n index={i}\n count={model.values.length}\n onRemove={\n hasValues(model) && model.values.length > 1\n ? () => commit(removeFieldFromZone(model, 'values', i))\n : undefined\n }\n onMove={(dir) => commit(moveWithinZone(model, 'values', i, i + dir))}\n >\n <div style={{ display: 'flex', gap: 4 }}>\n <select\n aria-label=\"Summarize values by\"\n data-testid={`cs-pivot-fields-values-agg-${i}`}\n value={model.values[i].agg}\n onChange={(e) =>\n commit(\n updateValueField(model, i, { agg: e.target.value as PivotAggregation }),\n )\n }\n style={selectStyle}\n >\n {(Object.keys(PIVOT_AGG_LABELS) as PivotAggregation[]).map((a) => (\n <option key={a} value={a}>\n {PIVOT_AGG_LABELS[a]}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Show values as\"\n data-testid={`cs-pivot-fields-values-showas-${i}`}\n value={model.values[i].showAs ?? 'normal'}\n onChange={(e) =>\n commit(\n updateValueField(model, i, { showAs: e.target.value as PivotShowAs }),\n )\n }\n style={selectStyle}\n >\n {(Object.keys(PIVOT_SHOW_AS_LABELS) as PivotShowAs[]).map((s) => (\n <option key={s} value={s}>\n {PIVOT_SHOW_AS_LABELS[s]}\n </option>\n ))}\n </select>\n </div>\n </Chip>\n )}\n </Zone>\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n\nconst linkBtn: CSSProperties = {\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'var(--cs-chrome-active-fg, #0e7490)',\n font: 'inherit',\n fontSize: 12,\n padding: 0,\n};\n\n/* ------------------------------------------------------------------ *\n * Zone — one drop target (Filters / Columns / Rows / Values).\n * ------------------------------------------------------------------ */\n\nfunction Zone({\n zone,\n model,\n children,\n onDrop,\n}: {\n zone: ZoneId;\n model: PivotModel;\n children: (column: number, index: number) => ReactNode;\n onDrop: (zone: ZoneId, raw: string) => void;\n}) {\n const [over, setOver] = useState(false);\n const entries: number[] =\n zone === 'values'\n ? model.values.map((v) => v.column)\n : zone === 'filters'\n ? (model.filters ?? []).map((f) => f.column)\n : model[zone].map((e) => e.column);\n\n return (\n <section\n data-testid={`cs-pivot-fields-zone-${zone}`}\n onDragOver={(e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n if (!over) setOver(true);\n }}\n onDragLeave={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node)) setOver(false);\n }}\n onDrop={(e) => {\n e.preventDefault();\n setOver(false);\n onDrop(zone, e.dataTransfer.getData('text/plain'));\n }}\n style={{\n border: over\n ? '1px dashed var(--cs-chrome-active-fg, #0e7490)'\n : '1px dashed var(--cs-chrome-border, #d5d9e0)',\n borderRadius: 8,\n padding: 8,\n background: over ? 'var(--cs-chrome-surface, #eef6f8)' : 'transparent',\n minHeight: 56,\n }}\n >\n <h4 style={{ ...sectionTitle, margin: '0 0 6px' }}>{ZONE_LABELS[zone]}</h4>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n {entries.length === 0 ? (\n <div style={{ fontSize: 12, opacity: 0.5, padding: '4px 2px' }}>Drop or add fields</div>\n ) : (\n entries.map((col, i) => children(col, i))\n )}\n </div>\n </section>\n );\n}\n\n/* ------------------------------------------------------------------ *\n * Chip — a placed field: label, move up/down, remove, extra controls.\n * ------------------------------------------------------------------ */\n\nfunction Chip({\n label,\n zone,\n index,\n count,\n onRemove,\n onMove,\n children,\n}: {\n label: string;\n zone: ZoneId;\n index: number;\n count: number;\n onRemove?: () => void;\n onMove: (dir: -1 | 1) => void;\n children?: ReactNode;\n}) {\n return (\n <div\n data-testid={`cs-pivot-fields-chip-${zone}-${index}`}\n draggable\n onDragStart={(e) => {\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData(\n 'text/plain',\n JSON.stringify({ from: 'zone', zone, index } satisfies DragPayload),\n );\n }}\n style={{ ...chipStyle, cursor: 'grab' }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>\n <Icon name=\"drag_indicator\" size={16} style={{ opacity: 0.4 }} />\n <span\n title={label}\n style={{\n flex: 1,\n fontSize: 13,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {label}\n </span>\n {index > 0 && (\n <button\n type=\"button\"\n aria-label=\"Move up\"\n data-testid={`cs-pivot-fields-chip-${zone}-${index}-up`}\n onClick={() => onMove(-1)}\n style={iconBtn}\n >\n <Icon name=\"keyboard_arrow_up\" size={16} />\n </button>\n )}\n {index < count - 1 && (\n <button\n type=\"button\"\n aria-label=\"Move down\"\n data-testid={`cs-pivot-fields-chip-${zone}-${index}-down`}\n onClick={() => onMove(1)}\n style={iconBtn}\n >\n <Icon name=\"keyboard_arrow_down\" size={16} />\n </button>\n )}\n {onRemove && (\n <button\n type=\"button\"\n aria-label={`Remove ${label}`}\n data-testid={`cs-pivot-fields-chip-${zone}-${index}-remove`}\n onClick={onRemove}\n style={iconBtn}\n >\n <Icon name=\"close\" size={16} />\n </button>\n )}\n </div>\n {children}\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Pivot table model. Excel's PivotCacheDefinition + PivotTableDefinition,\n * compressed to what we need for v0.1. The model is small and\n * JSON-serializable so it can live on `IWorkbookData.resources` the\n * same way chart models do.\n *\n * Conventions (same as charts):\n *\n * - Source range row 0 = header row → field names.\n * - Subsequent rows = records.\n * - Field references are column indices within the source range\n * (0-indexed). Names are looked up from the headers at render\n * time so the model survives a column rename — there's no\n * ambiguity until somebody changes the source range shape, at\n * which point the field count may shift.\n */\n\nexport type PivotAggregation = 'sum' | 'count' | 'average' | 'min' | 'max' | 'distinctCount';\n\nexport const PIVOT_AGG_LABELS: Record<PivotAggregation, string> = {\n sum: 'Sum',\n count: 'Count',\n average: 'Average',\n min: 'Min',\n max: 'Max',\n distinctCount: 'Distinct Count',\n};\n\n/** Pivot field reference — column index within the source range. */\n/** Date grouping for a (date) row field — buckets records by the derived\n * period instead of the raw date. 'none' keys by the raw value. */\nexport type DateGrouping = 'none' | 'year' | 'quarter' | 'month';\n\nexport const PIVOT_DATE_GROUP_LABELS: Record<DateGrouping, string> = {\n none: 'No grouping',\n year: 'Years',\n quarter: 'Quarters',\n month: 'Months',\n};\n\n/** Pivot field reference — column index within the source range, plus an\n * optional date grouping applied when bucketing rows. */\nexport type PivotFieldRef = { column: number; grouping?: DateGrouping };\n\n/** Pivot value field — a column to aggregate + the aggregation. */\n/** How a value field is displayed (Excel's \"Show Values As\"). 'normal' = the\n * raw aggregate; 'pctOfGrandTotal' = each cell as a % of the field's overall\n * grand total; 'pctOfColumnTotal' = each cell as a % of its column's total\n * (in a cross-tab; identical to grand total in the row-only layout). */\nexport type PivotShowAs = 'normal' | 'pctOfGrandTotal' | 'pctOfColumnTotal' | 'pctOfRowTotal';\n\nexport const PIVOT_SHOW_AS_LABELS: Record<PivotShowAs, string> = {\n normal: 'Normal',\n pctOfGrandTotal: '% of Grand Total',\n pctOfColumnTotal: '% of Column Total',\n pctOfRowTotal: '% of Row Total',\n};\n\nexport type PivotValueField = {\n column: number;\n agg: PivotAggregation;\n /** Display transform; absent/`'normal'` shows the raw aggregate. */\n showAs?: PivotShowAs;\n};\n\n/** P1 — a filter field. Source records are kept only when the value\n * in `column` is one of `allowedValues` (compared as strings). An\n * empty `allowedValues` excludes everything; absent entry means no\n * restriction. */\nexport type PivotFilter = {\n column: number;\n allowedValues: string[];\n};\n\nexport type PivotModel = {\n id: string;\n /** Sheet the SOURCE data lives on. */\n sourceSheetId: string;\n /** Source data range — first row is headers, subsequent rows are\n * records. */\n source: { startRow: number; endRow: number; startColumn: number; endColumn: number };\n /** Sheet the pivot OUTPUT lives on. Often the same as source, but\n * Excel lets you target a different sheet. */\n targetSheetId: string;\n /** Top-left cell of the pivot output (0-indexed row + col). */\n target: { row: number; column: number };\n /** Row fields, applied left-to-right. P0 ships single-field; the\n * array shape makes multi-field a P1 follow-up without a schema\n * bump. */\n rows: PivotFieldRef[];\n /** Column fields. Empty in P0 — every value column collapses into\n * one column. */\n cols: PivotFieldRef[];\n /** Value fields. Each one produces its own column in the output. */\n values: PivotValueField[];\n /** P1 — filter fields. Optional for backwards-compat; an absent or\n * empty array means no filtering. */\n filters?: PivotFilter[];\n /** Last written output extent so `Refresh` can clear the previous\n * output rectangle before writing the new one. Absent on freshly-\n * loaded pivots from pre-P1 workbooks — refresh in that case just\n * overwrites the new extent and leaves any residual rows. */\n lastOutputExtent?: { rows: number; cols: number };\n /** Display name. Auto-generated \"PivotTable N\" on insert; renameable\n * via the Pivots panel. */\n title?: string;\n};\n\nexport function newPivotId(): string {\n return `pt-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n}\n\n/** Plugin-resource name we use when stashing pivot models in\n * `IWorkbookData.resources`. Mirrors `CHARTS_RESOURCE_NAME` — survives\n * xlsx via the hidden `__casual_sheets_resources__` sheet. */\nexport const PIVOTS_RESOURCE_NAME = '__casual_sheets_pivots__';\n\nexport type PivotsResourceV1 = {\n v: 1;\n pivots: PivotModel[];\n};\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n DateGrouping,\n PivotAggregation,\n PivotFieldRef,\n PivotModel,\n PivotValueField,\n} from './types';\nimport { PIVOT_AGG_LABELS } from './types';\n\n/**\n * Pure compute step — turn raw source records into the laid-out cell\n * grid that gets written into the workbook. No FUniver dependency\n * here so it's trivially testable and so the same routine can run\n * server-side later (e.g. for an \"export pivot to CSV\" path).\n *\n * Scope as of P2:\n * - 1..N row fields (multi-row uses Excel's compact layout — see\n * {@link computePivot} below).\n * - Optional single column field → cross-tab / matrix layout (see\n * {@link computeMatrix} below). When present, the value field(s)\n * fan out across one block of columns per distinct column-field\n * key, with a \"Grand Total\" block on the right and a Grand Total\n * row at the bottom.\n * - One or more value fields, each gets its own column (no column\n * field) or its own column *within each* column-key block (with a\n * column field).\n * - Filters applied before bucketing (P1).\n *\n * Matrix layout (rows = [Region], cols = [Quarter], values = [Sum Sales]):\n *\n * [ Region | Q1 | Q2 | Grand Total ]\n * [ North | 100 | 120 | 220 ]\n * [ South | 80 | 95 | 175 ]\n * [ Grand T. | 180 | 215 | 395 ]\n *\n * Single-row output (unchanged from P0):\n *\n * [ row-field | Sum of Sales | Avg of Sales ]\n * [ North | 220 | 110 ]\n * [ South | 175 | 87.5 ]\n * [ Grand T. | 395 | 98.7 ]\n *\n * Multi-row compact layout (rows = [Region, Product], values = [Sum]):\n *\n * [ Region | Sum of Sales ]\n * [ East | 300 ] ← outer subtotal on the label row\n * [ A | 100 ] ← inner leaf, indent depth 1\n * [ B | 200 ]\n * [ West | 150 ]\n * [ A | 150 ]\n * [ Grand T. | 450 ]\n *\n * Indentation uses leading spaces in the label string (`' '.repeat\n * (depth)`) — Univer's IStyleData has no first-class indent property,\n * and spaces round-trip losslessly through xlsx.\n */\nexport type PivotCell = string | number | null;\nexport type PivotGrid = PivotCell[][];\n\n/** Metadata for each row of the output grid — lets drill-down map a\n * clicked cell back to the composite key path that produced it\n * without re-running the bucketing walk. */\nexport type PivotRowMeta =\n | { kind: 'header' }\n | { kind: 'subtotal'; keyPath: string[]; depth: number }\n | { kind: 'leaf'; keyPath: string[]; depth: number }\n | { kind: 'grand-total' };\n\n/** Metadata for each COLUMN of a matrix (cross-tab) output grid — lets\n * drill-down map a clicked column back to its column-field key. Only\n * populated when the pivot has a column field; non-matrix pivots leave\n * `colMeta` undefined.\n *\n * - `label` → the leading label column (row-field names).\n * - `value` → a value cell scoped to a single column-field key.\n * - `grand-total` → a value cell aggregating across all column keys\n * (the right-hand \"Grand Total\" block).\n */\nexport type PivotColMeta =\n | { kind: 'label' }\n | { kind: 'value'; colKeys: string[]; valueIndex: number }\n | { kind: 'grand-total'; valueIndex: number };\n\nexport type PivotComputeResult = {\n grid: PivotGrid;\n rowMeta: PivotRowMeta[];\n /** Present only for matrix (column-field) pivots. Index-aligned with\n * the columns of every grid row. */\n colMeta?: PivotColMeta[];\n};\n\n/**\n * Raw records read from the workbook source range. Row 0 is the\n * header row, rows 1.. are data. Cell values come in pre-coerced\n * by the caller (`apply.ts` reads them via `getValue()` which already\n * returns the right primitive type).\n */\nexport type SourceMatrix = {\n headers: string[];\n records: PivotCell[][];\n};\n\nexport function computePivot(source: SourceMatrix, model: PivotModel): PivotComputeResult {\n if (model.values.length === 0) {\n return { grid: [], rowMeta: [] };\n }\n\n // P2 — a column field switches the layout to a cross-tab / matrix.\n // The value field(s) fan out horizontally across one block per\n // distinct column key. Single-row + multi-row both supported. We\n // only honour the first column field; nested column fields are a\n // future follow-up (the model array shape allows it without a bump).\n if ((model.cols?.length ?? 0) > 0) {\n return computeMatrix(source, model);\n }\n\n // P1 — apply filter fields BEFORE bucketing. Each filter restricts\n // records to those whose value in `column` is one of `allowedValues`\n // (string-compared). Empty allowedValues excludes everything; the\n // dialog UI never produces that shape (uses remove-filter), but\n // compute defends against it.\n const filters = model.filters ?? [];\n const passesFilters = (rec: PivotCell[]): boolean => {\n for (const f of filters) {\n const allowed = new Set(f.allowedValues);\n const v = rec[f.column];\n const key = v == null ? '' : String(v);\n if (!allowed.has(key)) return false;\n }\n return true;\n };\n const filteredRecords =\n filters.length > 0 ? source.records.filter(passesFilters) : source.records;\n\n // Header row — column 0 is the outermost row field name (compact\n // layout uses one label column shared across all row-field levels);\n // subsequent columns are the value-field headers in model order.\n const rowFieldCols = model.rows.map((r) => r.column);\n const hasRowField = rowFieldCols.length > 0;\n const header: PivotCell[] = [];\n if (hasRowField) {\n header.push(source.headers[rowFieldCols[0]] ?? '');\n }\n for (const v of model.values) {\n header.push(`${PIVOT_AGG_LABELS[v.agg]} of ${source.headers[v.column] ?? ''}`);\n }\n\n const grid: PivotGrid = [header];\n const rowMeta: PivotRowMeta[] = [{ kind: 'header' }];\n\n if (!hasRowField) {\n // No row field — Grand Total only.\n const total: PivotCell[] = [];\n for (const v of model.values) {\n total.push(\n aggregate(\n filteredRecords.map((r) => r[v.column]),\n v.agg,\n ),\n );\n }\n grid.push(total);\n rowMeta.push({ kind: 'grand-total' });\n return { grid, rowMeta };\n }\n\n // Build the nested bucket tree. Each level keys by the value of the\n // corresponding row field; leaves hold the contributing record list.\n const root = buildTree(filteredRecords, model.rows);\n\n // Walk the tree in compact-layout order. For each row-field level we\n // emit either a subtotal row (intermediate levels) or a leaf row\n // (innermost level), then recurse into children.\n const walk = (node: TreeNode, keyPath: string[], depth: number): void => {\n // Sort keys ascending — Excel default sort order.\n const keys = [...node.children.keys()].sort((a, b) =>\n a.localeCompare(b, undefined, { numeric: true }),\n );\n const isInnermost = depth === rowFieldCols.length - 1;\n for (const key of keys) {\n const child = node.children.get(key)!;\n const path = [...keyPath, key];\n const cells: PivotCell[] = [`${' '.repeat(depth)}${key}`];\n for (const v of model.values) {\n cells.push(\n aggregate(\n child.records.map((r) => r[v.column]),\n v.agg,\n ),\n );\n }\n grid.push(cells);\n rowMeta.push(\n isInnermost\n ? { kind: 'leaf', keyPath: path, depth }\n : { kind: 'subtotal', keyPath: path, depth },\n );\n if (!isInnermost) walk(child, path, depth + 1);\n }\n };\n walk(root, [], 0);\n\n // Grand Total — aggregates ALL filtered records (regardless of row\n // bucketing depth) so the total always matches the visible records.\n const total: PivotCell[] = ['Grand Total'];\n for (const v of model.values) {\n total.push(\n aggregate(\n filteredRecords.map((r) => r[v.column]),\n v.agg,\n ),\n );\n }\n grid.push(total);\n rowMeta.push({ kind: 'grand-total' });\n\n // \"Show Values As → % of Grand Total\" per value field. The grand-total row\n // (just pushed) holds each value column's denominator; value columns start\n // at index 1 (column 0 is the shared row-field label).\n applyShowAsPercent(grid, model.values, 1);\n\n return { grid, rowMeta };\n}\n\n/**\n * Rewrite each value column flagged `showAs: 'pctOfGrandTotal'` as a percentage\n * of that column's grand total (the last grid row). Mutates `grid` in place;\n * the header row is left untouched and the grand-total cell becomes 100.0%.\n */\nfunction applyShowAsPercent(\n grid: PivotGrid,\n values: PivotValueField[],\n valueColStart: number,\n): void {\n if (grid.length < 2) return;\n const lastRow = grid.length - 1;\n values.forEach((v, vi) => {\n // In the row-only layout a value column's \"column total\" is its grand\n // total, so both percentage modes share the same denominator.\n if (v.showAs !== 'pctOfGrandTotal' && v.showAs !== 'pctOfColumnTotal') return;\n const col = valueColStart + vi;\n const denom = Number(grid[lastRow][col]);\n for (let r = 1; r < grid.length; r++) {\n const raw = grid[r][col];\n const n = typeof raw === 'number' ? raw : Number(raw);\n grid[r][col] = denom && Number.isFinite(n) ? `${((n / denom) * 100).toFixed(1)}%` : '0.0%';\n }\n });\n}\n\n/**\n * Cross-tab / matrix layout. Active when `model.cols` is non-empty.\n *\n * Columns fan out by the distinct values of the (first) column field;\n * within each column-key block there is one column per value field\n * (one block === one column for the common single-value case). A\n * right-hand \"Grand Total\" block aggregates across all column keys,\n * and a bottom Grand Total row aggregates down each column.\n *\n * Rows reuse the same compact bucket walk as {@link computePivot} so\n * multi-row matrices indent inner keys exactly like the non-matrix\n * path. The difference is purely horizontal: each row's value cells\n * are sliced per column key instead of being a single total.\n */\nfunction computeMatrix(source: SourceMatrix, model: PivotModel): PivotComputeResult {\n const filters = model.filters ?? [];\n const passesFilters = (rec: PivotCell[]): boolean => {\n for (const f of filters) {\n const allowed = new Set(f.allowedValues);\n const v = rec[f.column];\n const key = v == null ? '' : String(v);\n if (!allowed.has(key)) return false;\n }\n return true;\n };\n const filteredRecords =\n filters.length > 0 ? source.records.filter(passesFilters) : source.records;\n\n const colFields = model.cols.map((c) => c.column);\n const rowFieldCols = model.rows.map((r) => r.column);\n const hasRowField = rowFieldCols.length > 0;\n const values = model.values;\n const multiValue = values.length > 1;\n\n const tupleOf = (rec: PivotCell[]): string[] => colFields.map((c) => keyOf(rec[c]));\n\n // Distinct column-key TUPLES present in the data (one entry per column field,\n // outer-first), sorted level-by-level (numeric-aware). A single column field\n // reduces to 1-element tuples → identical output to the pre-nesting path. A\n // filter that empties a tuple drops that column (Excel — no empty columns).\n const seenTuples = new Map<string, string[]>();\n for (const rec of filteredRecords) {\n const t = tupleOf(rec);\n seenTuples.set(t.join('\\u0000'), t);\n }\n let tuples = [...seenTuples.values()].sort((a, b) => {\n for (let i = 0; i < a.length; i += 1) {\n const c = a[i].localeCompare(b[i], undefined, { numeric: true });\n if (c !== 0) return c;\n }\n return 0;\n });\n // A high-cardinality nest can explode the column count (and the single\n // setValues write). Truncate + flag; the dialog also caps the depth.\n const TUPLE_CAP = 2048;\n const tuplesCapped = tuples.length > TUPLE_CAP;\n if (tuplesCapped) tuples = tuples.slice(0, TUPLE_CAP);\n\n const labelHeader = hasRowField ? (source.headers[rowFieldCols[0]] ?? '') : '';\n const valueLabel = (vi: number): string =>\n `${PIVOT_AGG_LABELS[values[vi].agg]} of ${source.headers[values[vi].column] ?? ''}`;\n\n // colMeta — label, then one entry per (tuple, value) value cell, then the\n // grand-total block (one per value field). Drill-down decodes `colKeys`.\n const colMeta: PivotColMeta[] = [{ kind: 'label' }];\n for (const t of tuples) {\n for (let vi = 0; vi < values.length; vi += 1) {\n colMeta.push({ kind: 'value', colKeys: t, valueIndex: vi });\n }\n }\n for (let vi = 0; vi < values.length; vi += 1) {\n colMeta.push({ kind: 'grand-total', valueIndex: vi });\n }\n\n const grid: PivotGrid = [];\n const rowMeta: PivotRowMeta[] = [];\n\n // ---- Header rows -------------------------------------------------\n // One spanning row per column-field level (outer first), then — when there\n // are multiple value fields — a value-field sub-header row. A key is shown at\n // the start of its span and blanked across the rest (Univer has no cell merge\n // in setValues; labels still read left-to-right and round-trip through xlsx).\n for (let level = 0; level < colFields.length; level += 1) {\n const row: PivotCell[] = [level === 0 ? labelHeader : ''];\n let prevPrefix: string | null = null;\n for (const t of tuples) {\n const prefix = t.slice(0, level + 1).join('\\u0000');\n const show = prefix !== prevPrefix;\n prevPrefix = prefix;\n const label = t[level] === '' ? '(blank)' : t[level];\n for (let vi = 0; vi < values.length; vi += 1) {\n row.push(show && vi === 0 ? label : '');\n }\n }\n // Grand-total block — \"Grand Total\" on the first level row, blank below.\n for (let vi = 0; vi < values.length; vi += 1) {\n row.push(level === 0 && vi === 0 ? 'Grand Total' : '');\n }\n grid.push(row);\n rowMeta.push({ kind: 'header' });\n }\n if (multiValue) {\n const sub: PivotCell[] = [''];\n for (let i = 0; i < tuples.length; i += 1) {\n for (let vi = 0; vi < values.length; vi += 1) sub.push(valueLabel(vi));\n }\n for (let vi = 0; vi < values.length; vi += 1) sub.push(valueLabel(vi));\n grid.push(sub);\n rowMeta.push({ kind: 'header' });\n }\n const headerRowCount = colFields.length + (multiValue ? 1 : 0);\n\n // ---- Value rows --------------------------------------------------\n // For each column tuple, slice the subset to records matching every column\n // field, aggregate each value; finish with the across-all grand-total block.\n const valueCellsFor = (records: PivotCell[][]): PivotCell[] => {\n const cells: PivotCell[] = [];\n for (const t of tuples) {\n const slice = records.filter((rec) => colFields.every((c, i) => keyOf(rec[c]) === t[i]));\n for (const v of values) {\n cells.push(\n aggregate(\n slice.map((r) => r[v.column]),\n v.agg,\n ),\n );\n }\n }\n for (const v of values) {\n cells.push(\n aggregate(\n records.map((r) => r[v.column]),\n v.agg,\n ),\n );\n }\n return cells;\n };\n\n if (!hasRowField) {\n // No row field — a single Grand Total row carrying the column split.\n grid.push(['Grand Total', ...valueCellsFor(filteredRecords)]);\n rowMeta.push({ kind: 'grand-total' });\n return { grid, rowMeta, colMeta };\n }\n\n const root = buildTree(filteredRecords, model.rows);\n const walk = (node: TreeNode, keyPath: string[], depth: number): void => {\n const keys = [...node.children.keys()].sort((a, b) =>\n a.localeCompare(b, undefined, { numeric: true }),\n );\n const isInnermost = depth === rowFieldCols.length - 1;\n for (const key of keys) {\n const child = node.children.get(key)!;\n const path = [...keyPath, key];\n grid.push([`${' '.repeat(depth)}${key}`, ...valueCellsFor(child.records)]);\n rowMeta.push(\n isInnermost\n ? { kind: 'leaf', keyPath: path, depth }\n : { kind: 'subtotal', keyPath: path, depth },\n );\n if (!isInnermost) walk(child, path, depth + 1);\n }\n };\n walk(root, [], 0);\n\n // Bottom Grand Total row — column totals + the overall total.\n grid.push(['Grand Total', ...valueCellsFor(filteredRecords)]);\n rowMeta.push({ kind: 'grand-total' });\n\n // \"Show Values As → % of Grand Total\" for the cross-tab layout: every value\n // cell of a flagged field becomes its share of that field's overall grand\n // total (the bottom-right cell — last row's grand-total column for the field).\n applyMatrixShowAsPercent(grid, colMeta, values, headerRowCount);\n\n return { grid, rowMeta, colMeta };\n}\n\n/** Cross-tab analogue of {@link applyShowAsPercent}: divide every value cell of\n * each `pctOfGrandTotal` field by that field's overall grand total (the bottom\n * row's grand-total column). Mutates `grid` in place; header rows are skipped. */\nfunction applyMatrixShowAsPercent(\n grid: PivotGrid,\n colMeta: PivotColMeta[],\n values: PivotValueField[],\n headerRows: number,\n): void {\n const lastRow = grid.length - 1;\n if (lastRow < headerRows) return;\n values.forEach((v, vi) => {\n const mode = v.showAs;\n if (mode !== 'pctOfGrandTotal' && mode !== 'pctOfColumnTotal' && mode !== 'pctOfRowTotal') {\n return;\n }\n const cols = colMeta\n .map((m, i) => (m.kind !== 'label' && m.valueIndex === vi ? i : -1))\n .filter((i) => i >= 0);\n // Denominator per mode:\n // Grand → the field's bottom-right total (one value).\n // Column → each column's bottom total (per c; bottom row is touched last).\n // Row → each row's grand-total cell (per r; read before mutating the row).\n const gtCol = colMeta.findIndex((m) => m.kind === 'grand-total' && m.valueIndex === vi);\n const grandDenom = gtCol >= 0 ? Number(grid[lastRow][gtCol]) : 0;\n for (let r = headerRows; r < grid.length; r++) {\n const rowDenom = mode === 'pctOfRowTotal' && gtCol >= 0 ? Number(grid[r][gtCol]) : 0;\n for (const c of cols) {\n const denom =\n mode === 'pctOfColumnTotal'\n ? Number(grid[lastRow][c])\n : mode === 'pctOfRowTotal'\n ? rowDenom\n : grandDenom;\n const n = Number(grid[r][c]);\n grid[r][c] = denom && Number.isFinite(n) ? `${((n / denom) * 100).toFixed(1)}%` : '0.0%';\n }\n }\n });\n}\n\n/** Coerce a cell value to its string bucket key (null/empty → ''). */\nfunction keyOf(v: PivotCell): string {\n return v == null ? '' : String(v);\n}\n\n/** Excel serial number → {year, month(0-11)} (UTC), inverting the 1900\n * leap-bug offset our importer applies (parse-impl `excelSerialFromDate`). */\nfunction partsFromSerial(serial: number): { y: number; m: number } {\n const base = Date.UTC(1900, 0, 1);\n let days = Math.floor(serial) - 1;\n if (serial >= 60) days -= 1; // undo Excel's fictitious 1900-02-29\n const d = new Date(base + days * 86_400_000);\n return { y: d.getUTCFullYear(), m: d.getUTCMonth() };\n}\n\n/** Resolve a cell value to {year, month(0-11)}, handling both shapes dates take\n * in this app: an Excel serial number (imported xlsx) and a date string like\n * \"2025/01/10\" or \"2025-01-10\" (a DATE() formula / typed date). Returns null\n * when the value isn't a recognisable date. */\nfunction dateParts(value: PivotCell): { y: number; m: number } | null {\n if (typeof value === 'number' && Number.isFinite(value)) return partsFromSerial(value);\n const s = typeof value === 'string' ? value.trim() : '';\n if (s === '') return null;\n if (/^\\d+(\\.\\d+)?$/.test(s)) return partsFromSerial(Number(s)); // numeric string → serial\n const ymd = /^(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})/.exec(s);\n if (ymd) return { y: Number(ymd[1]), m: Number(ymd[2]) - 1 };\n const t = Date.parse(s);\n if (!Number.isNaN(t)) {\n const d = new Date(t);\n return { y: d.getUTCFullYear(), m: d.getUTCMonth() };\n }\n return null;\n}\n\n/** Bucket a row-field value for date grouping. 'none' (or a value that isn't a\n * recognisable date) returns the raw key; year/quarter/month derive a period\n * key. Keys sort lexicographically into chronological order (e.g. \"2025-01\" <\n * \"2025-02\", \"2025-Q1\" < \"2025-Q2\"). */\nexport function dateGroupKey(value: PivotCell, grouping: DateGrouping): string {\n if (grouping === 'none') return keyOf(value);\n const parts = dateParts(value);\n if (!parts) return keyOf(value);\n const { y, m } = parts;\n if (grouping === 'year') return String(y);\n if (grouping === 'quarter') return `${y}-Q${Math.floor(m / 3) + 1}`;\n return `${y}-${String(m + 1).padStart(2, '0')}`; // month\n}\n\ntype TreeNode = {\n records: PivotCell[][];\n children: Map<string, TreeNode>;\n};\n\nfunction buildTree(records: PivotCell[][], rowFields: PivotFieldRef[]): TreeNode {\n const root: TreeNode = { records: [], children: new Map() };\n for (const rec of records) {\n let node = root;\n node.records.push(rec);\n for (const field of rowFields) {\n const key = dateGroupKey(rec[field.column], field.grouping ?? 'none');\n let child = node.children.get(key);\n if (!child) {\n child = { records: [], children: new Map() };\n node.children.set(key, child);\n }\n child.records.push(rec);\n node = child;\n }\n }\n return root;\n}\n\nfunction aggregate(values: PivotCell[], agg: PivotAggregation): PivotCell {\n const nums: number[] = [];\n let nonNull = 0;\n for (const v of values) {\n if (v == null || v === '') continue;\n nonNull++;\n const n = typeof v === 'number' ? v : Number(v);\n if (Number.isFinite(n)) nums.push(n);\n }\n switch (agg) {\n case 'count':\n return nonNull;\n case 'sum':\n return nums.length === 0 ? 0 : nums.reduce((a, b) => a + b, 0);\n case 'average':\n return nums.length === 0 ? null : nums.reduce((a, b) => a + b, 0) / nums.length;\n case 'min':\n return nums.length === 0 ? null : Math.min(...nums);\n case 'max':\n return nums.length === 0 ? null : Math.max(...nums);\n case 'distinctCount': {\n // Count distinct non-empty values (compared as strings, like Excel's\n // \"Distinct Count\"). Empty/blank cells are ignored.\n const seen = new Set<string>();\n for (const v of values) {\n if (v == null || v === '') continue;\n seen.add(String(v));\n }\n return seen.size;\n }\n }\n}\n\n/** Used by the panel to render a friendly auto-name like\n * \"Sum of Sales by Region\" so a freshly inserted pivot has a label\n * that explains itself. */\nexport function defaultPivotTitle(source: SourceMatrix, model: PivotModel): string {\n const value = model.values[0];\n if (!value) return 'PivotTable';\n const valuePart = `${PIVOT_AGG_LABELS[value.agg]} of ${source.headers[value.column] ?? 'value'}`;\n const rowFields = model.rows.map((r) => source.headers[r.column] ?? 'group');\n const colFields = (model.cols ?? []).map((c) => source.headers[c.column] ?? 'group');\n const byPart = rowFields.length === 0 ? '' : ` by ${rowFields.join(' / ')}`;\n const acrossPart = colFields.length === 0 ? '' : ` across ${colFields.join(' / ')}`;\n if (!byPart && !acrossPart) return valuePart;\n return `${valuePart}${byPart}${acrossPart}`;\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FUniver } from '@univerjs/core/facade';\nimport { computePivot, type PivotGrid, type SourceMatrix } from './compute';\nimport type { PivotModel } from './types';\n\n/**\n * Read the source range, compute the pivot, then write the resulting\n * cell grid into the target sheet starting at `model.target`. The\n * write is one `setRangeValues` call so it lands as a single Univer\n * mutation — collab and undo both treat it atomically.\n *\n * If `prevExtent` is supplied (refresh path), the previous output\n * rectangle is cleared first so a shrunk pivot doesn't leave residual\n * rows from the prior write. Insert paths pass null.\n */\nexport function applyPivot(\n api: FUniver,\n model: PivotModel,\n prevExtent?: { rows: number; cols: number } | null,\n): { rows: number; cols: number } | null {\n const wb = api.getActiveWorkbook();\n if (!wb) return null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sheets = wb.getSheets() as any[];\n const sourceWs = sheets.find((s) => s.getSheetId?.() === model.sourceSheetId);\n const targetWs = sheets.find((s) => s.getSheetId?.() === model.targetSheetId);\n if (!sourceWs || !targetWs) return null;\n\n const matrix = readSourceMatrix(sourceWs, model.source);\n if (matrix.records.length === 0) return null;\n\n const { grid } = computePivot(matrix, model);\n if (grid.length === 0) return null;\n\n // Clear the previous extent first if we have one — keeps stale rows\n // from leaking through when the new grid is smaller (e.g. a filter\n // narrowed the row keys, or the source range shrank).\n if (prevExtent && (prevExtent.rows > grid.length || prevExtent.cols > (grid[0]?.length ?? 0))) {\n clearGridArea(targetWs, model.target, prevExtent);\n }\n\n writeGridToSheet(targetWs, model.target, grid);\n return { rows: grid.length, cols: grid[0]?.length ?? 0 };\n}\n\n/**\n * P1 — re-read source data and re-apply the pivot. Refreshing is what\n * makes pivots track upstream edits; without it the output frozen at\n * insert time goes stale. Returns the new extent (or null on failure).\n */\nexport function refreshPivot(\n api: FUniver,\n model: PivotModel,\n): { rows: number; cols: number } | null {\n return applyPivot(api, model, model.lastOutputExtent ?? null);\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction readSourceMatrix(ws: any, src: PivotModel['source']): SourceMatrix {\n const headers: string[] = [];\n for (let c = src.startColumn; c <= src.endColumn; c++) {\n const v = ws.getRange(src.startRow, c).getValue();\n headers.push(v == null ? '' : String(v));\n }\n const records: Array<Array<string | number | null>> = [];\n for (let r = src.startRow + 1; r <= src.endRow; r++) {\n const row: Array<string | number | null> = [];\n let anyValue = false;\n for (let c = src.startColumn; c <= src.endColumn; c++) {\n const v = ws.getRange(r, c).getValue();\n if (v == null || v === '') {\n row.push(null);\n } else if (typeof v === 'number' || typeof v === 'string') {\n row.push(v);\n anyValue = true;\n } else if (typeof v === 'boolean') {\n row.push(v ? 1 : 0);\n anyValue = true;\n } else {\n row.push(String(v));\n anyValue = true;\n }\n }\n // Skip blank rows — Excel treats them as terminators, but a\n // misclick that includes an extra blank row in the selection\n // shouldn't introduce a phantom \"(blank)\" key. Drop them.\n if (anyValue) records.push(row);\n }\n return { headers, records };\n}\n\n/** Blank an arbitrary rectangle on the sheet — used by refresh to\n * reset the previous output before writing the new grid. */\nfunction clearGridArea(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ws: any,\n target: { row: number; column: number },\n extent: { rows: number; cols: number },\n): void {\n const blank: Array<Array<{ v: null }>> = [];\n for (let r = 0; r < extent.rows; r += 1) {\n const row: Array<{ v: null }> = [];\n for (let c = 0; c < extent.cols; c += 1) {\n row.push({ v: null });\n }\n blank.push(row);\n }\n const range = ws.getRange(target.row, target.column, extent.rows, extent.cols);\n range.setValues(blank);\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction writeGridToSheet(ws: any, target: { row: number; column: number }, grid: PivotGrid): void {\n const rows = grid.length;\n const cols = grid[0]?.length ?? 0;\n if (rows === 0 || cols === 0) return;\n // Build the IRange-shaped object setRangeValues expects: a 2D\n // array of `{ v }` cell objects keyed by `[r-offset][c-offset]`.\n const cellMatrix: Array<Array<{ v: string | number | null }>> = grid.map((rowVals) =>\n rowVals.map((v) => ({ v })),\n );\n const range = ws.getRange(target.row, target.column, rows, cols);\n range.setValues(cellMatrix);\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Comments side panel: lists the thread comments on the active sheet (active +\n * resolved), navigates to a comment's cell on click, and resolves / reopens a\n * thread inline. \"Add comment\" opens Univer's comment-on-cell modal (the same\n * one as Review → New comment); the in-cell popup owns full reply threading.\n *\n * Ported from the standalone app's `shell/CommentsPanel`. The app-only collab\n * stores it depended on — `collab/comment-authors` (avatar authorship),\n * `collab/presence` (display name / initials) and `collab/comment-mentions`\n * (@-mention \"mentions you\" badge) — DO NOT exist in the SDK and are dropped:\n * the byline degrades to the in-band `personId` string carried on the comment\n * model (no avatar, no color), and the mentions-me highlight is omitted. The\n * `useUniverAPI()` / `useUI()` couplings are replaced by the `api` / `onClose`\n * panel-host props, and the Univer facade is reached through `api.univer`.\n */\nimport { useEffect, useMemo, useState, type CSSProperties } from 'react';\nimport { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';\n\nimport { ensurePluginByName } from '../univer';\nimport type { PanelComponentProps } from './extensions';\nimport { Icon } from './Icon';\nimport { PanelHeader, IconButton } from './panel-shell';\n\ninterface CommentRow {\n id: string;\n text: string;\n ref: string;\n author: string;\n replies: number;\n}\n\nfunction cleanText(stream: string | undefined): string {\n return (stream ?? '').replace(/[\\r\\n\\t]+/g, ' ').trim() || '(empty comment)';\n}\n\n/**\n * Active comments come straight off the facade (`getComments()` returns the\n * cell-location index; resolved threads leave it, so they're read separately).\n * Only root comments are listed — replies render under their root in the\n * in-cell popup.\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction readActive(univer: any): CommentRow[] {\n const ws = univer?.getActiveWorkbook?.()?.getActiveSheet?.();\n const all: any[] = ws?.getComments?.() ?? [];\n const rows: CommentRow[] = [];\n for (const c of all) {\n try {\n if (c.getIsRoot && !c.getIsRoot()) continue;\n const data = c.getCommentData?.() ?? {};\n let ref = '';\n try {\n ref = c.getRange?.()?.getA1Notation?.() ?? '';\n } catch {\n /* range no longer resolvable */\n }\n rows.push({\n id: c.id ?? data.id ?? ref,\n text: cleanText(data.text?.dataStream),\n ref,\n author: data.personId ?? '',\n replies: c.getReplies?.()?.length ?? 0,\n });\n } catch {\n /* skip malformed thread */\n }\n }\n return rows;\n}\n\n/**\n * Resolved comments have left the cell-location index, so `getComments()` no\n * longer returns them. Read them straight from the model — the only path to a\n * \"resolved\" view + reopen.\n */\nfunction readResolved(univer: any): CommentRow[] {\n try {\n const injector = (univer as { _injector?: { get(t: unknown): unknown } })?._injector;\n const model = injector?.get?.(SheetsThreadCommentModel) as any;\n const wb = univer?.getActiveWorkbook?.();\n const ws = wb?.getActiveSheet?.();\n if (!model?.getSubUnitAll || !wb || !ws) return [];\n const unitId = wb.getId();\n const subUnitId = ws.getSheetId?.() ?? ws.getId?.();\n const all: any[] = model.getSubUnitAll(unitId, subUnitId) ?? [];\n const rows: CommentRow[] = [];\n for (const c of all) {\n if (!c?.resolved) continue;\n rows.push({\n id: c.id,\n text: cleanText(c.text?.dataStream),\n ref: c.ref ?? '',\n author: c.personId ?? '',\n replies: (c.children ?? []).length,\n });\n }\n return rows;\n } catch {\n return [];\n }\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nconst header: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 12px',\n borderBottom: '1px solid var(--cs-chrome-border, #edeff3)',\n};\n\nconst rowCard: CSSProperties = {\n border: '1px solid var(--cs-chrome-border, #edeff3)',\n borderRadius: 8,\n padding: 10,\n display: 'flex',\n alignItems: 'flex-start',\n gap: 6,\n};\n\nconst iconBtn: CSSProperties = {\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n padding: 0,\n display: 'inline-flex',\n alignItems: 'center',\n};\n\nfunction CommentCard({\n row,\n resolved,\n onOpen,\n onToggle,\n}: {\n row: CommentRow;\n resolved: boolean;\n onOpen: (r: CommentRow) => void;\n onToggle: (id: string, value: boolean) => void;\n}) {\n return (\n <li\n data-testid={`cs-comments-panel-${resolved ? 'resolved-row' : 'row'}-${row.id}`}\n style={{ ...rowCard, opacity: resolved ? 0.72 : 1 }}\n >\n <button\n type=\"button\"\n onClick={() => onOpen(row)}\n title={`Go to ${row.ref || 'comment'}`}\n style={{\n flex: 1,\n minWidth: 0,\n textAlign: 'left',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n }}\n >\n <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span style={{ fontWeight: 600 }}>{row.ref || 'Comment'}</span>\n {row.author && <span style={{ opacity: 0.6, fontSize: 12 }}>{row.author}</span>}\n {row.replies > 0 && (\n <span\n title={`${row.replies} replies`}\n style={{\n opacity: 0.6,\n fontSize: 12,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 2,\n }}\n >\n <Icon name=\"reply\" size={13} />\n {row.replies}\n </span>\n )}\n </span>\n <span\n style={{\n fontSize: 13,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n }}\n >\n {row.text}\n </span>\n </button>\n <button\n type=\"button\"\n data-testid={`cs-comments-panel-${resolved ? 'reopen' : 'resolve'}-${row.id}`}\n aria-label={resolved ? 'Reopen comment' : 'Resolve comment'}\n title={resolved ? 'Reopen comment' : 'Resolve comment'}\n onClick={() => onToggle(row.id, !resolved)}\n style={iconBtn}\n >\n <Icon name={resolved ? 'undo' : 'check_circle'} size={16} />\n </button>\n </li>\n );\n}\n\nconst REFRESH_CMDS = (id: string) =>\n id.includes('comment') ||\n id === 'sheet.operation.set-worksheet-activate' ||\n id === 'doc.command-replace-snapshot';\n\nexport function CommentsPanel({ api, onClose }: PanelComponentProps) {\n const univer = (api as { univer?: any }).univer; // eslint-disable-line @typescript-eslint/no-explicit-any\n const [rows, setRows] = useState<CommentRow[]>([]);\n const [resolved, setResolved] = useState<CommentRow[]>([]);\n const [showResolved, setShowResolved] = useState(false);\n\n useEffect(() => {\n if (!univer) return;\n let cancelled = false;\n let disp: { dispose?: () => void } | undefined;\n const read = () => {\n if (cancelled) return;\n setRows(readActive(univer));\n setResolved(readResolved(univer));\n };\n // The thread-comment plugin is lazy — `getComments()` and\n // SheetsThreadCommentModel only resolve once its group is registered.\n void ensurePluginByName('threadComment').then(() => {\n if (cancelled) return;\n read();\n disp = univer.addEvent(univer.Event.CommandExecuted, (e: { id?: string }) => {\n if (e.id && REFRESH_CMDS(e.id)) read();\n });\n });\n return () => {\n cancelled = true;\n disp?.dispose?.();\n };\n }, [univer]);\n\n const empty = rows.length === 0 && resolved.length === 0;\n\n const openThread = (r: CommentRow) => {\n if (!univer || !r.ref) return;\n try {\n univer.getActiveWorkbook?.()?.getActiveSheet?.()?.getRange?.(r.ref)?.activate?.();\n } catch {\n /* range gone */\n }\n };\n\n const setResolvedState = async (commentId: string, value: boolean) => {\n if (!univer) return;\n try {\n const wb = univer.getActiveWorkbook?.();\n const ws = wb?.getActiveSheet?.();\n if (!wb || !ws) return;\n const subUnitId = ws.getSheetId?.() ?? ws.getId?.();\n await ensurePluginByName('threadComment');\n univer.executeCommand('thread-comment.command.resolve-comment', {\n unitId: wb.getId(),\n subUnitId,\n commentId,\n resolved: value,\n });\n } catch {\n /* command unavailable — plugin not loaded */\n }\n };\n\n const addComment = async () => {\n if (!univer) return;\n await ensurePluginByName('threadComment');\n univer.executeCommand('sheet.operation.show-comment-modal');\n };\n\n const handlers = useMemo(\n () => ({ open: openThread, toggle: setResolvedState }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [univer],\n );\n\n return (\n <div\n data-testid=\"cs-comments-panel\"\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\n >\n <PanelHeader\n icon=\"forum\"\n title=\"Comments\"\n count={rows.length}\n onClose={onClose}\n actions={<IconButton name=\"add_comment\" label=\"Add comment\" onClick={addComment} />}\n />\n\n <div style={{ flex: 1, overflow: 'auto', padding: 12 }}>\n {empty ? (\n <div\n data-testid=\"cs-comments-panel-empty\"\n style={{ textAlign: 'center', opacity: 0.75, padding: '24px 8px' }}\n >\n <Icon name=\"forum\" size={40} style={{ opacity: 0.4 }} />\n <div style={{ fontWeight: 600, marginTop: 8 }}>No comments yet</div>\n <div style={{ fontSize: 13, marginTop: 4 }}>\n Select a cell and add a comment to start a discussion — or use{' '}\n <strong>Review → New comment</strong>.\n </div>\n <button\n type=\"button\"\n data-testid=\"cs-comments-panel-empty-cta\"\n disabled={!univer}\n onClick={addComment}\n style={{\n marginTop: 12,\n padding: '6px 14px',\n borderRadius: 6,\n border: 'none',\n cursor: univer ? 'pointer' : 'default',\n background: 'var(--cs-chrome-active-fg, #0e7490)',\n color: '#fff',\n font: 'inherit',\n fontWeight: 600,\n }}\n >\n Add comment\n </button>\n </div>\n ) : (\n <>\n {rows.length > 0 && (\n <ul\n style={{\n listStyle: 'none',\n margin: 0,\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n }}\n >\n {rows.map((r) => (\n <CommentCard\n key={r.id}\n row={r}\n resolved={false}\n onOpen={handlers.open}\n onToggle={handlers.toggle}\n />\n ))}\n </ul>\n )}\n\n {resolved.length > 0 && (\n <div style={{ marginTop: rows.length > 0 ? 12 : 0 }}>\n <button\n type=\"button\"\n data-testid=\"cs-comments-panel-resolved-toggle\"\n aria-expanded={showResolved}\n onClick={() => setShowResolved((v) => !v)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n width: '100%',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'inherit',\n font: 'inherit',\n fontWeight: 600,\n padding: '4px 0',\n }}\n >\n <Icon name={showResolved ? 'expand_more' : 'chevron_right'} size={16} />\n Resolved\n <span style={{ opacity: 0.6, fontSize: 12 }}>{resolved.length}</span>\n </button>\n {showResolved && (\n <ul\n style={{\n listStyle: 'none',\n margin: '8px 0 0',\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n }}\n >\n {resolved.map((r) => (\n <CommentCard\n key={r.id}\n row={r}\n resolved\n onOpen={handlers.open}\n onToggle={handlers.toggle}\n />\n ))}\n </ul>\n )}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * History / Activity side panel — a self-contained, in-memory activity feed\n * of user-facing edits in the current session.\n *\n * Ported from the standalone app's HistoryPanel, but DECOUPLED from every\n * app-only coupling: the app version drove off two host-owned sources (a\n * shared Yjs op-log and IndexedDB-backed snapshot version history via\n * `useCollab`/`usePresence`/`local-history`). None of that exists in the SDK,\n * and persistent version history stays HOST-OWNED. So instead this panel\n * subscribes to the live `ICommandService.onCommandExecuted` stream, keeps a\n * bounded in-memory ring (last 100) of user-facing command executions, maps\n * each command id to a friendly label, and renders them newest-first.\n *\n * Ordering is derived from a monotonically incrementing sequence counter\n * (NOT wall-clock time) so nothing calls `Date.now()`/`new Date()` at module\n * load; a per-entry relative-age string is computed lazily at render time from\n * a capture timestamp taken inside the (post-mount) event handler.\n *\n * The app-only `useUI().toggleHistoryPanel` is replaced by the panel host's\n * `onClose`; the Univer facade + services are reached through the `api` prop's\n * `_injector`, matching StatusBar / FormulaBar precedent.\n */\nimport { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\nimport { CommandType, ICommandService, type ICommandInfo } from '@univerjs/core';\n\nimport type { PanelComponentProps } from './extensions';\nimport { Icon } from './Icon';\nimport { PanelHeader } from './panel-shell';\n\nconst RING_CAP = 100;\n\ninterface ActivityEntry {\n /** Monotonic sequence — sole source of ordering (no wall-clock at module load). */\n seq: number;\n /** Command id that fired (e.g. `sheet.command.set-range-values`). */\n id: string;\n /** Friendly one-line label. */\n label: string;\n /** Icon glyph for the row. */\n icon: string;\n /** Capture time (ms). Taken inside the handler, post-mount — safe. */\n t: number;\n}\n\n/**\n * Map a user-facing COMMAND id to a friendly label + icon. Commands (not\n * mutations) are the user-intent layer, so one command == one activity row —\n * no de-duping a single paste into a dozen mutation rows. Anything not mapped\n * still records with a de-namespaced fallback label so the feed stays honest.\n */\nconst COMMAND_LABELS: Record<string, { label: string; icon: string }> = {\n 'sheet.command.set-range-values': { label: 'Edited cells', icon: 'edit' },\n 'sheet.command.set-range-bold': { label: 'Toggled bold', icon: 'format_bold' },\n 'sheet.command.set-range-italic': { label: 'Toggled italic', icon: 'format_italic' },\n 'sheet.command.set-range-underline': { label: 'Toggled underline', icon: 'format_underlined' },\n 'sheet.command.set-range-stroke-through': {\n label: 'Toggled strikethrough',\n icon: 'strikethrough_s',\n },\n 'sheet.command.set-range-font-family': { label: 'Changed font', icon: 'font_download' },\n 'sheet.command.set-range-font-size': { label: 'Changed font size', icon: 'format_size' },\n 'sheet.command.set-range-text-color': { label: 'Changed text color', icon: 'format_color_text' },\n 'sheet.command.set-background-color': { label: 'Changed fill color', icon: 'format_color_fill' },\n 'sheet.command.set-range-text-align': { label: 'Changed alignment', icon: 'format_align_left' },\n 'sheet.command.set-range-vertical-align': {\n label: 'Changed alignment',\n icon: 'vertical_align_center',\n },\n 'sheet.command.set-border-command': { label: 'Changed borders', icon: 'border_all' },\n 'sheet.command.clear-selection-content': { label: 'Cleared cell contents', icon: 'backspace' },\n 'sheet.command.clear-selection-format': { label: 'Cleared formatting', icon: 'format_clear' },\n 'sheet.command.clear-selection-all': { label: 'Cleared cells', icon: 'clear_all' },\n 'sheet.command.insert-row': { label: 'Inserted row(s)', icon: 'add_row_above' },\n 'sheet.command.insert-row-before': { label: 'Inserted row above', icon: 'add_row_above' },\n 'sheet.command.insert-row-after': { label: 'Inserted row below', icon: 'add_row_below' },\n 'sheet.command.insert-col': { label: 'Inserted column(s)', icon: 'add_column_left' },\n 'sheet.command.insert-col-before': { label: 'Inserted column left', icon: 'add_column_left' },\n 'sheet.command.insert-col-after': { label: 'Inserted column right', icon: 'add_column_right' },\n 'sheet.command.remove-row': { label: 'Deleted row(s)', icon: 'delete' },\n 'sheet.command.remove-col': { label: 'Deleted column(s)', icon: 'delete' },\n 'sheet.command.delete-range-move-up': { label: 'Deleted cells', icon: 'delete' },\n 'sheet.command.delete-range-move-left': { label: 'Deleted cells', icon: 'delete' },\n 'sheet.command.insert-range-move-down': { label: 'Inserted cells', icon: 'add' },\n 'sheet.command.insert-range-move-right': { label: 'Inserted cells', icon: 'add' },\n 'sheet.command.move-range': { label: 'Moved cells', icon: 'open_with' },\n 'sheet.command.move-rows': { label: 'Moved row(s)', icon: 'swap_vert' },\n 'sheet.command.move-cols': { label: 'Moved column(s)', icon: 'swap_horiz' },\n 'sheet.command.add-worksheet-merge-all': { label: 'Merged cells', icon: 'cell_merge' },\n 'sheet.command.remove-worksheet-merge': { label: 'Unmerged cells', icon: 'grid_on' },\n 'sheet.command.set-worksheet-row-height': { label: 'Resized row(s)', icon: 'height' },\n 'sheet.command.set-worksheet-col-width': { label: 'Resized column(s)', icon: 'width_normal' },\n 'sheet.command.set-row-hidden': { label: 'Hid row(s)', icon: 'visibility_off' },\n 'sheet.command.set-specific-rows-visible': { label: 'Showed row(s)', icon: 'visibility' },\n 'sheet.command.set-col-hidden': { label: 'Hid column(s)', icon: 'visibility_off' },\n 'sheet.command.set-specific-cols-visible': { label: 'Showed column(s)', icon: 'visibility' },\n 'sheet.command.set-frozen': { label: 'Changed freeze panes', icon: 'ac_unit' },\n 'sheet.command.insert-sheet': { label: 'Added a sheet', icon: 'add_box' },\n 'sheet.command.remove-sheet': { label: 'Removed a sheet', icon: 'delete' },\n 'sheet.command.set-worksheet-name': {\n label: 'Renamed a sheet',\n icon: 'drive_file_rename_outline',\n },\n 'sheet.command.set-worksheet-order': { label: 'Reordered sheets', icon: 'reorder' },\n 'sheet.command.set-tab-color': { label: 'Changed tab color', icon: 'palette' },\n 'sheet.command.paste': { label: 'Pasted', icon: 'content_paste' },\n 'sheet.command.copy': { label: 'Copied', icon: 'content_copy' },\n 'sheet.command.cut': { label: 'Cut', icon: 'content_cut' },\n 'sheet.command.add-table': { label: 'Inserted a table', icon: 'table' },\n 'sheet.command.delete-table': { label: 'Deleted a table', icon: 'delete' },\n 'sheet.command.numfmt.set.numfmt': { label: 'Changed number format', icon: 'tag' },\n 'univer.command.undo': { label: 'Undo', icon: 'undo' },\n 'univer.command.redo': { label: 'Redo', icon: 'redo' },\n};\n\n/**\n * Which command ids count as \"user-facing activity\". We only record\n * `CommandType.COMMAND` (intent) executions, and we skip pure selection /\n * navigation / scroll operations even though some of those are dispatched as\n * COMMANDs — they're noise, not edits. The allow-list above IS the primary\n * signal; unmapped COMMANDs still record with a fallback label unless they\n * match an obvious noise prefix.\n */\nconst NOISE_PREFIXES = [\n 'sheet.operation.',\n 'sheet.command.set-selection',\n 'sheet.command.scroll',\n 'sheet.command.set-zoom',\n 'sheet.command.set-activate-cell-edit',\n 'sheet.command.set-cell-edit-visible',\n 'sheet.command.set-editor',\n 'formula.',\n 'univer.command.set-current-locale',\n];\n\nfunction isNoise(id: string): boolean {\n return NOISE_PREFIXES.some((p) => id.startsWith(p));\n}\n\nfunction labelFor(id: string): { label: string; icon: string } {\n const known = COMMAND_LABELS[id];\n if (known) return known;\n // De-namespace the id into something human-ish.\n const tail = id\n .replace(/^sheet\\.command\\./, '')\n .replace(/^univer\\.command\\./, '')\n .replace(/[.-]/g, ' ')\n .trim();\n return { label: tail ? tail.charAt(0).toUpperCase() + tail.slice(1) : 'Change', icon: 'bolt' };\n}\n\nfunction relativeTime(t: number, now: number): string {\n const delta = now - t;\n if (delta < 5_000) return 'just now';\n if (delta < 60_000) return `${Math.floor(delta / 1000)}s ago`;\n if (delta < 3_600_000) return `${Math.floor(delta / 60_000)}m ago`;\n return `${Math.floor(delta / 3_600_000)}h ago`;\n}\n\nconst headerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '10px 12px',\n borderBottom: '1px solid var(--cs-chrome-border, #edeff3)',\n};\n\nexport function HistoryPanel({ api, onClose }: PanelComponentProps) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const univer = (api as any).univer;\n const [entries, setEntries] = useState<ActivityEntry[]>([]);\n // Ordering counter — monotonic, initialised at 0 (no wall-clock at load).\n const seqRef = useRef(0);\n // Re-render tick so relative times refresh even without new activity.\n const [nowTick, setNowTick] = useState(0);\n\n useEffect(() => {\n if (!univer) return;\n const injector = (univer as { _injector?: { get(t: unknown): unknown } })._injector;\n const cmd = injector?.get(ICommandService) as\n | {\n onCommandExecuted: (cb: (info: ICommandInfo, options?: unknown) => void) => {\n dispose: () => void;\n };\n }\n | undefined;\n if (!cmd) return;\n\n const sub = cmd.onCommandExecuted((info) => {\n // Only intent-level COMMANDs; mutations/operations would spam the feed.\n // `type` is optional on ICommandInfo but the dispatcher populates it —\n // treat an explicit non-COMMAND type as a reject, and let undefined\n // fall through to the id-based allow-list below.\n if (info.type !== undefined && info.type !== CommandType.COMMAND) return;\n if (isNoise(info.id)) return;\n // Ignore anything not on the allow-list unless it looks like a real\n // sheet command (keeps the feed to genuine edits, not internal churn).\n if (!COMMAND_LABELS[info.id] && !info.id.startsWith('sheet.command.')) return;\n\n const { label, icon } = labelFor(info.id);\n const seq = ++seqRef.current;\n const entry: ActivityEntry = { seq, id: info.id, label, icon, t: Date.now() };\n setEntries((prev) => {\n const next = prev.length >= RING_CAP ? prev.slice(prev.length - RING_CAP + 1) : prev;\n return [...next, entry];\n });\n });\n return () => sub.dispose();\n }, [univer]);\n\n // Refresh relative timestamps once a minute while the panel is open.\n useEffect(() => {\n const h = setInterval(() => setNowTick((n) => n + 1), 60_000);\n return () => clearInterval(h);\n }, []);\n\n // Newest-first. Ordering is purely by seq — the render-time `now` only\n // affects the human-readable age string, never the order.\n const sorted = useMemo(() => [...entries].sort((a, b) => b.seq - a.seq), [entries]);\n const now = useMemo(() => Date.now(), [nowTick, entries.length]);\n\n const empty = sorted.length === 0;\n\n return (\n <div\n data-testid=\"cs-history-panel\"\n style={{ height: '100%', display: 'flex', flexDirection: 'column' }}\n >\n <PanelHeader icon=\"history\" title=\"Activity\" count={sorted.length} onClose={onClose} />\n\n <div style={{ flex: 1, overflow: 'auto', padding: 12 }}>\n {empty ? (\n <div\n data-testid=\"cs-history-panel-empty\"\n style={{ textAlign: 'center', opacity: 0.75, padding: '24px 8px' }}\n >\n <Icon name=\"history\" size={40} style={{ opacity: 0.4 }} />\n <div style={{ fontWeight: 600, marginTop: 8 }}>No activity yet</div>\n <div style={{ fontSize: 13, marginTop: 4 }}>\n Edits you make this session show up here.\n </div>\n </div>\n ) : (\n <ol\n role=\"list\"\n style={{\n listStyle: 'none',\n margin: 0,\n padding: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n }}\n >\n {sorted.map((e) => (\n <li\n key={e.seq}\n data-testid=\"cs-history-row\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '8px 8px',\n borderRadius: 8,\n }}\n >\n <span\n aria-hidden\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 28,\n height: 28,\n flex: '0 0 auto',\n borderRadius: 6,\n background: 'var(--cs-chrome-subtle-bg, #f4f5f8)',\n opacity: 0.9,\n }}\n >\n <Icon name={e.icon} size={16} />\n </span>\n <span style={{ flex: 1, minWidth: 0, fontSize: 13, fontWeight: 500 }}>\n {e.label}\n </span>\n <time\n dateTime={new Date(e.t).toISOString()}\n style={{ opacity: 0.6, fontSize: 12, whiteSpace: 'nowrap' }}\n >\n {relativeTime(e.t, now)}\n </time>\n </li>\n ))}\n </ol>\n )}\n </div>\n </div>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n */\n\n/**\n * Renders the currently-open side panel's body (built-in or host-supplied),\n * to the left of the rail. Returns null when no panel is open so the grid keeps\n * the full width. Each panel body receives `{ api, onClose }`.\n */\nimport { Suspense, type CSSProperties } from 'react';\n\nimport type { CasualSheetsAPI } from '../sheets/api';\nimport type { ChromeExtensions } from './extensions';\nimport { usePanels } from './panel-context';\nimport { BUILT_IN_PANELS } from './panel-registry';\n\nconst asideStyle: CSSProperties = {\n flex: '0 0 auto',\n width: 320,\n minWidth: 0,\n height: '100%',\n overflow: 'auto',\n borderLeft: '1px solid var(--color-divider, var(--cs-chrome-border, #edeff3))',\n background: 'var(--color-surface-alt, var(--cs-chrome-input-bg, #ffffff))',\n color: 'var(--color-text, var(--cs-chrome-fg, #201f1e))',\n fontSize: 13,\n};\n\nexport function PanelHost({\n api,\n extensions,\n}: {\n api: CasualSheetsAPI | null;\n extensions?: ChromeExtensions;\n}) {\n const panels = usePanels();\n const openId = panels.openPanelId;\n if (!openId || !api) return null;\n\n const builtIn = BUILT_IN_PANELS.find((p) => p.id === openId);\n const host = extensions?.panels?.find((p) => p.id === openId);\n const Body = builtIn?.component ?? host?.component;\n if (!Body) return null;\n\n return (\n <aside style={asideStyle} data-testid={`cs-panel-${openId}`}>\n {/* Panels may be lazy (e.g. Charts pulls echarts) — Suspense keeps the\n rest of the chrome painted while the chunk loads. */}\n <Suspense fallback={null}>\n <Body api={api} onClose={panels.close} />\n </Suspense>\n </aside>\n );\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * mountCasualSheets — the framework-agnostic imperative mount (doc 38 §1).\n *\n * React hosts render `<CasualSheets {...config} />`; vanilla / non-React hosts\n * call `mountCasualSheets(container, config)` and get back the same\n * `CasualSheetsAPI` the component hands to `onReady`, plus a `destroy()` that\n * unmounts the React root. This is the sheets peer of the docs SDK's\n * `renderAsync(input, container, options)` — one programmatic entry point that\n * returns the full imperative handle, so a host never has to stand up its own\n * React root to drive the editor.\n *\n * (`mountEmbedded` in `../embed-runtime` is a DIFFERENT, iframe-only entry: it\n * boots the postMessage embed runtime and returns `void`. This one mounts the\n * live editor into a DOM node the host already controls and returns the API.)\n *\n * The config is exactly `CasualSheetsProps` — the same declarative object the\n * component takes — so the two mount styles stay key-for-key identical (doc 38\n * §1). `react` / `react-dom` are peer deps the host already provides.\n */\n\nimport { createElement } from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\nimport { CasualSheets, type CasualSheetsProps } from './CasualSheets';\nimport type { CasualSheetsAPI } from './api';\n\n/** The handle returned by {@link mountCasualSheets}. */\nexport interface MountedCasualSheets {\n /** The imperative editor API — identical to the ref handed to `onReady`\n * (snapshot I/O, xlsx import/export, selection, command dispatch, undo/redo,\n * the `.on()/.off()` emitter, document mode, `api.univer` escape hatch). */\n readonly api: CasualSheetsAPI;\n /** Unmount the React root and dispose the editor. The imperative-mount peer\n * of a React unmount (doc 38 §4 `destroy`). Idempotent. */\n destroy(): void;\n}\n\n/**\n * Mount `<CasualSheets>` into a DOM node without a host React tree, and resolve\n * once the editor is ready with its {@link CasualSheetsAPI} + a `destroy()`.\n *\n * Any `onReady` / `onError` you pass in `options` still fires — this composes\n * with them rather than replacing them. The returned promise resolves on the\n * first `ready`; if boot fails before ready, it rejects with the boot error\n * (so callers awaiting the mount never hang). Errors after ready reach your\n * `onError` (prop or `api.on('error', …)`), not the promise.\n */\nexport function mountCasualSheets(\n container: HTMLElement,\n options: CasualSheetsProps,\n): Promise<MountedCasualSheets> {\n const root: Root = createRoot(container);\n let destroyed = false;\n const destroy = () => {\n if (destroyed) return;\n destroyed = true;\n // Defer off any in-flight render commit (Univer owns its own React root and\n // warns on a synchronous unmount mid-render), mirroring the component's\n // microtask-deferred disposal.\n queueMicrotask(() => root.unmount());\n };\n\n return new Promise<MountedCasualSheets>((resolve, reject) => {\n let settled = false;\n const onReady = (api: CasualSheetsAPI) => {\n // Preserve the host's own onReady first, then settle the mount promise.\n options.onReady?.(api);\n if (settled) return;\n settled = true;\n resolve({ api, destroy });\n };\n const onError = (err: Error) => {\n options.onError?.(err);\n // A boot error before `ready` would otherwise leave the promise pending.\n if (settled) return;\n settled = true;\n reject(err);\n };\n try {\n root.render(createElement(CasualSheets, { ...options, onReady, onError }));\n } catch (err) {\n destroy();\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SDK-owned LLM transport contract for the Sheets AI surface.\n *\n * This is the canonical `SheetsAiTransport` type that the `ai` prop on\n * `<CasualSheets>` accepts. It mirrors the reference app's transport\n * (`apps/web/src/ai/transport.ts`) but lives in the SDK so integrators can\n * type their transport straight off `@casualoffice/sheets` and reuse the\n * shipped implementations:\n * - `DirectAiTransport` — browser fetch straight to Anthropic (BYO key)\n * - `CollabAiTransport` — WebSocket to the collab server `/api/ai`; the\n * server holds the key and runs ONE LLM round per\n * `call()` (single-round), routing `tool_call`\n * frames back to this client's `toolExecutor`\n * - `DesktopAiTransport` — native llama.cpp model in the Casual Office\n * desktop shell via the `docops_llm_call` Tauri\n * command (no key, no server)\n *\n * The panel drives the tool loop (`drivesLoop = false` on every transport):\n * each `call()` performs one round and returns an Anthropic-shaped\n * `{ content, stop_reason }` payload.\n */\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport type SheetsAiToolExecutor = (\n toolName: string,\n args: Record<string, unknown>,\n) => Promise<unknown>;\n\nexport interface SheetsAiLlmPayload {\n model: string;\n system: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n messages: any[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tools: any[];\n max_tokens: number;\n apiKey?: string;\n toolExecutor?: SheetsAiToolExecutor;\n onText?: (text: string) => void;\n signal?: AbortSignal;\n maxToolRounds?: number;\n}\n\nexport interface SheetsAiLlmResult {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data: any;\n status: number;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n updatedHistory?: any[];\n capHit?: boolean;\n}\n\nexport interface SheetsAiTransport {\n call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult>;\n readonly requiresApiKey: boolean;\n readonly drivesLoop: boolean;\n}\n\n// ── DirectAiTransport ──────────────────────────────────────────────────────\n\nexport class DirectAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = true;\n readonly drivesLoop = false;\n\n async call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n if (!payload.apiKey) {\n return { data: { error: { message: 'No API key configured.' } }, status: 401 };\n }\n\n const useStream = !!payload.onText;\n\n const resp = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': payload.apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model: payload.model,\n max_tokens: payload.max_tokens,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n ...(useStream ? { stream: true } : {}),\n }),\n signal: payload.signal,\n });\n\n if (!useStream || !resp.body) {\n return { data: await resp.json(), status: resp.status };\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buf = '';\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const content: any[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let msgDelta: any = {};\n\n try {\n outer: while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split('\\n');\n buf = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') break outer;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ev: any;\n try {\n ev = JSON.parse(raw);\n } catch {\n continue;\n }\n\n if (ev.type === 'content_block_start' && ev.content_block?.type === 'text') {\n content.push({ type: 'text', text: '' });\n } else if (ev.type === 'content_block_start' && ev.content_block?.type === 'tool_use') {\n content.push({\n type: 'tool_use',\n id: ev.content_block.id,\n name: ev.content_block.name,\n input: {},\n });\n } else if (ev.type === 'content_block_delta') {\n const last = content[content.length - 1];\n if (ev.delta?.type === 'text_delta' && last?.type === 'text') {\n last.text += ev.delta.text ?? '';\n payload.onText?.(ev.delta.text ?? '');\n } else if (ev.delta?.type === 'input_json_delta' && last?.type === 'tool_use') {\n last._inputStr = (last._inputStr ?? '') + (ev.delta.partial_json ?? '');\n }\n } else if (ev.type === 'content_block_stop') {\n const last = content[content.length - 1];\n if (last?.type === 'tool_use' && last._inputStr) {\n try {\n last.input = JSON.parse(last._inputStr);\n } catch {\n /* leave empty */\n }\n delete last._inputStr;\n }\n } else if (ev.type === 'message_delta') {\n msgDelta = ev.delta ?? {};\n }\n }\n }\n } catch (err) {\n return { data: { error: { message: String(err) } }, status: 500 };\n }\n\n return {\n data: { content, stop_reason: msgDelta.stop_reason ?? 'end_turn' },\n status: resp.status,\n };\n }\n}\n\n// ── CollabAiTransport ──────────────────────────────────────────────────────\n\n/**\n * Routes AI orchestration through the collab server's `/api/ai` WebSocket.\n * The server holds the Anthropic key; `singleRound: true` means the server\n * runs ONE LLM round per `call()` and routes any `tool_call` frames back to\n * this client, which executes them via the payload's `toolExecutor`. The\n * panel/agent drives the multi-round loop from there (so `drivesLoop = false`).\n */\nexport class CollabAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = false;\n readonly drivesLoop = false;\n\n constructor(private readonly aiWsUrl: string) {}\n\n call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n return new Promise((resolve, reject) => {\n if (payload.signal?.aborted) {\n reject(Object.assign(new Error('AbortError'), { name: 'AbortError' }));\n return;\n }\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(this.aiWsUrl);\n } catch (err) {\n reject(new Error(`Failed to open AI WebSocket: ${String(err)}`));\n return;\n }\n\n let settled = false;\n\n const settle = (v: SheetsAiLlmResult | null, err?: Error) => {\n if (settled) return;\n settled = true;\n payload.signal?.removeEventListener('abort', onAbort);\n if (err) reject(err);\n else resolve(v!);\n };\n\n const onAbort = () => {\n try {\n ws.close(1000, 'aborted');\n } catch {\n /* ignore */\n }\n settle(null, Object.assign(new Error('AbortError'), { name: 'AbortError' }));\n };\n payload.signal?.addEventListener('abort', onAbort);\n\n ws.addEventListener('open', () => {\n ws.send(\n JSON.stringify({\n type: 'chat',\n model: payload.model,\n max_tokens: payload.max_tokens,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n singleRound: true,\n ...(payload.apiKey ? { apiKey: payload.apiKey } : {}),\n }),\n );\n });\n\n ws.addEventListener('message', ({ data }: MessageEvent<string>) => {\n let msg: Record<string, unknown>;\n try {\n msg = JSON.parse(data) as Record<string, unknown>;\n } catch {\n settle(null, new Error('AI WS: received non-JSON frame'));\n ws.close();\n return;\n }\n\n if (msg.type === 'round') {\n // Single-round reply: the panel/agent drives the loop from here.\n settle({\n data: {\n content: msg.content ?? [],\n stop_reason: (msg.stop_reason as string) ?? 'end_turn',\n },\n status: 200,\n });\n } else if (msg.type === 'text') {\n payload.onText?.(msg.text as string);\n } else if (msg.type === 'tool_call') {\n const id = msg.id as string;\n const toolName = msg.toolName as string;\n const args = (msg.args ?? {}) as Record<string, unknown>;\n\n if (!payload.toolExecutor) {\n ws.send(\n JSON.stringify({\n type: 'tool_result',\n id,\n error: 'no toolExecutor configured on this client',\n }),\n );\n return;\n }\n\n payload\n .toolExecutor(toolName, args)\n .then((result) => {\n ws.send(JSON.stringify({ type: 'tool_result', id, result }));\n })\n .catch((err) => {\n ws.send(\n JSON.stringify({\n type: 'tool_result',\n id,\n error: err instanceof Error ? err.message : String(err),\n }),\n );\n });\n } else if (msg.type === 'done') {\n settle({\n data: { ok: true },\n status: 200,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n updatedHistory: msg.history as any[],\n capHit: msg.capHit === true,\n });\n } else if (msg.type === 'error') {\n settle({\n data: { error: { message: msg.message as string } },\n status: 500,\n });\n }\n });\n\n ws.addEventListener('error', () => {\n settle(null, new Error('AI WebSocket connection failed'));\n });\n\n ws.addEventListener('close', ({ code, reason }: CloseEvent) => {\n if (!settled) {\n if (code === 1000 || reason === 'aborted') return;\n settle(null, new Error(`AI WebSocket closed unexpectedly (${code})`));\n }\n });\n });\n }\n}\n\n// ── DesktopAiTransport ─────────────────────────────────────────────────────\n\n/**\n * Routes AI calls to the native model loaded in the Casual Office desktop\n * shell (the llama.cpp worker) through the shared `docops_llm_call` Tauri\n * command — the same backend the document editor uses. No API key, no collab\n * server. Each `call()` performs one LLM round.\n */\nexport class DesktopAiTransport implements SheetsAiTransport {\n readonly requiresApiKey = false;\n readonly drivesLoop = false;\n\n async call(payload: SheetsAiLlmPayload): Promise<SheetsAiLlmResult> {\n const invoke = tauriInvoke();\n if (!invoke) {\n return {\n data: { error: { message: 'Native AI is only available in the desktop app.' } },\n status: 500,\n };\n }\n try {\n // The Rust command is docops_llm_call(args: DocopsLlmArgs), so the\n // payload MUST be nested under `args`. Inner fields are camelCase.\n const data = await invoke('docops_llm_call', {\n args: {\n model: payload.model,\n system: payload.system,\n messages: payload.messages,\n tools: payload.tools,\n maxTokens: payload.max_tokens,\n apiKey: payload.apiKey ?? '',\n },\n });\n return { data, status: 200 };\n } catch (err) {\n return { data: { error: { message: String(err) } }, status: 500 };\n }\n }\n}\n\n// ── Environment helpers ──────────────────────────────────────────────────────\n\n/** Tauri `invoke` when running inside the Casual Office desktop shell, else null. */\nfunction tauriInvoke(): ((cmd: string, args?: unknown) => Promise<unknown>) | null {\n const inv = (\n window as unknown as {\n __TAURI__?: { core?: { invoke?: (c: string, a?: unknown) => Promise<unknown> } };\n }\n ).__TAURI__?.core?.invoke;\n return typeof inv === 'function' ? inv : null;\n}\n\n/**\n * Derives the AI WebSocket URL: an explicit override wins, else the\n * `__COLLAB_WS_URL__` window global (same base as Yjs, `/yjs` → `/api/ai`),\n * else same-origin `/api/ai`.\n */\nfunction resolveAiWsUrl(explicit?: string): string {\n const base =\n explicit ??\n (window as unknown as { __COLLAB_WS_URL__?: string }).__COLLAB_WS_URL__ ??\n `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/yjs`;\n return base.replace(/\\/yjs$/, '').replace(/\\/+$/, '') + '/api/ai';\n}\n\n// ── Factory ──────────────────────────────────────────────────────────────────\n\nexport interface CreateSheetsAiTransportOptions {\n /** Explicit collab WS base URL (e.g. `wss://host/yjs`). Falls back to the\n * `__COLLAB_WS_URL__` window global, then same-origin. */\n collabWsUrl?: string;\n /** Force the browser-direct Anthropic transport (bring-your-own key) even\n * when a collab server is configured. */\n forceDirect?: boolean;\n}\n\n/**\n * Picks the transport for the current environment:\n * - `DesktopAiTransport` inside the desktop shell (native model),\n * - `CollabAiTransport` when a collab WS URL is available (server holds key),\n * - `DirectAiTransport` otherwise (user provides an Anthropic key).\n */\nexport function createSheetsAiTransport(\n opts: CreateSheetsAiTransportOptions = {},\n): SheetsAiTransport {\n if (!opts.forceDirect && tauriInvoke()) {\n return new DesktopAiTransport();\n }\n const hasCollab =\n !!opts.collabWsUrl || !!(window as unknown as { __COLLAB_WS_URL__?: string }).__COLLAB_WS_URL__;\n if (!opts.forceDirect && hasCollab) {\n return new CollabAiTransport(resolveAiWsUrl(opts.collabWsUrl));\n }\n return new DirectAiTransport();\n}\n","/**\n * Copyright 2026 Casual Office\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CasualSheetsIframe — the iframe-mounting variant of `<CasualSheets>`.\n * Sheet sibling of `@casualoffice/docs`'s `<CasualEditorIframe>`;\n * see doc 16 in the parent repo.\n *\n * Differs from CasualEditorIframe in one place: the embed URL params\n * carry `app=sheet` and the embed-runtime inside the iframe knows to\n * convert raw xlsx bytes into an `IWorkbookData` snapshot via\n * `xlsxToWorkbookData` before mounting `<CasualSheets>`.\n *\n * Public surface intentionally identical to CasualSheets. v0.6 will\n * rename CasualSheetsIframe → CasualSheets and the existing direct-\n * mount component → CasualSheetsDirect.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n type CSSProperties,\n type MutableRefObject,\n} from 'react';\n\nimport { EmbedHostTransport } from '../embed/EmbedHostTransport';\nimport type {\n CasualErrorData,\n CommandExecuteData,\n LoadResponseData,\n SaveResponseData,\n SelectionChangedData,\n SelectionFormatStateData,\n TelemetryEventData,\n} from '../embed/protocol';\n\n/** What the host-side load/save handlers consume + return. The wrapper\n * binds these to the host's FileSource via simple adapters. */\nexport interface HostFileBridge {\n open(docId: string): Promise<{ bytes: ArrayBuffer; name: string; etag?: string }>;\n save?(docId: string, bytes: ArrayBuffer, opts?: { etag?: string }): Promise<{ etag: string }>;\n}\n\nexport interface CasualSheetsIframeRef {\n setViewMode(mode: 'preview' | 'editor'): void;\n iframe(): HTMLIFrameElement | null;\n /** Dispatch a formatting / navigation command (bold, italic, undo, …)\n * against the iframe's active selection. `args` carries command payloads\n * (e.g. font family/size, colour) — forwarded over the protocol. v0.6+. */\n executeCommand(command: CommandExecuteData['command'], args?: CommandExecuteData['args']): void;\n}\n\nexport interface CasualSheetsIframeProps {\n /** Host-side bytes bridge. The wrapper round-trips load / save to the\n * iframe through postMessage; bytes never live in the iframe's origin\n * except in-memory while the workbook is open. */\n fileSource: HostFileBridge;\n docId: string;\n /** Default `editor`. Live changes push casual.command.set.viewmode. */\n viewMode?: 'preview' | 'editor';\n /** Default `/embed/sheets`. Consumer copies the SDK's\n * `dist/embed/{embed.html, embed-runtime.js, embed-runtime.css}`\n * to this path. */\n embedBasePath?: string;\n onSelectionChanged?: (data: SelectionChangedData) => void;\n /** Fires when the active cell's format flags change (bold, italic,\n * …). Drive's custom toolbar reflects this state in the button\n * \"pressed\" indicators. v0.6+. */\n onSelectionFormatState?: (data: SelectionFormatStateData) => void;\n onTelemetry?: (data: TelemetryEventData) => void;\n onError?: (data: CasualErrorData) => void;\n style?: CSSProperties;\n className?: string;\n testId?: string;\n}\n\nconst DEFAULT_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 'none',\n display: 'block',\n};\n\nexport const CasualSheetsIframe = forwardRef<CasualSheetsIframeRef, CasualSheetsIframeProps>(\n function CasualSheetsIframe(props, ref) {\n const {\n fileSource,\n docId,\n viewMode = 'editor',\n embedBasePath = '/embed/sheets',\n onSelectionChanged,\n onSelectionFormatState,\n onTelemetry,\n onError,\n style,\n className,\n testId = 'casual-sheets-iframe',\n } = props;\n\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const transportRef = useRef<EmbedHostTransport | null>(null);\n const fileSourceRef = useRef(fileSource);\n fileSourceRef.current = fileSource;\n\n const onLoad = useCallback(async (req: { docId: string }): Promise<LoadResponseData> => {\n try {\n const { bytes, name, etag } = await fileSourceRef.current.open(req.docId);\n return {\n ok: true,\n bytes,\n fileName: name,\n ...(etag !== undefined ? { etag } : {}),\n };\n } catch (err) {\n return {\n ok: false,\n code: 'open_failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }, []);\n\n const onSave = useCallback(\n async (req: {\n docId: string;\n bytes: ArrayBuffer;\n baseEtag?: string;\n }): Promise<SaveResponseData> => {\n try {\n if (!fileSourceRef.current.save) {\n return {\n ok: false,\n code: 'save_unsupported',\n message: 'host fileSource does not implement save',\n };\n }\n const opts = req.baseEtag !== undefined ? { etag: req.baseEtag } : undefined;\n const { etag } = await fileSourceRef.current.save(req.docId, req.bytes, opts);\n return { ok: true, etag };\n } catch (err) {\n return {\n ok: false,\n code: 'save_failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n },\n [],\n );\n\n const onIframeLoad = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe?.contentWindow) return;\n transportRef.current?.destroy();\n const transport = new EmbedHostTransport({\n app: 'sheet',\n iframeWindow: iframe.contentWindow,\n embedOrigin: window.location.origin,\n });\n transport.on({\n onLoadRequest: onLoad,\n onSaveRequest: onSave,\n ...(onSelectionChanged ? { onSelectionChanged } : {}),\n ...(onSelectionFormatState ? { onSelectionFormatState } : {}),\n ...(onTelemetry ? { onTelemetry } : {}),\n ...(onError ? { onError } : {}),\n onEditorReady: () => {\n transport.sendHostHello({ capabilities: ['load', 'save'] });\n transport.sendSetViewMode({ viewMode });\n },\n });\n transportRef.current = transport;\n }, [\n onLoad,\n onSave,\n onSelectionChanged,\n onSelectionFormatState,\n onTelemetry,\n onError,\n viewMode,\n ]);\n\n useEffect(() => {\n transportRef.current?.sendSetViewMode({ viewMode });\n }, [viewMode]);\n\n useEffect(() => {\n return () => {\n transportRef.current?.destroy();\n transportRef.current = null;\n };\n }, []);\n\n if (ref) {\n const apiRef = ref as MutableRefObject<CasualSheetsIframeRef | null>;\n apiRef.current = {\n setViewMode: (mode) => transportRef.current?.sendSetViewMode({ viewMode: mode }),\n iframe: () => iframeRef.current,\n executeCommand: (command, args) =>\n transportRef.current?.sendCommandExecute({ command, args }),\n };\n }\n\n const url =\n `${embedBasePath}/embed.html` +\n `?app=sheet` +\n `&docId=${encodeURIComponent(docId)}` +\n `&viewMode=${viewMode}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={url}\n onLoad={onIframeLoad}\n title=\"Casual Sheets\"\n sandbox=\"allow-scripts allow-same-origin allow-downloads allow-modals\"\n style={{ ...DEFAULT_STYLE, ...style }}\n className={className}\n data-testid={testId}\n />\n );\n },\n);\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","first","import_react","import_jsx_runtime","import_react","import_jsx_runtime","MUTED","import_react","import_jsx_runtime","DIVIDER","import_core","series","import_react","import_jsx_runtime","import_react","import_jsx_runtime","rangeToA1","import_react","import_jsx_runtime","host","import_react","import_react_dom","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","secondaryBtnStyle","primaryBtnStyle","env","import_react","import_core","import_facade","import_sheets","import_core","import_core","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","total","import_jsx_runtime","PIVOT_AGG_LABELS","f","model","labelFor","PIVOT_AGG_LABELS","import_react","import_jsx_runtime","iconBtn","REFRESH_CMDS","import_react","import_core","import_jsx_runtime","ChartsPanel","import_jsx_runtime","import_react","import_jsx_runtime","asideStyle","import_jsx_runtime","ChartLayer","import_react","import_react","import_jsx_runtime","DEFAULT_STYLE","CasualSheetsIframe"]}
|