@pixerate/editor-react 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/canvas/index.cjs +180 -68
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +36 -6
- package/dist/canvas/index.d.ts +36 -6
- package/dist/canvas/index.js +113 -1
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-MHTAR3RS.js → chunk-25S5EHH4.js} +84 -27
- package/dist/chunk-25S5EHH4.js.map +1 -0
- package/dist/image-editor/index.d.cts +3 -3
- package/dist/image-editor/index.d.ts +3 -3
- package/dist/index.cjs +94 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -17
- package/dist/index.d.ts +26 -17
- package/dist/index.js +17 -2
- package/dist/index.js.map +1 -1
- package/dist/spreadsheet/index.cjs +78 -21
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +8 -9
- package/dist/spreadsheet/index.d.ts +8 -9
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-MHTAR3RS.js.map +0 -1
|
@@ -29,8 +29,12 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
29
29
|
const [activeCell, setActiveCell] = useState(controller.activeCell);
|
|
30
30
|
const [selectedRange, setSelectedRange] = useState(controller.selectedRange);
|
|
31
31
|
const [editingCell, setEditingCell] = useState(null);
|
|
32
|
-
const [draftValue,
|
|
32
|
+
const [draftValue, setDraftState] = useState("");
|
|
33
33
|
settersRef.current = { setDoc, setActiveCell, setSelectedRange };
|
|
34
|
+
const setDraftValue = useCallback((value) => {
|
|
35
|
+
controller.draftValue = value;
|
|
36
|
+
setDraftState(value);
|
|
37
|
+
}, [controller]);
|
|
34
38
|
const setCellValue = useCallback((rowId, colId, raw) => {
|
|
35
39
|
controller.setCellValue(rowId, colId, raw);
|
|
36
40
|
setDoc({ ...controller.document });
|
|
@@ -163,7 +167,7 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
166
|
-
import { useRef as useRef5, useState as
|
|
170
|
+
import { useRef as useRef5, useState as useState5, useMemo as useMemo3, useEffect as useEffect4, useCallback as useCallback3 } from "react";
|
|
167
171
|
import {
|
|
168
172
|
indexToColName,
|
|
169
173
|
getSpreadsheetMenuItems,
|
|
@@ -172,12 +176,27 @@ import {
|
|
|
172
176
|
} from "@pixerate/editor/spreadsheet";
|
|
173
177
|
|
|
174
178
|
// src/spreadsheet/SpreadsheetContextMenu.tsx
|
|
175
|
-
import React, { useEffect, useRef as useRef2 } from "react";
|
|
179
|
+
import React, { useEffect, useLayoutEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
180
|
+
import { clampMenuPosition } from "@pixerate/editor/spreadsheet";
|
|
176
181
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
182
|
+
var VIEWPORT_MARGIN = 4;
|
|
177
183
|
var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
178
184
|
const menuRef = useRef2(null);
|
|
179
185
|
const onCloseRef = useRef2(onClose);
|
|
180
186
|
onCloseRef.current = onClose;
|
|
187
|
+
const [position, setPosition] = useState2({ x, y });
|
|
188
|
+
useLayoutEffect(() => {
|
|
189
|
+
const menu = menuRef.current;
|
|
190
|
+
if (!menu || typeof window === "undefined") return;
|
|
191
|
+
const { width, height } = menu.getBoundingClientRect();
|
|
192
|
+
const next = clampMenuPosition(
|
|
193
|
+
{ x, y },
|
|
194
|
+
{ width, height },
|
|
195
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
196
|
+
VIEWPORT_MARGIN
|
|
197
|
+
);
|
|
198
|
+
setPosition((prev) => prev.x === next.x && prev.y === next.y ? prev : next);
|
|
199
|
+
}, [x, y, items]);
|
|
181
200
|
useEffect(() => {
|
|
182
201
|
const handlePointer = (e) => {
|
|
183
202
|
if (!menuRef.current?.contains(e.target)) onCloseRef.current();
|
|
@@ -199,7 +218,13 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
199
218
|
role: "menu",
|
|
200
219
|
"aria-label": "Table actions",
|
|
201
220
|
className: "fixed z-50 min-w-[14rem] rounded-md border border-border bg-popover py-1 text-xs text-popover-foreground shadow-lg",
|
|
202
|
-
style: {
|
|
221
|
+
style: {
|
|
222
|
+
left: position.x,
|
|
223
|
+
top: position.y,
|
|
224
|
+
maxHeight: `calc(100vh - ${VIEWPORT_MARGIN * 2}px)`,
|
|
225
|
+
overflowY: "auto",
|
|
226
|
+
background: "var(--popover, var(--background, #fff))"
|
|
227
|
+
},
|
|
203
228
|
onContextMenu: (e) => e.preventDefault(),
|
|
204
229
|
onKeyDown: (e) => e.stopPropagation(),
|
|
205
230
|
children: items.map((item) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
@@ -236,7 +261,7 @@ var SpreadsheetGroupRow = ({
|
|
|
236
261
|
}) => {
|
|
237
262
|
const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
|
|
238
263
|
return /* @__PURE__ */ jsxs2("tr", { className: "border-b border-border bg-muted/40 font-semibold", "data-group-key": group.key, style: { height: 28 }, children: [
|
|
239
|
-
/* @__PURE__ */ jsx2("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted
|
|
264
|
+
/* @__PURE__ */ jsx2("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center", children: /* @__PURE__ */ jsx2(
|
|
240
265
|
"button",
|
|
241
266
|
{
|
|
242
267
|
type: "button",
|
|
@@ -267,7 +292,7 @@ var SpreadsheetGroupRow = ({
|
|
|
267
292
|
};
|
|
268
293
|
|
|
269
294
|
// src/spreadsheet/useSpreadsheetTableInteractions.ts
|
|
270
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef3, useState as
|
|
295
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
|
|
271
296
|
import {
|
|
272
297
|
computeFillTarget,
|
|
273
298
|
normalizeRange
|
|
@@ -312,13 +337,14 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
|
312
337
|
setTimeout(() => {
|
|
313
338
|
if (copiedRef.current) return;
|
|
314
339
|
const s = stateRef.current;
|
|
315
|
-
navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange))
|
|
340
|
+
Promise.resolve(navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange))).catch(() => {
|
|
341
|
+
});
|
|
316
342
|
}, 0);
|
|
317
343
|
}, []);
|
|
318
344
|
return { copyShortcutFallback };
|
|
319
345
|
}
|
|
320
346
|
function useFillHandle(state) {
|
|
321
|
-
const [drag, setDrag] =
|
|
347
|
+
const [drag, setDrag] = useState3(null);
|
|
322
348
|
const dragRef = useRef3(drag);
|
|
323
349
|
dragRef.current = drag;
|
|
324
350
|
const stateRef = useRef3(state);
|
|
@@ -349,15 +375,15 @@ function useFillHandle(state) {
|
|
|
349
375
|
}
|
|
350
376
|
|
|
351
377
|
// src/spreadsheet/FormulaHints.tsx
|
|
352
|
-
import { useEffect as useEffect3, useLayoutEffect, useMemo as useMemo2, useRef as useRef4, useState as
|
|
378
|
+
import { useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
353
379
|
import { applyFormulaSuggestion, getFormulaHints } from "@pixerate/editor/spreadsheet";
|
|
354
380
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
355
381
|
var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
356
|
-
const [caret, setCaret] =
|
|
357
|
-
const [focused, setFocused] =
|
|
358
|
-
const [selected, setSelected] =
|
|
359
|
-
const [dismissed, setDismissed] =
|
|
360
|
-
const [position, setPosition] =
|
|
382
|
+
const [caret, setCaret] = useState4(null);
|
|
383
|
+
const [focused, setFocused] = useState4(false);
|
|
384
|
+
const [selected, setSelected] = useState4(0);
|
|
385
|
+
const [dismissed, setDismissed] = useState4(false);
|
|
386
|
+
const [position, setPosition] = useState4(null);
|
|
361
387
|
const pendingCaret = useRef4(null);
|
|
362
388
|
const hints = useMemo2(
|
|
363
389
|
() => getFormulaHints(value, caret ?? value.length, { limit }),
|
|
@@ -426,7 +452,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
426
452
|
input.removeEventListener("keydown", onKeyDown);
|
|
427
453
|
};
|
|
428
454
|
}, [inputRef]);
|
|
429
|
-
|
|
455
|
+
useLayoutEffect2(() => {
|
|
430
456
|
const input = inputRef.current;
|
|
431
457
|
const at = pendingCaret.current;
|
|
432
458
|
if (!input || at === null || input.value !== value) return;
|
|
@@ -435,7 +461,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
435
461
|
setCaret(at);
|
|
436
462
|
setSelected(0);
|
|
437
463
|
}, [value, inputRef]);
|
|
438
|
-
|
|
464
|
+
useLayoutEffect2(() => {
|
|
439
465
|
const input = inputRef.current;
|
|
440
466
|
if (!visible || !input) return;
|
|
441
467
|
const rect = input.getBoundingClientRect();
|
|
@@ -512,6 +538,20 @@ function frozenCellStyle(viewRow, viewCol) {
|
|
|
512
538
|
background: "var(--background, #fff)"
|
|
513
539
|
};
|
|
514
540
|
}
|
|
541
|
+
var coordKey = (cell) => cell ? `${indexToColName(cell.col)}${cell.row + 1}` : "";
|
|
542
|
+
function spillBorderStyle(range, row, col) {
|
|
543
|
+
const line = "1px solid color-mix(in srgb, var(--primary, #6366f1) 60%, transparent)";
|
|
544
|
+
return {
|
|
545
|
+
position: "absolute",
|
|
546
|
+
inset: 0,
|
|
547
|
+
pointerEvents: "none",
|
|
548
|
+
zIndex: 5,
|
|
549
|
+
borderTop: row === range.startRow ? line : void 0,
|
|
550
|
+
borderBottom: row === range.endRow ? line : void 0,
|
|
551
|
+
borderLeft: col === range.startCol ? line : void 0,
|
|
552
|
+
borderRight: col === range.endCol ? line : void 0
|
|
553
|
+
};
|
|
554
|
+
}
|
|
515
555
|
var SpreadsheetEditor = ({
|
|
516
556
|
state: externalState,
|
|
517
557
|
readOnly = false,
|
|
@@ -525,14 +565,14 @@ var SpreadsheetEditor = ({
|
|
|
525
565
|
const gridRef = useRef5(null);
|
|
526
566
|
const formulaBarRef = useRef5(null);
|
|
527
567
|
const cellInputRef = useRef5(null);
|
|
528
|
-
const [resizingColId, setResizingColId] =
|
|
529
|
-
const [hoveredColId, setHoveredColId] =
|
|
530
|
-
const [resizeStartX, setResizeStartX] =
|
|
531
|
-
const [resizeStartWidth, setResizeStartWidth] =
|
|
568
|
+
const [resizingColId, setResizingColId] = useState5(null);
|
|
569
|
+
const [hoveredColId, setHoveredColId] = useState5(null);
|
|
570
|
+
const [resizeStartX, setResizeStartX] = useState5(0);
|
|
571
|
+
const [resizeStartWidth, setResizeStartWidth] = useState5(0);
|
|
532
572
|
const view = state.viewModel;
|
|
533
573
|
const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);
|
|
534
574
|
const { fillTarget, startFill, extendFill } = useFillHandle(state);
|
|
535
|
-
const [menu, setMenu] =
|
|
575
|
+
const [menu, setMenu] = useState5(null);
|
|
536
576
|
const filter = state.document.table?.filter;
|
|
537
577
|
const filteredColIds = useMemo3(
|
|
538
578
|
() => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),
|
|
@@ -554,12 +594,18 @@ var SpreadsheetEditor = ({
|
|
|
554
594
|
if (!row || !col) return "";
|
|
555
595
|
return state.getCell(row.id, col.id).raw;
|
|
556
596
|
}, [state.activeCell, state.document]);
|
|
597
|
+
const activeSpill = useMemo3(
|
|
598
|
+
() => state.activeCell ? state.controller.getSpillAt(state.activeCell.row, state.activeCell.col) : null,
|
|
599
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
600
|
+
[state.controller, state.activeCell, state.document]
|
|
601
|
+
);
|
|
602
|
+
const spillFormula = activeSpill && !activeRawValue && activeSpill.key !== coordKey(state.activeCell) ? activeSpill.formula : "";
|
|
557
603
|
const coordLabel = useMemo3(() => {
|
|
558
604
|
if (!state.activeCell) return "--";
|
|
559
605
|
const colName = indexToColName(state.activeCell.col);
|
|
560
606
|
return `${colName}${state.activeCell.row + 1}`;
|
|
561
607
|
}, [state.activeCell]);
|
|
562
|
-
const [formulaDraft, setFormulaDraft] =
|
|
608
|
+
const [formulaDraft, setFormulaDraft] = useState5(null);
|
|
563
609
|
const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
|
|
564
610
|
const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
|
|
565
611
|
useEffect4(() => {
|
|
@@ -603,7 +649,10 @@ var SpreadsheetEditor = ({
|
|
|
603
649
|
e.preventDefault();
|
|
604
650
|
state.commitEditing();
|
|
605
651
|
state.moveCursor(e.shiftKey ? "left" : "right");
|
|
652
|
+
} else {
|
|
653
|
+
return;
|
|
606
654
|
}
|
|
655
|
+
gridRef.current?.focus();
|
|
607
656
|
return;
|
|
608
657
|
}
|
|
609
658
|
if (!state.activeCell) return;
|
|
@@ -651,6 +700,7 @@ var SpreadsheetEditor = ({
|
|
|
651
700
|
} else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
652
701
|
const col = state.document.columns[state.activeCell.col];
|
|
653
702
|
if (!col?.readOnly) {
|
|
703
|
+
e.preventDefault();
|
|
654
704
|
state.startEditing(state.activeCell.row, state.activeCell.col, e.key);
|
|
655
705
|
}
|
|
656
706
|
}
|
|
@@ -843,7 +893,9 @@ var SpreadsheetEditor = ({
|
|
|
843
893
|
placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
|
|
844
894
|
"aria-label": "Formula bar",
|
|
845
895
|
readOnly: formulaBarReadOnly,
|
|
846
|
-
|
|
896
|
+
"data-spill-formula": !state.editingCell && formulaDraft === null && spillFormula ? "true" : void 0,
|
|
897
|
+
style: !state.editingCell && formulaDraft === null && spillFormula ? { color: "var(--muted-foreground, #94a3b8)" } : void 0,
|
|
898
|
+
value: state.editingCell ? state.draftValue : formulaDraft ?? (activeRawValue || spillFormula),
|
|
847
899
|
onFocus: () => {
|
|
848
900
|
if (!state.editingCell) setFormulaDraft(activeRawValue);
|
|
849
901
|
},
|
|
@@ -878,8 +930,8 @@ var SpreadsheetEditor = ({
|
|
|
878
930
|
)
|
|
879
931
|
] }),
|
|
880
932
|
/* @__PURE__ */ jsx4("div", { className: "relative flex-1 overflow-auto", children: /* @__PURE__ */ jsxs4("table", { className: "border-collapse table-fixed w-max min-w-full", children: [
|
|
881
|
-
/* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsxs4("tr", { className: "h-7 bg-muted
|
|
882
|
-
/* @__PURE__ */ jsx4("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted
|
|
933
|
+
/* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsxs4("tr", { className: "h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs", children: [
|
|
934
|
+
/* @__PURE__ */ jsx4("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
|
|
883
935
|
view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ jsxs4(
|
|
884
936
|
"th",
|
|
885
937
|
{
|
|
@@ -976,7 +1028,7 @@ var SpreadsheetEditor = ({
|
|
|
976
1028
|
/* @__PURE__ */ jsx4(
|
|
977
1029
|
"td",
|
|
978
1030
|
{
|
|
979
|
-
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted
|
|
1031
|
+
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none",
|
|
980
1032
|
style: viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop, zIndex: 15 } : void 0,
|
|
981
1033
|
children: displayRowIndex + 1
|
|
982
1034
|
}
|
|
@@ -1023,6 +1075,10 @@ var SpreadsheetEditor = ({
|
|
|
1023
1075
|
value: state.draftValue,
|
|
1024
1076
|
onChange: (e) => state.setDraftValue(e.target.value),
|
|
1025
1077
|
onBlur: () => state.commitEditing(),
|
|
1078
|
+
onFocus: (e) => {
|
|
1079
|
+
const end = e.currentTarget.value.length;
|
|
1080
|
+
e.currentTarget.setSelectionRange(end, end);
|
|
1081
|
+
},
|
|
1026
1082
|
autoFocus: true
|
|
1027
1083
|
}
|
|
1028
1084
|
),
|
|
@@ -1035,6 +1091,7 @@ var SpreadsheetEditor = ({
|
|
|
1035
1091
|
children: cell.error || (cell.value ?? "")
|
|
1036
1092
|
}
|
|
1037
1093
|
),
|
|
1094
|
+
activeSpill && rangeContains(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
1038
1095
|
showFillHandle && /* @__PURE__ */ jsx4(
|
|
1039
1096
|
"div",
|
|
1040
1097
|
{
|
|
@@ -1100,4 +1157,4 @@ export {
|
|
|
1100
1157
|
FormulaHints,
|
|
1101
1158
|
SpreadsheetEditor
|
|
1102
1159
|
};
|
|
1103
|
-
//# sourceMappingURL=chunk-
|
|
1160
|
+
//# sourceMappingURL=chunk-25S5EHH4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/spreadsheet/useSpreadsheetEditor.ts","../src/spreadsheet/SpreadsheetEditor.tsx","../src/spreadsheet/SpreadsheetContextMenu.tsx","../src/spreadsheet/SpreadsheetGroupRow.tsx","../src/spreadsheet/useSpreadsheetTableInteractions.ts","../src/spreadsheet/FormulaHints.tsx"],"sourcesContent":["import { useState, useRef, useCallback, useMemo } from 'react';\nimport {\n SpreadsheetController,\n bindSpreadsheetTableActions,\n type SpreadsheetControllerOptions,\n type SpreadsheetDocument,\n type CellCoordinate,\n type CellRange,\n type SpreadsheetColumn,\n type SpreadsheetRow,\n type SpreadsheetDataSource\n} from '@pixerate/editor/spreadsheet';\n\nexport function useSpreadsheetEditor(options: SpreadsheetControllerOptions = {}) {\n // Callbacks are read through a ref so they are never stale.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const settersRef = useRef<{\n setDoc?: (doc: SpreadsheetDocument) => void;\n setActiveCell?: (cell: CellCoordinate | null) => void;\n setSelectedRange?: (range: CellRange | null) => void;\n }>({});\n\n // Create the controller first so the initial state reflects its document\n // (including default rows and columns when no document is passed).\n const [controller] = useState(\n () =>\n new SpreadsheetController({\n ...options,\n onDocumentChange: (updated) => {\n settersRef.current.setDoc?.({ ...updated });\n optionsRef.current.onDocumentChange?.(updated);\n },\n onSelectionChange: (active, range) => {\n settersRef.current.setActiveCell?.(active);\n settersRef.current.setSelectedRange?.(range);\n optionsRef.current.onSelectionChange?.(active, range);\n },\n onCellCommit: (rowId, colId, raw, value) => {\n optionsRef.current.onCellCommit?.(rowId, colId, raw, value);\n },\n }),\n );\n\n const [doc, setDoc] = useState<SpreadsheetDocument>(() => ({ ...controller.document }));\n const [activeCell, setActiveCell] = useState<CellCoordinate | null>(controller.activeCell);\n const [selectedRange, setSelectedRange] = useState<CellRange | null>(controller.selectedRange);\n const [editingCell, setEditingCell] = useState<CellCoordinate | null>(null);\n const [draftValue, setDraftState] = useState<string>('');\n settersRef.current = { setDoc, setActiveCell, setSelectedRange };\n\n // The controller commits its own `draftValue` (`commitEditing()` without an\n // argument), so typed text must reach it, not just React state.\n const setDraftValue = useCallback((value: string) => {\n controller.draftValue = value;\n setDraftState(value);\n }, [controller]);\n\n const setCellValue = useCallback((rowId: string, colId: string, raw: string) => {\n controller.setCellValue(rowId, colId, raw);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const selectCell = useCallback((row: number, col: number, extendSelection = false) => {\n controller.selectCell(row, col, extendSelection);\n setActiveCell(controller.activeCell);\n setSelectedRange(controller.selectedRange);\n }, [controller]);\n\n const selectRange = useCallback((range: CellRange) => {\n controller.selectRange(range);\n setSelectedRange(controller.selectedRange);\n }, [controller]);\n\n const startEditing = useCallback((row?: number, col?: number, initialVal?: string) => {\n controller.startEditing(row, col, initialVal);\n setActiveCell(controller.activeCell);\n setEditingCell(controller.editingCell);\n setDraftValue(controller.draftValue);\n }, [controller]);\n\n const commitEditing = useCallback((val?: string) => {\n controller.commitEditing(val);\n setEditingCell(null);\n setDraftValue('');\n setDoc({ ...controller.document });\n }, [controller]);\n\n const cancelEditing = useCallback(() => {\n controller.cancelEditing();\n setEditingCell(null);\n setDraftValue('');\n }, [controller]);\n\n const moveCursor = useCallback((dir: 'up' | 'down' | 'left' | 'right', extend = false) => {\n controller.moveCursor(dir, extend);\n setActiveCell(controller.activeCell);\n setSelectedRange(controller.selectedRange);\n }, [controller]);\n\n const insertColumn = useCallback((index: number, config?: Partial<SpreadsheetColumn>) => {\n controller.insertColumn(index, config);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const deleteColumn = useCallback((colId: string) => {\n controller.deleteColumn(colId);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const insertRow = useCallback((index: number, config?: Partial<SpreadsheetRow>) => {\n controller.insertRow(index, config);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const deleteRow = useCallback((rowId: string) => {\n controller.deleteRow(rowId);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const setColumnWidth = useCallback((colId: string, width: number) => {\n controller.setColumnWidth(colId, width);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const autoFitColumnWidth = useCallback((colId: string, customWidth?: number) => {\n controller.autoFitColumnWidth(colId, customWidth);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const registerDataSource = useCallback((ds: SpreadsheetDataSource) => {\n controller.registerDataSource(ds);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const setPrimaryDataSource = useCallback((id: string | undefined) => {\n controller.setPrimaryDataSource(id);\n setDoc({ ...controller.document });\n }, [controller]);\n\n const recalculateAll = useCallback(() => {\n controller.recalculateAll();\n setDoc({ ...controller.document });\n }, [controller]);\n\n const undo = useCallback(() => {\n controller.undo();\n setDoc({ ...controller.document });\n }, [controller]);\n\n const redo = useCallback(() => {\n controller.redo();\n setDoc({ ...controller.document });\n }, [controller]);\n\n // Table operations (sort, filters, freeze, hide, merge, autofill, categories,\n // transpose, CSV, clipboard). The controller reports their changes through\n // onDocumentChange / onSelectionChange, which update the state above.\n const tableActions = useMemo(() => bindSpreadsheetTableActions(controller), [controller]);\n // What to render: visible rows (with group headers) and columns, frozen\n // offsets and merged-cell spans. Recomputed whenever the document changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const viewModel = useMemo(() => controller.getViewModel(), [controller, doc]);\n\n return {\n document: doc,\n activeCell,\n selectedRange,\n editingCell,\n draftValue,\n setDraftValue,\n controller,\n getCell: (rowId: string, colId: string) => controller.getCell(rowId, colId),\n setCellValue,\n selectCell,\n selectRange,\n startEditing,\n commitEditing,\n cancelEditing,\n moveCursor,\n insertColumn,\n deleteColumn,\n insertRow,\n deleteRow,\n setColumnWidth,\n autoFitColumnWidth,\n loadDocument: (document: SpreadsheetDocument) => {\n controller.loadDocument(document);\n setDoc({ ...controller.document });\n setActiveCell(null);\n setSelectedRange(null);\n setEditingCell(null);\n setDraftValue('');\n },\n syncWithDataSource: () => {\n controller.syncWithDataSource();\n controller.recalculateAll();\n setDoc({ ...controller.document });\n },\n registerDataSource,\n setPrimaryDataSource,\n recalculateAll,\n exportToTsv: (range?: CellRange | null) => controller.exportToTsv(range),\n importFromTsv: (data: string) => {\n controller.importFromTsv(data);\n setDoc({ ...controller.document });\n },\n ...tableActions,\n viewModel,\n undo,\n redo\n };\n}\n","import React, { useRef, useState, useMemo, useEffect, useCallback } from 'react';\nimport {\n indexToColName,\n getSpreadsheetMenuItems,\n normalizeRange,\n rangeContains,\n type SpreadsheetColumn,\n type SpreadsheetRow,\n type CellData,\n type CellRange,\n type SpreadsheetMenuItem,\n type SpreadsheetViewColumn,\n type SpreadsheetViewRow\n} from '@pixerate/editor/spreadsheet';\nimport { useSpreadsheetEditor } from './useSpreadsheetEditor';\nimport { SpreadsheetContextMenu } from './SpreadsheetContextMenu';\nimport { SpreadsheetGroupRow } from './SpreadsheetGroupRow';\nimport { useFillHandle, useSpreadsheetClipboard } from './useSpreadsheetTableInteractions';\n\n// Sizes of the sticky header row and row-number column, for frozen-pane offsets.\nconst COLUMN_HEADER_HEIGHT = 28;\nconst ROW_HEADER_WIDTH = 48;\n\n/** Sticky positioning for cells in frozen rows and/or columns. */\nfunction frozenCellStyle(\n viewRow: Extract<SpreadsheetViewRow, { kind: 'row' }>,\n viewCol: SpreadsheetViewColumn\n): React.CSSProperties | undefined {\n if (!viewRow.frozen && !viewCol.frozen) return undefined;\n return {\n position: 'sticky',\n ...(viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop } : {}),\n ...(viewCol.frozen ? { left: ROW_HEADER_WIDTH + viewCol.stickyLeft } : {}),\n zIndex: viewRow.frozen && viewCol.frozen ? 14 : viewRow.frozen ? 12 : 11,\n background: 'var(--background, #fff)'\n };\n}\nimport { FormulaHints } from './FormulaHints';\n\nconst coordKey = (cell: { row: number; col: number } | null) => (cell ? `${indexToColName(cell.col)}${cell.row + 1}` : '');\n\n/** Thin border drawn on the outer edges of a dynamic array's spill range. */\nfunction spillBorderStyle(range: CellRange, row: number, col: number): React.CSSProperties {\n const line = '1px solid color-mix(in srgb, var(--primary, #6366f1) 60%, transparent)';\n return {\n position: 'absolute',\n inset: 0,\n pointerEvents: 'none',\n zIndex: 5,\n borderTop: row === range.startRow ? line : undefined,\n borderBottom: row === range.endRow ? line : undefined,\n borderLeft: col === range.startCol ? line : undefined,\n borderRight: col === range.endCol ? line : undefined\n };\n}\n\nexport interface SpreadsheetEditorProps {\n state?: ReturnType<typeof useSpreadsheetEditor>;\n readOnly?: boolean;\n customCellRenderer?: (props: { row: SpreadsheetRow; col: SpreadsheetColumn; cell: CellData }) => React.ReactNode;\n onAddColumnClick?: () => void;\n onColumnHeaderClick?: (col: SpreadsheetColumn) => void;\n onColumnResize?: (colId: string, width: number) => void;\n}\n\nexport const SpreadsheetEditor: React.FC<SpreadsheetEditorProps> = ({\n state: externalState,\n readOnly = false,\n customCellRenderer,\n onAddColumnClick,\n onColumnHeaderClick,\n onColumnResize\n}) => {\n const defaultState = useSpreadsheetEditor();\n const state = externalState || defaultState;\n const gridRef = useRef<HTMLDivElement>(null);\n const formulaBarRef = useRef<HTMLInputElement>(null);\n const cellInputRef = useRef<HTMLInputElement>(null);\n\n const [resizingColId, setResizingColId] = useState<string | null>(null);\n const [hoveredColId, setHoveredColId] = useState<string | null>(null);\n const [resizeStartX, setResizeStartX] = useState(0);\n const [resizeStartWidth, setResizeStartWidth] = useState(0);\n\n // Table operations: render model, clipboard, fill handle and context menu.\n const view = state.viewModel;\n const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);\n const { fillTarget, startFill, extendFill } = useFillHandle(state);\n const [menu, setMenu] = useState<{ x: number; y: number; items: SpreadsheetMenuItem[] } | null>(null);\n const filter = state.document.table?.filter;\n const filteredColIds = useMemo(\n () => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),\n [filter]\n );\n\n const handleCellContextMenu = useCallback((rIdx: number, cIdx: number, e: React.MouseEvent) => {\n if (readOnly) return;\n e.preventDefault();\n if (state.editingCell) state.commitEditing();\n if (!state.selectedRange || !rangeContains(state.selectedRange, rIdx, cIdx)) {\n state.selectCell(rIdx, cIdx);\n }\n setMenu({ x: e.clientX, y: e.clientY, items: getSpreadsheetMenuItems(state.controller, { row: rIdx, col: cIdx }) });\n }, [readOnly, state]);\n\n const activeRawValue = useMemo(() => {\n if (!state.activeCell) return '';\n const row = state.document.rows[state.activeCell.row];\n const col = state.document.columns[state.activeCell.col];\n if (!row || !col) return '';\n return state.getCell(row.id, col.id).raw;\n }, [state.activeCell, state.document]);\n\n // The dynamic array under the active cell (anchor or spilled cell): it gets\n // a border, and a spilled cell shows the anchor's formula greyed out.\n const activeSpill = useMemo(\n () => (state.activeCell ? state.controller.getSpillAt(state.activeCell.row, state.activeCell.col) : null),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [state.controller, state.activeCell, state.document]\n );\n const spillFormula = activeSpill && !activeRawValue && activeSpill.key !== coordKey(state.activeCell) ? activeSpill.formula : '';\n\n const coordLabel = useMemo(() => {\n if (!state.activeCell) return '--';\n const colName = indexToColName(state.activeCell.col);\n return `${colName}${state.activeCell.row + 1}`;\n }, [state.activeCell]);\n\n // Text typed in the formula bar while no cell editor is open.\n const [formulaDraft, setFormulaDraft] = useState<string | null>(null);\n const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : undefined;\n const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;\n\n useEffect(() => {\n setFormulaDraft(null);\n }, [state.activeCell?.row, state.activeCell?.col]);\n\n const commitFormulaBar = () => {\n if (state.editingCell) {\n state.commitEditing();\n return;\n }\n if (formulaDraft === null || !state.activeCell) return;\n const row = state.document.rows[state.activeCell.row];\n const col = state.document.columns[state.activeCell.col];\n if (row && col && !formulaBarReadOnly && formulaDraft !== activeRawValue) {\n state.setCellValue(row.id, col.id, formulaDraft);\n }\n setFormulaDraft(null);\n };\n\n const handleCellClick = useCallback((rIdx: number, cIdx: number, e: React.MouseEvent) => {\n if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {\n state.commitEditing();\n }\n state.selectCell(rIdx, cIdx, e.shiftKey);\n }, [state]);\n\n const handleCellDblClick = useCallback((rIdx: number, cIdx: number) => {\n if (readOnly) return;\n const col = state.document.columns[cIdx];\n if (col?.readOnly) return;\n state.startEditing(rIdx, cIdx);\n }, [readOnly, state]);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (state.editingCell) {\n if (e.key === 'Enter') {\n e.preventDefault();\n state.commitEditing();\n state.moveCursor('down');\n } else if (e.key === 'Escape') {\n e.preventDefault();\n state.cancelEditing();\n } else if (e.key === 'Tab') {\n e.preventDefault();\n state.commitEditing();\n state.moveCursor(e.shiftKey ? 'left' : 'right');\n } else {\n return;\n }\n // The cell input unmounts; keep focus on the grid so typing continues.\n gridRef.current?.focus();\n return;\n }\n\n if (!state.activeCell) return;\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n state.moveCursor('up', e.shiftKey);\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n state.moveCursor('down', e.shiftKey);\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n state.moveCursor('left', e.shiftKey);\n } else if (e.key === 'ArrowRight') {\n e.preventDefault();\n state.moveCursor('right', e.shiftKey);\n } else if (e.key === 'Tab') {\n e.preventDefault();\n state.moveCursor(e.shiftKey ? 'left' : 'right');\n } else if (e.key === 'Enter') {\n e.preventDefault();\n const col = state.document.columns[state.activeCell.col];\n if (!readOnly && !col?.readOnly) {\n state.startEditing();\n }\n } else if (e.key === 'Backspace' || e.key === 'Delete') {\n if (readOnly) return;\n const row = state.document.rows[state.activeCell.row];\n const col = state.document.columns[state.activeCell.col];\n if (row && col && !col.readOnly) {\n e.preventDefault();\n state.setCellValue(row.id, col.id, '');\n }\n } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'z') {\n // With Shift held, e.key is 'Z'.\n e.preventDefault();\n if (e.shiftKey) {\n state.redo();\n } else {\n state.undo();\n }\n } else if (e.ctrlKey && !e.metaKey && e.key.toLowerCase() === 'y') {\n e.preventDefault();\n state.redo();\n } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'c') {\n // Copy the selection, not the whole sheet. The browser's copy event\n // writes TSV, HTML and the internal format; the fallback writes TSV.\n copyShortcutFallback();\n } else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {\n const col = state.document.columns[state.activeCell.col];\n if (!col?.readOnly) {\n // The key becomes the draft; without preventDefault the browser would\n // also type it into the newly focused cell input (\"1\" -> \"11\").\n e.preventDefault();\n state.startEditing(state.activeCell.row, state.activeCell.col, e.key);\n }\n }\n }, [readOnly, state, copyShortcutFallback]);\n // The resize effect reads these through refs: re-running it on every width\n // update would reset the in-progress drag (and skip onColumnResize).\n const stateRef = useRef(state);\n stateRef.current = state;\n const onColumnResizeRef = useRef(onColumnResize);\n onColumnResizeRef.current = onColumnResize;\n\n useEffect(() => {\n if (!resizingColId) return;\n\n if (typeof document !== 'undefined') {\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n }\n\n let rafId: number | null = null;\n let pendingWidth = resizeStartWidth;\n let hasDragged = false;\n\n const handleMouseMove = (e: MouseEvent) => {\n const delta = e.clientX - resizeStartX;\n if (Math.abs(delta) > 2) {\n hasDragged = true;\n }\n pendingWidth = Math.max(30, resizeStartWidth + delta);\n\n if (rafId === null) {\n rafId = requestAnimationFrame(() => {\n rafId = null;\n stateRef.current.setColumnWidth(resizingColId, pendingWidth);\n });\n }\n };\n\n const handleMouseUp = () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n if (hasDragged) {\n stateRef.current.setColumnWidth(resizingColId, pendingWidth);\n onColumnResizeRef.current?.(resizingColId, pendingWidth);\n }\n setResizingColId(null);\n if (typeof document !== 'undefined') {\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n };\n\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n return () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n }\n if (typeof document !== 'undefined') {\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, [resizingColId, resizeStartX, resizeStartWidth]);\n\n const measureElementContentWidth = useCallback((el: HTMLElement, container: HTMLElement): number => {\n if (typeof document === 'undefined') return 0;\n\n let maxW = el.scrollWidth || 0;\n const firstChild = el.firstElementChild as HTMLElement | null;\n if (firstChild && firstChild.scrollWidth > maxW) {\n maxW = firstChild.scrollWidth;\n }\n\n const truncated = el.querySelectorAll<HTMLElement>('.truncate, [title], span, div');\n truncated.forEach((node) => {\n if (node.scrollWidth > maxW) {\n maxW = node.scrollWidth;\n }\n });\n\n try {\n const clone = (firstChild ? firstChild.cloneNode(true) : el.cloneNode(true)) as HTMLElement;\n clone.style.cssText = `\n position: absolute !important;\n visibility: hidden !important;\n width: max-content !important;\n min-width: max-content !important;\n max-width: none !important;\n overflow: visible !important;\n white-space: nowrap !important;\n pointer-events: none !important;\n top: -9999px !important;\n left: -9999px !important;\n `;\n\n const allNodes = clone.querySelectorAll<HTMLElement>('*');\n allNodes.forEach((node) => {\n node.style.maxWidth = 'none';\n node.style.overflow = 'visible';\n node.style.textOverflow = 'clip';\n node.style.whiteSpace = 'nowrap';\n if (\n node.classList.contains('truncate') ||\n node.classList.contains('min-w-0') ||\n node.classList.contains('w-full') ||\n node.classList.contains('max-w-0') ||\n node.classList.contains('flex-1')\n ) {\n node.style.width = 'max-content';\n node.style.minWidth = 'max-content';\n }\n });\n\n container.appendChild(clone);\n const rect = clone.getBoundingClientRect();\n container.removeChild(clone);\n\n if (rect.width > maxW) {\n maxW = rect.width;\n }\n } catch {\n // Ignore cloning/measuring errors\n }\n\n return maxW;\n }, []);\n\n const autoFitColumn = useCallback((colId: string, colIndex: number) => {\n const col = state.document.columns.find((c) => c.id === colId);\n if (!col) return;\n\n let calculatedWidth = 0;\n\n if (gridRef.current && typeof document !== 'undefined') {\n const table = gridRef.current.querySelector('table');\n if (table) {\n // Look cells up by column index: hidden columns and merges shift DOM positions.\n const th = table.querySelector(`thead th[data-col=\"${colIndex}\"]`) as HTMLElement | null;\n if (th) {\n const headerInner = (th.firstElementChild as HTMLElement) || th;\n const headerW = measureElementContentWidth(headerInner, gridRef.current);\n calculatedWidth = Math.max(calculatedWidth, headerW + 28);\n }\n\n const rows = table.querySelectorAll('tbody tr');\n const sampleLimit = Math.min(rows.length, 150);\n for (let r = 0; r < sampleLimit; r++) {\n const tr = rows[r];\n const td = tr.querySelector(`td[data-col=\"${colIndex}\"][colspan=\"1\"]`) as HTMLElement | null;\n if (td) {\n const cellW = measureElementContentWidth(td, gridRef.current);\n calculatedWidth = Math.max(calculatedWidth, cellW + 20);\n }\n }\n }\n }\n\n if (calculatedWidth > 0) {\n const finalWidth = Math.min(600, Math.max(50, Math.ceil(calculatedWidth)));\n state.setColumnWidth(colId, finalWidth);\n } else {\n state.autoFitColumnWidth?.(colId);\n }\n\n const updatedCol = state.document.columns.find((c) => c.id === colId);\n if (updatedCol && onColumnResize) {\n onColumnResize(updatedCol.id, updatedCol.width || 130);\n }\n }, [state, measureElementContentWidth, onColumnResize]);\n\n const handleResizeDblClick = useCallback((colId: string, colIndex: number, e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n autoFitColumn(colId, colIndex);\n }, [autoFitColumn]);\n\n const handleHeaderDblClick = useCallback((colId: string, colIndex: number, e: React.MouseEvent) => {\n const target = e.currentTarget as HTMLElement | null;\n if (target) {\n const rect = target.getBoundingClientRect();\n if (rect.right - e.clientX <= 12) {\n e.preventDefault();\n e.stopPropagation();\n autoFitColumn(colId, colIndex);\n }\n }\n }, [autoFitColumn]);\n\n const isCellSelected = (rIdx: number, cIdx: number) => {\n if (!state.selectedRange) return false;\n const minR = Math.min(state.selectedRange.startRow, state.selectedRange.endRow);\n const maxR = Math.max(state.selectedRange.startRow, state.selectedRange.endRow);\n const minC = Math.min(state.selectedRange.startCol, state.selectedRange.endCol);\n const maxC = Math.max(state.selectedRange.startCol, state.selectedRange.endCol);\n return rIdx >= minR && rIdx <= maxR && cIdx >= minC && cIdx <= maxC;\n };\n\n const isActiveCell = (rIdx: number, cIdx: number) => {\n return state.activeCell?.row === rIdx && state.activeCell?.col === cIdx;\n };\n\n return (\n <div\n ref={gridRef}\n className=\"flex flex-col h-full w-full overflow-hidden border border-border bg-background select-none outline-none text-foreground font-sans text-xs\"\n tabIndex={0}\n onKeyDown={handleKeyDown}\n role=\"grid\"\n aria-label=\"Spreadsheet\"\n >\n {/* Formula Bar */}\n <div className=\"flex items-center gap-2 border-b border-border bg-muted/20 px-3 py-1.5 text-xs font-mono\">\n <div className=\"flex h-6 min-w-[3rem] items-center justify-center rounded border border-border bg-background px-1.5 font-semibold text-foreground\">\n {coordLabel}\n </div>\n <div className=\"flex items-center text-muted-foreground select-none\">\n <span className=\"italic font-serif font-bold text-sm text-primary\">fx</span>\n </div>\n <input\n ref={formulaBarRef}\n type=\"text\"\n className=\"flex-1 bg-transparent px-2 py-0.5 outline-none font-sans text-xs text-foreground placeholder:text-muted-foreground/60 focus:bg-background focus:ring-1 focus:ring-primary rounded\"\n placeholder=\"Enter a value or formula (e.g. =SUM(A1:A5))\"\n aria-label=\"Formula bar\"\n readOnly={formulaBarReadOnly}\n data-spill-formula={!state.editingCell && formulaDraft === null && spillFormula ? 'true' : undefined}\n style={!state.editingCell && formulaDraft === null && spillFormula ? { color: 'var(--muted-foreground, #94a3b8)' } : undefined}\n value={state.editingCell ? state.draftValue : formulaDraft ?? (activeRawValue || spillFormula)}\n onFocus={() => {\n if (!state.editingCell) setFormulaDraft(activeRawValue);\n }}\n onChange={(e) => {\n if (state.editingCell) {\n state.setDraftValue(e.target.value);\n } else if (state.activeCell) {\n setFormulaDraft(e.target.value);\n }\n }}\n onBlur={() => commitFormulaBar()}\n onKeyDown={(e) => {\n // Keys typed here must not reach the grid's navigation handler.\n e.stopPropagation();\n if (e.key === 'Enter') {\n e.preventDefault();\n commitFormulaBar();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setFormulaDraft(null);\n if (state.editingCell) state.cancelEditing();\n }\n }}\n />\n {!formulaBarReadOnly && (\n <FormulaHints\n inputRef={formulaBarRef}\n value={state.editingCell ? state.draftValue : formulaDraft ?? activeRawValue}\n onAccept={(next) => (state.editingCell ? state.setDraftValue(next) : setFormulaDraft(next))}\n />\n )}\n </div>\n\n {/* Main Grid */}\n <div className=\"relative flex-1 overflow-auto\">\n <table className=\"border-collapse table-fixed w-max min-w-full\">\n <thead>\n <tr className=\"h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs\">\n <th className=\"w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium\">\n #\n </th>\n {view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => (\n <th\n key={col.id}\n data-col={cIdx}\n className={`relative border-r border-border px-2 text-left font-medium text-muted-foreground hover:bg-muted/90 transition-colors group overflow-hidden max-w-0 ${\n onColumnHeaderClick ? 'cursor-pointer' : 'cursor-default'\n }`}\n style={{\n width: col.width || 130,\n minWidth: col.width || 130,\n maxWidth: col.width || 130,\n overflow: 'hidden',\n ...(frozen ? { position: 'sticky', left: ROW_HEADER_WIDTH + stickyLeft, zIndex: 25, background: 'var(--muted, #f4f4f5)' } : {})\n }}\n onClick={() => onColumnHeaderClick?.(col)}\n onDoubleClick={(e) => handleHeaderDblClick(col.id, cIdx, e)}\n >\n <div className=\"flex items-center justify-between gap-1 min-w-0 overflow-hidden truncate\">\n <span className=\"truncate font-semibold text-foreground text-xs min-w-0\">{col.title}</span>\n {filteredColIds.has(col.id) && (\n <span className=\"text-[10px] text-primary shrink-0\" title=\"Filtered\" data-filtered=\"true\">⏷</span>\n )}\n <span className=\"text-[10px] text-muted-foreground/70 font-mono font-normal shrink-0\">({col.key})</span>\n </div>\n {/* Column Resize Handle */}\n <div\n className=\"col-resize-handle\"\n style={{ position: 'absolute', top: 0, bottom: 0, width: 12, right: -6, cursor: 'col-resize', zIndex: 20, display: 'flex', justifyContent: 'center', touchAction: 'none' }}\n onMouseEnter={() => setHoveredColId(col.id)}\n onMouseLeave={() => setHoveredColId((cur) => cur === col.id ? null : cur)}\n onMouseDown={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setResizingColId(col.id);\n setResizeStartX(e.clientX);\n setResizeStartWidth(col.width || 130);\n }}\n onDoubleClick={(e) => handleResizeDblClick(col.id, cIdx, e)}\n role=\"separator\"\n aria-orientation=\"vertical\"\n >\n <div\n className=\"col-resize-handle-line\"\n style={{\n width: 2,\n height: '100%',\n pointerEvents: 'none',\n transition: 'background-color 150ms ease',\n backgroundColor: resizingColId === col.id ? 'var(--primary, #6366f1)' : hoveredColId === col.id ? 'color-mix(in srgb, var(--primary, #6366f1) 75%, transparent)' : 'transparent'\n }}\n />\n </div>\n </th>\n ))}\n {onAddColumnClick && (\n <th\n className=\"w-10 min-w-[2.5rem] px-1 text-center bg-muted/40 hover:bg-muted cursor-pointer transition-colors\"\n onClick={onAddColumnClick}\n title=\"Add Column\"\n >\n <span className=\"text-xs font-bold text-muted-foreground\">+</span>\n </th>\n )}\n </tr>\n </thead>\n <tbody>\n {view.rows.map((viewRow) => {\n if (viewRow.kind === 'group') {\n return (\n <SpreadsheetGroupRow\n key={`group:${viewRow.group.key}`}\n group={viewRow.group}\n columns={view.columns}\n groupColId={state.document.table?.grouping?.colId ?? ''}\n onToggle={state.toggleGroupCollapsed}\n trailingCell={!!onAddColumnClick}\n />\n );\n }\n const displayRowIndex = viewRow.index;\n const selection = state.selectedRange ? normalizeRange(state.selectedRange) : null;\n return (\n <tr\n key={viewRow.row.id}\n data-row={displayRowIndex}\n className={`border-b border-border hover:bg-muted/10 transition-colors ${viewRow.section !== 'body' ? 'bg-muted/30 font-semibold' : ''}`}\n style={{ height: viewRow.row.height || 32 }}\n >\n <td\n className=\"w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none\"\n style={viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop, zIndex: 15 } : undefined}\n >\n {displayRowIndex + 1}\n </td>\n {view.columns.map((viewCol) => {\n // A merged cell renders its top-left cell, spanning the merge.\n const span = view.getCellSpan(displayRowIndex, viewCol.index);\n if (!span) return null;\n const rIdx = span.source.row;\n const cIdx = span.source.col;\n const row = state.document.rows[rIdx];\n const col = state.document.columns[cIdx];\n const cell = state.getCell(row.id, col.id);\n const selected = isCellSelected(rIdx, cIdx);\n const active = isActiveCell(rIdx, cIdx);\n const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;\n\n const inFillPreview = !!fillTarget && !selected && rangeContains(fillTarget, displayRowIndex, viewCol.index);\n const showFillHandle =\n !readOnly &&\n !isEditing &&\n !!selection &&\n (span.merge\n ? rangeContains(span.merge, selection.endRow, selection.endCol)\n : selection.endRow === rIdx && selection.endCol === cIdx);\n\n return (\n <td\n key={viewCol.column.id}\n data-row={rIdx}\n data-col={cIdx}\n rowSpan={span.rowSpan}\n colSpan={span.colSpan}\n className={`relative border-r border-border px-2 py-1 truncate max-w-0 text-foreground transition-colors ${\n selected ? 'bg-primary/10' : ''\n } ${active ? 'ring-2 ring-primary ring-inset z-10' : ''} ${viewCol.header ? 'font-semibold' : ''}`}\n style={{\n maxWidth: 0,\n overflow: 'hidden',\n ...frozenCellStyle(viewRow, viewCol),\n ...(inFillPreview ? { outline: '1px dashed var(--primary, #6366f1)', outlineOffset: -1 } : {})\n }}\n onClick={(e) => handleCellClick(rIdx, cIdx, e)}\n onDoubleClick={() => handleCellDblClick(rIdx, cIdx)}\n onContextMenu={(e) => handleCellContextMenu(rIdx, cIdx, e)}\n onMouseOver={() => extendFill(displayRowIndex, viewCol.index)}\n >\n {isEditing ? (\n <>\n <input\n ref={cellInputRef}\n type=\"text\"\n className=\"absolute inset-0 w-full h-full px-2 py-1 bg-background text-foreground outline-none font-sans text-xs border-2 border-primary z-20\"\n value={state.draftValue}\n onChange={(e) => state.setDraftValue(e.target.value)}\n onBlur={() => state.commitEditing()}\n onFocus={(e) => {\n // Caret after the draft (e.g. the key that started editing).\n const end = e.currentTarget.value.length;\n e.currentTarget.setSelectionRange(end, end);\n }}\n autoFocus\n />\n <FormulaHints inputRef={cellInputRef} value={state.draftValue} onAccept={state.setDraftValue} />\n </>\n ) : customCellRenderer ? (\n customCellRenderer({ row, col, cell })\n ) : (\n <span\n className={`truncate block max-w-full ${cell.error ? 'text-destructive font-semibold' : ''}`}\n title={cell.error ? cell.errorMessage ?? cell.error : undefined}\n >\n {cell.error || (cell.value ?? '')}\n </span>\n )}\n {activeSpill && rangeContains(activeSpill.range, rIdx, cIdx) && (\n <span aria-hidden=\"true\" className=\"spreadsheet-spill-border\" style={spillBorderStyle(activeSpill.range, rIdx, cIdx)} />\n )}\n {showFillHandle && (\n <div\n className=\"spreadsheet-fill-handle\"\n aria-label=\"Fill handle\"\n onMouseDown={startFill}\n onClick={(e) => e.stopPropagation()}\n style={{ position: 'absolute', right: 0, bottom: 0, width: 7, height: 7, background: 'var(--primary, #6366f1)', cursor: 'crosshair', zIndex: 25 }}\n />\n )}\n </td>\n );\n })}\n {onAddColumnClick && <td className=\"w-10 min-w-[2.5rem] bg-muted/10 border-r border-border\" />}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n {menu && (\n <SpreadsheetContextMenu\n items={menu.items}\n x={menu.x}\n y={menu.y}\n onClose={() => {\n setMenu(null);\n gridRef.current?.focus();\n }}\n />\n )}\n <style>{`\n .col-resize-handle:hover .col-resize-handle-line {\n background-color: var(--primary, #6366f1);\n opacity: 0.75;\n }\n .col-resize-handle.active .col-resize-handle-line {\n background-color: var(--primary, #6366f1);\n opacity: 1;\n }\n table.table-fixed th {\n overflow: hidden;\n }\n table.table-fixed td {\n max-width: 0;\n overflow: hidden;\n }\n `}</style>\n </div>\n );\n};\n","import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { clampMenuPosition, type SpreadsheetMenuItem } from '@pixerate/editor/spreadsheet';\n\n// Gap kept between the menu and the viewport edges.\nconst VIEWPORT_MARGIN = 4;\n\nexport interface SpreadsheetContextMenuProps {\n items: SpreadsheetMenuItem[];\n x: number;\n y: number;\n onClose: () => void;\n}\n\n/** The table context menu (sort, filter, freeze, hide, merge, categories, transpose). */\nexport const SpreadsheetContextMenu: React.FC<SpreadsheetContextMenuProps> = ({ items, x, y, onClose }) => {\n const menuRef = useRef<HTMLDivElement>(null);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const [position, setPosition] = useState({ x, y });\n\n // Keep the (fixed) menu inside the viewport: near the right or bottom edge\n // it opens to the left of / above the pointer instead of being cut off.\n useLayoutEffect(() => {\n const menu = menuRef.current;\n if (!menu || typeof window === 'undefined') return;\n const { width, height } = menu.getBoundingClientRect();\n const next = clampMenuPosition(\n { x, y },\n { width, height },\n { width: window.innerWidth, height: window.innerHeight },\n VIEWPORT_MARGIN\n );\n setPosition((prev) => (prev.x === next.x && prev.y === next.y ? prev : next));\n }, [x, y, items]);\n\n useEffect(() => {\n const handlePointer = (e: MouseEvent) => {\n if (!menuRef.current?.contains(e.target as Node)) onCloseRef.current();\n };\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onCloseRef.current();\n };\n window.addEventListener('mousedown', handlePointer);\n window.addEventListener('keydown', handleKey);\n return () => {\n window.removeEventListener('mousedown', handlePointer);\n window.removeEventListener('keydown', handleKey);\n };\n }, []);\n\n return (\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label=\"Table actions\"\n className=\"fixed z-50 min-w-[14rem] rounded-md border border-border bg-popover py-1 text-xs text-popover-foreground shadow-lg\"\n style={{\n left: position.x,\n top: position.y,\n maxHeight: `calc(100vh - ${VIEWPORT_MARGIN * 2}px)`,\n overflowY: 'auto',\n background: 'var(--popover, var(--background, #fff))'\n }}\n onContextMenu={(e) => e.preventDefault()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {items.map((item) => (\n <React.Fragment key={item.id}>\n {item.separatorBefore && <div role=\"separator\" className=\"my-1 h-px bg-border\" />}\n <button\n type=\"button\"\n role=\"menuitem\"\n data-action={item.id}\n disabled={item.disabled}\n className=\"block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent\"\n onClick={() => {\n onClose();\n item.run();\n }}\n >\n {item.label}\n </button>\n </React.Fragment>\n ))}\n </div>\n );\n};\n","import React from 'react';\nimport type { SpreadsheetRowGroup, SpreadsheetViewColumn } from '@pixerate/editor/spreadsheet';\n\nexport interface SpreadsheetGroupRowProps {\n group: SpreadsheetRowGroup;\n columns: SpreadsheetViewColumn[];\n /** Column the rows are grouped by: shows the group label and toggle. */\n groupColId: string;\n onToggle: (key: string) => void;\n /** Render a trailing cell for the \"add column\" column. */\n trailingCell?: boolean;\n}\n\nconst formatSummary = (value: number | null) => (value === null ? '–' : String(value));\n\n/** A category header row: collapse toggle, label, row count and per-column summaries. */\nexport const SpreadsheetGroupRow: React.FC<SpreadsheetGroupRowProps> = ({\n group,\n columns,\n groupColId,\n onToggle,\n trailingCell\n}) => {\n // The label goes in the grouping column, or the first column when that one is hidden.\n const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;\n return (\n <tr className=\"border-b border-border bg-muted/40 font-semibold\" data-group-key={group.key} style={{ height: 28 }}>\n <td className=\"w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center\">\n <button\n type=\"button\"\n aria-label={`${group.collapsed ? 'Expand' : 'Collapse'} group ${group.label}`}\n aria-expanded={!group.collapsed}\n className=\"h-5 w-5 rounded text-[10px] text-muted-foreground hover:bg-muted\"\n onClick={(e) => {\n e.stopPropagation();\n onToggle(group.key);\n }}\n >\n {group.collapsed ? '▸' : '▾'}\n </button>\n </td>\n {columns.map(({ column }) => {\n const summary = group.summaries[column.id];\n return (\n <td key={column.id} className=\"border-r border-border px-2 py-1 truncate max-w-0 text-foreground\" style={{ maxWidth: 0, overflow: 'hidden' }}>\n {column.id === labelColId ? (\n <span className=\"truncate\">\n {group.label} <span className=\"font-normal text-muted-foreground\">({group.rowIndices.length})</span>\n </span>\n ) : summary !== undefined ? (\n <span className=\"truncate\" data-summary={column.id}>{formatSummary(summary)}</span>\n ) : null}\n </td>\n );\n })}\n {trailingCell && <td className=\"w-10 min-w-[2.5rem] bg-muted/10 border-r border-border\" />}\n </tr>\n );\n};\n","import { useCallback, useEffect, useRef, useState, type RefObject } from 'react';\nimport {\n computeFillTarget,\n normalizeRange,\n type CellRange\n} from '@pixerate/editor/spreadsheet';\nimport type { useSpreadsheetEditor } from './useSpreadsheetEditor';\n\ntype SpreadsheetState = ReturnType<typeof useSpreadsheetEditor>;\n\n/** True when focus is in the grid itself, not in a text input (cell editor, formula bar). */\nfunction gridHasFocus(grid: HTMLElement | null): boolean {\n if (!grid || typeof document === 'undefined') return false;\n const active = document.activeElement;\n if (!active || !grid.contains(active)) return false;\n return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);\n}\n\n/**\n * Copy and paste for the grid. Copy writes TSV, an HTML table and the\n * lossless `application/x.pixerate.spreadsheet+json` format; paste prefers\n * that format, then HTML, then TSV.\n *\n * The listeners are on `document`: with no text selection the browser fires\n * `copy`/`paste` at `<body>`, not at the focused grid. Text inputs inside the\n * grid keep native copy/paste.\n */\nexport function useSpreadsheetClipboard(\n gridRef: RefObject<HTMLElement | null>,\n state: SpreadsheetState,\n readOnly: boolean\n) {\n const stateRef = useRef(state);\n stateRef.current = state;\n const readOnlyRef = useRef(readOnly);\n readOnlyRef.current = readOnly;\n // Set when a copy event wrote the selection, so the keyboard fallback is skipped.\n const copiedRef = useRef(false);\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n const handleCopy = (e: ClipboardEvent) => {\n const s = stateRef.current;\n if (!gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData || !s.selectedRange) return;\n for (const [type, data] of Object.entries(s.copyToClipboardData(s.selectedRange))) {\n e.clipboardData.setData(type, data);\n }\n copiedRef.current = true;\n e.preventDefault();\n };\n const handlePaste = (e: ClipboardEvent) => {\n const s = stateRef.current;\n if (readOnlyRef.current || !gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData) return;\n if (s.pasteClipboardData(e.clipboardData)) e.preventDefault();\n };\n document.addEventListener('copy', handleCopy);\n document.addEventListener('paste', handlePaste);\n return () => {\n document.removeEventListener('copy', handleCopy);\n document.removeEventListener('paste', handlePaste);\n };\n }, [gridRef]);\n\n /**\n * Call on Mod+C (without preventing default). The browser normally follows\n * with a `copy` event; where it doesn't (no selection in some browsers),\n * the selection is written as plain TSV instead.\n */\n const copyShortcutFallback = useCallback(() => {\n copiedRef.current = false;\n setTimeout(() => {\n if (copiedRef.current) return;\n const s = stateRef.current;\n // Rejected when clipboard access is denied; nothing else to fall back to.\n Promise.resolve(navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange))).catch(() => {});\n }, 0);\n }, []);\n\n return { copyShortcutFallback };\n}\n\n/**\n * Fill handle dragging: press on the handle, move over cells, release to\n * autofill from the selection into the dragged range (one undo step).\n */\nexport function useFillHandle(state: SpreadsheetState) {\n const [drag, setDrag] = useState<{ source: CellRange; target: CellRange | null } | null>(null);\n const dragRef = useRef(drag);\n dragRef.current = drag;\n const stateRef = useRef(state);\n stateRef.current = state;\n const dragging = drag !== null;\n\n useEffect(() => {\n if (!dragging) return;\n const handleMouseUp = () => {\n const current = dragRef.current;\n setDrag(null);\n if (current?.target) stateRef.current.autofill(current.source, current.target);\n };\n window.addEventListener('mouseup', handleMouseUp);\n return () => window.removeEventListener('mouseup', handleMouseUp);\n }, [dragging]);\n\n const startFill = useCallback((e: { preventDefault(): void; stopPropagation(): void }) => {\n e.preventDefault();\n e.stopPropagation();\n const range = stateRef.current.selectedRange;\n if (range) setDrag({ source: normalizeRange(range), target: null });\n }, []);\n\n const extendFill = useCallback((row: number, col: number) => {\n const current = dragRef.current;\n if (!current) return;\n setDrag({ source: current.source, target: computeFillTarget(current.source, { row, col }) });\n }, []);\n\n return { fillTarget: drag?.target ?? null, isFilling: dragging, startFill, extendFill };\n}\n","import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { applyFormulaSuggestion, getFormulaHints } from '@pixerate/editor/spreadsheet';\n\nexport interface FormulaHintsProps {\n /** The input being edited (a cell editor or the formula bar). */\n inputRef: React.RefObject<HTMLInputElement | null>;\n /** The input's current value. */\n value: string;\n /** Called with the new value when a suggestion is accepted. */\n onAccept: (value: string) => void;\n /** Maximum number of function suggestions (default 8). */\n limit?: number;\n}\n\n/**\n * Formula autocomplete for an input: while the value starts with `=`, lists\n * functions matching the name at the caret (name, signature, description) and,\n * inside a call, shows the signature with the current argument highlighted.\n *\n * Keys are handled on the input itself, before the grid sees them: ArrowUp /\n * ArrowDown move the selection, Tab accepts it, Escape closes the list.\n * Enter is left alone so it still commits the cell.\n */\nexport const FormulaHints: React.FC<FormulaHintsProps> = ({ inputRef, value, onAccept, limit = 8 }) => {\n const [caret, setCaret] = useState<number | null>(null);\n const [focused, setFocused] = useState(false);\n const [selected, setSelected] = useState(0);\n const [dismissed, setDismissed] = useState(false);\n const [position, setPosition] = useState<{ top: number; left: number; width: number } | null>(null);\n const pendingCaret = useRef<number | null>(null);\n\n const hints = useMemo(\n () => getFormulaHints(value, caret ?? value.length, { limit }),\n [value, caret, limit],\n );\n const suggestions = dismissed ? [] : hints.suggestions;\n const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));\n const visible = focused && value.trimStart().startsWith('=') && (suggestions.length > 0 || !!hints.activeCall);\n\n // The key listener reads the latest state through a ref.\n const latest = useRef({ suggestions, selected: selectedIndex, value, caret, onAccept });\n latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };\n\n const accept = (index: number) => {\n const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;\n const suggestion = list[index];\n if (!suggestion) return;\n const next = applyFormulaSuggestion(current, at ?? current.length, suggestion.name);\n pendingCaret.current = next.caret;\n commit(next.value);\n };\n\n useEffect(() => {\n const input = inputRef.current;\n if (!input) return;\n const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);\n const onInput = () => {\n setDismissed(false);\n setSelected(0);\n syncCaret();\n };\n const onFocus = () => {\n setFocused(true);\n syncCaret();\n };\n const onBlur = () => setFocused(false);\n // A native listener on the input runs before React's delegated handlers,\n // so stopping propagation keeps these keys away from the grid.\n const onKeyDown = (e: KeyboardEvent) => {\n const { suggestions: list } = latest.current;\n if (list.length === 0) return;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n e.stopPropagation();\n const step = e.key === 'ArrowDown' ? 1 : -1;\n setSelected((i) => (i + step + list.length) % list.length);\n } else if (e.key === 'Tab' && !e.shiftKey) {\n e.preventDefault();\n e.stopPropagation();\n accept(latest.current.selected);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n setDismissed(true);\n }\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('keyup', syncCaret);\n input.addEventListener('click', syncCaret);\n input.addEventListener('select', syncCaret);\n input.addEventListener('focus', onFocus);\n input.addEventListener('blur', onBlur);\n input.addEventListener('keydown', onKeyDown);\n // Inputs focused on mount (autoFocus) fired `focus` before this effect ran.\n if (typeof document !== 'undefined' && document.activeElement === input) onFocus();\n return () => {\n input.removeEventListener('input', onInput);\n input.removeEventListener('keyup', syncCaret);\n input.removeEventListener('click', syncCaret);\n input.removeEventListener('select', syncCaret);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('blur', onBlur);\n input.removeEventListener('keydown', onKeyDown);\n };\n }, [inputRef]);\n\n // After accepting, put the caret inside the inserted parenthesis.\n useLayoutEffect(() => {\n const input = inputRef.current;\n const at = pendingCaret.current;\n if (!input || at === null || input.value !== value) return;\n pendingCaret.current = null;\n input.setSelectionRange(at, at);\n setCaret(at);\n setSelected(0);\n }, [value, inputRef]);\n\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (!visible || !input) return;\n const rect = input.getBoundingClientRect();\n setPosition({ top: rect.bottom + 2, left: rect.left, width: rect.width });\n }, [visible, value, inputRef]);\n\n if (!visible) return null;\n\n const { activeCall } = hints;\n return (\n <div\n data-formula-hints=\"\"\n className=\"rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs font-sans overflow-hidden\"\n style={{\n position: 'fixed',\n top: position?.top ?? 0,\n left: position?.left ?? 0,\n minWidth: Math.max(260, position?.width ?? 0),\n maxWidth: 440,\n zIndex: 50,\n visibility: position ? 'visible' : 'hidden'\n }}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeCall && (\n <div data-formula-signature=\"\" className=\"px-2 py-1.5 border-b border-border bg-muted/30\">\n <div className=\"font-mono\">\n {activeCall.parts.map((part, i) => (\n <span\n key={i}\n data-active={part.active ? '' : undefined}\n className={part.active ? 'font-bold text-primary underline' : ''}\n >\n {part.text}\n </span>\n ))}\n </div>\n <div className=\"mt-0.5 text-muted-foreground\">\n {activeCall.argument ? (\n <>\n <span className=\"font-semibold\">{activeCall.argument.name}</span>: {activeCall.argument.description}\n </>\n ) : (\n activeCall.description\n )}\n </div>\n </div>\n )}\n {suggestions.length > 0 && (\n <ul role=\"listbox\" aria-label=\"Formula suggestions\" className=\"max-h-64 overflow-auto py-1 m-0 list-none p-0\">\n {suggestions.map((s, i) => (\n <li\n key={s.name}\n role=\"option\"\n aria-selected={i === selectedIndex}\n className={`cursor-pointer px-2 py-1 ${i === selectedIndex ? 'bg-primary/10' : 'hover:bg-muted/50'}`}\n onMouseEnter={() => setSelected(i)}\n onMouseDown={(e) => {\n // Keep focus in the input so the edit isn't committed by blur.\n e.preventDefault();\n accept(i);\n }}\n >\n <div className=\"font-mono font-semibold text-foreground\">{s.signature}</div>\n <div className=\"text-muted-foreground truncate\">{s.description}</div>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n"],"mappings":";AAAA,SAAS,UAAU,QAAQ,aAAa,eAAe;AACvD;AAAA,EACE;AAAA,EACA;AAAA,OAQK;AAEA,SAAS,qBAAqB,UAAwC,CAAC,GAAG;AAE/E,QAAM,aAAa,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,aAAa,OAIhB,CAAC,CAAC;AAIL,QAAM,CAAC,UAAU,IAAI;AAAA,IACnB,MACE,IAAI,sBAAsB;AAAA,MACxB,GAAG;AAAA,MACH,kBAAkB,CAAC,YAAY;AAC7B,mBAAW,QAAQ,SAAS,EAAE,GAAG,QAAQ,CAAC;AAC1C,mBAAW,QAAQ,mBAAmB,OAAO;AAAA,MAC/C;AAAA,MACA,mBAAmB,CAAC,QAAQ,UAAU;AACpC,mBAAW,QAAQ,gBAAgB,MAAM;AACzC,mBAAW,QAAQ,mBAAmB,KAAK;AAC3C,mBAAW,QAAQ,oBAAoB,QAAQ,KAAK;AAAA,MACtD;AAAA,MACA,cAAc,CAAC,OAAO,OAAO,KAAK,UAAU;AAC1C,mBAAW,QAAQ,eAAe,OAAO,OAAO,KAAK,KAAK;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACL;AAEA,QAAM,CAAC,KAAK,MAAM,IAAI,SAA8B,OAAO,EAAE,GAAG,WAAW,SAAS,EAAE;AACtF,QAAM,CAAC,YAAY,aAAa,IAAI,SAAgC,WAAW,UAAU;AACzF,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA2B,WAAW,aAAa;AAC7F,QAAM,CAAC,aAAa,cAAc,IAAI,SAAgC,IAAI;AAC1E,QAAM,CAAC,YAAY,aAAa,IAAI,SAAiB,EAAE;AACvD,aAAW,UAAU,EAAE,QAAQ,eAAe,iBAAiB;AAI/D,QAAM,gBAAgB,YAAY,CAAC,UAAkB;AACnD,eAAW,aAAa;AACxB,kBAAc,KAAK;AAAA,EACrB,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,eAAe,YAAY,CAAC,OAAe,OAAe,QAAgB;AAC9E,eAAW,aAAa,OAAO,OAAO,GAAG;AACzC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,aAAa,YAAY,CAAC,KAAa,KAAa,kBAAkB,UAAU;AACpF,eAAW,WAAW,KAAK,KAAK,eAAe;AAC/C,kBAAc,WAAW,UAAU;AACnC,qBAAiB,WAAW,aAAa;AAAA,EAC3C,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,cAAc,YAAY,CAAC,UAAqB;AACpD,eAAW,YAAY,KAAK;AAC5B,qBAAiB,WAAW,aAAa;AAAA,EAC3C,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,eAAe,YAAY,CAAC,KAAc,KAAc,eAAwB;AACpF,eAAW,aAAa,KAAK,KAAK,UAAU;AAC5C,kBAAc,WAAW,UAAU;AACnC,mBAAe,WAAW,WAAW;AACrC,kBAAc,WAAW,UAAU;AAAA,EACrC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,gBAAgB,YAAY,CAAC,QAAiB;AAClD,eAAW,cAAc,GAAG;AAC5B,mBAAe,IAAI;AACnB,kBAAc,EAAE;AAChB,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,gBAAgB,YAAY,MAAM;AACtC,eAAW,cAAc;AACzB,mBAAe,IAAI;AACnB,kBAAc,EAAE;AAAA,EAClB,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,aAAa,YAAY,CAAC,KAAuC,SAAS,UAAU;AACxF,eAAW,WAAW,KAAK,MAAM;AACjC,kBAAc,WAAW,UAAU;AACnC,qBAAiB,WAAW,aAAa;AAAA,EAC3C,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,eAAe,YAAY,CAAC,OAAe,WAAwC;AACvF,eAAW,aAAa,OAAO,MAAM;AACrC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,eAAe,YAAY,CAAC,UAAkB;AAClD,eAAW,aAAa,KAAK;AAC7B,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,YAAY,YAAY,CAAC,OAAe,WAAqC;AACjF,eAAW,UAAU,OAAO,MAAM;AAClC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,YAAY,YAAY,CAAC,UAAkB;AAC/C,eAAW,UAAU,KAAK;AAC1B,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,iBAAiB,YAAY,CAAC,OAAe,UAAkB;AACnE,eAAW,eAAe,OAAO,KAAK;AACtC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,qBAAqB,YAAY,CAAC,OAAe,gBAAyB;AAC9E,eAAW,mBAAmB,OAAO,WAAW;AAChD,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,qBAAqB,YAAY,CAAC,OAA8B;AACpE,eAAW,mBAAmB,EAAE;AAChC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,uBAAuB,YAAY,CAAC,OAA2B;AACnE,eAAW,qBAAqB,EAAE;AAClC,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,iBAAiB,YAAY,MAAM;AACvC,eAAW,eAAe;AAC1B,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,OAAO,YAAY,MAAM;AAC7B,eAAW,KAAK;AAChB,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,OAAO,YAAY,MAAM;AAC7B,eAAW,KAAK;AAChB,WAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAKf,QAAM,eAAe,QAAQ,MAAM,4BAA4B,UAAU,GAAG,CAAC,UAAU,CAAC;AAIxF,QAAM,YAAY,QAAQ,MAAM,WAAW,aAAa,GAAG,CAAC,YAAY,GAAG,CAAC;AAE5E,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,CAAC,OAAe,UAAkB,WAAW,QAAQ,OAAO,KAAK;AAAA,IAC1E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,CAACA,cAAkC;AAC/C,iBAAW,aAAaA,SAAQ;AAChC,aAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AACjC,oBAAc,IAAI;AAClB,uBAAiB,IAAI;AACrB,qBAAe,IAAI;AACnB,oBAAc,EAAE;AAAA,IAClB;AAAA,IACA,oBAAoB,MAAM;AACxB,iBAAW,mBAAmB;AAC9B,iBAAW,eAAe;AAC1B,aAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,CAAC,UAA6B,WAAW,YAAY,KAAK;AAAA,IACvE,eAAe,CAAC,SAAiB;AAC/B,iBAAW,cAAc,IAAI;AAC7B,aAAO,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,IACnC;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACpNA,SAAgB,UAAAC,SAAQ,YAAAC,WAAU,WAAAC,UAAS,aAAAC,YAAW,eAAAC,oBAAmB;AACzE;AAAA,EACE;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,OAQK;;;ACbP,OAAO,SAAS,WAAW,iBAAiB,UAAAC,SAAQ,YAAAC,iBAAgB;AACpE,SAAS,yBAAmD;AAkEpD,SAC2B,KAD3B;AA/DR,IAAM,kBAAkB;AAUjB,IAAM,yBAAgE,CAAC,EAAE,OAAO,GAAG,GAAG,QAAQ,MAAM;AACzG,QAAM,UAAUD,QAAuB,IAAI;AAC3C,QAAM,aAAaA,QAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,EAAE,GAAG,EAAE,CAAC;AAIjD,kBAAgB,MAAM;AACpB,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,QAAQ,OAAO,WAAW,YAAa;AAC5C,UAAM,EAAE,OAAO,OAAO,IAAI,KAAK,sBAAsB;AACrD,UAAM,OAAO;AAAA,MACX,EAAE,GAAG,EAAE;AAAA,MACP,EAAE,OAAO,OAAO;AAAA,MAChB,EAAE,OAAO,OAAO,YAAY,QAAQ,OAAO,YAAY;AAAA,MACvD;AAAA,IACF;AACA,gBAAY,CAAC,SAAU,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,OAAO,IAAK;AAAA,EAC9E,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC;AAEhB,YAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,MAAkB;AACvC,UAAI,CAAC,QAAQ,SAAS,SAAS,EAAE,MAAc,EAAG,YAAW,QAAQ;AAAA,IACvE;AACA,UAAM,YAAY,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,SAAU,YAAW,QAAQ;AAAA,IAC7C;AACA,WAAO,iBAAiB,aAAa,aAAa;AAClD,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM;AACX,aAAO,oBAAoB,aAAa,aAAa;AACrD,aAAO,oBAAoB,WAAW,SAAS;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAU;AAAA,MACV,OAAO;AAAA,QACL,MAAM,SAAS;AAAA,QACf,KAAK,SAAS;AAAA,QACd,WAAW,gBAAgB,kBAAkB,CAAC;AAAA,QAC9C,WAAW;AAAA,QACX,YAAY;AAAA,MACd;AAAA,MACA,eAAe,CAAC,MAAM,EAAE,eAAe;AAAA,MACvC,WAAW,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAEnC,gBAAM,IAAI,CAAC,SACV,qBAAC,MAAM,UAAN,EACE;AAAA,aAAK,mBAAmB,oBAAC,SAAI,MAAK,aAAY,WAAU,uBAAsB;AAAA,QAC/E;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,eAAa,KAAK;AAAA,YAClB,UAAU,KAAK;AAAA,YACf,WAAU;AAAA,YACV,SAAS,MAAM;AACb,sBAAQ;AACR,mBAAK,IAAI;AAAA,YACX;AAAA,YAEC,eAAK;AAAA;AAAA,QACR;AAAA,WAdmB,KAAK,EAe1B,CACD;AAAA;AAAA,EACH;AAEJ;;;AC1DM,gBAAAC,MAmBsB,QAAAC,aAnBtB;AAfN,IAAM,gBAAgB,CAAC,UAA0B,UAAU,OAAO,WAAM,OAAO,KAAK;AAG7E,IAAM,sBAA0D,CAAC;AAAA,EACtE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,aAAa,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,UAAU,IAAI,aAAa,QAAQ,CAAC,GAAG,OAAO;AACrG,SACA,gBAAAA,MAAC,QAAG,WAAU,oDAAmD,kBAAgB,MAAM,KAAK,OAAO,EAAE,QAAQ,GAAG,GAC9G;AAAA,oBAAAD,KAAC,QAAG,WAAU,oFACZ,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY,GAAG,MAAM,YAAY,WAAW,UAAU,UAAU,MAAM,KAAK;AAAA,QAC3E,iBAAe,CAAC,MAAM;AAAA,QACtB,WAAU;AAAA,QACV,SAAS,CAAC,MAAM;AACd,YAAE,gBAAgB;AAClB,mBAAS,MAAM,GAAG;AAAA,QACpB;AAAA,QAEC,gBAAM,YAAY,WAAM;AAAA;AAAA,IAC3B,GACF;AAAA,IACC,QAAQ,IAAI,CAAC,EAAE,OAAO,MAAM;AAC3B,YAAM,UAAU,MAAM,UAAU,OAAO,EAAE;AACzC,aACE,gBAAAA,KAAC,QAAmB,WAAU,qEAAoE,OAAO,EAAE,UAAU,GAAG,UAAU,SAAS,GACxI,iBAAO,OAAO,aACb,gBAAAC,MAAC,UAAK,WAAU,YACb;AAAA,cAAM;AAAA,QAAM;AAAA,QAAC,gBAAAA,MAAC,UAAK,WAAU,qCAAoC;AAAA;AAAA,UAAE,MAAM,WAAW;AAAA,UAAO;AAAA,WAAC;AAAA,SAC/F,IACE,YAAY,SACd,gBAAAD,KAAC,UAAK,WAAU,YAAW,gBAAc,OAAO,IAAK,wBAAc,OAAO,GAAE,IAC1E,QAPG,OAAO,EAQhB;AAAA,IAEJ,CAAC;AAAA,IACA,gBAAgB,gBAAAA,KAAC,QAAG,WAAU,0DAAyD;AAAA,KAC1F;AAEF;;;AC1DA,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgC;AACzE;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAMP,SAAS,aAAa,MAAmC;AACvD,MAAI,CAAC,QAAQ,OAAO,aAAa,YAAa,QAAO;AACrD,QAAM,SAAS,SAAS;AACxB,MAAI,CAAC,UAAU,CAAC,KAAK,SAAS,MAAM,EAAG,QAAO;AAC9C,SAAO,EAAE,kBAAkB,oBAAoB,kBAAkB;AACnE;AAWO,SAAS,wBACd,SACA,OACA,UACA;AACA,QAAM,WAAWD,QAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,cAAcA,QAAO,QAAQ;AACnC,cAAY,UAAU;AAEtB,QAAM,YAAYA,QAAO,KAAK;AAE9B,EAAAD,WAAU,MAAM;AACd,QAAI,OAAO,aAAa,YAAa;AACrC,UAAM,aAAa,CAAC,MAAsB;AACxC,YAAM,IAAI,SAAS;AACnB,UAAI,CAAC,aAAa,QAAQ,OAAO,KAAK,EAAE,eAAe,CAAC,EAAE,iBAAiB,CAAC,EAAE,cAAe;AAC7F,iBAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,EAAE,oBAAoB,EAAE,aAAa,CAAC,GAAG;AACjF,UAAE,cAAc,QAAQ,MAAM,IAAI;AAAA,MACpC;AACA,gBAAU,UAAU;AACpB,QAAE,eAAe;AAAA,IACnB;AACA,UAAM,cAAc,CAAC,MAAsB;AACzC,YAAM,IAAI,SAAS;AACnB,UAAI,YAAY,WAAW,CAAC,aAAa,QAAQ,OAAO,KAAK,EAAE,eAAe,CAAC,EAAE,cAAe;AAChG,UAAI,EAAE,mBAAmB,EAAE,aAAa,EAAG,GAAE,eAAe;AAAA,IAC9D;AACA,aAAS,iBAAiB,QAAQ,UAAU;AAC5C,aAAS,iBAAiB,SAAS,WAAW;AAC9C,WAAO,MAAM;AACX,eAAS,oBAAoB,QAAQ,UAAU;AAC/C,eAAS,oBAAoB,SAAS,WAAW;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAOZ,QAAM,uBAAuBD,aAAY,MAAM;AAC7C,cAAU,UAAU;AACpB,eAAW,MAAM;AACf,UAAI,UAAU,QAAS;AACvB,YAAM,IAAI,SAAS;AAEnB,cAAQ,QAAQ,UAAU,WAAW,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAChG,GAAG,CAAC;AAAA,EACN,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,qBAAqB;AAChC;AAMO,SAAS,cAAc,OAAyB;AACrD,QAAM,CAAC,MAAM,OAAO,IAAIG,UAAiE,IAAI;AAC7F,QAAM,UAAUD,QAAO,IAAI;AAC3B,UAAQ,UAAU;AAClB,QAAM,WAAWA,QAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,WAAW,SAAS;AAE1B,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,UAAM,gBAAgB,MAAM;AAC1B,YAAM,UAAU,QAAQ;AACxB,cAAQ,IAAI;AACZ,UAAI,SAAS,OAAQ,UAAS,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,MAAM;AAAA,IAC/E;AACA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,YAAYD,aAAY,CAAC,MAA2D;AACxF,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,UAAM,QAAQ,SAAS,QAAQ;AAC/B,QAAI,MAAO,SAAQ,EAAE,QAAQ,eAAe,KAAK,GAAG,QAAQ,KAAK,CAAC;AAAA,EACpE,GAAG,CAAC,CAAC;AAEL,QAAM,aAAaA,aAAY,CAAC,KAAa,QAAgB;AAC3D,UAAM,UAAU,QAAQ;AACxB,QAAI,CAAC,QAAS;AACd,YAAQ,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AAAA,EAC7F,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,YAAY,MAAM,UAAU,MAAM,WAAW,UAAU,WAAW,WAAW;AACxF;;;ACtHA,SAAgB,aAAAI,YAAW,mBAAAC,kBAAiB,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AAC7E,SAAS,wBAAwB,uBAAuB;AAkJ1C,SAWA,UAXA,OAAAC,MAWA,QAAAC,aAXA;AA5HP,IAAM,eAA4C,CAAC,EAAE,UAAU,OAAO,UAAU,QAAQ,EAAE,MAAM;AACrG,QAAM,CAAC,OAAO,QAAQ,IAAIF,UAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,CAAC;AAC1C,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA8D,IAAI;AAClG,QAAM,eAAeD,QAAsB,IAAI;AAE/C,QAAM,QAAQD;AAAA,IACZ,MAAM,gBAAgB,OAAO,SAAS,MAAM,QAAQ,EAAE,MAAM,CAAC;AAAA,IAC7D,CAAC,OAAO,OAAO,KAAK;AAAA,EACtB;AACA,QAAM,cAAc,YAAY,CAAC,IAAI,MAAM;AAC3C,QAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,YAAY,SAAS,CAAC,CAAC;AAC5E,QAAM,UAAU,WAAW,MAAM,UAAU,EAAE,WAAW,GAAG,MAAM,YAAY,SAAS,KAAK,CAAC,CAAC,MAAM;AAGnG,QAAM,SAASC,QAAO,EAAE,aAAa,UAAU,eAAe,OAAO,OAAO,SAAS,CAAC;AACtF,SAAO,UAAU,EAAE,aAAa,UAAU,eAAe,OAAO,OAAO,SAAS;AAEhF,QAAM,SAAS,CAAC,UAAkB;AAChC,UAAM,EAAE,aAAa,MAAM,OAAO,SAAS,OAAO,IAAI,UAAU,OAAO,IAAI,OAAO;AAClF,UAAM,aAAa,KAAK,KAAK;AAC7B,QAAI,CAAC,WAAY;AACjB,UAAM,OAAO,uBAAuB,SAAS,MAAM,QAAQ,QAAQ,WAAW,IAAI;AAClF,iBAAa,UAAU,KAAK;AAC5B,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,EAAAH,WAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AACZ,UAAM,YAAY,MAAM,SAAS,MAAM,kBAAkB,MAAM,MAAM,MAAM;AAC3E,UAAM,UAAU,MAAM;AACpB,mBAAa,KAAK;AAClB,kBAAY,CAAC;AACb,gBAAU;AAAA,IACZ;AACA,UAAM,UAAU,MAAM;AACpB,iBAAW,IAAI;AACf,gBAAU;AAAA,IACZ;AACA,UAAM,SAAS,MAAM,WAAW,KAAK;AAGrC,UAAM,YAAY,CAAC,MAAqB;AACtC,YAAM,EAAE,aAAa,KAAK,IAAI,OAAO;AACrC,UAAI,KAAK,WAAW,EAAG;AACvB,UAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,WAAW;AAChD,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,cAAM,OAAO,EAAE,QAAQ,cAAc,IAAI;AACzC,oBAAY,CAAC,OAAO,IAAI,OAAO,KAAK,UAAU,KAAK,MAAM;AAAA,MAC3D,WAAW,EAAE,QAAQ,SAAS,CAAC,EAAE,UAAU;AACzC,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,eAAO,OAAO,QAAQ,QAAQ;AAAA,MAChC,WAAW,EAAE,QAAQ,UAAU;AAC7B,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,iBAAiB,SAAS,OAAO;AACvC,UAAM,iBAAiB,SAAS,SAAS;AACzC,UAAM,iBAAiB,SAAS,SAAS;AACzC,UAAM,iBAAiB,UAAU,SAAS;AAC1C,UAAM,iBAAiB,SAAS,OAAO;AACvC,UAAM,iBAAiB,QAAQ,MAAM;AACrC,UAAM,iBAAiB,WAAW,SAAS;AAE3C,QAAI,OAAO,aAAa,eAAe,SAAS,kBAAkB,MAAO,SAAQ;AACjF,WAAO,MAAM;AACX,YAAM,oBAAoB,SAAS,OAAO;AAC1C,YAAM,oBAAoB,SAAS,SAAS;AAC5C,YAAM,oBAAoB,SAAS,SAAS;AAC5C,YAAM,oBAAoB,UAAU,SAAS;AAC7C,YAAM,oBAAoB,SAAS,OAAO;AAC1C,YAAM,oBAAoB,QAAQ,MAAM;AACxC,YAAM,oBAAoB,WAAW,SAAS;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAGb,EAAAC,iBAAgB,MAAM;AACpB,UAAM,QAAQ,SAAS;AACvB,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,SAAS,OAAO,QAAQ,MAAM,UAAU,MAAO;AACpD,iBAAa,UAAU;AACvB,UAAM,kBAAkB,IAAI,EAAE;AAC9B,aAAS,EAAE;AACX,gBAAY,CAAC;AAAA,EACf,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,EAAAA,iBAAgB,MAAM;AACpB,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,WAAW,CAAC,MAAO;AACxB,UAAM,OAAO,MAAM,sBAAsB;AACzC,gBAAY,EAAE,KAAK,KAAK,SAAS,GAAG,MAAM,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC;AAAA,EAC1E,GAAG,CAAC,SAAS,OAAO,QAAQ,CAAC;AAE7B,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,EAAE,WAAW,IAAI;AACvB,SACE,gBAAAK;AAAA,IAAC;AAAA;AAAA,MACC,sBAAmB;AAAA,MACnB,WAAU;AAAA,MACV,OAAO;AAAA,QACL,UAAU;AAAA,QACV,KAAK,UAAU,OAAO;AAAA,QACtB,MAAM,UAAU,QAAQ;AAAA,QACxB,UAAU,KAAK,IAAI,KAAK,UAAU,SAAS,CAAC;AAAA,QAC5C,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,YAAY,WAAW,YAAY;AAAA,MACrC;AAAA,MACA,aAAa,CAAC,MAAM,EAAE,eAAe;AAAA,MAEpC;AAAA,sBACC,gBAAAA,MAAC,SAAI,0BAAuB,IAAG,WAAU,kDACvC;AAAA,0BAAAD,KAAC,SAAI,WAAU,aACZ,qBAAW,MAAM,IAAI,CAAC,MAAM,MAC3B,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC,eAAa,KAAK,SAAS,KAAK;AAAA,cAChC,WAAW,KAAK,SAAS,qCAAqC;AAAA,cAE7D,eAAK;AAAA;AAAA,YAJD;AAAA,UAKP,CACD,GACH;AAAA,UACA,gBAAAA,KAAC,SAAI,WAAU,gCACZ,qBAAW,WACV,gBAAAC,MAAA,YACE;AAAA,4BAAAD,KAAC,UAAK,WAAU,iBAAiB,qBAAW,SAAS,MAAK;AAAA,YAAO;AAAA,YAAG,WAAW,SAAS;AAAA,aAC1F,IAEA,WAAW,aAEf;AAAA,WACF;AAAA,QAED,YAAY,SAAS,KACpB,gBAAAA,KAAC,QAAG,MAAK,WAAU,cAAW,uBAAsB,WAAU,iDAC3D,sBAAY,IAAI,CAAC,GAAG,MACnB,gBAAAC;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,iBAAe,MAAM;AAAA,YACrB,WAAW,4BAA4B,MAAM,gBAAgB,kBAAkB,mBAAmB;AAAA,YAClG,cAAc,MAAM,YAAY,CAAC;AAAA,YACjC,aAAa,CAAC,MAAM;AAElB,gBAAE,eAAe;AACjB,qBAAO,CAAC;AAAA,YACV;AAAA,YAEA;AAAA,8BAAAD,KAAC,SAAI,WAAU,2CAA2C,YAAE,WAAU;AAAA,cACtE,gBAAAA,KAAC,SAAI,WAAU,kCAAkC,YAAE,aAAY;AAAA;AAAA;AAAA,UAZ1D,EAAE;AAAA,QAaT,CACD,GACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AJwQM,SAoMkB,YAAAE,WAnMhB,OAAAC,MADF,QAAAC,aAAA;AAlbN,IAAM,uBAAuB;AAC7B,IAAM,mBAAmB;AAGzB,SAAS,gBACP,SACA,SACiC;AACjC,MAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,OAAQ,QAAO;AAC/C,SAAO;AAAA,IACL,UAAU;AAAA,IACV,GAAI,QAAQ,SAAS,EAAE,KAAK,uBAAuB,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC1E,GAAI,QAAQ,SAAS,EAAE,MAAM,mBAAmB,QAAQ,WAAW,IAAI,CAAC;AAAA,IACxE,QAAQ,QAAQ,UAAU,QAAQ,SAAS,KAAK,QAAQ,SAAS,KAAK;AAAA,IACtE,YAAY;AAAA,EACd;AACF;AAGA,IAAM,WAAW,CAAC,SAA+C,OAAO,GAAG,eAAe,KAAK,GAAG,CAAC,GAAG,KAAK,MAAM,CAAC,KAAK;AAGvH,SAAS,iBAAiB,OAAkB,KAAa,KAAkC;AACzF,QAAM,OAAO;AACb,SAAO;AAAA,IACL,UAAU;AAAA,IACV,OAAO;AAAA,IACP,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,WAAW,QAAQ,MAAM,WAAW,OAAO;AAAA,IAC3C,cAAc,QAAQ,MAAM,SAAS,OAAO;AAAA,IAC5C,YAAY,QAAQ,MAAM,WAAW,OAAO;AAAA,IAC5C,aAAa,QAAQ,MAAM,SAAS,OAAO;AAAA,EAC7C;AACF;AAWO,IAAM,oBAAsD,CAAC;AAAA,EAClE,OAAO;AAAA,EACP,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,eAAe,qBAAqB;AAC1C,QAAM,QAAQ,iBAAiB;AAC/B,QAAM,UAAUC,QAAuB,IAAI;AAC3C,QAAM,gBAAgBA,QAAyB,IAAI;AACnD,QAAM,eAAeA,QAAyB,IAAI;AAElD,QAAM,CAAC,eAAe,gBAAgB,IAAIC,UAAwB,IAAI;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAwB,IAAI;AACpE,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,CAAC;AAClD,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,CAAC;AAG1D,QAAM,OAAO,MAAM;AACnB,QAAM,EAAE,qBAAqB,IAAI,wBAAwB,SAAS,OAAO,QAAQ;AACjF,QAAM,EAAE,YAAY,WAAW,WAAW,IAAI,cAAc,KAAK;AACjE,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAwE,IAAI;AACpG,QAAM,SAAS,MAAM,SAAS,OAAO;AACrC,QAAM,iBAAiBC;AAAA,IACrB,MAAM,IAAI,IAAI,QAAQ,UAAU,OAAO,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;AAAA,IACrE,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,wBAAwBC,aAAY,CAAC,MAAc,MAAc,MAAwB;AAC7F,QAAI,SAAU;AACd,MAAE,eAAe;AACjB,QAAI,MAAM,YAAa,OAAM,cAAc;AAC3C,QAAI,CAAC,MAAM,iBAAiB,CAAC,cAAc,MAAM,eAAe,MAAM,IAAI,GAAG;AAC3E,YAAM,WAAW,MAAM,IAAI;AAAA,IAC7B;AACA,YAAQ,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,SAAS,OAAO,wBAAwB,MAAM,YAAY,EAAE,KAAK,MAAM,KAAK,KAAK,CAAC,EAAE,CAAC;AAAA,EACpH,GAAG,CAAC,UAAU,KAAK,CAAC;AAEpB,QAAM,iBAAiBD,SAAQ,MAAM;AACnC,QAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,UAAM,MAAM,MAAM,SAAS,KAAK,MAAM,WAAW,GAAG;AACpD,UAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG;AACvD,QAAI,CAAC,OAAO,CAAC,IAAK,QAAO;AACzB,WAAO,MAAM,QAAQ,IAAI,IAAI,IAAI,EAAE,EAAE;AAAA,EACvC,GAAG,CAAC,MAAM,YAAY,MAAM,QAAQ,CAAC;AAIrC,QAAM,cAAcA;AAAA,IAClB,MAAO,MAAM,aAAa,MAAM,WAAW,WAAW,MAAM,WAAW,KAAK,MAAM,WAAW,GAAG,IAAI;AAAA;AAAA,IAEpG,CAAC,MAAM,YAAY,MAAM,YAAY,MAAM,QAAQ;AAAA,EACrD;AACA,QAAM,eAAe,eAAe,CAAC,kBAAkB,YAAY,QAAQ,SAAS,MAAM,UAAU,IAAI,YAAY,UAAU;AAE9H,QAAM,aAAaA,SAAQ,MAAM;AAC/B,QAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,UAAM,UAAU,eAAe,MAAM,WAAW,GAAG;AACnD,WAAO,GAAG,OAAO,GAAG,MAAM,WAAW,MAAM,CAAC;AAAA,EAC9C,GAAG,CAAC,MAAM,UAAU,CAAC;AAGrB,QAAM,CAAC,cAAc,eAAe,IAAID,UAAwB,IAAI;AACpE,QAAM,eAAe,MAAM,aAAa,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG,IAAI;AACvF,QAAM,qBAAqB,YAAY,CAAC,MAAM,cAAc,CAAC,CAAC,cAAc;AAE5E,EAAAG,WAAU,MAAM;AACd,oBAAgB,IAAI;AAAA,EACtB,GAAG,CAAC,MAAM,YAAY,KAAK,MAAM,YAAY,GAAG,CAAC;AAEjD,QAAM,mBAAmB,MAAM;AAC7B,QAAI,MAAM,aAAa;AACrB,YAAM,cAAc;AACpB;AAAA,IACF;AACA,QAAI,iBAAiB,QAAQ,CAAC,MAAM,WAAY;AAChD,UAAM,MAAM,MAAM,SAAS,KAAK,MAAM,WAAW,GAAG;AACpD,UAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG;AACvD,QAAI,OAAO,OAAO,CAAC,sBAAsB,iBAAiB,gBAAgB;AACxE,YAAM,aAAa,IAAI,IAAI,IAAI,IAAI,YAAY;AAAA,IACjD;AACA,oBAAgB,IAAI;AAAA,EACtB;AAEA,QAAM,kBAAkBD,aAAY,CAAC,MAAc,MAAc,MAAwB;AACvF,QAAI,MAAM,gBAAgB,MAAM,YAAY,QAAQ,QAAQ,MAAM,YAAY,QAAQ,OAAO;AAC3F,YAAM,cAAc;AAAA,IACtB;AACA,UAAM,WAAW,MAAM,MAAM,EAAE,QAAQ;AAAA,EACzC,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,qBAAqBA,aAAY,CAAC,MAAc,SAAiB;AACrE,QAAI,SAAU;AACd,UAAM,MAAM,MAAM,SAAS,QAAQ,IAAI;AACvC,QAAI,KAAK,SAAU;AACnB,UAAM,aAAa,MAAM,IAAI;AAAA,EAC/B,GAAG,CAAC,UAAU,KAAK,CAAC;AAEpB,QAAM,gBAAgBA,aAAY,CAAC,MAA2B;AAC5D,QAAI,MAAM,aAAa;AACrB,UAAI,EAAE,QAAQ,SAAS;AACrB,UAAE,eAAe;AACjB,cAAM,cAAc;AACpB,cAAM,WAAW,MAAM;AAAA,MACzB,WAAW,EAAE,QAAQ,UAAU;AAC7B,UAAE,eAAe;AACjB,cAAM,cAAc;AAAA,MACtB,WAAW,EAAE,QAAQ,OAAO;AAC1B,UAAE,eAAe;AACjB,cAAM,cAAc;AACpB,cAAM,WAAW,EAAE,WAAW,SAAS,OAAO;AAAA,MAChD,OAAO;AACL;AAAA,MACF;AAEA,cAAQ,SAAS,MAAM;AACvB;AAAA,IACF;AAEA,QAAI,CAAC,MAAM,WAAY;AAEvB,QAAI,EAAE,QAAQ,WAAW;AACvB,QAAE,eAAe;AACjB,YAAM,WAAW,MAAM,EAAE,QAAQ;AAAA,IACnC,WAAW,EAAE,QAAQ,aAAa;AAChC,QAAE,eAAe;AACjB,YAAM,WAAW,QAAQ,EAAE,QAAQ;AAAA,IACrC,WAAW,EAAE,QAAQ,aAAa;AAChC,QAAE,eAAe;AACjB,YAAM,WAAW,QAAQ,EAAE,QAAQ;AAAA,IACrC,WAAW,EAAE,QAAQ,cAAc;AACjC,QAAE,eAAe;AACjB,YAAM,WAAW,SAAS,EAAE,QAAQ;AAAA,IACtC,WAAW,EAAE,QAAQ,OAAO;AAC1B,QAAE,eAAe;AACjB,YAAM,WAAW,EAAE,WAAW,SAAS,OAAO;AAAA,IAChD,WAAW,EAAE,QAAQ,SAAS;AAC5B,QAAE,eAAe;AACjB,YAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG;AACvD,UAAI,CAAC,YAAY,CAAC,KAAK,UAAU;AAC/B,cAAM,aAAa;AAAA,MACrB;AAAA,IACF,WAAW,EAAE,QAAQ,eAAe,EAAE,QAAQ,UAAU;AACtD,UAAI,SAAU;AACd,YAAM,MAAM,MAAM,SAAS,KAAK,MAAM,WAAW,GAAG;AACpD,YAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG;AACvD,UAAI,OAAO,OAAO,CAAC,IAAI,UAAU;AAC/B,UAAE,eAAe;AACjB,cAAM,aAAa,IAAI,IAAI,IAAI,IAAI,EAAE;AAAA,MACvC;AAAA,IACF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,YAAY,MAAM,KAAK;AAElE,QAAE,eAAe;AACjB,UAAI,EAAE,UAAU;AACd,cAAM,KAAK;AAAA,MACb,OAAO;AACL,cAAM,KAAK;AAAA,MACb;AAAA,IACF,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW,EAAE,IAAI,YAAY,MAAM,KAAK;AACjE,QAAE,eAAe;AACjB,YAAM,KAAK;AAAA,IACb,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,YAAY,MAAM,KAAK;AAGlE,2BAAqB;AAAA,IACvB,WAAW,CAAC,YAAY,EAAE,IAAI,WAAW,KAAK,CAAC,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,EAAE,QAAQ;AACnF,YAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,WAAW,GAAG;AACvD,UAAI,CAAC,KAAK,UAAU;AAGlB,UAAE,eAAe;AACjB,cAAM,aAAa,MAAM,WAAW,KAAK,MAAM,WAAW,KAAK,EAAE,GAAG;AAAA,MACtE;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,oBAAoB,CAAC;AAG1C,QAAM,WAAWH,QAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,oBAAoBA,QAAO,cAAc;AAC/C,oBAAkB,UAAU;AAE5B,EAAAI,WAAU,MAAM;AACd,QAAI,CAAC,cAAe;AAEpB,QAAI,OAAO,aAAa,aAAa;AACnC,eAAS,KAAK,MAAM,SAAS;AAC7B,eAAS,KAAK,MAAM,aAAa;AAAA,IACnC;AAEA,QAAI,QAAuB;AAC3B,QAAI,eAAe;AACnB,QAAI,aAAa;AAEjB,UAAM,kBAAkB,CAAC,MAAkB;AACzC,YAAM,QAAQ,EAAE,UAAU;AAC1B,UAAI,KAAK,IAAI,KAAK,IAAI,GAAG;AACvB,qBAAa;AAAA,MACf;AACA,qBAAe,KAAK,IAAI,IAAI,mBAAmB,KAAK;AAEpD,UAAI,UAAU,MAAM;AAClB,gBAAQ,sBAAsB,MAAM;AAClC,kBAAQ;AACR,mBAAS,QAAQ,eAAe,eAAe,YAAY;AAAA,QAC7D,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM;AAC1B,UAAI,UAAU,MAAM;AAClB,6BAAqB,KAAK;AAC1B,gBAAQ;AAAA,MACV;AACA,UAAI,YAAY;AACd,iBAAS,QAAQ,eAAe,eAAe,YAAY;AAC3D,0BAAkB,UAAU,eAAe,YAAY;AAAA,MACzD;AACA,uBAAiB,IAAI;AACrB,UAAI,OAAO,aAAa,aAAa;AACnC,iBAAS,KAAK,MAAM,SAAS;AAC7B,iBAAS,KAAK,MAAM,aAAa;AAAA,MACnC;AAAA,IACF;AAEA,WAAO,iBAAiB,aAAa,eAAe;AACpD,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM;AACX,UAAI,UAAU,MAAM;AAClB,6BAAqB,KAAK;AAAA,MAC5B;AACA,UAAI,OAAO,aAAa,aAAa;AACnC,iBAAS,KAAK,MAAM,SAAS;AAC7B,iBAAS,KAAK,MAAM,aAAa;AAAA,MACnC;AACA,aAAO,oBAAoB,aAAa,eAAe;AACvD,aAAO,oBAAoB,WAAW,aAAa;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,eAAe,cAAc,gBAAgB,CAAC;AAElD,QAAM,6BAA6BD,aAAY,CAAC,IAAiB,cAAmC;AAClG,QAAI,OAAO,aAAa,YAAa,QAAO;AAE5C,QAAI,OAAO,GAAG,eAAe;AAC7B,UAAM,aAAa,GAAG;AACtB,QAAI,cAAc,WAAW,cAAc,MAAM;AAC/C,aAAO,WAAW;AAAA,IACpB;AAEA,UAAM,YAAY,GAAG,iBAA8B,+BAA+B;AAClF,cAAU,QAAQ,CAAC,SAAS;AAC1B,UAAI,KAAK,cAAc,MAAM;AAC3B,eAAO,KAAK;AAAA,MACd;AAAA,IACF,CAAC;AAED,QAAI;AACF,YAAM,QAAS,aAAa,WAAW,UAAU,IAAI,IAAI,GAAG,UAAU,IAAI;AAC1E,YAAM,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAatB,YAAM,WAAW,MAAM,iBAA8B,GAAG;AACxD,eAAS,QAAQ,CAAC,SAAS;AACzB,aAAK,MAAM,WAAW;AACtB,aAAK,MAAM,WAAW;AACtB,aAAK,MAAM,eAAe;AAC1B,aAAK,MAAM,aAAa;AACxB,YACE,KAAK,UAAU,SAAS,UAAU,KAClC,KAAK,UAAU,SAAS,SAAS,KACjC,KAAK,UAAU,SAAS,QAAQ,KAChC,KAAK,UAAU,SAAS,SAAS,KACjC,KAAK,UAAU,SAAS,QAAQ,GAChC;AACA,eAAK,MAAM,QAAQ;AACnB,eAAK,MAAM,WAAW;AAAA,QACxB;AAAA,MACF,CAAC;AAED,gBAAU,YAAY,KAAK;AAC3B,YAAM,OAAO,MAAM,sBAAsB;AACzC,gBAAU,YAAY,KAAK;AAE3B,UAAI,KAAK,QAAQ,MAAM;AACrB,eAAO,KAAK;AAAA,MACd;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA,aAAY,CAAC,OAAe,aAAqB;AACrE,UAAM,MAAM,MAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK;AAC7D,QAAI,CAAC,IAAK;AAEV,QAAI,kBAAkB;AAEtB,QAAI,QAAQ,WAAW,OAAO,aAAa,aAAa;AACtD,YAAM,QAAQ,QAAQ,QAAQ,cAAc,OAAO;AACnD,UAAI,OAAO;AAET,cAAM,KAAK,MAAM,cAAc,sBAAsB,QAAQ,IAAI;AACjE,YAAI,IAAI;AACN,gBAAM,cAAe,GAAG,qBAAqC;AAC7D,gBAAM,UAAU,2BAA2B,aAAa,QAAQ,OAAO;AACvE,4BAAkB,KAAK,IAAI,iBAAiB,UAAU,EAAE;AAAA,QAC1D;AAEA,cAAM,OAAO,MAAM,iBAAiB,UAAU;AAC9C,cAAM,cAAc,KAAK,IAAI,KAAK,QAAQ,GAAG;AAC7C,iBAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,gBAAM,KAAK,KAAK,CAAC;AACjB,gBAAM,KAAK,GAAG,cAAc,gBAAgB,QAAQ,iBAAiB;AACrE,cAAI,IAAI;AACN,kBAAM,QAAQ,2BAA2B,IAAI,QAAQ,OAAO;AAC5D,8BAAkB,KAAK,IAAI,iBAAiB,QAAQ,EAAE;AAAA,UACxD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,kBAAkB,GAAG;AACvB,YAAM,aAAa,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,eAAe,CAAC,CAAC;AACzE,YAAM,eAAe,OAAO,UAAU;AAAA,IACxC,OAAO;AACL,YAAM,qBAAqB,KAAK;AAAA,IAClC;AAEA,UAAM,aAAa,MAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK;AACpE,QAAI,cAAc,gBAAgB;AAChC,qBAAe,WAAW,IAAI,WAAW,SAAS,GAAG;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,OAAO,4BAA4B,cAAc,CAAC;AAEtD,QAAM,uBAAuBA,aAAY,CAAC,OAAe,UAAkB,MAAwB;AACjG,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,kBAAc,OAAO,QAAQ;AAAA,EAC/B,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,uBAAuBA,aAAY,CAAC,OAAe,UAAkB,MAAwB;AACjG,UAAM,SAAS,EAAE;AACjB,QAAI,QAAQ;AACV,YAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAI,KAAK,QAAQ,EAAE,WAAW,IAAI;AAChC,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,sBAAc,OAAO,QAAQ;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,iBAAiB,CAAC,MAAc,SAAiB;AACrD,QAAI,CAAC,MAAM,cAAe,QAAO;AACjC,UAAM,OAAO,KAAK,IAAI,MAAM,cAAc,UAAU,MAAM,cAAc,MAAM;AAC9E,UAAM,OAAO,KAAK,IAAI,MAAM,cAAc,UAAU,MAAM,cAAc,MAAM;AAC9E,UAAM,OAAO,KAAK,IAAI,MAAM,cAAc,UAAU,MAAM,cAAc,MAAM;AAC9E,UAAM,OAAO,KAAK,IAAI,MAAM,cAAc,UAAU,MAAM,cAAc,MAAM;AAC9E,WAAO,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ;AAAA,EACjE;AAEA,QAAM,eAAe,CAAC,MAAc,SAAiB;AACnD,WAAO,MAAM,YAAY,QAAQ,QAAQ,MAAM,YAAY,QAAQ;AAAA,EACrE;AAEA,SACE,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAU;AAAA,MACV,UAAU;AAAA,MACV,WAAW;AAAA,MACX,MAAK;AAAA,MACL,cAAW;AAAA,MAGX;AAAA,wBAAAA,MAAC,SAAI,WAAU,4FACb;AAAA,0BAAAD,KAAC,SAAI,WAAU,qIACZ,sBACH;AAAA,UACA,gBAAAA,KAAC,SAAI,WAAU,uDACb,0BAAAA,KAAC,UAAK,WAAU,oDAAmD,gBAAE,GACvE;AAAA,UACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,WAAU;AAAA,cACV,aAAY;AAAA,cACZ,cAAW;AAAA,cACX,UAAU;AAAA,cACV,sBAAoB,CAAC,MAAM,eAAe,iBAAiB,QAAQ,eAAe,SAAS;AAAA,cAC3F,OAAO,CAAC,MAAM,eAAe,iBAAiB,QAAQ,eAAe,EAAE,OAAO,mCAAmC,IAAI;AAAA,cACrH,OAAO,MAAM,cAAc,MAAM,aAAa,iBAAiB,kBAAkB;AAAA,cACjF,SAAS,MAAM;AACb,oBAAI,CAAC,MAAM,YAAa,iBAAgB,cAAc;AAAA,cACxD;AAAA,cACA,UAAU,CAAC,MAAM;AACf,oBAAI,MAAM,aAAa;AACrB,wBAAM,cAAc,EAAE,OAAO,KAAK;AAAA,gBACpC,WAAW,MAAM,YAAY;AAC3B,kCAAgB,EAAE,OAAO,KAAK;AAAA,gBAChC;AAAA,cACF;AAAA,cACA,QAAQ,MAAM,iBAAiB;AAAA,cAC/B,WAAW,CAAC,MAAM;AAEhB,kBAAE,gBAAgB;AAClB,oBAAI,EAAE,QAAQ,SAAS;AACrB,oBAAE,eAAe;AACjB,mCAAiB;AAAA,gBACnB,WAAW,EAAE,QAAQ,UAAU;AAC7B,oBAAE,eAAe;AACjB,kCAAgB,IAAI;AACpB,sBAAI,MAAM,YAAa,OAAM,cAAc;AAAA,gBAC7C;AAAA,cACF;AAAA;AAAA,UACF;AAAA,UACC,CAAC,sBACA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,UAAU;AAAA,cACV,OAAO,MAAM,cAAc,MAAM,aAAa,gBAAgB;AAAA,cAC9D,UAAU,CAAC,SAAU,MAAM,cAAc,MAAM,cAAc,IAAI,IAAI,gBAAgB,IAAI;AAAA;AAAA,UAC3F;AAAA,WAEJ;AAAA,QAGA,gBAAAA,KAAC,SAAI,WAAU,iCACb,0BAAAC,MAAC,WAAM,WAAU,gDACf;AAAA,0BAAAD,KAAC,WACC,0BAAAC,MAAC,QAAG,WAAU,mEACZ;AAAA,4BAAAD,KAAC,QAAG,WAAU,kIAAiI,eAE/I;AAAA,YACC,KAAK,QAAQ,IAAI,CAAC,EAAE,QAAQ,KAAK,OAAO,MAAM,QAAQ,WAAW,MAChE,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBAEC,YAAU;AAAA,gBACV,WAAW,sJACT,sBAAsB,mBAAmB,gBAC3C;AAAA,gBACA,OAAO;AAAA,kBACL,OAAO,IAAI,SAAS;AAAA,kBACpB,UAAU,IAAI,SAAS;AAAA,kBACvB,UAAU,IAAI,SAAS;AAAA,kBACvB,UAAU;AAAA,kBACV,GAAI,SAAS,EAAE,UAAU,UAAU,MAAM,mBAAmB,YAAY,QAAQ,IAAI,YAAY,wBAAwB,IAAI,CAAC;AAAA,gBAC/H;AAAA,gBACA,SAAS,MAAM,sBAAsB,GAAG;AAAA,gBACxC,eAAe,CAAC,MAAM,qBAAqB,IAAI,IAAI,MAAM,CAAC;AAAA,gBAE1D;AAAA,kCAAAA,MAAC,SAAI,WAAU,4EACb;AAAA,oCAAAD,KAAC,UAAK,WAAU,0DAA0D,cAAI,OAAM;AAAA,oBACnF,eAAe,IAAI,IAAI,EAAE,KACxB,gBAAAA,KAAC,UAAK,WAAU,qCAAoC,OAAM,YAAW,iBAAc,QAAO,oBAAC;AAAA,oBAE7F,gBAAAC,MAAC,UAAK,WAAU,uEAAsE;AAAA;AAAA,sBAAE,IAAI;AAAA,sBAAI;AAAA,uBAAC;AAAA,qBACnG;AAAA,kBAEA,gBAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO,EAAE,UAAU,YAAY,KAAK,GAAG,QAAQ,GAAG,OAAO,IAAI,OAAO,IAAI,QAAQ,cAAc,QAAQ,IAAI,SAAS,QAAQ,gBAAgB,UAAU,aAAa,OAAO;AAAA,sBACzK,cAAc,MAAM,gBAAgB,IAAI,EAAE;AAAA,sBAC1C,cAAc,MAAM,gBAAgB,CAAC,QAAQ,QAAQ,IAAI,KAAK,OAAO,GAAG;AAAA,sBACxE,aAAa,CAAC,MAAM;AAClB,0BAAE,eAAe;AACjB,0BAAE,gBAAgB;AAClB,yCAAiB,IAAI,EAAE;AACvB,wCAAgB,EAAE,OAAO;AACzB,4CAAoB,IAAI,SAAS,GAAG;AAAA,sBACtC;AAAA,sBACA,eAAe,CAAC,MAAM,qBAAqB,IAAI,IAAI,MAAM,CAAC;AAAA,sBAC1D,MAAK;AAAA,sBACL,oBAAiB;AAAA,sBAEjB,0BAAAA;AAAA,wBAAC;AAAA;AAAA,0BACC,WAAU;AAAA,0BACV,OAAO;AAAA,4BACL,OAAO;AAAA,4BACP,QAAQ;AAAA,4BACR,eAAe;AAAA,4BACf,YAAY;AAAA,4BACZ,iBAAiB,kBAAkB,IAAI,KAAK,4BAA4B,iBAAiB,IAAI,KAAK,iEAAiE;AAAA,0BACrK;AAAA;AAAA,sBACF;AAAA;AAAA,kBACF;AAAA;AAAA;AAAA,cAjDK,IAAI;AAAA,YAkDX,CACD;AAAA,YACA,oBACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS;AAAA,gBACT,OAAM;AAAA,gBAEN,0BAAAA,KAAC,UAAK,WAAU,2CAA0C,eAAC;AAAA;AAAA,YAC7D;AAAA,aAEJ,GACF;AAAA,UACA,gBAAAA,KAAC,WACE,eAAK,KAAK,IAAI,CAAC,YAAY;AAC1B,gBAAI,QAAQ,SAAS,SAAS;AAC5B,qBACE,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBAEC,OAAO,QAAQ;AAAA,kBACf,SAAS,KAAK;AAAA,kBACd,YAAY,MAAM,SAAS,OAAO,UAAU,SAAS;AAAA,kBACrD,UAAU,MAAM;AAAA,kBAChB,cAAc,CAAC,CAAC;AAAA;AAAA,gBALX,SAAS,QAAQ,MAAM,GAAG;AAAA,cAMjC;AAAA,YAEJ;AACA,kBAAM,kBAAkB,QAAQ;AAChC,kBAAM,YAAY,MAAM,gBAAgBO,gBAAe,MAAM,aAAa,IAAI;AAC9E,mBACA,gBAAAN;AAAA,cAAC;AAAA;AAAA,gBAEC,YAAU;AAAA,gBACV,WAAW,8DAA8D,QAAQ,YAAY,SAAS,8BAA8B,EAAE;AAAA,gBACtI,OAAO,EAAE,QAAQ,QAAQ,IAAI,UAAU,GAAG;AAAA,gBAE1C;AAAA,kCAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAU;AAAA,sBACV,OAAO,QAAQ,SAAS,EAAE,KAAK,uBAAuB,QAAQ,WAAW,QAAQ,GAAG,IAAI;AAAA,sBAEvF,4BAAkB;AAAA;AAAA,kBACrB;AAAA,kBACC,KAAK,QAAQ,IAAI,CAAC,YAAY;AAE7B,0BAAM,OAAO,KAAK,YAAY,iBAAiB,QAAQ,KAAK;AAC5D,wBAAI,CAAC,KAAM,QAAO;AAClB,0BAAM,OAAO,KAAK,OAAO;AACzB,0BAAM,OAAO,KAAK,OAAO;AACzB,0BAAM,MAAM,MAAM,SAAS,KAAK,IAAI;AACpC,0BAAM,MAAM,MAAM,SAAS,QAAQ,IAAI;AACvC,0BAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,IAAI,EAAE;AACzC,0BAAM,WAAW,eAAe,MAAM,IAAI;AAC1C,0BAAM,SAAS,aAAa,MAAM,IAAI;AACtC,0BAAM,YAAY,MAAM,aAAa,QAAQ,QAAQ,MAAM,aAAa,QAAQ;AAEhF,0BAAM,gBAAgB,CAAC,CAAC,cAAc,CAAC,YAAY,cAAc,YAAY,iBAAiB,QAAQ,KAAK;AAC3G,0BAAM,iBACJ,CAAC,YACD,CAAC,aACD,CAAC,CAAC,cACD,KAAK,QACF,cAAc,KAAK,OAAO,UAAU,QAAQ,UAAU,MAAM,IAC5D,UAAU,WAAW,QAAQ,UAAU,WAAW;AAExD,2BACE,gBAAAC;AAAA,sBAAC;AAAA;AAAA,wBAEC,YAAU;AAAA,wBACV,YAAU;AAAA,wBACV,SAAS,KAAK;AAAA,wBACd,SAAS,KAAK;AAAA,wBACd,WAAW,gGACT,WAAW,kBAAkB,EAC/B,IAAI,SAAS,wCAAwC,EAAE,IAAI,QAAQ,SAAS,kBAAkB,EAAE;AAAA,wBAChG,OAAO;AAAA,0BACL,UAAU;AAAA,0BACV,UAAU;AAAA,0BACV,GAAG,gBAAgB,SAAS,OAAO;AAAA,0BACnC,GAAI,gBAAgB,EAAE,SAAS,sCAAsC,eAAe,GAAG,IAAI,CAAC;AAAA,wBAC9F;AAAA,wBACA,SAAS,CAAC,MAAM,gBAAgB,MAAM,MAAM,CAAC;AAAA,wBAC7C,eAAe,MAAM,mBAAmB,MAAM,IAAI;AAAA,wBAClD,eAAe,CAAC,MAAM,sBAAsB,MAAM,MAAM,CAAC;AAAA,wBACzD,aAAa,MAAM,WAAW,iBAAiB,QAAQ,KAAK;AAAA,wBAE3D;AAAA,sCACC,gBAAAA,MAAAF,WAAA,EACE;AAAA,4CAAAC;AAAA,8BAAC;AAAA;AAAA,gCACC,KAAK;AAAA,gCACL,MAAK;AAAA,gCACL,WAAU;AAAA,gCACV,OAAO,MAAM;AAAA,gCACb,UAAU,CAAC,MAAM,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,gCACnD,QAAQ,MAAM,MAAM,cAAc;AAAA,gCAClC,SAAS,CAAC,MAAM;AAEd,wCAAM,MAAM,EAAE,cAAc,MAAM;AAClC,oCAAE,cAAc,kBAAkB,KAAK,GAAG;AAAA,gCAC5C;AAAA,gCACA,WAAS;AAAA;AAAA,4BACX;AAAA,4BACA,gBAAAA,KAAC,gBAAa,UAAU,cAAc,OAAO,MAAM,YAAY,UAAU,MAAM,eAAe;AAAA,6BAChG,IACE,qBACF,mBAAmB,EAAE,KAAK,KAAK,KAAK,CAAC,IAErC,gBAAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAW,6BAA6B,KAAK,QAAQ,mCAAmC,EAAE;AAAA,8BAC1F,OAAO,KAAK,QAAQ,KAAK,gBAAgB,KAAK,QAAQ;AAAA,8BAErD,eAAK,UAAU,KAAK,SAAS;AAAA;AAAA,0BAChC;AAAA,0BAED,eAAe,cAAc,YAAY,OAAO,MAAM,IAAI,KACzD,gBAAAA,KAAC,UAAK,eAAY,QAAO,WAAU,4BAA2B,OAAO,iBAAiB,YAAY,OAAO,MAAM,IAAI,GAAG;AAAA,0BAEvH,kBACC,gBAAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,WAAU;AAAA,8BACV,cAAW;AAAA,8BACX,aAAa;AAAA,8BACb,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,8BAClC,OAAO,EAAE,UAAU,YAAY,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,2BAA2B,QAAQ,aAAa,QAAQ,GAAG;AAAA;AAAA,0BAClJ;AAAA;AAAA;AAAA,sBAzDG,QAAQ,OAAO;AAAA,oBA2DtB;AAAA,kBAEJ,CAAC;AAAA,kBACA,oBAAoB,gBAAAA,KAAC,QAAG,WAAU,0DAAyD;AAAA;AAAA;AAAA,cAjGvF,QAAQ,IAAI;AAAA,YAkGnB;AAAA,UAEF,CAAC,GACH;AAAA,WACF,GACF;AAAA,QACC,QACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,KAAK;AAAA,YACZ,GAAG,KAAK;AAAA,YACR,GAAG,KAAK;AAAA,YACR,SAAS,MAAM;AACb,sBAAQ,IAAI;AACZ,sBAAQ,SAAS,MAAM;AAAA,YACzB;AAAA;AAAA,QACF;AAAA,QAEF,gBAAAA,KAAC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAgBN;AAAA;AAAA;AAAA,EACJ;AAEJ;","names":["document","useRef","useState","useMemo","useEffect","useCallback","normalizeRange","useRef","useState","jsx","jsxs","useCallback","useEffect","useRef","useState","useEffect","useLayoutEffect","useMemo","useRef","useState","jsx","jsxs","Fragment","jsx","jsxs","useRef","useState","useMemo","useCallback","useEffect","normalizeRange"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ImageEditorController, ImageEditorState, ImageEditorTool, CropBox, AspectRatio, ImageAdjustments, DepthMaskOptions, CreateAnnotationPayload, Annotation, ImagePoint, ExportOptions, SerializedImageEditorState, ImageEditorOptions, InpaintHook, RemoveBackgroundHook, ImageEditorAIHooks } from '@pixerate/editor/image-editor';
|
|
2
|
-
import
|
|
2
|
+
import React from 'react';
|
|
3
3
|
|
|
4
4
|
interface UseImageEditorReturn {
|
|
5
5
|
controller: ImageEditorController;
|
|
@@ -55,13 +55,13 @@ interface ImageEditorProps {
|
|
|
55
55
|
editor?: UseImageEditorReturn;
|
|
56
56
|
src?: string;
|
|
57
57
|
className?: string;
|
|
58
|
-
style?:
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
59
|
onSave?: (dataUrl: string) => void;
|
|
60
60
|
exportOptions?: ExportOptions;
|
|
61
61
|
onInpaint?: InpaintHook;
|
|
62
62
|
onRemoveBackground?: RemoveBackgroundHook;
|
|
63
63
|
aiHooks?: ImageEditorAIHooks;
|
|
64
64
|
}
|
|
65
|
-
declare const ImageEditor:
|
|
65
|
+
declare const ImageEditor: React.FC<ImageEditorProps>;
|
|
66
66
|
|
|
67
67
|
export { ImageEditor, type ImageEditorProps, type UseImageEditorReturn, useImageEditor };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ImageEditorController, ImageEditorState, ImageEditorTool, CropBox, AspectRatio, ImageAdjustments, DepthMaskOptions, CreateAnnotationPayload, Annotation, ImagePoint, ExportOptions, SerializedImageEditorState, ImageEditorOptions, InpaintHook, RemoveBackgroundHook, ImageEditorAIHooks } from '@pixerate/editor/image-editor';
|
|
2
|
-
import
|
|
2
|
+
import React from 'react';
|
|
3
3
|
|
|
4
4
|
interface UseImageEditorReturn {
|
|
5
5
|
controller: ImageEditorController;
|
|
@@ -55,13 +55,13 @@ interface ImageEditorProps {
|
|
|
55
55
|
editor?: UseImageEditorReturn;
|
|
56
56
|
src?: string;
|
|
57
57
|
className?: string;
|
|
58
|
-
style?:
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
59
|
onSave?: (dataUrl: string) => void;
|
|
60
60
|
exportOptions?: ExportOptions;
|
|
61
61
|
onInpaint?: InpaintHook;
|
|
62
62
|
onRemoveBackground?: RemoveBackgroundHook;
|
|
63
63
|
aiHooks?: ImageEditorAIHooks;
|
|
64
64
|
}
|
|
65
|
-
declare const ImageEditor:
|
|
65
|
+
declare const ImageEditor: React.FC<ImageEditorProps>;
|
|
66
66
|
|
|
67
67
|
export { ImageEditor, type ImageEditorProps, type UseImageEditorReturn, useImageEditor };
|