@pixerate/editor-react 0.15.0 → 0.16.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 +4 -0
- package/dist/canvas/index.cjs +219 -118
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +59 -3
- package/dist/canvas/index.d.ts +59 -3
- package/dist/canvas/index.js +103 -0
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-7SPRQZ6H.js +216 -0
- package/dist/chunk-7SPRQZ6H.js.map +1 -0
- package/dist/{chunk-QVQYYHJ5.js → chunk-FYIPXHAE.js} +21 -13
- package/dist/chunk-FYIPXHAE.js.map +1 -0
- package/dist/{chunk-LPFZMZ3L.js → chunk-XTFR3IMK.js} +676 -322
- package/dist/chunk-XTFR3IMK.js.map +1 -0
- package/dist/chunk-XWFU2CSG.js +167 -0
- package/dist/chunk-XWFU2CSG.js.map +1 -0
- package/dist/generation/index.cjs +235 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +60 -0
- package/dist/generation/index.d.ts +60 -0
- package/dist/generation/index.js +13 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/image-editor/index.cjs +684 -336
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +60 -2
- package/dist/image-editor/index.d.ts +60 -2
- package/dist/image-editor/index.js +13 -3
- package/dist/index.cjs +1881 -648
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +143 -4
- package/dist/index.d.ts +143 -4
- package/dist/index.js +626 -73
- package/dist/index.js.map +1 -1
- package/dist/persistence/index.cjs +191 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +77 -0
- package/dist/persistence/index.d.ts +77 -0
- package/dist/persistence/index.js +9 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/spreadsheet/index.cjs +17 -10
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +2 -0
- package/dist/spreadsheet/index.d.ts +2 -0
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +18 -2
- package/dist/chunk-LPFZMZ3L.js.map +0 -1
- package/dist/chunk-QVQYYHJ5.js.map +0 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// src/generation/useGenerationPlan.ts
|
|
2
|
+
import { useEffect, useMemo, useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
estimateJobProgress,
|
|
5
|
+
planGenerationRequest
|
|
6
|
+
} from "@pixerate/editor/generation";
|
|
7
|
+
function useGenerationPlan(request, capabilities, options = {}) {
|
|
8
|
+
const key = JSON.stringify([request, capabilities, options]);
|
|
9
|
+
return useMemo(() => planGenerationRequest(request, capabilities, options), [key]);
|
|
10
|
+
}
|
|
11
|
+
function useJobProgress(options) {
|
|
12
|
+
const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
|
|
13
|
+
const [tick, setTick] = useState(() => Date.now());
|
|
14
|
+
const ticking = !done && now === void 0;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!ticking) return;
|
|
17
|
+
setTick(Date.now());
|
|
18
|
+
const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
|
|
19
|
+
return () => clearInterval(id);
|
|
20
|
+
}, [ticking, intervalMs]);
|
|
21
|
+
return estimateJobProgress({ startedAt, expectedMs, done, now: now ?? tick });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/generation/GenerationSettings.tsx
|
|
25
|
+
import { useId, useMemo as useMemo2 } from "react";
|
|
26
|
+
import {
|
|
27
|
+
getGenerationControls,
|
|
28
|
+
getReferenceSlots,
|
|
29
|
+
getRequestValue,
|
|
30
|
+
parseControlValue,
|
|
31
|
+
removeReference,
|
|
32
|
+
setRequestValue
|
|
33
|
+
} from "@pixerate/editor/generation";
|
|
34
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
35
|
+
var inputClass = "w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring";
|
|
36
|
+
function Control({
|
|
37
|
+
control,
|
|
38
|
+
value,
|
|
39
|
+
id,
|
|
40
|
+
onValue
|
|
41
|
+
}) {
|
|
42
|
+
const shown = value ?? control.defaultValue;
|
|
43
|
+
if (control.kind === "checkbox") {
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
"input",
|
|
46
|
+
{
|
|
47
|
+
id,
|
|
48
|
+
type: "checkbox",
|
|
49
|
+
"data-field": control.key,
|
|
50
|
+
checked: Boolean(shown),
|
|
51
|
+
onChange: (e) => onValue(parseControlValue(control, e.target.checked))
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (control.kind === "select") {
|
|
56
|
+
return /* @__PURE__ */ jsxs(
|
|
57
|
+
"select",
|
|
58
|
+
{
|
|
59
|
+
id,
|
|
60
|
+
"data-field": control.key,
|
|
61
|
+
className: inputClass,
|
|
62
|
+
value: shown === void 0 ? "" : String(shown),
|
|
63
|
+
onChange: (e) => onValue(parseControlValue(control, e.target.value)),
|
|
64
|
+
children: [
|
|
65
|
+
shown === void 0 && /* @__PURE__ */ jsx("option", { value: "", children: "Default" }),
|
|
66
|
+
control.options.map((option) => /* @__PURE__ */ jsx("option", { value: String(option.value), children: option.label }, String(option.value)))
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (control.kind === "textarea") {
|
|
72
|
+
return /* @__PURE__ */ jsx(
|
|
73
|
+
"textarea",
|
|
74
|
+
{
|
|
75
|
+
id,
|
|
76
|
+
"data-field": control.key,
|
|
77
|
+
className: inputClass,
|
|
78
|
+
rows: 2,
|
|
79
|
+
maxLength: control.maxLength,
|
|
80
|
+
value: typeof value === "string" ? value : "",
|
|
81
|
+
onChange: (e) => onValue(parseControlValue(control, e.target.value))
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const numeric = typeof shown === "number" ? shown : void 0;
|
|
86
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
"input",
|
|
89
|
+
{
|
|
90
|
+
id,
|
|
91
|
+
type: control.kind === "range" ? "range" : "number",
|
|
92
|
+
"data-field": control.key,
|
|
93
|
+
className: control.kind === "range" ? "flex-1" : inputClass,
|
|
94
|
+
min: control.min,
|
|
95
|
+
max: control.max,
|
|
96
|
+
step: control.step ?? "any",
|
|
97
|
+
value: numeric ?? (control.kind === "range" ? control.min ?? 0 : ""),
|
|
98
|
+
onChange: (e) => onValue(parseControlValue(control, e.target.value))
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
control.kind === "range" && /* @__PURE__ */ jsx("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
var GenerationSettings = ({
|
|
105
|
+
capabilities,
|
|
106
|
+
value,
|
|
107
|
+
onChange,
|
|
108
|
+
plan: planProp,
|
|
109
|
+
strategy,
|
|
110
|
+
showAdjustments = true,
|
|
111
|
+
onAddReference,
|
|
112
|
+
renderReference,
|
|
113
|
+
className = ""
|
|
114
|
+
}) => {
|
|
115
|
+
const baseId = useId();
|
|
116
|
+
const controls = useMemo2(() => getGenerationControls(capabilities), [capabilities]);
|
|
117
|
+
const computed = useGenerationPlan(value, capabilities, { strategy });
|
|
118
|
+
const plan = planProp ?? computed;
|
|
119
|
+
const slots = getReferenceSlots(capabilities, value);
|
|
120
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
|
|
121
|
+
controls.map((control) => {
|
|
122
|
+
const id = `${baseId}-${control.key}`;
|
|
123
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
|
|
124
|
+
/* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
|
|
125
|
+
/* @__PURE__ */ jsx(
|
|
126
|
+
Control,
|
|
127
|
+
{
|
|
128
|
+
control,
|
|
129
|
+
id,
|
|
130
|
+
value: getRequestValue(value, control.key),
|
|
131
|
+
onValue: (next) => onChange(setRequestValue(value, control.key, next))
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
] }, control.key);
|
|
135
|
+
}),
|
|
136
|
+
slots.map((slot) => /* @__PURE__ */ jsxs("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
|
|
137
|
+
/* @__PURE__ */ jsxs("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
|
|
138
|
+
slot.label,
|
|
139
|
+
" ",
|
|
140
|
+
/* @__PURE__ */ jsxs("span", { className: "tabular-nums", "data-reference-count": "", children: [
|
|
141
|
+
"(",
|
|
142
|
+
slot.references.length,
|
|
143
|
+
"/",
|
|
144
|
+
slot.max,
|
|
145
|
+
")"
|
|
146
|
+
] }),
|
|
147
|
+
slot.min > 0 && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: " *" })
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ jsxs("ul", { className: "flex flex-wrap gap-1", children: [
|
|
150
|
+
slot.references.map((ref) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
|
|
151
|
+
renderReference ? renderReference(ref) : /* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate", children: ref.id }),
|
|
152
|
+
/* @__PURE__ */ jsx(
|
|
153
|
+
"button",
|
|
154
|
+
{
|
|
155
|
+
type: "button",
|
|
156
|
+
"aria-label": `Remove ${slot.label} ${ref.id}`,
|
|
157
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
158
|
+
onClick: () => onChange(removeReference(value, slot.role, ref.id)),
|
|
159
|
+
children: "\xD7"
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
] }, ref.id)),
|
|
163
|
+
onAddReference && slot.canAdd && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
164
|
+
"button",
|
|
165
|
+
{
|
|
166
|
+
type: "button",
|
|
167
|
+
className: "rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground",
|
|
168
|
+
onClick: () => onAddReference(slot.role),
|
|
169
|
+
children: "Add"
|
|
170
|
+
}
|
|
171
|
+
) })
|
|
172
|
+
] })
|
|
173
|
+
] }, slot.role)),
|
|
174
|
+
showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ jsx("ul", { role: "status", className: "flex flex-col gap-0.5 text-xs text-muted-foreground", "data-generation-adjustments": "", children: plan.adjustments.map((adjustment, index) => /* @__PURE__ */ jsx("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
|
|
175
|
+
showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ jsx("ul", { role: "alert", className: "flex flex-col gap-0.5 text-xs text-destructive", "data-generation-errors": "", children: plan.errors.map((error, index) => /* @__PURE__ */ jsx("li", { "data-error-field": error.field, children: error.message }, index)) })
|
|
176
|
+
] });
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// src/generation/JobProgress.tsx
|
|
180
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
181
|
+
var JobProgress = ({ title, className = "", ...options }) => {
|
|
182
|
+
const progress = useJobProgress(options);
|
|
183
|
+
return /* @__PURE__ */ jsxs2("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
|
|
184
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
|
|
185
|
+
title && /* @__PURE__ */ jsx2("span", { className: "truncate text-foreground", children: title }),
|
|
186
|
+
/* @__PURE__ */ jsx2("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
|
|
187
|
+
] }),
|
|
188
|
+
/* @__PURE__ */ jsx2(
|
|
189
|
+
"div",
|
|
190
|
+
{
|
|
191
|
+
role: "progressbar",
|
|
192
|
+
"aria-label": title ?? "Generation progress",
|
|
193
|
+
"aria-valuemin": 0,
|
|
194
|
+
"aria-valuemax": 100,
|
|
195
|
+
"aria-valuenow": progress.percent,
|
|
196
|
+
"aria-valuetext": `${progress.percent}%, ${progress.label}`,
|
|
197
|
+
className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
|
|
198
|
+
children: /* @__PURE__ */ jsx2(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: "h-full rounded-full bg-primary transition-[width] duration-500",
|
|
202
|
+
style: { width: `${progress.percent}%`, background: "var(--primary, currentColor)" }
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
] });
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export {
|
|
211
|
+
useGenerationPlan,
|
|
212
|
+
useJobProgress,
|
|
213
|
+
GenerationSettings,
|
|
214
|
+
JobProgress
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=chunk-7SPRQZ6H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generation/useGenerationPlan.ts","../src/generation/GenerationSettings.tsx","../src/generation/JobProgress.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport {\n estimateJobProgress,\n planGenerationRequest,\n type GenerationPlan,\n type GenerationRequest,\n type JobProgressEstimate,\n type ModelCapabilities,\n type PlanOptions,\n} from '@pixerate/editor/generation';\n\n/**\n * Plans `request` against `capabilities` (see `planGenerationRequest`) and\n * returns the adjusted request, adjustments and errors. Recomputed only when\n * the request, capabilities or options change by value, so inline objects are fine.\n */\nexport function useGenerationPlan(\n request: GenerationRequest,\n capabilities: ModelCapabilities,\n options: PlanOptions = {},\n): GenerationPlan {\n const key = JSON.stringify([request, capabilities, options]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => planGenerationRequest(request, capabilities, options), [key]);\n}\n\nexport interface UseJobProgressOptions {\n startedAt: number | Date | string;\n expectedMs?: number;\n done?: boolean;\n /** Fixed current time (disables ticking; useful for SSR and tests). */\n now?: number | Date | string;\n /** Re-render interval while running in ms (default 1000). */\n intervalMs?: number;\n}\n\n/** Ticking `estimateJobProgress` for a running job; stops ticking when `done`. */\nexport function useJobProgress(options: UseJobProgressOptions): JobProgressEstimate {\n const { startedAt, expectedMs, done, now, intervalMs = 1000 } = options;\n const [tick, setTick] = useState(() => Date.now());\n const ticking = !done && now === undefined;\n useEffect(() => {\n if (!ticking) return;\n setTick(Date.now());\n const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));\n return () => clearInterval(id);\n }, [ticking, intervalMs]);\n return estimateJobProgress({ startedAt, expectedMs, done, now: now ?? tick });\n}\n","import React, { useId, useMemo } from 'react';\nimport {\n getGenerationControls,\n getReferenceSlots,\n getRequestValue,\n parseControlValue,\n removeReference,\n setRequestValue,\n type GenerationControl,\n type GenerationPlan,\n type GenerationReference,\n type GenerationRequest,\n type ModelCapabilities,\n type PlanStrategy,\n type ReferenceRole,\n} from '@pixerate/editor/generation';\nimport { useGenerationPlan } from './useGenerationPlan';\n\nexport interface GenerationSettingsProps {\n capabilities: ModelCapabilities;\n /** The request being edited (controlled). */\n value: GenerationRequest;\n onChange: (next: GenerationRequest) => void;\n /** A plan computed elsewhere; otherwise one is computed with `strategy`. */\n plan?: GenerationPlan;\n /** Strategy for the built-in plan (default `nearest`). */\n strategy?: PlanStrategy;\n /** List plan adjustments and errors under the controls (default `true`). */\n showAdjustments?: boolean;\n /** Shows an \"Add\" button per reference role; you pick the asset and call `onChange`. */\n onAddReference?: (role: ReferenceRole) => void;\n /** Custom rendering of a reference chip (default: its id). */\n renderReference?: (reference: GenerationReference) => React.ReactNode;\n className?: string;\n}\n\nconst inputClass =\n 'w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring';\n\nfunction Control({\n control,\n value,\n id,\n onValue,\n}: {\n control: GenerationControl;\n value: unknown;\n id: string;\n onValue: (value: unknown) => void;\n}) {\n const shown = value ?? control.defaultValue;\n if (control.kind === 'checkbox') {\n return (\n <input\n id={id}\n type=\"checkbox\"\n data-field={control.key}\n checked={Boolean(shown)}\n onChange={(e) => onValue(parseControlValue(control, e.target.checked))}\n />\n );\n }\n if (control.kind === 'select') {\n return (\n <select\n id={id}\n data-field={control.key}\n className={inputClass}\n value={shown === undefined ? '' : String(shown)}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n >\n {shown === undefined && <option value=\"\">Default</option>}\n {control.options!.map((option) => (\n <option key={String(option.value)} value={String(option.value)}>\n {option.label}\n </option>\n ))}\n </select>\n );\n }\n if (control.kind === 'textarea') {\n return (\n <textarea\n id={id}\n data-field={control.key}\n className={inputClass}\n rows={2}\n maxLength={control.maxLength}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n />\n );\n }\n const numeric = typeof shown === 'number' ? shown : undefined;\n return (\n <div className=\"flex items-center gap-2\">\n <input\n id={id}\n type={control.kind === 'range' ? 'range' : 'number'}\n data-field={control.key}\n className={control.kind === 'range' ? 'flex-1' : inputClass}\n min={control.min}\n max={control.max}\n step={control.step ?? 'any'}\n value={numeric ?? (control.kind === 'range' ? (control.min ?? 0) : '')}\n onChange={(e) => onValue(parseControlValue(control, e.target.value))}\n />\n {control.kind === 'range' && (\n <span className=\"w-10 text-right tabular-nums text-muted-foreground\" data-field-value=\"\">\n {numeric ?? '–'}\n </span>\n )}\n </div>\n );\n}\n\n/**\n * Headless-styled settings form generated from a model's capabilities:\n * selects for choices, sliders/number inputs for ranges, text areas for\n * negative/system prompts, checkboxes for boolean params, reference slots by\n * role, and the plan's adjustments and errors. Controlled via `value` / `onChange`.\n */\nexport const GenerationSettings: React.FC<GenerationSettingsProps> = ({\n capabilities,\n value,\n onChange,\n plan: planProp,\n strategy,\n showAdjustments = true,\n onAddReference,\n renderReference,\n className = '',\n}) => {\n const baseId = useId();\n const controls = useMemo(() => getGenerationControls(capabilities), [capabilities]);\n const computed = useGenerationPlan(value, capabilities, { strategy });\n const plan = planProp ?? computed;\n const slots = getReferenceSlots(capabilities, value);\n\n return (\n <div className={`flex flex-col gap-3 text-sm ${className}`} data-generation-settings=\"\" data-model={capabilities.id}>\n {controls.map((control) => {\n const id = `${baseId}-${control.key}`;\n return (\n <div key={control.key} className=\"flex flex-col gap-1\" data-control={control.key}>\n <label htmlFor={id} className=\"text-xs font-medium text-muted-foreground\" title={control.description}>\n {control.label}\n </label>\n <Control\n control={control}\n id={id}\n value={getRequestValue(value, control.key)}\n onValue={(next) => onChange(setRequestValue(value, control.key, next))}\n />\n </div>\n );\n })}\n\n {slots.map((slot) => (\n <fieldset key={slot.role} className=\"flex flex-col gap-1\" data-reference-role={slot.role}>\n <legend className=\"text-xs font-medium text-muted-foreground\" title={slot.description}>\n {slot.label}{' '}\n <span className=\"tabular-nums\" data-reference-count=\"\">\n ({slot.references.length}/{slot.max})\n </span>\n {slot.min > 0 && <span className=\"text-destructive\"> *</span>}\n </legend>\n <ul className=\"flex flex-wrap gap-1\">\n {slot.references.map((ref) => (\n <li key={ref.id} className=\"flex items-center gap-1 rounded border border-border px-1.5 py-0.5\" data-reference-id={ref.id}>\n {renderReference ? renderReference(ref) : <span className=\"max-w-[10rem] truncate\">{ref.id}</span>}\n <button\n type=\"button\"\n aria-label={`Remove ${slot.label} ${ref.id}`}\n className=\"text-muted-foreground hover:text-foreground\"\n onClick={() => onChange(removeReference(value, slot.role, ref.id))}\n >\n ×\n </button>\n </li>\n ))}\n {onAddReference && slot.canAdd && (\n <li>\n <button\n type=\"button\"\n className=\"rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground\"\n onClick={() => onAddReference(slot.role)}\n >\n Add\n </button>\n </li>\n )}\n </ul>\n </fieldset>\n ))}\n\n {showAdjustments && plan.adjustments.length > 0 && (\n <ul role=\"status\" className=\"flex flex-col gap-0.5 text-xs text-muted-foreground\" data-generation-adjustments=\"\">\n {plan.adjustments.map((adjustment, index) => (\n <li key={index} data-adjustment-field={adjustment.field} data-adjustment-kind={adjustment.kind}>\n {adjustment.reason}\n </li>\n ))}\n </ul>\n )}\n {showAdjustments && plan.errors.length > 0 && (\n <ul role=\"alert\" className=\"flex flex-col gap-0.5 text-xs text-destructive\" data-generation-errors=\"\">\n {plan.errors.map((error, index) => (\n <li key={index} data-error-field={error.field}>\n {error.message}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { useJobProgress, type UseJobProgressOptions } from './useGenerationPlan';\n\nexport interface JobProgressProps extends UseJobProgressOptions {\n /** Text shown before the time label, e.g. the model name. */\n title?: string;\n /** Extra classes for the root. */\n className?: string;\n}\n\n/**\n * Headless-styled progress bar for a generation job that reports no progress\n * of its own: time-based percent (held at 95% until `done`) with a\n * \"~2m left\" / \"Almost done…\" label. Exposes `role=\"progressbar\"`.\n */\nexport const JobProgress: React.FC<JobProgressProps> = ({ title, className = '', ...options }) => {\n const progress = useJobProgress(options);\n return (\n <div className={`flex flex-col gap-1 text-sm ${className}`} data-job-progress=\"\" data-done={options.done ? '' : undefined}>\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n {title && <span className=\"truncate text-foreground\">{title}</span>}\n <span data-job-progress-label=\"\" aria-live=\"polite\">\n {progress.label}\n </span>\n </div>\n <div\n role=\"progressbar\"\n aria-label={title ?? 'Generation progress'}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress.percent}\n aria-valuetext={`${progress.percent}%, ${progress.label}`}\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n >\n <div\n className=\"h-full rounded-full bg-primary transition-[width] duration-500\"\n style={{ width: `${progress.percent}%`, background: 'var(--primary, currentColor)' }}\n />\n </div>\n </div>\n );\n};\n"],"mappings":";AAAA,SAAS,WAAW,SAAS,gBAAgB;AAC7C;AAAA,EACE;AAAA,EACA;AAAA,OAMK;AAOA,SAAS,kBACd,SACA,cACA,UAAuB,CAAC,GACR;AAChB,QAAM,MAAM,KAAK,UAAU,CAAC,SAAS,cAAc,OAAO,CAAC;AAE3D,SAAO,QAAQ,MAAM,sBAAsB,SAAS,cAAc,OAAO,GAAG,CAAC,GAAG,CAAC;AACnF;AAaO,SAAS,eAAe,SAAqD;AAClF,QAAM,EAAE,WAAW,YAAY,MAAM,KAAK,aAAa,IAAK,IAAI;AAChE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM,KAAK,IAAI,CAAC;AACjD,QAAM,UAAU,CAAC,QAAQ,QAAQ;AACjC,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,YAAQ,KAAK,IAAI,CAAC;AAClB,UAAM,KAAK,YAAY,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,UAAU,CAAC;AAC1E,WAAO,MAAM,cAAc,EAAE;AAAA,EAC/B,GAAG,CAAC,SAAS,UAAU,CAAC;AACxB,SAAO,oBAAoB,EAAE,WAAW,YAAY,MAAM,KAAK,OAAO,KAAK,CAAC;AAC9E;;;AChDA,SAAgB,OAAO,WAAAA,gBAAe;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAsCD,cAWA,YAXA;AAjBN,IAAM,aACJ;AAEF,SAAS,QAAQ;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,SAAS,QAAQ;AAC/B,MAAI,QAAQ,SAAS,YAAY;AAC/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,cAAY,QAAQ;AAAA,QACpB,SAAS,QAAQ,KAAK;AAAA,QACtB,UAAU,CAAC,MAAM,QAAQ,kBAAkB,SAAS,EAAE,OAAO,OAAO,CAAC;AAAA;AAAA,IACvE;AAAA,EAEJ;AACA,MAAI,QAAQ,SAAS,UAAU;AAC7B,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,cAAY,QAAQ;AAAA,QACpB,WAAW;AAAA,QACX,OAAO,UAAU,SAAY,KAAK,OAAO,KAAK;AAAA,QAC9C,UAAU,CAAC,MAAM,QAAQ,kBAAkB,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,QAElE;AAAA,oBAAU,UAAa,oBAAC,YAAO,OAAM,IAAG,qBAAO;AAAA,UAC/C,QAAQ,QAAS,IAAI,CAAC,WACrB,oBAAC,YAAkC,OAAO,OAAO,OAAO,KAAK,GAC1D,iBAAO,SADG,OAAO,OAAO,KAAK,CAEhC,CACD;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AACA,MAAI,QAAQ,SAAS,YAAY;AAC/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,cAAY,QAAQ;AAAA,QACpB,WAAW;AAAA,QACX,MAAM;AAAA,QACN,WAAW,QAAQ;AAAA,QACnB,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,QAC3C,UAAU,CAAC,MAAM,QAAQ,kBAAkB,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA,IACrE;AAAA,EAEJ;AACA,QAAM,UAAU,OAAO,UAAU,WAAW,QAAQ;AACpD,SACE,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAM,QAAQ,SAAS,UAAU,UAAU;AAAA,QAC3C,cAAY,QAAQ;AAAA,QACpB,WAAW,QAAQ,SAAS,UAAU,WAAW;AAAA,QACjD,KAAK,QAAQ;AAAA,QACb,KAAK,QAAQ;AAAA,QACb,MAAM,QAAQ,QAAQ;AAAA,QACtB,OAAO,YAAY,QAAQ,SAAS,UAAW,QAAQ,OAAO,IAAK;AAAA,QACnE,UAAU,CAAC,MAAM,QAAQ,kBAAkB,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA,IACrE;AAAA,IACC,QAAQ,SAAS,WAChB,oBAAC,UAAK,WAAU,sDAAqD,oBAAiB,IACnF,qBAAW,UACd;AAAA,KAEJ;AAEJ;AAQO,IAAM,qBAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAAM;AACJ,QAAM,SAAS,MAAM;AACrB,QAAM,WAAWC,SAAQ,MAAM,sBAAsB,YAAY,GAAG,CAAC,YAAY,CAAC;AAClF,QAAM,WAAW,kBAAkB,OAAO,cAAc,EAAE,SAAS,CAAC;AACpE,QAAM,OAAO,YAAY;AACzB,QAAM,QAAQ,kBAAkB,cAAc,KAAK;AAEnD,SACE,qBAAC,SAAI,WAAW,+BAA+B,SAAS,IAAI,4BAAyB,IAAG,cAAY,aAAa,IAC9G;AAAA,aAAS,IAAI,CAAC,YAAY;AACzB,YAAM,KAAK,GAAG,MAAM,IAAI,QAAQ,GAAG;AACnC,aACE,qBAAC,SAAsB,WAAU,uBAAsB,gBAAc,QAAQ,KAC3E;AAAA,4BAAC,WAAM,SAAS,IAAI,WAAU,6CAA4C,OAAO,QAAQ,aACtF,kBAAQ,OACX;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,OAAO,gBAAgB,OAAO,QAAQ,GAAG;AAAA,YACzC,SAAS,CAAC,SAAS,SAAS,gBAAgB,OAAO,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,QACvE;AAAA,WATQ,QAAQ,GAUlB;AAAA,IAEJ,CAAC;AAAA,IAEA,MAAM,IAAI,CAAC,SACV,qBAAC,cAAyB,WAAU,uBAAsB,uBAAqB,KAAK,MAClF;AAAA,2BAAC,YAAO,WAAU,6CAA4C,OAAO,KAAK,aACvE;AAAA,aAAK;AAAA,QAAO;AAAA,QACb,qBAAC,UAAK,WAAU,gBAAe,wBAAqB,IAAG;AAAA;AAAA,UACnD,KAAK,WAAW;AAAA,UAAO;AAAA,UAAE,KAAK;AAAA,UAAI;AAAA,WACtC;AAAA,QACC,KAAK,MAAM,KAAK,oBAAC,UAAK,WAAU,oBAAmB,gBAAE;AAAA,SACxD;AAAA,MACA,qBAAC,QAAG,WAAU,wBACX;AAAA,aAAK,WAAW,IAAI,CAAC,QACpB,qBAAC,QAAgB,WAAU,sEAAqE,qBAAmB,IAAI,IACpH;AAAA,4BAAkB,gBAAgB,GAAG,IAAI,oBAAC,UAAK,WAAU,0BAA0B,cAAI,IAAG;AAAA,UAC3F;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY,UAAU,KAAK,KAAK,IAAI,IAAI,EAAE;AAAA,cAC1C,WAAU;AAAA,cACV,SAAS,MAAM,SAAS,gBAAgB,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA,cAClE;AAAA;AAAA,UAED;AAAA,aATO,IAAI,EAUb,CACD;AAAA,QACA,kBAAkB,KAAK,UACtB,oBAAC,QACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS,MAAM,eAAe,KAAK,IAAI;AAAA,YACxC;AAAA;AAAA,QAED,GACF;AAAA,SAEJ;AAAA,SAjCa,KAAK,IAkCpB,CACD;AAAA,IAEA,mBAAmB,KAAK,YAAY,SAAS,KAC5C,oBAAC,QAAG,MAAK,UAAS,WAAU,uDAAsD,+BAA4B,IAC3G,eAAK,YAAY,IAAI,CAAC,YAAY,UACjC,oBAAC,QAAe,yBAAuB,WAAW,OAAO,wBAAsB,WAAW,MACvF,qBAAW,UADL,KAET,CACD,GACH;AAAA,IAED,mBAAmB,KAAK,OAAO,SAAS,KACvC,oBAAC,QAAG,MAAK,SAAQ,WAAU,kDAAiD,0BAAuB,IAChG,eAAK,OAAO,IAAI,CAAC,OAAO,UACvB,oBAAC,QAAe,oBAAkB,MAAM,OACrC,gBAAM,WADA,KAET,CACD,GACH;AAAA,KAEJ;AAEJ;;;ACrMM,SACY,OAAAC,MADZ,QAAAC,aAAA;AAJC,IAAM,cAA0C,CAAC,EAAE,OAAO,YAAY,IAAI,GAAG,QAAQ,MAAM;AAChG,QAAM,WAAW,eAAe,OAAO;AACvC,SACE,gBAAAA,MAAC,SAAI,WAAW,+BAA+B,SAAS,IAAI,qBAAkB,IAAG,aAAW,QAAQ,OAAO,KAAK,QAC9G;AAAA,oBAAAA,MAAC,SAAI,WAAU,iEACZ;AAAA,eAAS,gBAAAD,KAAC,UAAK,WAAU,4BAA4B,iBAAM;AAAA,MAC5D,gBAAAA,KAAC,UAAK,2BAAwB,IAAG,aAAU,UACxC,mBAAS,OACZ;AAAA,OACF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY,SAAS;AAAA,QACrB,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,iBAAe,SAAS;AAAA,QACxB,kBAAgB,GAAG,SAAS,OAAO,MAAM,SAAS,KAAK;AAAA,QACvD,WAAU;AAAA,QAEV,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,GAAG,SAAS,OAAO,KAAK,YAAY,+BAA+B;AAAA;AAAA,QACrF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":["useMemo","useMemo","jsx","jsxs"]}
|
|
@@ -173,12 +173,13 @@ import {
|
|
|
173
173
|
getSpreadsheetMenuItems,
|
|
174
174
|
normalizeRange as normalizeRange2,
|
|
175
175
|
rangeContains,
|
|
176
|
-
|
|
176
|
+
formatCellForDisplay,
|
|
177
|
+
numberFormatColorToCss
|
|
177
178
|
} from "@pixerate/editor/spreadsheet";
|
|
178
179
|
|
|
179
180
|
// src/spreadsheet/SpreadsheetContextMenu.tsx
|
|
180
181
|
import React, { useEffect, useLayoutEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
181
|
-
import { clampMenuPosition } from "@pixerate/editor/spreadsheet";
|
|
182
|
+
import { clampMenuPosition, runSpreadsheetMenuItem } from "@pixerate/editor/spreadsheet";
|
|
182
183
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
183
184
|
var VIEWPORT_MARGIN = 4;
|
|
184
185
|
var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
@@ -236,11 +237,12 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
236
237
|
type: "button",
|
|
237
238
|
role: "menuitem",
|
|
238
239
|
"data-action": item.id,
|
|
240
|
+
"data-checked": item.checked ? "" : void 0,
|
|
239
241
|
disabled: item.disabled,
|
|
240
|
-
className:
|
|
242
|
+
className: `block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent ${item.checked ? "font-semibold" : ""}`,
|
|
241
243
|
onClick: () => {
|
|
242
244
|
onClose();
|
|
243
|
-
item
|
|
245
|
+
runSpreadsheetMenuItem(item);
|
|
244
246
|
},
|
|
245
247
|
children: item.label
|
|
246
248
|
}
|
|
@@ -553,6 +555,19 @@ function spillBorderStyle(range, row, col) {
|
|
|
553
555
|
borderRight: col === range.endCol ? line : void 0
|
|
554
556
|
};
|
|
555
557
|
}
|
|
558
|
+
function CellText({ cell }) {
|
|
559
|
+
const shown = formatCellForDisplay(cell);
|
|
560
|
+
return /* @__PURE__ */ jsx4(
|
|
561
|
+
"span",
|
|
562
|
+
{
|
|
563
|
+
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
564
|
+
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
565
|
+
"data-numeric": shown.numeric ? "" : void 0,
|
|
566
|
+
style: shown.numeric || shown.color ? { ...shown.numeric ? { textAlign: "right" } : {}, ...shown.color ? { color: numberFormatColorToCss(shown.color) } : {} } : void 0,
|
|
567
|
+
children: shown.text
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
}
|
|
556
571
|
var SpreadsheetEditor = ({
|
|
557
572
|
state: externalState,
|
|
558
573
|
readOnly = false,
|
|
@@ -1084,14 +1099,7 @@ var SpreadsheetEditor = ({
|
|
|
1084
1099
|
}
|
|
1085
1100
|
),
|
|
1086
1101
|
/* @__PURE__ */ jsx4(FormulaHints, { inputRef: cellInputRef, value: state.draftValue, onAccept: state.setDraftValue })
|
|
1087
|
-
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ jsx4(
|
|
1088
|
-
"span",
|
|
1089
|
-
{
|
|
1090
|
-
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
1091
|
-
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
1092
|
-
children: formatCellDisplay(cell)
|
|
1093
|
-
}
|
|
1094
|
-
),
|
|
1102
|
+
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ jsx4(CellText, { cell }),
|
|
1095
1103
|
activeSpill && rangeContains(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
1096
1104
|
showFillHandle && /* @__PURE__ */ jsx4(
|
|
1097
1105
|
"div",
|
|
@@ -1158,4 +1166,4 @@ export {
|
|
|
1158
1166
|
FormulaHints,
|
|
1159
1167
|
SpreadsheetEditor
|
|
1160
1168
|
};
|
|
1161
|
-
//# sourceMappingURL=chunk-
|
|
1169
|
+
//# sourceMappingURL=chunk-FYIPXHAE.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 formatCellForDisplay,\n numberFormatColorToCss\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\n/** A cell's display text: formatted with its number format, numbers right-aligned, `[Red]`-style colours applied. */\nfunction CellText({ cell }: { cell: CellData }) {\n const shown = formatCellForDisplay(cell);\n return (\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 data-numeric={shown.numeric ? '' : undefined}\n style={\n shown.numeric || shown.color\n ? { ...(shown.numeric ? { textAlign: 'right' as const } : {}), ...(shown.color ? { color: numberFormatColorToCss(shown.color) } : {}) }\n : undefined\n }\n >\n {shown.text}\n </span>\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 <CellText cell={cell} />\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, runSpreadsheetMenuItem, 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 data-checked={item.checked ? '' : undefined}\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 item.checked ? 'font-semibold' : ''\n }`}\n onClick={() => {\n onClose();\n runSpreadsheetMenuItem(item);\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":"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","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"]}
|