use-chisel 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +99 -1607
- package/dist/persistence.d.ts +30 -0
- package/dist/theme.d.ts +1 -0
- package/dist/workspace/color-picker.d.ts +6 -0
- package/dist/workspace/color.d.ts +9 -0
- package/dist/workspace/comment-box.d.ts +28 -0
- package/dist/workspace/comment-drag-handle.d.ts +3 -0
- package/dist/workspace/comments.d.ts +80 -0
- package/dist/workspace/composer-position.d.ts +13 -0
- package/dist/workspace/confirmation.d.ts +11 -0
- package/dist/workspace/hover-dismiss.d.ts +4 -0
- package/dist/workspace/mode-shortcuts.d.ts +1 -0
- package/dist/workspace/page-control.d.ts +7 -0
- package/dist/workspace/preview-navigation.d.ts +4 -0
- package/dist/workspace/preview.d.ts +3 -0
- package/dist/workspace/style-changes.d.ts +15 -0
- package/dist/workspace/styles.d.ts +1 -0
- package/dist/workspace/thread-morph.d.ts +1 -0
- package/dist/workspace/workspace.d.ts +51 -0
- package/dist/workspace-entry.d.ts +6 -0
- package/dist/workspace-entry.js +394 -0
- package/package.json +20 -7
package/dist/index.js
CHANGED
|
@@ -1,879 +1,36 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{ label: "Georgia", value: "Georgia, \"Times New Roman\", serif" },
|
|
10
|
-
|
|
11
|
-
];
|
|
12
|
-
const COLOR_FORMATS = ["Hex", "RGB", "RGBA", "HSL"];
|
|
13
|
-
const COLOR_MODES = ["Solid", "Gradient", "Image"];
|
|
14
|
-
const NUMERIC_CONTROLS = [
|
|
15
|
-
{ label: "Font Size", property: "fontSize", cssProperty: "font-size", min: 8, max: 96, step: 1, unit: "px" },
|
|
16
|
-
{ label: "Line", property: "lineHeight", cssProperty: "line-height", min: 8, max: 120, step: 1, unit: "px" },
|
|
17
|
-
{ label: "Tracking", property: "letterSpacing", cssProperty: "letter-spacing", min: -2, max: 12, step: 0.25, unit: "px" },
|
|
18
|
-
{ label: "Padding X", property: "paddingInline", cssProperty: "padding-inline", min: 0, max: 120, step: 1, unit: "px" },
|
|
19
|
-
{ label: "Padding Y", property: "paddingBlock", cssProperty: "padding-block", min: 0, max: 120, step: 1, unit: "px" },
|
|
20
|
-
{ label: "Margin X", property: "marginInline", cssProperty: "margin-inline", min: -80, max: 160, step: 1, unit: "px" },
|
|
21
|
-
{ label: "Margin Y", property: "marginBlock", cssProperty: "margin-block", min: -80, max: 160, step: 1, unit: "px" },
|
|
22
|
-
{ label: "Radius", property: "borderRadius", cssProperty: "border-radius", min: 0, max: 80, step: 1, unit: "px" },
|
|
23
|
-
{ label: "Opacity", property: "opacity", cssProperty: "opacity", min: 0, max: 1, step: 0.01, unit: "" },
|
|
24
|
-
{ label: "Width", property: "width", cssProperty: "width", min: 0, max: 1200, step: 1, unit: "px" },
|
|
25
|
-
{ label: "Height", property: "height", cssProperty: "height", min: 0, max: 1200, step: 1, unit: "px" }
|
|
26
|
-
];
|
|
27
|
-
const STYLE_PROPERTIES = [
|
|
28
|
-
"color",
|
|
29
|
-
"backgroundColor",
|
|
30
|
-
"backgroundImage",
|
|
31
|
-
"backgroundPosition",
|
|
32
|
-
"backgroundSize",
|
|
33
|
-
"fontFamily",
|
|
34
|
-
"fontSize",
|
|
35
|
-
"lineHeight",
|
|
36
|
-
"letterSpacing",
|
|
37
|
-
"paddingInline",
|
|
38
|
-
"paddingBlock",
|
|
39
|
-
"marginInline",
|
|
40
|
-
"marginBlock",
|
|
41
|
-
"borderRadius",
|
|
42
|
-
"opacity",
|
|
43
|
-
"width",
|
|
44
|
-
"height"
|
|
45
|
-
];
|
|
46
|
-
export function EditableRegion({ id, as, children, ...props }) {
|
|
47
|
-
const Component = (as ?? "span");
|
|
48
|
-
return (_jsx(Component, { "data-chisel-id": id, ...props, children: children }));
|
|
49
|
-
}
|
|
50
|
-
export function Chisel({ enabled = process.env.NODE_ENV !== "production", position = "right", projectName = "Next.js app" }) {
|
|
51
|
-
const [hovered, setHovered] = React.useState(null);
|
|
52
|
-
const [selected, setSelected] = React.useState(null);
|
|
53
|
-
const [selectedElements, setSelectedElements] = React.useState([]);
|
|
54
|
-
const [hoverRect, setHoverRect] = React.useState(null);
|
|
55
|
-
const [selectedRects, setSelectedRects] = React.useState([]);
|
|
56
|
-
const [copied, setCopied] = React.useState(false);
|
|
57
|
-
const [versions, setVersions] = React.useState(() => [createVersion(1)]);
|
|
58
|
-
const [activeVersionId, setActiveVersionId] = React.useState("version-1");
|
|
59
|
-
const [versionsOpen, setVersionsOpen] = React.useState(false);
|
|
60
|
-
const snapshots = React.useRef(new WeakMap());
|
|
61
|
-
const baselines = React.useRef(new Map());
|
|
62
|
-
const routeKey = React.useRef("");
|
|
63
|
-
const hoveredRef = React.useRef(null);
|
|
64
|
-
const selectedRef = React.useRef(null);
|
|
65
|
-
const selectedElementsRef = React.useRef([]);
|
|
66
|
-
const hoverFrame = React.useRef(null);
|
|
67
|
-
const rectFrame = React.useRef(null);
|
|
68
|
-
React.useEffect(() => {
|
|
69
|
-
if (!enabled)
|
|
70
|
-
return;
|
|
71
|
-
const clearHover = () => {
|
|
72
|
-
if (!hoveredRef.current)
|
|
73
|
-
return;
|
|
74
|
-
hoveredRef.current = null;
|
|
75
|
-
setHovered(null);
|
|
76
|
-
setHoverRect(null);
|
|
77
|
-
};
|
|
78
|
-
const scheduleHoverRect = (target) => {
|
|
79
|
-
if (hoverFrame.current !== null)
|
|
80
|
-
window.cancelAnimationFrame(hoverFrame.current);
|
|
81
|
-
hoverFrame.current = window.requestAnimationFrame(() => {
|
|
82
|
-
hoverFrame.current = null;
|
|
83
|
-
if (hoveredRef.current !== target)
|
|
84
|
-
return;
|
|
85
|
-
setHoverRect(rectToJSON(target.getBoundingClientRect()));
|
|
86
|
-
});
|
|
87
|
-
};
|
|
88
|
-
const scheduleRects = () => {
|
|
89
|
-
if (rectFrame.current !== null)
|
|
90
|
-
return;
|
|
91
|
-
rectFrame.current = window.requestAnimationFrame(() => {
|
|
92
|
-
rectFrame.current = null;
|
|
93
|
-
const currentHovered = hoveredRef.current;
|
|
94
|
-
const currentSelected = selectedRef.current;
|
|
95
|
-
const currentSelectedElements = selectedElementsRef.current;
|
|
96
|
-
setHoverRect((current) => (currentHovered ? rectToJSON(currentHovered.getBoundingClientRect()) : current));
|
|
97
|
-
setSelectedRects(currentSelectedElements.map((element) => rectToJSON(element.getBoundingClientRect())));
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
const onMove = (event) => {
|
|
101
|
-
const target = event.target;
|
|
102
|
-
if (!(target instanceof HTMLElement) || isEditorElement(target)) {
|
|
103
|
-
clearHover();
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (target === hoveredRef.current)
|
|
107
|
-
return;
|
|
108
|
-
hoveredRef.current = target;
|
|
109
|
-
setHovered(target);
|
|
110
|
-
scheduleHoverRect(target);
|
|
111
|
-
};
|
|
112
|
-
const onClick = (event) => {
|
|
113
|
-
const target = event.target;
|
|
114
|
-
if (!(target instanceof HTMLElement) || isEditorElement(target))
|
|
115
|
-
return;
|
|
116
|
-
event.preventDefault();
|
|
117
|
-
event.stopPropagation();
|
|
118
|
-
selectElements(event.shiftKey ? toggleElementSelection(selectedElementsRef.current, target) : [target]);
|
|
119
|
-
};
|
|
120
|
-
const onKeyDown = (event) => {
|
|
121
|
-
const target = event.target;
|
|
122
|
-
if (target instanceof HTMLElement && isEditorElement(target))
|
|
123
|
-
return;
|
|
124
|
-
if (event.key === "Escape") {
|
|
125
|
-
selectedRef.current = null;
|
|
126
|
-
selectedElementsRef.current = [];
|
|
127
|
-
setSelected(null);
|
|
128
|
-
setSelectedElements([]);
|
|
129
|
-
setSelectedRects([]);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
document.addEventListener("mousemove", onMove, true);
|
|
133
|
-
document.addEventListener("click", onClick, true);
|
|
134
|
-
document.addEventListener("keydown", onKeyDown);
|
|
135
|
-
window.addEventListener("resize", scheduleRects);
|
|
136
|
-
window.addEventListener("scroll", scheduleRects, true);
|
|
137
|
-
return () => {
|
|
138
|
-
if (hoverFrame.current !== null)
|
|
139
|
-
window.cancelAnimationFrame(hoverFrame.current);
|
|
140
|
-
if (rectFrame.current !== null)
|
|
141
|
-
window.cancelAnimationFrame(rectFrame.current);
|
|
142
|
-
document.removeEventListener("mousemove", onMove, true);
|
|
143
|
-
document.removeEventListener("click", onClick, true);
|
|
144
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
145
|
-
window.removeEventListener("resize", scheduleRects);
|
|
146
|
-
window.removeEventListener("scroll", scheduleRects, true);
|
|
147
|
-
};
|
|
148
|
-
}, [enabled]);
|
|
149
|
-
React.useEffect(() => {
|
|
150
|
-
selectedRef.current = selected;
|
|
151
|
-
}, [selected]);
|
|
152
|
-
React.useEffect(() => {
|
|
153
|
-
selectedElementsRef.current = selectedElements;
|
|
154
|
-
}, [selectedElements]);
|
|
155
|
-
React.useEffect(() => {
|
|
156
|
-
if (!selectedElements.length)
|
|
157
|
-
return;
|
|
158
|
-
let frame = null;
|
|
159
|
-
const scheduleSelectedRect = () => {
|
|
160
|
-
if (frame !== null)
|
|
161
|
-
return;
|
|
162
|
-
frame = window.requestAnimationFrame(() => {
|
|
163
|
-
frame = null;
|
|
164
|
-
setSelectedRects(selectedElements.map((element) => rectToJSON(element.getBoundingClientRect())));
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
if (typeof ResizeObserver === "undefined") {
|
|
168
|
-
const id = window.setInterval(scheduleSelectedRect, 750);
|
|
169
|
-
return () => {
|
|
170
|
-
if (frame !== null)
|
|
171
|
-
window.cancelAnimationFrame(frame);
|
|
172
|
-
window.clearInterval(id);
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
const observer = new ResizeObserver(scheduleSelectedRect);
|
|
176
|
-
for (const element of selectedElements)
|
|
177
|
-
observer.observe(element);
|
|
178
|
-
return () => {
|
|
179
|
-
if (frame !== null)
|
|
180
|
-
window.cancelAnimationFrame(frame);
|
|
181
|
-
observer.disconnect();
|
|
182
|
-
};
|
|
183
|
-
}, [selected, selectedElements]);
|
|
184
|
-
React.useEffect(() => {
|
|
185
|
-
if (!enabled)
|
|
186
|
-
return;
|
|
187
|
-
const key = getRouteStorageKey();
|
|
188
|
-
routeKey.current = key;
|
|
189
|
-
const storedVersions = readStoredVersions(key);
|
|
190
|
-
const nextVersions = storedVersions.length ? storedVersions : [createVersion(1)];
|
|
191
|
-
setVersions(nextVersions);
|
|
192
|
-
setActiveVersionId(nextVersions[0].id);
|
|
193
|
-
window.setTimeout(() => applyVersionToDom(nextVersions[0], baselines.current), 0);
|
|
194
|
-
}, [enabled]);
|
|
195
|
-
React.useEffect(() => {
|
|
196
|
-
if (!enabled || !routeKey.current)
|
|
197
|
-
return;
|
|
198
|
-
window.localStorage.setItem(routeKey.current, JSON.stringify(versions));
|
|
199
|
-
}, [enabled, versions]);
|
|
200
|
-
if (!enabled)
|
|
201
|
-
return null;
|
|
202
|
-
const selectionCount = selectedElements.length;
|
|
203
|
-
const snapshot = selected ? snapshots.current.get(selected) : undefined;
|
|
204
|
-
const canEditText = Boolean(selectionCount <= 1 && selected && selected.children.length === 0);
|
|
205
|
-
const sourceHint = selected ? getSourceHint(selected) : undefined;
|
|
206
|
-
const selector = selected ? getBestSelector(selected) : "";
|
|
207
|
-
const changedValues = selected && snapshot ? getChanges(selected, snapshot) : [];
|
|
208
|
-
const activeVersion = versions.find((version) => version.id === activeVersionId) ?? versions[0] ?? createVersion(1);
|
|
209
|
-
const selectedComputedStyle = selected ? getComputedStyle(selected) : null;
|
|
210
|
-
const getSelectedTargets = () => (selectedElements.length ? selectedElements : selected ? [selected] : []);
|
|
211
|
-
function selectElements(elements) {
|
|
212
|
-
for (const element of elements)
|
|
213
|
-
ensureSnapshot(element, snapshots.current);
|
|
214
|
-
const nextSelected = elements[elements.length - 1] ?? null;
|
|
215
|
-
selectedElementsRef.current = elements;
|
|
216
|
-
selectedRef.current = nextSelected;
|
|
217
|
-
setSelectedElements(elements);
|
|
218
|
-
setSelected(nextSelected);
|
|
219
|
-
setSelectedRects(elements.map((element) => rectToJSON(element.getBoundingClientRect())));
|
|
220
|
-
}
|
|
221
|
-
const refreshSelectedRects = () => {
|
|
222
|
-
setSelectedRects(selectedElements.map((element) => rectToJSON(element.getBoundingClientRect())));
|
|
223
|
-
};
|
|
224
|
-
const addVersion = () => {
|
|
225
|
-
const nextVersion = {
|
|
226
|
-
id: `version-${Date.now()}`,
|
|
227
|
-
name: `Version ${versions.length + 1}`,
|
|
228
|
-
elements: cloneVersionElements(activeVersion.elements)
|
|
229
|
-
};
|
|
230
|
-
setVersions((current) => [...current, nextVersion]);
|
|
231
|
-
setActiveVersionId(nextVersion.id);
|
|
232
|
-
setVersionsOpen(false);
|
|
233
|
-
applyVersionToDom(nextVersion, baselines.current);
|
|
234
|
-
refreshSelectedRects();
|
|
235
|
-
};
|
|
236
|
-
const selectVersion = (version) => {
|
|
237
|
-
setActiveVersionId(version.id);
|
|
238
|
-
setVersionsOpen(false);
|
|
239
|
-
applyVersionToDom(version, baselines.current);
|
|
240
|
-
refreshSelectedRects();
|
|
241
|
-
};
|
|
242
|
-
const applyNumeric = (control, value) => {
|
|
243
|
-
const next = control.unit === "px" ? `${value}px` : String(value);
|
|
244
|
-
applyStyleValue(control, next);
|
|
245
|
-
};
|
|
246
|
-
const applyStyleValue = (control, value) => {
|
|
247
|
-
const targets = getSelectedTargets();
|
|
248
|
-
if (!targets.length)
|
|
249
|
-
return;
|
|
250
|
-
for (const element of targets) {
|
|
251
|
-
ensureElementBaseline(element, getElementKey(element), baselines.current);
|
|
252
|
-
element.style[control.property] = value;
|
|
253
|
-
recordElementChange(element, { styles: { [control.property]: value } });
|
|
254
|
-
}
|
|
255
|
-
refreshSelectedRects();
|
|
256
|
-
};
|
|
257
|
-
const applyColor = (property, value) => {
|
|
258
|
-
const targets = getSelectedTargets();
|
|
259
|
-
if (!targets.length)
|
|
260
|
-
return;
|
|
261
|
-
for (const element of targets) {
|
|
262
|
-
ensureElementBaseline(element, getElementKey(element), baselines.current);
|
|
263
|
-
if (property === "backgroundColor" && isBackgroundImageValue(value)) {
|
|
264
|
-
element.style.backgroundImage = value;
|
|
265
|
-
if (value.startsWith("url(")) {
|
|
266
|
-
element.style.backgroundPosition = "center";
|
|
267
|
-
element.style.backgroundSize = "cover";
|
|
268
|
-
recordElementChange(element, { styles: { backgroundImage: value, backgroundPosition: "center", backgroundSize: "cover" } });
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
recordElementChange(element, { styles: { backgroundImage: value } });
|
|
272
|
-
}
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
element.style[property] = value;
|
|
276
|
-
if (property === "backgroundColor") {
|
|
277
|
-
element.style.backgroundImage = "";
|
|
278
|
-
element.style.backgroundPosition = "";
|
|
279
|
-
element.style.backgroundSize = "";
|
|
280
|
-
recordElementChange(element, { styles: { backgroundColor: value, backgroundImage: "", backgroundPosition: "", backgroundSize: "" } });
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
recordElementChange(element, { styles: { [property]: value } });
|
|
284
|
-
}
|
|
285
|
-
refreshSelectedRects();
|
|
286
|
-
};
|
|
287
|
-
const applyFontFamily = (value) => {
|
|
288
|
-
const targets = getSelectedTargets();
|
|
289
|
-
if (!targets.length)
|
|
290
|
-
return;
|
|
291
|
-
for (const element of targets) {
|
|
292
|
-
ensureElementBaseline(element, getElementKey(element), baselines.current);
|
|
293
|
-
element.style.fontFamily = value;
|
|
294
|
-
recordElementChange(element, { styles: { fontFamily: value } });
|
|
295
|
-
}
|
|
296
|
-
refreshSelectedRects();
|
|
297
|
-
};
|
|
298
|
-
const previewFontFamily = (value) => {
|
|
299
|
-
const targets = getSelectedTargets();
|
|
300
|
-
if (!targets.length)
|
|
301
|
-
return;
|
|
302
|
-
for (const element of targets) {
|
|
303
|
-
ensureElementBaseline(element, getElementKey(element), baselines.current);
|
|
304
|
-
element.style.fontFamily = value;
|
|
305
|
-
}
|
|
306
|
-
refreshSelectedRects();
|
|
307
|
-
};
|
|
308
|
-
const applyText = (value) => {
|
|
309
|
-
if (!selected || !canEditText)
|
|
310
|
-
return;
|
|
311
|
-
ensureElementBaseline(selected, getElementKey(selected), baselines.current);
|
|
312
|
-
selected.textContent = value;
|
|
313
|
-
recordElementChange(selected, { text: value });
|
|
314
|
-
refreshSelectedRects();
|
|
315
|
-
};
|
|
316
|
-
const resetSelected = () => {
|
|
317
|
-
const targets = getSelectedTargets();
|
|
318
|
-
if (!targets.length)
|
|
319
|
-
return;
|
|
320
|
-
for (const element of targets) {
|
|
321
|
-
const elementSnapshot = snapshots.current.get(element);
|
|
322
|
-
const baseline = baselines.current.get(getElementKey(element));
|
|
323
|
-
for (const property of STYLE_PROPERTIES) {
|
|
324
|
-
element.style[property] = baseline?.styles[property] ?? "";
|
|
325
|
-
}
|
|
326
|
-
if (element === selected && canEditText)
|
|
327
|
-
element.textContent = baseline?.text ?? elementSnapshot?.text ?? "";
|
|
328
|
-
removeElementChange(element);
|
|
329
|
-
}
|
|
330
|
-
refreshSelectedRects();
|
|
331
|
-
};
|
|
332
|
-
function recordElementChange(element, patch) {
|
|
333
|
-
const key = getElementKey(element);
|
|
334
|
-
ensureElementBaseline(element, key, baselines.current);
|
|
335
|
-
setVersions((current) => current.map((version) => {
|
|
336
|
-
if (version.id !== activeVersionId)
|
|
337
|
-
return version;
|
|
338
|
-
const existing = version.elements[key];
|
|
339
|
-
return {
|
|
340
|
-
...version,
|
|
341
|
-
elements: {
|
|
342
|
-
...version.elements,
|
|
343
|
-
[key]: {
|
|
344
|
-
selector: getBestSelector(element),
|
|
345
|
-
sourceHint: getSourceHint(element),
|
|
346
|
-
text: patch.text ?? existing?.text,
|
|
347
|
-
styles: {
|
|
348
|
-
...(existing?.styles ?? {}),
|
|
349
|
-
...(patch.styles ?? {})
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
}));
|
|
355
|
-
}
|
|
356
|
-
function removeElementChange(element) {
|
|
357
|
-
const key = getElementKey(element);
|
|
358
|
-
setVersions((current) => current.map((version) => {
|
|
359
|
-
if (version.id !== activeVersionId)
|
|
360
|
-
return version;
|
|
361
|
-
const { [key]: _removed, ...elements } = version.elements;
|
|
362
|
-
return { ...version, elements };
|
|
363
|
-
}));
|
|
364
|
-
}
|
|
365
|
-
const copyPrompt = async () => {
|
|
366
|
-
const prompt = getPrompt();
|
|
367
|
-
if (!prompt)
|
|
368
|
-
return;
|
|
369
|
-
await navigator.clipboard.writeText(prompt);
|
|
370
|
-
setCopied(true);
|
|
371
|
-
window.setTimeout(() => setCopied(false), 1600);
|
|
372
|
-
};
|
|
373
|
-
function getPrompt() {
|
|
374
|
-
const selectedRect = selected ? rectToJSON(selected.getBoundingClientRect()) : undefined;
|
|
375
|
-
if (Object.keys(activeVersion.elements).length)
|
|
376
|
-
return buildPageAgentPrompt({ projectName, version: activeVersion, baselines: baselines.current });
|
|
377
|
-
if (!selected || !snapshot || !selectedRect)
|
|
378
|
-
return undefined;
|
|
379
|
-
return buildAgentPrompt({
|
|
380
|
-
projectName,
|
|
381
|
-
element: selected,
|
|
382
|
-
snapshot,
|
|
383
|
-
rect: selectedRect,
|
|
384
|
-
selector,
|
|
385
|
-
sourceHint,
|
|
386
|
-
changes: changedValues
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
return (_jsxs("div", { "data-chisel-root": "true", className: "chisel-root", children: [_jsx(ChiselStyles, {}), hoverRect && hovered && !selectedElements.includes(hovered) ? _jsx(Box, { rect: hoverRect, tone: "hover" }) : null, selectedRects.map((rect, index) => (_jsx(Box, { rect: rect, tone: "selected" }, `${rect.left}-${rect.top}-${index}`))), _jsx("aside", { className: `chisel-panel chisel-panel-${position}`, "aria-label": "Chisel editor", children: _jsx("div", { className: "chisel-panel-wrapper", children: _jsx("div", { className: "chisel-panel-inner", children: _jsxs("div", { className: "chisel-folder chisel-folder-root", children: [_jsx("header", { className: "chisel-folder-header chisel-panel-header", children: _jsxs("div", { className: "chisel-panel-toolbar", children: [_jsx("button", { className: "chisel-toolbar-add", type: "button", "aria-label": "Add version", onClick: addVersion, children: "+" }), _jsxs("div", { className: "chisel-preset-manager", children: [_jsxs("button", { className: "chisel-preset-trigger", type: "button", "aria-expanded": versionsOpen, "aria-haspopup": "listbox", onClick: () => setVersionsOpen((open) => !open), children: [_jsx("span", { className: "chisel-preset-trigger-label", children: activeVersion.name }), _jsx("span", { className: "chisel-chevron", "aria-hidden": "true" })] }), versionsOpen ? (_jsx("div", { className: "chisel-preset-dropdown", role: "listbox", "aria-label": "Page versions", children: _jsx("div", { className: "chisel-preset-list", children: versions.map((version) => (_jsxs("button", { className: "chisel-preset-item", type: "button", role: "option", "aria-selected": version.id === activeVersion.id, "data-active": version.id === activeVersion.id, onClick: () => selectVersion(version), children: [_jsx("span", { className: "chisel-preset-name", children: version.name }), _jsx("span", { className: "chisel-preset-count", children: Object.keys(version.elements).length })] }, version.id))) }) })) : null] }), _jsx("button", { className: "chisel-toolbar-add", type: "button", onClick: () => {
|
|
390
|
-
selectedRef.current = null;
|
|
391
|
-
selectedElementsRef.current = [];
|
|
392
|
-
setSelected(null);
|
|
393
|
-
setSelectedElements([]);
|
|
394
|
-
setSelectedRects([]);
|
|
395
|
-
}, "aria-label": "Clear selection", children: "\u00D7" })] }) }), selected && snapshot ? (_jsxs("div", { className: "chisel-content", children: [_jsxs("div", { className: "chisel-text-control", children: [_jsx("span", { className: "chisel-text-label", children: selectionCount > 1 ? "Selection" : "Element" }), _jsx("code", { className: "chisel-text-code", children: selectionCount > 1 ? `${selectionCount} elements` : selected.tagName.toLowerCase() })] }), _jsxs("div", { className: "chisel-text-control chisel-selector-row", children: [_jsx("span", { className: "chisel-text-label", children: "Selector" }), _jsx("code", { className: "chisel-selector", children: selector })] }), _jsxs("div", { className: sourceHint ? "chisel-text-control" : "chisel-text-control chisel-warning-row", children: [_jsx("span", { className: "chisel-text-label", children: "Source" }), _jsx("span", { className: sourceHint ? "chisel-text-value" : "chisel-warning", children: sourceHint ? `Source hint: ${sourceHint}` : "Low-confidence source mapping" })] }), _jsxs("div", { className: "chisel-folder", children: [_jsx("div", { className: "chisel-folder-header", children: _jsx("div", { className: "chisel-folder-header-top", children: _jsx("div", { className: "chisel-folder-title-row", children: _jsx("span", { className: "chisel-folder-title", children: "Content" }) }) }) }), _jsx("div", { className: "chisel-folder-content", children: _jsxs("div", { className: "chisel-folder-inner", children: [_jsxs("label", { className: "chisel-text-control chisel-textarea-control", children: [_jsx("span", { className: "chisel-text-label", children: "Text" }), _jsx("textarea", { className: "chisel-text-input", value: selected.textContent ?? "", onChange: (event) => applyText(event.target.value), disabled: !canEditText, rows: 3 })] }), !canEditText ? _jsx("div", { className: "chisel-note-row", children: selectionCount > 1 ? "Text editing is enabled for one element at a time." : "Text editing is enabled for simple text elements." }) : null] }) })] }), _jsxs("div", { className: "chisel-folder", children: [_jsx("div", { className: "chisel-folder-header", children: _jsx("div", { className: "chisel-folder-header-top", children: _jsx("div", { className: "chisel-folder-title-row", children: _jsx("span", { className: "chisel-folder-title", children: "Color" }) }) }) }), _jsx("div", { className: "chisel-folder-content", children: _jsxs("div", { className: "chisel-folder-inner", children: [_jsx(ColorControl, { label: "Text", value: selected.style.color || toHex(selectedComputedStyle?.color ?? "#000000"), onChange: (value) => applyColor("color", value) }), _jsx(ColorControl, { label: "Fill", value: selected.style.backgroundImage ||
|
|
396
|
-
(selectedComputedStyle?.backgroundImage && selectedComputedStyle.backgroundImage !== "none" ? selectedComputedStyle.backgroundImage : selected.style.backgroundColor || toHex(selectedComputedStyle?.backgroundColor ?? "#ffffff")), onChange: (value) => applyColor("backgroundColor", value), supportsBackgroundImages: true })] }) })] }), _jsxs("div", { className: "chisel-folder", children: [_jsx("div", { className: "chisel-folder-header", children: _jsx("div", { className: "chisel-folder-header-top", children: _jsx("div", { className: "chisel-folder-title-row", children: _jsx("span", { className: "chisel-folder-title", children: "Style" }) }) }) }), _jsx("div", { className: "chisel-folder-content", children: _jsxs("div", { className: "chisel-folder-inner", children: [_jsx(FontFamilyControl, { value: selectedComputedStyle?.fontFamily ?? "", onChange: applyFontFamily, onPreview: previewFontFamily }), NUMERIC_CONTROLS.map((control) => (_jsx(SliderControl, { control: control, computedStyle: selectedComputedStyle, element: selected, onSlide: (value) => applyNumeric(control, value), onValueChange: (value) => applyStyleValue(control, value) }, control.cssProperty)))] }) })] }), _jsxs("div", { className: "chisel-folder", children: [_jsx("div", { className: "chisel-folder-header", children: _jsxs("div", { className: "chisel-folder-header-top", children: [_jsx("div", { className: "chisel-folder-title-row", children: _jsx("span", { className: "chisel-folder-title", children: "Changes" }) }), _jsx("span", { className: "chisel-folder-count", children: changedValues.length })] }) }), _jsx("div", { className: "chisel-folder-content", children: _jsx("div", { className: "chisel-folder-inner", children: changedValues.length ? (changedValues.map((change) => (_jsxs("div", { className: "chisel-text-control", children: [_jsx("span", { className: "chisel-text-label", children: change.property }), _jsx("strong", { className: "chisel-text-value", children: String(change.after) })] }, change.property)))) : (_jsx("div", { className: "chisel-note-row", children: "No preview changes yet." })) }) })] }), _jsxs("div", { className: "chisel-actions", children: [_jsx("button", { className: "chisel-button", type: "button", onClick: resetSelected, children: "Reset" }), _jsx("button", { className: "chisel-button", type: "button", onClick: copyPrompt, children: copied ? "Copied" : "Copy agent prompt" })] })] })) : (_jsxs("div", { className: "chisel-empty", children: [_jsx("div", { className: "chisel-note-row", children: "Select any visible element to edit its text and style preview." }), _jsx("button", { className: "chisel-button", type: "button", children: "Next" })] }))] }) }) }) })] }));
|
|
397
|
-
}
|
|
398
|
-
function Box({ rect, tone }) {
|
|
399
|
-
return (_jsx("div", { className: `chisel-box chisel-box-${tone}`, style: {
|
|
400
|
-
transform: `translate3d(${rect.left}px, ${rect.top}px, 0)`,
|
|
401
|
-
width: rect.width,
|
|
402
|
-
height: rect.height
|
|
403
|
-
} }));
|
|
404
|
-
}
|
|
405
|
-
function FontFamilyControl({ value, onChange, onPreview }) {
|
|
406
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
407
|
-
const rootRef = React.useRef(null);
|
|
408
|
-
const options = React.useMemo(() => getFontFamilyOptions(value), [value]);
|
|
409
|
-
const selectedOption = getMatchingFontOption(value, options);
|
|
410
|
-
const selectedLabel = selectedOption?.label ?? getFontFamilyLabel(value) ?? "Font";
|
|
411
|
-
React.useEffect(() => {
|
|
412
|
-
if (!isOpen)
|
|
413
|
-
return;
|
|
414
|
-
const closeOnOutsidePointer = (event) => {
|
|
415
|
-
const target = event.target;
|
|
416
|
-
if (target instanceof Node && rootRef.current?.contains(target))
|
|
417
|
-
return;
|
|
418
|
-
onPreview(value);
|
|
419
|
-
setIsOpen(false);
|
|
420
|
-
};
|
|
421
|
-
const closeOnEscape = (event) => {
|
|
422
|
-
if (event.key !== "Escape")
|
|
423
|
-
return;
|
|
424
|
-
onPreview(value);
|
|
425
|
-
setIsOpen(false);
|
|
426
|
-
};
|
|
427
|
-
document.addEventListener("pointerdown", closeOnOutsidePointer, true);
|
|
428
|
-
document.addEventListener("keydown", closeOnEscape);
|
|
429
|
-
return () => {
|
|
430
|
-
document.removeEventListener("pointerdown", closeOnOutsidePointer, true);
|
|
431
|
-
document.removeEventListener("keydown", closeOnEscape);
|
|
432
|
-
};
|
|
433
|
-
}, [isOpen, onPreview, value]);
|
|
434
|
-
const openMenu = () => {
|
|
435
|
-
setIsOpen((open) => {
|
|
436
|
-
if (open) {
|
|
437
|
-
onPreview(value);
|
|
438
|
-
return false;
|
|
439
|
-
}
|
|
440
|
-
return true;
|
|
441
|
-
});
|
|
442
|
-
};
|
|
443
|
-
const closeMenu = () => {
|
|
444
|
-
onPreview(value);
|
|
445
|
-
setIsOpen(false);
|
|
446
|
-
};
|
|
447
|
-
const selectFont = (option) => {
|
|
448
|
-
onChange(option.value);
|
|
449
|
-
setIsOpen(false);
|
|
450
|
-
};
|
|
451
|
-
return (_jsxs("div", { className: "chisel-font-control", ref: rootRef, children: [_jsx("span", { className: "chisel-font-label", children: "Font" }), _jsxs("div", { className: "chisel-font-picker", children: [_jsxs("button", { className: "chisel-font-trigger", type: "button", "aria-expanded": isOpen, "aria-haspopup": "listbox", onClick: openMenu, children: [_jsx("span", { className: "chisel-font-trigger-label", children: selectedLabel }), _jsx("span", { className: "chisel-chevron", "aria-hidden": "true" })] }), isOpen ? (_jsx("div", { className: "chisel-preset-dropdown chisel-font-dropdown", role: "listbox", "aria-label": "Font family", onMouseLeave: closeMenu, children: _jsx("div", { className: "chisel-preset-list chisel-font-list", children: options.map((option) => (_jsx("button", { className: "chisel-preset-item chisel-font-item", "data-active": isMatchingFontFamily(value, option.value), onClick: () => selectFont(option), onFocus: () => onPreview(option.value), onPointerEnter: () => onPreview(option.value), role: "option", style: { fontFamily: option.value }, type: "button", children: _jsx("span", { className: "chisel-preset-name", children: option.label }) }, option.value))) }) })) : null] })] }));
|
|
452
|
-
}
|
|
453
|
-
function ColorControl({ label, value, onChange, supportsBackgroundImages = false }) {
|
|
454
|
-
const parsedGradient = parseGradientValue(value);
|
|
455
|
-
const parsedImageUrl = parseImageUrlValue(value);
|
|
456
|
-
const initialMode = supportsBackgroundImages && parsedGradient ? "Gradient" : supportsBackgroundImages && parsedImageUrl !== undefined ? "Image" : "Solid";
|
|
457
|
-
const initialDraft = parsedGradient?.start ?? (parsedImageUrl !== undefined ? "#FFFFFF" : getColorDisplayValue(value));
|
|
458
|
-
const [mode, setMode] = React.useState(initialMode);
|
|
459
|
-
const [format, setFormat] = React.useState(() => inferColorFormat(initialDraft));
|
|
460
|
-
const [draft, setDraft] = React.useState(initialDraft);
|
|
461
|
-
const [gradientStart, setGradientStart] = React.useState(parsedGradient?.start ?? initialDraft);
|
|
462
|
-
const [gradientEnd, setGradientEnd] = React.useState(parsedGradient?.end ?? "#FFFFFF");
|
|
463
|
-
const [activeGradientStop, setActiveGradientStop] = React.useState("start");
|
|
464
|
-
const [imageUrl, setImageUrl] = React.useState(parsedImageUrl ?? "");
|
|
465
|
-
const [imageFileName, setImageFileName] = React.useState("");
|
|
466
|
-
const [isInvalid, setIsInvalid] = React.useState(false);
|
|
467
|
-
const [isPickerOpen, setIsPickerOpen] = React.useState(false);
|
|
468
|
-
const pickerRef = React.useRef(null);
|
|
469
|
-
const currentColorValue = mode === "Gradient" ? (activeGradientStop === "start" ? gradientStart : gradientEnd) : draft;
|
|
470
|
-
const currentHex = toHex(currentColorValue).toUpperCase();
|
|
471
|
-
const currentAlpha = getColorAlpha(currentColorValue);
|
|
472
|
-
const currentHsv = React.useMemo(() => rgbToHsv(hexToRgb(currentHex)), [currentHex]);
|
|
473
|
-
const summaryValue = mode === "Gradient" ? "Gradient" : mode === "Image" ? "Image" : draft;
|
|
474
|
-
React.useEffect(() => {
|
|
475
|
-
const nextGradient = parseGradientValue(value);
|
|
476
|
-
const nextImageUrl = parseImageUrlValue(value);
|
|
477
|
-
if (supportsBackgroundImages && nextGradient) {
|
|
478
|
-
const nextDraft = activeGradientStop === "end" ? nextGradient.end : nextGradient.start;
|
|
479
|
-
setMode("Gradient");
|
|
480
|
-
setGradientStart(nextGradient.start);
|
|
481
|
-
setGradientEnd(nextGradient.end);
|
|
482
|
-
setDraft(nextDraft);
|
|
483
|
-
setFormat(inferColorFormat(nextDraft));
|
|
484
|
-
setIsInvalid(false);
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
if (supportsBackgroundImages && nextImageUrl !== undefined) {
|
|
488
|
-
setMode("Image");
|
|
489
|
-
setImageUrl(nextImageUrl);
|
|
490
|
-
setDraft("#FFFFFF");
|
|
491
|
-
setIsInvalid(false);
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
const displayValue = getColorDisplayValue(value);
|
|
495
|
-
setMode("Solid");
|
|
496
|
-
setDraft((currentDraft) => (currentDraft && toHex(currentDraft) === toHex(displayValue) ? currentDraft : displayValue));
|
|
497
|
-
setFormat(inferColorFormat(displayValue));
|
|
498
|
-
setIsInvalid(false);
|
|
499
|
-
}, [activeGradientStop, supportsBackgroundImages, value]);
|
|
500
|
-
React.useEffect(() => {
|
|
501
|
-
if (!isPickerOpen)
|
|
502
|
-
return;
|
|
503
|
-
const closeOnOutsidePointer = (event) => {
|
|
504
|
-
const target = event.target;
|
|
505
|
-
if (target instanceof Node && pickerRef.current?.contains(target))
|
|
506
|
-
return;
|
|
507
|
-
setIsPickerOpen(false);
|
|
508
|
-
};
|
|
509
|
-
document.addEventListener("pointerdown", closeOnOutsidePointer, true);
|
|
510
|
-
return () => document.removeEventListener("pointerdown", closeOnOutsidePointer, true);
|
|
511
|
-
}, [isPickerOpen]);
|
|
512
|
-
const applyColorValue = (nextValue) => {
|
|
513
|
-
const normalized = normalizeColorInput(nextValue);
|
|
514
|
-
if (!normalized) {
|
|
515
|
-
setIsInvalid(nextValue.trim().length > 0);
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
const formatted = normalizeHexColor(normalized) ?? normalized;
|
|
519
|
-
setFormat(inferColorFormat(formatted));
|
|
520
|
-
setDraft(formatted);
|
|
521
|
-
setIsInvalid(false);
|
|
522
|
-
if (mode === "Gradient") {
|
|
523
|
-
applyGradientStop(activeGradientStop, formatted);
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
onChange(formatted);
|
|
527
|
-
};
|
|
528
|
-
const applyFormattedColor = (nextHex, nextAlpha = currentAlpha, nextFormat = format) => {
|
|
529
|
-
const formatted = formatColorValue(nextHex, nextAlpha, nextFormat);
|
|
530
|
-
setDraft(formatted);
|
|
531
|
-
setIsInvalid(false);
|
|
532
|
-
if (mode === "Gradient") {
|
|
533
|
-
applyGradientStop(activeGradientStop, formatted);
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
onChange(formatted);
|
|
537
|
-
};
|
|
538
|
-
const applySaturationValue = (event, rect) => {
|
|
539
|
-
const saturation = clamp(((event.clientX - rect.left) / rect.width) * 100, 0, 100);
|
|
540
|
-
const brightness = clamp((1 - (event.clientY - rect.top) / rect.height) * 100, 0, 100);
|
|
541
|
-
applyFormattedColor(hsvToHex(currentHsv.h, saturation, brightness));
|
|
542
|
-
};
|
|
543
|
-
const applyHue = (event, rect) => {
|
|
544
|
-
const hue = clamp(((event.clientX - rect.left) / rect.width) * 360, 0, 360);
|
|
545
|
-
applyFormattedColor(hsvToHex(hue, currentHsv.s, currentHsv.v));
|
|
546
|
-
};
|
|
547
|
-
const applyAlpha = (event, rect) => {
|
|
548
|
-
const alpha = clamp((event.clientX - rect.left) / rect.width, 0, 1);
|
|
549
|
-
applyFormattedColor(currentHex, alpha);
|
|
550
|
-
};
|
|
551
|
-
const selectFormat = (nextFormat) => {
|
|
552
|
-
setFormat(nextFormat);
|
|
553
|
-
applyFormattedColor(currentHex, currentAlpha, nextFormat);
|
|
554
|
-
};
|
|
555
|
-
const selectMode = (nextMode) => {
|
|
556
|
-
if (nextMode !== "Solid" && !supportsBackgroundImages)
|
|
557
|
-
return;
|
|
558
|
-
setMode(nextMode);
|
|
559
|
-
if (nextMode === "Solid")
|
|
560
|
-
onChange(draft);
|
|
561
|
-
if (nextMode === "Gradient") {
|
|
562
|
-
const nextStart = gradientStart || draft;
|
|
563
|
-
setGradientStart(nextStart);
|
|
564
|
-
setActiveGradientStop("start");
|
|
565
|
-
setDraft(nextStart);
|
|
566
|
-
onChange(getGradientValue(nextStart, gradientEnd));
|
|
567
|
-
}
|
|
568
|
-
if (nextMode === "Image" && imageUrl.trim())
|
|
569
|
-
onChange(getImageValue(imageUrl));
|
|
570
|
-
};
|
|
571
|
-
const selectGradientStop = (stop) => {
|
|
572
|
-
const nextDraft = stop === "start" ? gradientStart : gradientEnd;
|
|
573
|
-
setActiveGradientStop(stop);
|
|
574
|
-
setDraft(nextDraft);
|
|
575
|
-
setFormat(inferColorFormat(nextDraft));
|
|
576
|
-
setIsInvalid(false);
|
|
577
|
-
};
|
|
578
|
-
const applyGradientStop = (stop, nextValue) => {
|
|
579
|
-
const nextStart = stop === "start" ? nextValue : gradientStart;
|
|
580
|
-
const nextEnd = stop === "end" ? nextValue : gradientEnd;
|
|
581
|
-
setGradientStart(nextStart);
|
|
582
|
-
setGradientEnd(nextEnd);
|
|
583
|
-
onChange(getGradientValue(nextStart, nextEnd));
|
|
584
|
-
};
|
|
585
|
-
const applyGradientStopValue = (stop, nextValue) => {
|
|
586
|
-
const normalized = normalizeColorInput(nextValue);
|
|
587
|
-
if (stop === "start")
|
|
588
|
-
setGradientStart(nextValue);
|
|
589
|
-
else
|
|
590
|
-
setGradientEnd(nextValue);
|
|
591
|
-
setActiveGradientStop(stop);
|
|
592
|
-
setDraft(nextValue);
|
|
593
|
-
if (!normalized) {
|
|
594
|
-
setIsInvalid(nextValue.trim().length > 0);
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
const formatted = normalizeHexColor(normalized) ?? normalized;
|
|
598
|
-
setFormat(inferColorFormat(formatted));
|
|
599
|
-
setDraft(formatted);
|
|
600
|
-
setIsInvalid(false);
|
|
601
|
-
applyGradientStop(stop, formatted);
|
|
602
|
-
};
|
|
603
|
-
const applyImageUrl = (nextValue) => {
|
|
604
|
-
setImageUrl(nextValue);
|
|
605
|
-
setImageFileName("");
|
|
606
|
-
if (nextValue.trim())
|
|
607
|
-
onChange(getImageValue(nextValue));
|
|
608
|
-
};
|
|
609
|
-
const applyImageFile = (event) => {
|
|
610
|
-
const file = event.currentTarget.files?.[0];
|
|
611
|
-
if (!file)
|
|
612
|
-
return;
|
|
613
|
-
setImageFileName(file.name);
|
|
614
|
-
const reader = new FileReader();
|
|
615
|
-
reader.onload = () => {
|
|
616
|
-
if (typeof reader.result !== "string")
|
|
617
|
-
return;
|
|
618
|
-
setImageUrl(reader.result);
|
|
619
|
-
onChange(getImageValue(reader.result));
|
|
620
|
-
};
|
|
621
|
-
reader.readAsDataURL(file);
|
|
622
|
-
};
|
|
623
|
-
return (_jsxs("div", { className: "chisel-color-control", "data-picker-open": isPickerOpen, ref: pickerRef, children: [_jsx("span", { className: "chisel-color-label", children: label }), _jsxs("span", { className: "chisel-color-inputs", children: [_jsx("button", { className: "chisel-color-swatch", "aria-expanded": isPickerOpen, "aria-label": `${label} color picker`, onClick: () => setIsPickerOpen((open) => !open), style: { background: mode === "Gradient" ? getGradientValue(gradientStart, gradientEnd) : mode === "Image" && imageUrl ? getImageValue(imageUrl) : draft }, type: "button" }), _jsx("input", { className: "chisel-color-value-input", "aria-label": `${label} color value`, autoCapitalize: "off", autoComplete: "off", autoCorrect: "off", "data-invalid": isInvalid, readOnly: mode !== "Solid", spellCheck: false, style: { width: `${Math.max(7.5, Math.min(summaryValue.length + 0.5, 18))}ch` }, value: summaryValue, onBlur: () => {
|
|
624
|
-
if (mode === "Solid")
|
|
625
|
-
applyColorValue(draft);
|
|
626
|
-
}, onChange: (event) => {
|
|
627
|
-
if (mode !== "Solid")
|
|
628
|
-
return;
|
|
629
|
-
const nextDraft = event.target.value;
|
|
630
|
-
setDraft(nextDraft);
|
|
631
|
-
applyColorValue(nextDraft);
|
|
632
|
-
}, onKeyDown: (event) => {
|
|
633
|
-
if (event.key === "Enter") {
|
|
634
|
-
event.preventDefault();
|
|
635
|
-
applyColorValue(draft);
|
|
636
|
-
event.currentTarget.blur();
|
|
637
|
-
}
|
|
638
|
-
if (event.key === "Escape") {
|
|
639
|
-
event.preventDefault();
|
|
640
|
-
setDraft(initialDraft);
|
|
641
|
-
setIsInvalid(false);
|
|
642
|
-
setIsPickerOpen(false);
|
|
643
|
-
event.currentTarget.blur();
|
|
644
|
-
}
|
|
645
|
-
} })] }), isPickerOpen ? (_jsxs("div", { className: "chisel-color-popover", role: "dialog", "aria-label": `${label} custom color picker`, children: [_jsxs("div", { className: "chisel-color-tabs", children: [COLOR_MODES.map((colorMode) => (_jsx("button", { className: "chisel-color-tab", "data-active": mode === colorMode, "aria-disabled": colorMode !== "Solid" && !supportsBackgroundImages, onClick: () => selectMode(colorMode), type: "button", children: colorMode }, colorMode))), _jsx("button", { className: "chisel-color-close", "aria-label": "Close color picker", onClick: () => setIsPickerOpen(false), type: "button", children: "\u00D7" })] }), mode !== "Image" ? (_jsxs(_Fragment, { children: [mode === "Gradient" ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "chisel-color-gradient-preview", style: { backgroundImage: getGradientValue(gradientStart, gradientEnd) } }), _jsxs("div", { className: "chisel-color-stop-buttons", role: "group", "aria-label": `${label} gradient endpoints`, children: [_jsxs("button", { className: "chisel-color-stop-button", "data-active": activeGradientStop === "start", "aria-label": `${label} gradient From`, onClick: () => selectGradientStop("start"), type: "button", children: [_jsx("span", { className: "chisel-color-stop-swatch", style: { background: gradientStart } }), _jsx("span", { children: "From" })] }), _jsxs("button", { className: "chisel-color-stop-button", "data-active": activeGradientStop === "end", "aria-label": `${label} gradient To`, onClick: () => selectGradientStop("end"), type: "button", children: [_jsx("span", { className: "chisel-color-stop-swatch", style: { background: gradientEnd } }), _jsx("span", { children: "To" })] })] })] })) : null, _jsx("div", { className: "chisel-color-field", onPointerDown: (event) => {
|
|
646
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
647
|
-
applySaturationValue(event, rect);
|
|
648
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
649
|
-
}, onPointerMove: (event) => {
|
|
650
|
-
if (!(event.buttons & 1))
|
|
651
|
-
return;
|
|
652
|
-
applySaturationValue(event, event.currentTarget.getBoundingClientRect());
|
|
653
|
-
}, style: { backgroundColor: `hsl(${currentHsv.h} 100% 50%)` }, children: _jsx("span", { className: "chisel-color-field-cursor", style: {
|
|
654
|
-
left: `clamp(6px, ${currentHsv.s}%, calc(100% - 6px))`,
|
|
655
|
-
top: `clamp(6px, ${100 - currentHsv.v}%, calc(100% - 6px))`,
|
|
656
|
-
backgroundColor: currentHex
|
|
657
|
-
} }) }), _jsx("div", { className: "chisel-color-hue", onPointerDown: (event) => {
|
|
658
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
659
|
-
applyHue(event, rect);
|
|
660
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
661
|
-
}, onPointerMove: (event) => {
|
|
662
|
-
if (!(event.buttons & 1))
|
|
663
|
-
return;
|
|
664
|
-
applyHue(event, event.currentTarget.getBoundingClientRect());
|
|
665
|
-
}, children: _jsx("span", { className: "chisel-color-hue-cursor", style: { left: `clamp(4px, ${(currentHsv.h / 360) * 100}%, calc(100% - 4px))` } }) }), _jsxs("div", { className: "chisel-color-alpha", onPointerDown: (event) => {
|
|
666
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
667
|
-
applyAlpha(event, rect);
|
|
668
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
669
|
-
}, onPointerMove: (event) => {
|
|
670
|
-
if (!(event.buttons & 1))
|
|
671
|
-
return;
|
|
672
|
-
applyAlpha(event, event.currentTarget.getBoundingClientRect());
|
|
673
|
-
}, style: { "--chisel-alpha-color": currentHex }, children: [_jsx("span", { className: "chisel-color-alpha-fill", style: { width: `${currentAlpha * 100}%` } }), _jsx("span", { className: "chisel-color-alpha-cursor", style: { left: `clamp(8px, ${currentAlpha * 100}%, calc(100% - 8px))`, backgroundColor: colorWithAlpha(currentHex, currentAlpha) } })] }), _jsxs("div", { className: "chisel-color-format-row", children: [_jsx("select", { className: "chisel-color-format-select", "aria-label": `${label} color format`, value: format, onChange: (event) => selectFormat(event.target.value), children: COLOR_FORMATS.map((option) => (_jsx("option", { value: option, children: option }, option))) }), _jsx("input", { className: "chisel-color-format-input", "aria-label": `${label} formatted color value`, autoCapitalize: "off", autoComplete: "off", autoCorrect: "off", "data-invalid": isInvalid, spellCheck: false, value: draft, onBlur: () => applyColorValue(draft), onChange: (event) => {
|
|
674
|
-
const nextDraft = event.target.value;
|
|
675
|
-
setDraft(nextDraft);
|
|
676
|
-
applyColorValue(nextDraft);
|
|
677
|
-
} })] })] })) : null, mode === "Gradient" ? (_jsxs(_Fragment, { children: [_jsxs("label", { className: "chisel-color-extra-row", children: [_jsx("span", { children: "From" }), _jsx("input", { "aria-label": `${label} gradient From value`, value: gradientStart, onFocus: () => selectGradientStop("start"), onChange: (event) => applyGradientStopValue("start", event.target.value) })] }), _jsxs("label", { className: "chisel-color-extra-row", children: [_jsx("span", { children: "To" }), _jsx("input", { "aria-label": `${label} gradient To value`, value: gradientEnd, onFocus: () => selectGradientStop("end"), onChange: (event) => applyGradientStopValue("end", event.target.value) })] })] })) : null, mode === "Image" ? (_jsxs(_Fragment, { children: [_jsxs("label", { className: "chisel-color-extra-row", children: [_jsx("span", { children: "URL" }), _jsx("input", { "aria-label": `${label} image URL`, value: imageUrl, onChange: (event) => applyImageUrl(event.target.value), placeholder: "https://..." })] }), _jsxs("label", { className: "chisel-color-upload-row", children: [_jsx("span", { children: "Upload" }), _jsx("span", { className: "chisel-color-upload-name", children: imageFileName || "Choose image" }), _jsx("input", { "aria-label": `${label} image upload`, accept: "image/*", type: "file", onChange: applyImageFile })] })] })) : null] })) : null] }));
|
|
678
|
-
}
|
|
679
|
-
function SliderControl({ control, computedStyle, element, onSlide, onValueChange }) {
|
|
680
|
-
const computed = computedStyle ?? getComputedStyle(element);
|
|
681
|
-
const raw = computed[control.property];
|
|
682
|
-
const parsed = parseFloat(raw);
|
|
683
|
-
const fallback = control.property === "width" ? element.getBoundingClientRect().width : control.property === "height" ? element.getBoundingClientRect().height : control.min;
|
|
684
|
-
const value = Number.isFinite(parsed) ? parsed : fallback;
|
|
685
|
-
const clamped = clamp(value, control.min, control.max);
|
|
686
|
-
const percent = getSliderPercent(clamped, control.min, control.max);
|
|
687
|
-
const authoredValue = element.style[control.property];
|
|
688
|
-
const displayValue = authoredValue || `${formatNumber(value)}${control.unit}`;
|
|
689
|
-
const inferredUnit = getInferredUnit(displayValue, control);
|
|
690
|
-
const [draft, setDraft] = React.useState(displayValue);
|
|
691
|
-
const [isEditing, setIsEditing] = React.useState(false);
|
|
692
|
-
const [isInvalid, setIsInvalid] = React.useState(false);
|
|
693
|
-
const [unitMenuOpen, setUnitMenuOpen] = React.useState(false);
|
|
694
|
-
const inputRef = React.useRef(null);
|
|
695
|
-
const dragState = React.useRef(null);
|
|
696
|
-
const suppressClickFocus = React.useRef(false);
|
|
697
|
-
const unitOptions = React.useMemo(() => getSupportedUnits(control), [control]);
|
|
698
|
-
const handleStyle = {
|
|
699
|
-
left: `max(5px, ${percent}% - 9px)`,
|
|
700
|
-
"--chisel-handle-opacity": percent < 18 ? "0.18" : "1",
|
|
701
|
-
"--chisel-handle-scale": percent < 18 ? "0.25" : "1"
|
|
702
|
-
};
|
|
703
|
-
React.useEffect(() => {
|
|
704
|
-
if (!isEditing) {
|
|
705
|
-
setDraft(displayValue);
|
|
706
|
-
setIsInvalid(false);
|
|
707
|
-
}
|
|
708
|
-
}, [displayValue, isEditing]);
|
|
709
|
-
const commitDraft = (nextDraft = draft) => {
|
|
710
|
-
const normalized = normalizeStyleInput(nextDraft, control, element, inferredUnit);
|
|
711
|
-
if (!normalized) {
|
|
712
|
-
setIsInvalid(true);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
setDraft(normalized);
|
|
716
|
-
setIsInvalid(false);
|
|
717
|
-
onValueChange(normalized);
|
|
718
|
-
};
|
|
719
|
-
const focusValueInput = () => {
|
|
720
|
-
inputRef.current?.focus();
|
|
721
|
-
inputRef.current?.select();
|
|
722
|
-
};
|
|
723
|
-
const applyPointerValue = (clientX, rect) => {
|
|
724
|
-
const nextValue = getSliderValueFromPointer(clientX, rect, control);
|
|
725
|
-
setDraft(`${formatNumber(nextValue)}${control.unit}`);
|
|
726
|
-
setIsInvalid(false);
|
|
727
|
-
onSlide(nextValue);
|
|
728
|
-
};
|
|
729
|
-
const openUnitMenu = () => {
|
|
730
|
-
if (unitOptions.length <= 1)
|
|
731
|
-
return;
|
|
732
|
-
setUnitMenuOpen(true);
|
|
733
|
-
focusValueInput();
|
|
734
|
-
};
|
|
735
|
-
const applyUnit = (unit) => {
|
|
736
|
-
const nextValue = convertStyleInputToUnit(draft, unit, control, element, inferredUnit);
|
|
737
|
-
if (!nextValue) {
|
|
738
|
-
setIsInvalid(true);
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
setDraft(nextValue);
|
|
742
|
-
setIsInvalid(false);
|
|
743
|
-
onValueChange(nextValue);
|
|
744
|
-
setUnitMenuOpen(false);
|
|
745
|
-
inputRef.current?.focus();
|
|
746
|
-
};
|
|
747
|
-
return (_jsxs("div", { className: "chisel-slider", "data-units-open": unitMenuOpen, onDoubleClick: (event) => {
|
|
748
|
-
event.preventDefault();
|
|
749
|
-
event.stopPropagation();
|
|
750
|
-
openUnitMenu();
|
|
751
|
-
}, onClick: () => {
|
|
752
|
-
if (suppressClickFocus.current) {
|
|
753
|
-
suppressClickFocus.current = false;
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
window.setTimeout(focusValueInput, 0);
|
|
757
|
-
}, onMouseUp: () => {
|
|
758
|
-
if (!suppressClickFocus.current)
|
|
759
|
-
window.setTimeout(focusValueInput, 0);
|
|
760
|
-
}, onPointerCancel: (event) => {
|
|
761
|
-
if (dragState.current?.pointerId !== event.pointerId)
|
|
762
|
-
return;
|
|
763
|
-
dragState.current = null;
|
|
764
|
-
}, onPointerDown: (event) => {
|
|
765
|
-
event.preventDefault();
|
|
766
|
-
dragState.current = {
|
|
767
|
-
pointerId: event.pointerId,
|
|
768
|
-
startX: event.clientX,
|
|
769
|
-
rect: event.currentTarget.getBoundingClientRect(),
|
|
770
|
-
dragging: false
|
|
771
|
-
};
|
|
772
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
773
|
-
window.setTimeout(focusValueInput, 0);
|
|
774
|
-
}, onPointerMove: (event) => {
|
|
775
|
-
const state = dragState.current;
|
|
776
|
-
if (!state || state.pointerId !== event.pointerId)
|
|
777
|
-
return;
|
|
778
|
-
if (!state.dragging && Math.abs(event.clientX - state.startX) < 4)
|
|
779
|
-
return;
|
|
780
|
-
state.dragging = true;
|
|
781
|
-
inputRef.current?.blur();
|
|
782
|
-
event.preventDefault();
|
|
783
|
-
applyPointerValue(event.clientX, state.rect);
|
|
784
|
-
}, onPointerUp: (event) => {
|
|
785
|
-
const state = dragState.current;
|
|
786
|
-
if (!state || state.pointerId !== event.pointerId)
|
|
787
|
-
return;
|
|
788
|
-
if (state.dragging) {
|
|
789
|
-
suppressClickFocus.current = true;
|
|
790
|
-
window.setTimeout(() => {
|
|
791
|
-
suppressClickFocus.current = false;
|
|
792
|
-
}, 250);
|
|
793
|
-
applyPointerValue(event.clientX, state.rect);
|
|
794
|
-
}
|
|
795
|
-
if (!state.dragging)
|
|
796
|
-
window.setTimeout(focusValueInput, 0);
|
|
797
|
-
dragState.current = null;
|
|
798
|
-
}, children: [_jsx("span", { className: "chisel-slider-label", children: control.label }), _jsx("span", { className: "chisel-slider-hashmarks", "aria-hidden": "true", children: Array.from({ length: 9 }, (_, index) => (_jsx("span", { className: "chisel-slider-hashmark", style: { left: `${(index + 1) * 10}%` } }, index))) }), _jsx("span", { className: "chisel-slider-fill", style: { width: `${percent}%` } }), _jsx("span", { className: "chisel-slider-handle", style: handleStyle }), _jsx("input", { type: "range", min: control.min, max: control.max, step: control.step, value: clamped, onChange: (event) => onSlide(Number(event.target.value)) }), _jsx("input", { ref: inputRef, className: "chisel-slider-value-input", "aria-label": `${control.label} value`, autoCapitalize: "off", autoComplete: "off", autoCorrect: "off", "data-invalid": isInvalid, spellCheck: false, value: draft, onBlur: () => {
|
|
799
|
-
commitDraft();
|
|
800
|
-
setIsEditing(false);
|
|
801
|
-
setUnitMenuOpen(false);
|
|
802
|
-
}, onChange: (event) => {
|
|
803
|
-
const nextDraft = event.target.value;
|
|
804
|
-
setDraft(nextDraft);
|
|
805
|
-
const normalized = normalizeStyleInput(nextDraft, control, element, inferredUnit);
|
|
806
|
-
if (!normalized) {
|
|
807
|
-
setIsInvalid(nextDraft.trim().length > 0);
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
|
-
setIsInvalid(false);
|
|
811
|
-
onValueChange(normalized);
|
|
812
|
-
if (normalized !== nextDraft && isCompleteUnitConversion(nextDraft))
|
|
813
|
-
setDraft(normalized);
|
|
814
|
-
}, onFocus: (event) => {
|
|
815
|
-
setIsEditing(true);
|
|
816
|
-
event.currentTarget.select();
|
|
817
|
-
}, onMouseDown: (event) => {
|
|
818
|
-
window.setTimeout(() => {
|
|
819
|
-
event.currentTarget.focus();
|
|
820
|
-
event.currentTarget.select();
|
|
821
|
-
}, 0);
|
|
822
|
-
}, onMouseUp: (event) => {
|
|
823
|
-
window.setTimeout(() => {
|
|
824
|
-
event.currentTarget.focus();
|
|
825
|
-
event.currentTarget.select();
|
|
826
|
-
}, 0);
|
|
827
|
-
}, onDoubleClick: (event) => {
|
|
828
|
-
event.preventDefault();
|
|
829
|
-
event.stopPropagation();
|
|
830
|
-
openUnitMenu();
|
|
831
|
-
}, onKeyDown: (event) => {
|
|
832
|
-
if (event.key === "Enter") {
|
|
833
|
-
event.preventDefault();
|
|
834
|
-
commitDraft();
|
|
835
|
-
event.currentTarget.blur();
|
|
836
|
-
}
|
|
837
|
-
if (isArrowStepKey(event.key)) {
|
|
838
|
-
const nextValue = stepStyleInput(draft, control, element, inferredUnit, event.shiftKey ? 10 : 1, isIncrementKey(event.key));
|
|
839
|
-
if (!nextValue)
|
|
840
|
-
return;
|
|
841
|
-
event.preventDefault();
|
|
842
|
-
setDraft(nextValue);
|
|
843
|
-
setIsInvalid(false);
|
|
844
|
-
onValueChange(nextValue);
|
|
845
|
-
}
|
|
846
|
-
if (event.key === "Escape") {
|
|
847
|
-
event.preventDefault();
|
|
848
|
-
setDraft(displayValue);
|
|
849
|
-
setIsInvalid(false);
|
|
850
|
-
setUnitMenuOpen(false);
|
|
851
|
-
event.currentTarget.blur();
|
|
852
|
-
}
|
|
853
|
-
} }), unitMenuOpen ? (_jsx("div", { className: "chisel-unit-menu", role: "listbox", "aria-label": `${control.label} units`, children: unitOptions.map((unit) => (_jsx("button", { className: "chisel-unit-option", "data-active": unit === inferredUnit, onClick: (event) => {
|
|
854
|
-
event.preventDefault();
|
|
855
|
-
applyUnit(unit);
|
|
856
|
-
}, onPointerDown: (event) => {
|
|
857
|
-
event.preventDefault();
|
|
858
|
-
event.stopPropagation();
|
|
859
|
-
}, role: "option", type: "button", children: unit || "unitless" }, unit || "unitless"))) })) : null] }));
|
|
860
|
-
}
|
|
861
|
-
function ChiselStyles() {
|
|
862
|
-
return (_jsx("style", { children: `
|
|
1
|
+
"use client";import{jsx as u,jsxs as w,Fragment as We}from"react/jsx-runtime";import*as p from"react";import{forwardRef as Bt,createElement as Rt}from"react";var Ra=e=>e?.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();function Ma(e,a,t=[]){if(a==null)throw new Error("[lucide]: iconNode is required when icon name is used");return{name:Ra(e),size:24,node:a,...t.length>0?{aliases:t}:{}}}var Da=e=>{let a="",t=!1;for(let o of e){if(o==="-"||o==="_"||o<=" "){t=a.length>0;continue}a.length===0?a+=o.toLowerCase():a+=t?o.toUpperCase():o,t=!1}return a};var Ta=e=>{let a=Da(e);return a.charAt(0).toUpperCase()+a.slice(1)};import{forwardRef as Ft,createElement as Ea}from"react";var Ge=(...e)=>e.filter((a,t,o)=>!!a&&a.trim()!==""&&o.indexOf(a)===t).join(" ").trim();var Le={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};function na(e){return e!=null}function qa(e,a={}){let t=a.attributeNames??{},o=M=>t[M]??M,r=e.size??e.width??Le.width,n=e.size??e.height??Le.height,i=e.aliases?.filter(M=>typeof M=="string"&&M.trim()!=="").map(M=>`lucide-${M}`)??[],c=[...e.name?[`lucide-${e.name}`]:[],...i],f=a.className?.split(" ").filter(Boolean)??[],g=a.includeDefaultClasses===!1?Ge(...f):Ge("lucide",...c,...f),S=a.absoluteStrokeWidth?Number(a.strokeWidth??Le["stroke-width"])*Number(e.size??e.width??Le.width)/Number(a.size??a.width??Le.width):a.strokeWidth??Le["stroke-width"];return["svg",{...Object.entries(Le).reduce((M,[F,k])=>(M[o(F)]=k,M),{}),..."color"in a&&a.color&&{[o("stroke")]:a.color},..."size"in a&&na(a.size)&&{[o("width")]:a.size,[o("height")]:a.size},..."width"in a&&na(a.width)&&{[o("width")]:a.width},..."height"in a&&na(a.height)&&{[o("height")]:a.height},[o("stroke-width")]:S,...g&&{[o("class")]:g},[o("viewBox")]:`0 0 ${r} ${n}`,...a.hasA11yProp===!1?{[o("aria-hidden")]:"true"}:{},..."attributes"in a&&a.attributes},e.node.map(M=>{let[F,k,P]=M,T=a.nonScalingStroke?{[o("vector-effect")]:"non-scaling-stroke",...k}:k;return P?[F,T,P]:[F,T]})]}function Ua(e,a={}){return qa(e,{...a,attributeNames:{...a.attributeNames,class:"className","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-linejoin":"strokeLinejoin","vector-effect":"vectorEffect"}})}var Oa=e=>{for(let a in e)if(a.startsWith("aria-")||a==="role"||a==="title")return!0;return!1};import{createContext as Pt,useContext as At,useMemo as Xo,createElement as Ko}from"react";var vt=Pt({});var Ha=()=>At(vt);var Na=Ft(({color:e,size:a,width:t,height:o,strokeWidth:r,absoluteStrokeWidth:n,nonScalingStroke:i,className:c="",children:f,iconNode:g=[],icon:S={node:g,aliases:[],size:24},...A},M)=>{let{size:F=24,strokeWidth:k=2,absoluteStrokeWidth:P=!1,nonScalingStroke:T=!1,color:q="currentColor",className:H=""}=Ha()??{},ae=!!f||Oa(A),[v,U,B=[]]=Ua(S,{color:e??q,width:t??a??F,height:o??a??F,strokeWidth:r??k,absoluteStrokeWidth:n??P,nonScalingStroke:i??T,className:Ge(H,c),hasA11yProp:ae,attributes:A});return Ea(v,{ref:M,...U},[...B.map(([W,G])=>Ea(W,G)),...Array.isArray(f)?f:[f]])});function Pe(e,a=[],t=[]){let o=typeof e=="string"?Ma(e,a,t):e,r=Bt(({className:n,...i},c)=>Rt(Na,{ref:c,icon:o,className:n,...i}));return o.name&&(r.displayName=Ta(o.name)),r}var Ga={name:"chevron-down",size:24,node:[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]};Ga.node;var Ae=Pe(Ga);var Va={name:"plus",size:24,node:[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]};Va.node;var Ve=Pe(Va);var za={name:"x",size:24,node:[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]};za.node;var ze=Pe(za);var Wa=`
|
|
2
|
+
:is(.chisel-root,.feedback-shell,.chisel-sign-in,.chisel-color-picker,.comment-box) :focus{outline:none}
|
|
3
|
+
.chisel-root,.feedback-shell,.chisel-sign-in,.chisel-color-picker,.comment-box{color-scheme:light;--chisel-ui-panel-shadow:0 4px 20px rgba(0,0,0,.08);--chisel-ui-canvas:#f7f7f7;--chisel-ui-surface:#ffffff;--chisel-ui-raised:#f5f5f5;--chisel-ui-inset:#eeeeee;--chisel-ui-hover:#f0f0f0;--chisel-ui-selected:#eaeaea;--chisel-ui-border:#e2e2e2;--chisel-ui-border-strong:#c4c4c4;--chisel-ui-text:#242424;--chisel-ui-secondary:#626262;--chisel-ui-muted:#686868;--chisel-ui-focus:#2468d3;--chisel-ui-accent-text:#2468d3;--chisel-ui-accent-surface:#edf4ff;--chisel-ui-action:#242424;--chisel-ui-action-text:#ffffff;--chisel-ui-danger:#b33737;--chisel-ui-avatar:#ededed;--chisel-ui-avatar-text:#565656;--chisel-ui-scrollbar:#c2c2c2;--chisel-ui-checker-light:#e5e5e5;--chisel-ui-checker-dark:#c7c7c7;}
|
|
4
|
+
@media(prefers-color-scheme:dark){.chisel-root,.feedback-shell,.chisel-sign-in,.chisel-color-picker,.comment-box{color-scheme:dark;--chisel-ui-panel-shadow:0 4px 20px #0003;--chisel-ui-canvas:#171717;--chisel-ui-surface:#222222;--chisel-ui-raised:#2a2a2a;--chisel-ui-inset:#191919;--chisel-ui-hover:#303030;--chisel-ui-selected:#383838;--chisel-ui-border:#3c3c3c;--chisel-ui-border-strong:#555555;--chisel-ui-text:#ededed;--chisel-ui-secondary:#b7b7b7;--chisel-ui-muted:#a5a5a5;--chisel-ui-focus:#8bb9ff;--chisel-ui-accent-text:#8bb9ff;--chisel-ui-accent-surface:#253447;--chisel-ui-action:#ededed;--chisel-ui-action-text:#111111;--chisel-ui-danger:#ffa5a5;--chisel-ui-avatar:#383838;--chisel-ui-avatar-text:#cccccc;--chisel-ui-scrollbar:#50504d;--chisel-ui-checker-light:#555555;--chisel-ui-checker-dark:#333333;}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.chisel-root,.feedback-shell,.chisel-sign-in,.chisel-color-picker,.comment-box{--chisel-ui-font:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--chisel-ui-space:4px;--chisel-ui-control:40px;--chisel-ui-radius:8px;--chisel-ui-text-size:13px;--chisel-ui-small:12px;--chisel-ui-motion:120ms cubic-bezier(.2,0,0,1);--chisel-ui-popover-shadow:0 2px 6px #0000000f,0 12px 36px #0000001f;}
|
|
8
|
+
@media(prefers-color-scheme:dark){.chisel-root,.feedback-shell,.chisel-sign-in,.chisel-color-picker,.comment-box{--chisel-ui-popover-shadow:0 0 0 1px #ffffff0d,0 4px 12px #0003,0 16px 40px #0004;}}
|
|
9
|
+
`;function ca(e,a){return{schemaVersion:1,activeVersionId:e.some(o=>o.id===a)?a:e[0]?.id??a,versions:e}}function Xa(e){if(e===null)return{migrated:!1};let a;try{a=JSON.parse(e)}catch{return{migrated:!1,warning:"Saved edits could not be read. Edits will be kept for this session."}}if(Array.isArray(a)){let t=a.filter(Ka);return a.length>0&&t.length===0?{migrated:!1,warning:"Saved edits are malformed. Edits will be kept for this session."}:{envelope:ca(t,t[0]?.id??"version-1"),migrated:t.length===a.length,warning:t.length<a.length?"Some malformed saved versions were skipped. Recovered edits will be kept for this session until you make a change.":void 0}}return Mt(a)?{envelope:a,migrated:!1}:{migrated:!1,warning:"Saved edits use an unsupported or malformed format. Edits will be kept for this session."}}function Mt(e){return!ve(e)||e.schemaVersion!==1||typeof e.activeVersionId!="string"||!Array.isArray(e.versions)||!e.versions.every(Ka)?!1:e.versions.length===0||e.versions.some(a=>a.id===e.activeVersionId)}function Ka(e){return!ve(e)||typeof e.id!="string"||typeof e.name!="string"||!ve(e.elements)?!1:Object.values(e.elements).every(Dt)}function Dt(e){return!(!ve(e)||typeof e.selector!="string"||!ve(e.styles)||e.sourceHint!==void 0&&typeof e.sourceHint!="string"||e.text!==void 0&&typeof e.text!="string"||!Object.values(e.styles).every(a=>typeof a=="string")||e.asset!==void 0&&!Tt(e.asset))}function Tt(e){return ve(e)&&typeof e.fileName=="string"&&typeof e.mimeType=="string"&&typeof e.size=="number"&&Number.isFinite(e.size)&&e.size>=0}function ve(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}var qt=["px","rem","em"],Ut=[{label:"Inter",value:'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'},{label:"System",value:'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'},{label:"Arial",value:"Arial, Helvetica, sans-serif"},{label:"Georgia",value:'Georgia, "Times New Roman", serif'},{label:"Mono",value:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"}],Ot=["Hex","RGB","RGBA","HSL"],Ht=["Solid","Gradient","Image"],Et=[{label:"Font Size",property:"fontSize",cssProperty:"font-size",min:8,max:96,step:1,unit:"px"},{label:"Line",property:"lineHeight",cssProperty:"line-height",min:8,max:120,step:1,unit:"px"},{label:"Tracking",property:"letterSpacing",cssProperty:"letter-spacing",min:-2,max:12,step:.25,unit:"px"},{label:"Padding X",property:"paddingInline",cssProperty:"padding-inline",min:0,max:120,step:1,unit:"px"},{label:"Padding Y",property:"paddingBlock",cssProperty:"padding-block",min:0,max:120,step:1,unit:"px"},{label:"Margin X",property:"marginInline",cssProperty:"margin-inline",min:-80,max:160,step:1,unit:"px"},{label:"Margin Y",property:"marginBlock",cssProperty:"margin-block",min:-80,max:160,step:1,unit:"px"},{label:"Radius",property:"borderRadius",cssProperty:"border-radius",min:0,max:80,step:1,unit:"px"},{label:"Opacity",property:"opacity",cssProperty:"opacity",min:0,max:1,step:.01,unit:""},{label:"Width",property:"width",cssProperty:"width",min:0,max:1200,step:1,unit:"px"},{label:"Height",property:"height",cssProperty:"height",min:0,max:1200,step:1,unit:"px"}],Sa=["color","backgroundColor","backgroundImage","backgroundPosition","backgroundSize","fontFamily","fontSize","lineHeight","letterSpacing","paddingInline","paddingBlock","marginInline","marginBlock","borderRadius","opacity","width","height"],Nt=new Set(["area","audio","base","br","button","canvas","col","embed","hr","iframe","img","input","link","meta","object","param","picture","portal","select","source","textarea","track","video","wbr"]),La="chisel:locationchange",ea=0,la,Ke=!1,$a=0,xa=new Map,Xe=new WeakMap;function Sr({id:e,as:a,children:t,...o}){return u(a??"span",{"data-chisel-id":e,...o,children:t})}function wr({enabled:e=process.env.NODE_ENV!=="production",position:a="right",projectName:t="Next.js app",embedded:o=!1}){let[r,n]=p.useState(null),[i,c]=p.useState(null),[f,g]=p.useState(null),[S,A]=p.useState([]),[M,F]=p.useState(null),[k,P]=p.useState([]),[T,q]=p.useState(!1),[H,ae]=p.useState(""),[v,U]=p.useState(()=>[pa(1)]),[B,W]=p.useState("version-1"),[G,K]=p.useState(!1),[te,E]=p.useState(""),[fe,oe]=p.useState(""),[re,le]=p.useState(!1),[$,ee]=p.useState([]),[m,I]=p.useState(0),[Z,j]=p.useState(""),se=p.useRef(new WeakMap),O=p.useRef(new Map),N=p.useRef(new Map),xe=p.useRef(""),V=p.useRef(null),ne=p.useRef(null),X=p.useRef([]),Je=p.useRef(null),Qe=p.useRef([]),me=p.useRef(null),Ie=p.useRef(null),ye=p.useRef(null),Ue=p.useRef(!1),ge=p.useRef(null),s=p.useRef(null),L=p.useRef(null),b=p.useRef(!0),D=r?new URLSearchParams(r.search).has("editor"):!1,Q=e&&(o||D),ya=r?ut(r.pathname,r.search):"";if(p.useEffect(()=>()=>ha(N.current),[]),p.useEffect(()=>{let l=()=>n(Kt());return l(),$t(l)},[]),p.useEffect(()=>{if(Q){Ue.current=!0;return}if(!Ue.current||(Ue.current=!1,o))return;let l=v.find(d=>d.id===B)??v[0];l&&Qa(l,O.current,N.current),ha(N.current),V.current=null,ne.current=null,X.current=[],c(null),g(null),A([]),F(null),P([]),q(!1)},[B,Q,o,v]),p.useEffect(()=>{if(!Q||!o)return;let l=()=>{let d=document.documentElement?.dataset.chiselSelection,x=d?document.querySelector(d):null;x instanceof HTMLElement&&!Be(x)&&Ye([x])};return window.addEventListener("chisel:select",l),()=>window.removeEventListener("chisel:select",l)},[Q,o]),p.useEffect(()=>{if(!Q){Ke=!1;return}let l=()=>{ge.current===null&&(ge.current=window.requestAnimationFrame(()=>{ge.current=null;let x=V.current,h=X.current;F(C=>x?ie(x.getBoundingClientRect()):C),P(h.map(C=>ie(C.getBoundingClientRect())))}))},d=x=>{let h=x.target;h instanceof HTMLElement&&Be(h)||x.key==="Escape"&&(ne.current=null,X.current=[],g(null),A([]),P([]))};return document.addEventListener("keydown",d),window.addEventListener("resize",l),window.addEventListener("scroll",l,!0),()=>{ge.current!==null&&window.cancelAnimationFrame(ge.current),s.current!==null&&window.cancelAnimationFrame(s.current),document.removeEventListener("keydown",d),window.removeEventListener("resize",l),window.removeEventListener("scroll",l,!0)}},[Q]),p.useEffect(()=>{ne.current=f},[f]),p.useEffect(()=>{X.current=S},[S]),p.useEffect(()=>{if(!S.length)return;let l=null,d=()=>{l===null&&(l=window.requestAnimationFrame(()=>{l=null,P(S.map(h=>ie(h.getBoundingClientRect())))}))};if(typeof ResizeObserver>"u"){let h=window.setInterval(d,750);return()=>{l!==null&&window.cancelAnimationFrame(l),window.clearInterval(h)}}let x=new ResizeObserver(d);for(let h of S)x.observe(h);return()=>{l!==null&&window.cancelAnimationFrame(l),x.disconnect()}},[f,S]),p.useEffect(()=>{if(!Q)return;let l=jt(ya);xe.current=l,oe(""),V.current=null,ne.current=null,X.current=[],c(null),g(null),A([]),F(null),P([]);let d=v.find(_=>_.id===B)??v[0];d&&Qa(d,O.current,N.current),O.current.clear(),ha(N.current);let x=Jt(r?.pathname??window.location.pathname,r?.search??window.location.search),h=Qt(l,x);b.current=!h.warning,E(h.warning??"");let C=h.envelope?.versions.length?h.envelope.versions:[pa(1)],y=h.envelope?.activeVersionId??C[0].id;U(C),W(y),oe(l);let R=C.find(_=>_.id===y)??C[0],z=window.setTimeout(()=>aa(R,C,O.current,N.current),0);if(h.migrated&&h.envelope){let _=Ja(l,C,y);_&&E(_)}return Ke=!1,()=>window.clearTimeout(z)},[ya,Q]),p.useEffect(()=>{if(!Q||!b.current||!xe.current||fe!==xe.current)return;let l=Ja(xe.current,v,B);l&&E(l)},[B,Q,fe,v]),p.useEffect(()=>{if(!Q||typeof MutationObserver>"u"||!document.body)return;let l=null,d=()=>{l=null;let h=v.find(y=>y.id===B)??v[0];h&&aa(h,v,O.current,N.current,!1),V.current&&!V.current.isConnected&&(V.current=null,c(null),F(null));let C=X.current.filter(y=>y.isConnected);if(C.length!==X.current.length){let y=C[C.length-1]??null;X.current=C,ne.current=y,A(C),g(y),P(C.map(R=>ie(R.getBoundingClientRect())))}},x=new MutationObserver(h=>{if(Ke)return;let C=h.some(R=>{let z=R.target instanceof HTMLElement?R.target:R.target.parentElement;return z&&Xe.has(z)?!1:z&&!Be(z)?!0:Array.from(R.addedNodes).some(_=>{let Ba=_ instanceof HTMLElement?_:_.parentElement;return!!(Ba&&!Be(Ba))})}),y=h.some(R=>Array.from(R.removedNodes).some(z=>z instanceof HTMLElement&&((V.current?z===V.current||z.contains(V.current):!1)||X.current.some(_=>z===_||z.contains(_)))));!C&&!y||l===null&&(l=window.requestAnimationFrame(d))});return x.observe(document.body,{attributes:!0,attributeFilter:["style"],characterData:!0,childList:!0,subtree:!0}),()=>{x.disconnect(),l!==null&&window.cancelAnimationFrame(l)}},[B,Q,v]),p.useEffect(()=>{if(!re)return;let l=h=>{let C=Y(h,0,Math.max(0,$.length-1)),y=$[C];I(C),y&&(V.current=y,c(y),F(ie(y.getBoundingClientRect())),j(at(y)))},d=()=>{Ye(Qe.current.filter(h=>h.isConnected)),le(!1),window.requestAnimationFrame(()=>Je.current?.focus())},x=h=>{let C=$[m],y=m;if(h.key==="ArrowDown")y=m+1;else if(h.key==="ArrowUp")y=m-1;else if(h.key==="Home")y=0;else if(h.key==="End")y=$.length-1;else if(h.key==="ArrowRight"&&C){let R=$.find(z=>z.parentElement===C);R&&(y=$.indexOf(R))}else if(h.key==="ArrowLeft"&&C){let R=C.parentElement;for(;R&&!$.includes(R);)R=R.parentElement;R&&(y=$.indexOf(R))}else if(h.key==="Enter"&&C){Ye(h.shiftKey?Ya(X.current,C):[C]),h.shiftKey||le(!1),h.preventDefault();return}else if(h.key==="Escape"){d(),h.preventDefault();return}else return;l(y),h.preventDefault()};return document.addEventListener("keydown",x),()=>document.removeEventListener("keydown",x)},[re,$,m]),p.useEffect(()=>{H&&(me.current?.focus(),me.current?.select())},[H]),p.useEffect(()=>{if(!G)return;let l=h=>{K(!1),h&&window.requestAnimationFrame(()=>ye.current?.focus())},d=h=>{h.target instanceof Node&&Ie.current?.contains(h.target)||l(!0)},x=h=>{h.key==="Escape"&&(l(!0),h.preventDefault())};return document.addEventListener("pointerdown",d,!0),document.addEventListener("keydown",x),()=>{document.removeEventListener("pointerdown",d,!0),document.removeEventListener("keydown",x)}},[G]),!Q)return null;let he=S.length,Oe=f?se.current.get(f):void 0,fa=!!(he<=1&&f&&tt(f)),He=f?De(f):void 0,Pa=f?$e(f):"",ue=v.find(l=>l.id===B)??v[0]??pa(1),_e=he>1?S.flatMap(l=>ao(ue.elements[de(l)])):f&&Oe?eo(f,Oe):[],Ce=f?getComputedStyle(f):null,Ee=l=>he>1&&new Set(S.map(d=>getComputedStyle(d)[l])).size>1,Ne=()=>S.length?S:f?[f]:[];function Ye(l){for(let x of l)Wt(x,se.current);let d=l[l.length-1]??null;if(X.current=l,ne.current=d,A(l),g(d),P(l.map(x=>ie(x.getBoundingClientRect()))),o&&d){let x=d.getBoundingClientRect();window.dispatchEvent(new CustomEvent("chisel:selection",{detail:{selector:$e(d),tag:d.tagName.toLowerCase(),x:x.left+x.width/2+window.scrollX,y:x.top+x.height/2+window.scrollY,offsetX:.5,offsetY:.5}}))}}let Se=()=>{P(S.map(l=>ie(l.getBoundingClientRect())))},Aa=(l,d)=>{let x=document.elementsFromPoint(l,d).find(h=>h instanceof HTMLElement&&!Be(h));return x instanceof HTMLElement?lo(x):null},mt=l=>{L.current={x:l.clientX,y:l.clientY},s.current===null&&(s.current=window.requestAnimationFrame(()=>{s.current=null;let d=L.current;if(!d)return;let x=Aa(d.x,d.y);if(!x){V.current=null,c(null),F(null);return}x!==V.current&&(V.current=x,c(x),F(ie(x.getBoundingClientRect())))}))},ht=l=>{l.preventDefault(),l.stopPropagation();let d=Aa(l.clientX,l.clientY);d&&(le(!1),Ye(l.shiftKey?Ya(X.current,d):[d]))},Lt=()=>{let l=so();Qe.current=X.current,ee(l),I(0),le(!0);let d=l[0];d?(V.current=d,c(d),F(ie(d.getBoundingClientRect())),j(at(d))):j("No visible elements available")},xt=()=>{let l={id:`version-${Date.now()}`,name:`Version ${v.length+1}`,elements:Xt(ue.elements)};ia(d=>[...d,l]),W(l.id),K(!1);for(let[d,x]of Object.entries(ue.elements)){if(!x.asset)continue;let h=N.current.get(be(ue.id,d));h&&N.current.set(be(l.id,d),h)}aa(l,[...v,l],O.current,N.current),Se()},It=l=>{W(l.id),K(!1),aa(l,v,O.current,N.current),Se(),window.requestAnimationFrame(()=>ye.current?.focus())},gt=(l,d)=>{let x=l.unit==="px"?`${d}px`:String(d);va(l,x)},va=(l,d)=>{let x=Ne();if(x.length){for(let h of x)ke(h,de(h),O.current),ce(h),h.style[l.property]=d,we(h,{styles:{[l.property]:d}});Se()}},Fa=(l,d,x)=>{let h=Ne();if(h.length){for(let C of h){let y=de(C);if(ke(C,de(C),O.current),ce(C),l==="backgroundColor"&&ho(d)){if(C.style.backgroundImage=d,d.startsWith("url(")){let R=ga(d),z=be(B,y);x&&R?_t(N.current,z,R):ma(N.current,z),C.style.backgroundPosition="center",C.style.backgroundSize="cover",we(C,{styles:{backgroundImage:x?"":d,backgroundPosition:"center",backgroundSize:"cover"},asset:x??null})}else we(C,{styles:{backgroundImage:d},asset:null});continue}if(C.style[l]=d,l==="backgroundColor"){ma(N.current,be(B,y)),C.style.backgroundImage="",C.style.backgroundPosition="",C.style.backgroundSize="",we(C,{styles:{backgroundColor:d,backgroundImage:"",backgroundPosition:"",backgroundSize:""},asset:null});continue}we(C,{styles:{[l]:d}})}Se()}},Ct=l=>{let d=Ne();if(d.length){for(let x of d)ke(x,de(x),O.current),ce(x),x.style.fontFamily=l,we(x,{styles:{fontFamily:l}});Se()}},St=l=>{let d=Ne();if(d.length)for(let x of d)ke(x,de(x),O.current),ce(x),x.style.fontFamily=l},wt=l=>{!f||!fa||(ke(f,de(f),O.current),ce(f),f.textContent=l,we(f,{text:l}),Se())},kt=()=>{let l=Ne();if(l.length){for(let d of l){let x=se.current.get(d),h=de(d),C=O.current.get(h),y=ue.elements[h];if(y){ce(d);for(let R of Object.keys(y.styles))d.style[R]=C?.styles[R]??"";typeof y.text=="string"&&tt(d)&&(d.textContent=C?.text??x?.text??""),bt(d),y.asset&&ma(N.current,be(B,h))}}Se()}};function we(l,d){let x=de(l);ke(l,x,O.current),ia(h=>h.map(C=>{if(C.id!==B)return C;let y=C.elements[x];return{...C,elements:{...C.elements,[x]:{selector:$e(l),sourceHint:De(l),text:d.text??y?.text,asset:d.asset===null?void 0:d.asset??y?.asset,styles:{...y?.styles??{},...d.styles??{}}}}}}))}function bt(l){let d=de(l),x=v.some(h=>h.id!==B&&!!h.elements[d]);ia(h=>h.map(C=>{if(C.id!==B)return C;let{[d]:y,...R}=C.elements;return{...C,elements:R}})),x||O.current.delete(d)}function ia(l){b.current=!0,U(l)}let yt=async()=>{let l=f?ie(f.getBoundingClientRect()):void 0,d=Object.keys(ue.elements).length?oo({projectName:t,version:ue,baselines:O.current}):f&&Oe&&l?to({projectName:t,element:f,snapshot:Oe,rect:l,selector:Pa,sourceHint:He,changes:_e}):void 0;if(d)try{if(!navigator.clipboard?.writeText)throw new Error("Clipboard unavailable");await navigator.clipboard.writeText(d),ae(""),q(!0),window.setTimeout(()=>q(!1),1600)}catch{q(!1),ae(d)}};return w("div",{"data-chisel-root":"true",className:"chisel-root",children:[u(zt,{}),u("div",{className:"chisel-visually-hidden","aria-live":"polite",children:Z}),u("div",{className:"chisel-inspection-layer","aria-hidden":"true",onPointerMove:mt,onPointerLeave:()=>{L.current=null,s.current!==null&&window.cancelAnimationFrame(s.current),s.current=null,V.current=null,c(null),F(null)},onClick:ht}),M&&i&&!S.includes(i)?u(Za,{rect:M,tone:"hover"}):null,k.map((l,d)=>u(Za,{rect:l,tone:"selected"},`${l.left}-${l.top}-${d}`)),u("aside",{className:`chisel-panel chisel-panel-${a}`,"aria-label":"Chisel editor",children:u("div",{className:"chisel-panel-wrapper",children:u("div",{className:"chisel-panel-inner",children:w("div",{className:"chisel-folder chisel-folder-root",children:[u("header",{className:"chisel-folder-header chisel-panel-header",children:w("div",{className:"chisel-panel-toolbar",children:[u("button",{className:"chisel-toolbar-add",type:"button","aria-label":"Add version",onClick:xt,children:u(Ve,{size:16,strokeWidth:1.75,"aria-hidden":"true"})}),w("div",{className:"chisel-preset-manager",ref:Ie,children:[w("button",{className:"chisel-preset-trigger",type:"button","aria-expanded":G,"aria-haspopup":"listbox",ref:ye,onClick:()=>K(l=>{let d=!l;return d&&window.requestAnimationFrame(()=>Ie.current?.querySelector('[role="option"][aria-selected="true"]')?.focus()),d}),children:[u("span",{className:"chisel-preset-trigger-label",children:ue.name}),u(Ae,{className:"chisel-chevron",size:16,strokeWidth:1.75,"aria-hidden":"true"})]}),G?u("div",{className:"chisel-preset-dropdown",role:"listbox","aria-label":"Page versions",onKeyDown:ka,children:u("div",{className:"chisel-preset-list",children:v.map(l=>w("button",{className:"chisel-preset-item",type:"button",role:"option","aria-selected":l.id===ue.id,"data-active":l.id===ue.id,onClick:()=>It(l),children:[u("span",{className:"chisel-preset-name",children:l.name}),u("span",{className:"chisel-preset-count",children:Object.keys(l.elements).length})]},l.id))})}):null]}),u("button",{className:"chisel-toolbar-add",type:"button",onClick:()=>{ne.current=null,X.current=[],g(null),A([]),P([])},"aria-label":"Clear selection",children:u(ze,{size:16,strokeWidth:1.75,"aria-hidden":"true"})})]})}),te?u("div",{className:"chisel-note-row chisel-warning",role:"alert",children:te}):null,f&&Oe?w("div",{className:"chisel-content",children:[w("div",{className:"chisel-text-control chisel-context-row",children:[u("span",{className:"chisel-text-label",children:he>1?"Selection":"Element"}),u("code",{className:"chisel-text-code",children:he>1?`${he} elements`:f.tagName.toLowerCase()})]}),he===1?w(We,{children:[w("div",{className:"chisel-text-control chisel-context-row chisel-selector-row",children:[u("span",{className:"chisel-text-label",children:"Selector"}),u("code",{className:"chisel-selector",children:Pa})]}),w("div",{className:He?"chisel-text-control chisel-context-row":"chisel-text-control chisel-context-row chisel-warning-row",children:[u("span",{className:"chisel-text-label",children:"Source"}),u("span",{className:He?"chisel-text-value":"chisel-warning",children:He?`Source hint: ${He}`:"Low-confidence source mapping"})]})]}):null,w("div",{className:"chisel-folder",children:[u("div",{className:"chisel-folder-header",children:u("div",{className:"chisel-folder-header-top",children:u("div",{className:"chisel-folder-title-row",children:u("span",{className:"chisel-folder-title",children:"Content"})})})}),u("div",{className:"chisel-folder-content",children:w("div",{className:"chisel-folder-inner",children:[w("label",{className:"chisel-text-control chisel-textarea-control",children:[u("span",{className:"chisel-text-label",children:"Text"}),u("textarea",{className:"chisel-text-input",value:f.textContent??"",onChange:l=>wt(l.target.value),disabled:!fa,rows:3})]}),fa?null:u("div",{className:"chisel-note-row",children:he>1?"Text editing is enabled for one element at a time.":"Text editing is enabled for simple text elements."})]})})]}),w("div",{className:"chisel-folder",children:[u("div",{className:"chisel-folder-header",children:u("div",{className:"chisel-folder-header-top",children:u("div",{className:"chisel-folder-title-row",children:u("span",{className:"chisel-folder-title",children:"Color"})})})}),u("div",{className:"chisel-folder-content",children:w("div",{className:"chisel-folder-inner",children:[u(ja,{label:"Text",value:f.style.color||Me(Ce?.color??"#000000"),onChange:l=>Fa("color",l),mixed:Ee("color")}),u(ja,{label:"Fill",value:f.style.backgroundImage||(Ce?.backgroundImage&&Ce.backgroundImage!=="none"?Ce.backgroundImage:f.style.backgroundColor||Me(Ce?.backgroundColor??"#ffffff")),onChange:(l,d)=>Fa("backgroundColor",l,d),supportsBackgroundImages:!0,unavailableAsset:ue.elements[de(f)]?.asset,mixed:Ee("backgroundColor")||Ee("backgroundImage")})]})})]}),w("div",{className:"chisel-folder",children:[u("div",{className:"chisel-folder-header",children:u("div",{className:"chisel-folder-header-top",children:u("div",{className:"chisel-folder-title-row",children:u("span",{className:"chisel-folder-title",children:"Style"})})})}),u("div",{className:"chisel-folder-content",children:w("div",{className:"chisel-folder-inner",children:[u(Gt,{value:Ce?.fontFamily??"",onChange:Ct,onPreview:St,mixed:Ee("fontFamily")}),Et.map(l=>u(Vt,{control:l,computedStyle:Ce,element:f,mixed:Ee(l.property),onSlide:d=>gt(l,d),onValueChange:d=>va(l,d)},l.cssProperty))]})})]}),w("div",{className:"chisel-folder",children:[u("div",{className:"chisel-folder-header",children:w("div",{className:"chisel-folder-header-top",children:[u("div",{className:"chisel-folder-title-row",children:u("span",{className:"chisel-folder-title",children:"Changes"})}),u("span",{className:"chisel-folder-count",children:_e.length})]})}),u("div",{className:"chisel-folder-content",children:u("div",{className:"chisel-folder-inner",children:_e.length?_e.map((l,d)=>w("div",{className:"chisel-text-control",children:[u("span",{className:"chisel-text-label",children:l.property}),u("strong",{className:"chisel-text-value",children:String(l.after)})]},`${l.property}-${d}`)):u("div",{className:"chisel-note-row",children:"No preview changes yet."})})})]}),w("div",{className:"chisel-actions",children:[u("button",{className:"chisel-button",type:"button",onClick:kt,children:"Reset"}),u("button",{className:"chisel-button chisel-button-primary",type:"button",onClick:yt,children:T?"Copied":"Copy agent prompt"})]}),T?u("div",{className:"chisel-note-row",role:"status",children:"Prompt copied"}):null,H?w("div",{className:"chisel-note-row",role:"alert",children:["Press Cmd+C/Ctrl+C",u("textarea",{ref:me,readOnly:!0,value:H,"aria-label":"Agent prompt copy fallback"})]}):null]}):w("div",{className:"chisel-empty",children:[u("div",{className:"chisel-note-row",children:"Select any visible element to edit its text and style preview."}),u("button",{className:"chisel-button",type:"button",ref:Je,onClick:Lt,"aria-pressed":re,children:"Pick element"})]})]})})})})]})}function Za({rect:e,tone:a}){return u("div",{className:`chisel-box chisel-box-${a}`,style:{transform:`translate3d(${e.left}px, ${e.top}px, 0)`,width:e.width,height:e.height}})}function Gt({value:e,onChange:a,onPreview:t,mixed:o=!1}){let[r,n]=p.useState(!1),i=p.useRef(null),c=p.useRef(null),f=p.useRef(e),g=p.useMemo(()=>io(e),[e]),S=no(e,g),A=o?"Mixed":S?.label??Ze(e)??"Font";p.useEffect(()=>{r||(f.current=e)},[r,e]),p.useEffect(()=>{if(!r)return;let k=T=>{let q=T.target;q instanceof Node&&i.current?.contains(q)||(t(f.current),n(!1),window.requestAnimationFrame(()=>c.current?.focus()))},P=T=>{T.key==="Escape"&&(t(f.current),n(!1),window.requestAnimationFrame(()=>c.current?.focus()))};return document.addEventListener("pointerdown",k,!0),document.addEventListener("keydown",P),()=>{document.removeEventListener("pointerdown",k,!0),document.removeEventListener("keydown",P)}},[r,t]);let M=()=>{if(r){t(f.current),n(!1);return}f.current=e,n(!0),window.requestAnimationFrame(()=>i.current?.querySelector('[role="option"][aria-selected="true"]')?.focus())},F=k=>{f.current=k.value,a(k.value),n(!1),window.requestAnimationFrame(()=>c.current?.focus())};return w("div",{className:"chisel-font-control",ref:i,children:[u("span",{className:"chisel-font-label",children:"Font"}),w("div",{className:"chisel-font-picker",children:[w("button",{className:"chisel-font-trigger",ref:c,type:"button","aria-expanded":r,"aria-haspopup":"listbox",onClick:M,children:[u("span",{className:"chisel-font-trigger-label",children:A}),u(Ae,{className:"chisel-chevron",size:16,strokeWidth:1.75,"aria-hidden":"true"})]}),r?u("div",{className:"chisel-preset-dropdown chisel-font-dropdown",role:"listbox","aria-label":"Font family",onKeyDown:ka,children:u("div",{className:"chisel-preset-list chisel-font-list",children:g.map(k=>u("button",{className:"chisel-preset-item chisel-font-item","data-active":ua(e,k.value),"aria-selected":ua(e,k.value),onClick:()=>F(k),onFocus:()=>t(k.value),onPointerEnter:()=>t(k.value),role:"option",style:{fontFamily:k.value},type:"button",children:u("span",{className:"chisel-preset-name",children:k.label})},k.value))})}):null]})]})}function ja({label:e,value:a,onChange:t,supportsBackgroundImages:o=!1,unavailableAsset:r,mixed:n=!1}){let i=lt(a),c=ga(a),f=o&&i?"Gradient":o&&(c!==void 0||r)?"Image":"Solid",g=i?.start??(c!==void 0?"#FFFFFF":rt(a)),[S,A]=p.useState(f),[M,F]=p.useState(()=>Fe(g)),[k,P]=p.useState(g),[T,q]=p.useState(i?.start??g),[H,ae]=p.useState(i?.end??"#FFFFFF"),[v,U]=p.useState("start"),[B,W]=p.useState(c??""),[G,K]=p.useState(""),[te,E]=p.useState(!1),[fe,oe]=p.useState(!1),re=p.useRef(null),le=p.useRef(null),$=S==="Gradient"?v==="start"?T:H:k,ee=Me($).toUpperCase(),m=mo($),I=p.useMemo(()=>uo(ba(ee)),[ee]),Z=n?"Mixed":S==="Gradient"?"Gradient":S==="Image"?"Image":k;p.useEffect(()=>{let s=lt(a),L=ga(a);if(o&&s){let D=v==="end"?s.end:s.start;A("Gradient"),q(s.start),ae(s.end),P(D),F(Fe(D)),E(!1);return}if(o&&L!==void 0){A("Image"),W(L),P("#FFFFFF"),E(!1);return}if(o&&r){A("Image"),W(""),K(""),E(!1);return}let b=rt(a);A("Solid"),P(D=>D&&Me(D)===Me(b)?D:b),F(Fe(b)),E(!1)},[v,o,r,a]),p.useEffect(()=>{if(!fe)return;let s=b=>{let D=b.target;D instanceof Node&&re.current?.contains(D)||(oe(!1),window.requestAnimationFrame(()=>le.current?.focus()))},L=b=>{b.key==="Escape"&&(oe(!1),window.requestAnimationFrame(()=>le.current?.focus()),b.preventDefault())};return document.addEventListener("pointerdown",s,!0),document.addEventListener("keydown",L),()=>{document.removeEventListener("pointerdown",s,!0),document.removeEventListener("keydown",L)}},[fe]);let j=s=>{let L=ot(s);if(!L){E(s.trim().length>0);return}let b=Te(L)??L;if(F(Fe(b)),P(b),E(!1),S==="Gradient"){Ie(v,b);return}t(b)},se=(s,L=m,b=M)=>{let D=po(s,L,b);if(P(D),E(!1),S==="Gradient"){Ie(v,D);return}t(D)},O=(s,L)=>{let b=Y((s.clientX-L.left)/L.width*100,0,100),D=Y((1-(s.clientY-L.top)/L.height)*100,0,100);se(ta(I.h,b,D))},N=(s,L)=>{let b=Y((s.clientX-L.left)/L.width*360,0,360);se(ta(b,I.s,I.v))},xe=(s,L)=>{let b=Y((s.clientX-L.left)/L.width,0,1);se(ee,b)},V=s=>{if(!ra(s.key))return;let L=s.shiftKey?10:1,b=Y(I.s+(s.key==="ArrowRight"?L:s.key==="ArrowLeft"?-L:0),0,100),D=Y(I.v+(s.key==="ArrowUp"?L:s.key==="ArrowDown"?-L:0),0,100);se(ta(I.h,b,D)),s.preventDefault()},ne=s=>{if(!ra(s.key))return;let L=s.shiftKey?10:1,b=Y(I.h+(Ca(s.key)?L:-L),0,360);se(ta(b,I.s,I.v)),s.preventDefault()},X=s=>{if(!ra(s.key))return;let L=s.shiftKey?.1:.01;se(ee,Y(m+(Ca(s.key)?L:-L),0,1)),s.preventDefault()},Je=s=>{F(s),se(ee,m,s)},Qe=s=>{if(!(s!=="Solid"&&!o)){if(A(s),s==="Solid"&&t(k),s==="Gradient"){let L=T||k;q(L),U("start"),P(L),t(oa(L,H))}s==="Image"&&B.trim()&&t(Re(B))}},me=s=>{let L=s==="start"?T:H;U(s),P(L),F(Fe(L)),E(!1)},Ie=(s,L)=>{let b=s==="start"?L:T,D=s==="end"?L:H;q(b),ae(D),t(oa(b,D))},ye=(s,L)=>{let b=ot(L);if(s==="start"?q(L):ae(L),U(s),P(L),!b){E(L.trim().length>0);return}let D=Te(b)??b;F(Fe(D)),P(D),E(!1),Ie(s,D)},Ue=s=>{W(s),K(""),t(s.trim()?Re(s):"")},ge=s=>{let L=s.currentTarget.files?.[0];if(!L)return;let b=URL.createObjectURL(L);K(L.name),W(b),t(Re(b),{fileName:L.name,mimeType:L.type,size:L.size})};return w("div",{className:"chisel-color-control","data-picker-open":fe,ref:re,children:[u("span",{className:"chisel-color-label",children:e}),w("span",{className:"chisel-color-inputs",children:[u("button",{className:"chisel-color-swatch",ref:le,"aria-expanded":fe,"aria-label":`${e} color picker`,onClick:()=>oe(s=>!s),style:{background:S==="Gradient"?oa(T,H):S==="Image"&&B?Re(B):k},type:"button"}),u("input",{className:"chisel-color-value-input","aria-label":`${e} color value`,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off","data-invalid":te,readOnly:S!=="Solid",spellCheck:!1,style:{width:`${Math.max(7.5,Math.min(Z.length+.5,18))}ch`},value:Z,onBlur:()=>{S==="Solid"&&j(k)},onChange:s=>{if(S!=="Solid")return;let L=s.target.value;P(L),j(L)},onKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),j(k),s.currentTarget.blur()),s.key==="Escape"&&(s.preventDefault(),P(g),E(!1),oe(!1),s.currentTarget.blur())}})]}),fe?w("div",{className:"chisel-color-popover",role:"dialog","aria-label":`${e} custom color picker`,children:[w("div",{className:"chisel-color-tabs",children:[Ht.map(s=>u("button",{className:"chisel-color-tab","data-active":S===s,"aria-disabled":s!=="Solid"&&!o,onClick:()=>Qe(s),type:"button",children:s},s)),u("button",{className:"chisel-color-close","aria-label":"Close color picker",onClick:()=>oe(!1),type:"button",children:"\xD7"})]}),S!=="Image"?w(We,{children:[S==="Gradient"?w(We,{children:[u("div",{className:"chisel-color-gradient-preview",style:{backgroundImage:oa(T,H)}}),w("div",{className:"chisel-color-stop-buttons",role:"group","aria-label":`${e} gradient endpoints`,children:[w("button",{className:"chisel-color-stop-button","data-active":v==="start","aria-label":`${e} gradient From`,onClick:()=>me("start"),type:"button",children:[u("span",{className:"chisel-color-stop-swatch",style:{background:T}}),u("span",{children:"From"})]}),w("button",{className:"chisel-color-stop-button","data-active":v==="end","aria-label":`${e} gradient To`,onClick:()=>me("end"),type:"button",children:[u("span",{className:"chisel-color-stop-swatch",style:{background:H}}),u("span",{children:"To"})]})]})]}):null,u("div",{className:"chisel-color-field",role:"slider",tabIndex:0,"aria-label":`${e} saturation and brightness`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":I.s,"aria-valuetext":`Saturation ${I.s}%, brightness ${I.v}%`,onKeyDown:V,onPointerDown:s=>{let L=s.currentTarget.getBoundingClientRect();O(s,L),s.currentTarget.setPointerCapture(s.pointerId)},onPointerMove:s=>{s.buttons&1&&O(s,s.currentTarget.getBoundingClientRect())},style:{backgroundColor:`hsl(${I.h} 100% 50%)`},children:u("span",{className:"chisel-color-field-cursor",style:{left:`clamp(10px, ${I.s}%, calc(100% - 10px))`,top:`clamp(10px, ${100-I.v}%, calc(100% - 10px))`,backgroundColor:ee}})}),u("div",{className:"chisel-color-hue",role:"slider",tabIndex:0,"aria-label":`${e} hue`,"aria-valuemin":0,"aria-valuemax":360,"aria-valuenow":I.h,onKeyDown:ne,onPointerDown:s=>{let L=s.currentTarget.getBoundingClientRect();N(s,L),s.currentTarget.setPointerCapture(s.pointerId)},onPointerMove:s=>{s.buttons&1&&N(s,s.currentTarget.getBoundingClientRect())},children:u("span",{className:"chisel-color-hue-cursor",style:{left:`clamp(8px, ${I.h/360*100}%, calc(100% - 8px))`}})}),w("div",{className:"chisel-color-alpha",role:"slider",tabIndex:0,"aria-label":`${e} alpha`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":Math.round(m*100),"aria-valuetext":`${Math.round(m*100)}%`,onKeyDown:X,onPointerDown:s=>{let L=s.currentTarget.getBoundingClientRect();xe(s,L),s.currentTarget.setPointerCapture(s.pointerId)},onPointerMove:s=>{s.buttons&1&&xe(s,s.currentTarget.getBoundingClientRect())},style:{"--chisel-alpha-color":ee},children:[u("span",{className:"chisel-color-alpha-fill",style:{width:`${m*100}%`}}),u("span",{className:"chisel-color-alpha-cursor",style:{left:`clamp(12px, ${m*100}%, calc(100% - 12px))`,backgroundColor:ct(ee,m)}})]}),w("div",{className:"chisel-color-format-row",children:[u("select",{className:"chisel-color-format-select","aria-label":`${e} color format`,value:M,onChange:s=>Je(s.target.value),children:Ot.map(s=>u("option",{value:s,children:s},s))}),u("input",{className:"chisel-color-format-input","aria-label":`${e} formatted color value`,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off","data-invalid":te,spellCheck:!1,value:k,onBlur:()=>j(k),onChange:s=>{let L=s.target.value;P(L),j(L)}})]})]}):null,S==="Gradient"?w(We,{children:[w("label",{className:"chisel-color-extra-row",children:[u("span",{children:"From"}),u("input",{"aria-label":`${e} gradient From value`,value:T,onFocus:()=>me("start"),onChange:s=>ye("start",s.target.value)})]}),w("label",{className:"chisel-color-extra-row",children:[u("span",{children:"To"}),u("input",{"aria-label":`${e} gradient To value`,value:H,onFocus:()=>me("end"),onChange:s=>ye("end",s.target.value)})]})]}):null,S==="Image"?w(We,{children:[w("label",{className:"chisel-color-extra-row",children:[u("span",{children:"URL"}),u("input",{"aria-label":`${e} image URL`,value:B,onChange:s=>Ue(s.target.value),placeholder:"https://..."})]}),w("label",{className:"chisel-color-upload-row",children:[u("span",{children:"Upload"}),u("span",{className:"chisel-color-upload-name",children:G||"Choose image"}),u("input",{"aria-label":`${e} image upload`,accept:"image/*",type:"file",onChange:ge})]}),r&&!B.startsWith("blob:")?w("div",{className:"chisel-note-row",role:"status",children:["Re-select this asset: ",r.fileName]}):null]}):null]}):null]})}function Vt({control:e,computedStyle:a,element:t,onSlide:o,onValueChange:r,mixed:n=!1}){let c=(a??getComputedStyle(t))[e.property],f=parseFloat(c),g=e.property==="width"?t.getBoundingClientRect().width:e.property==="height"?t.getBoundingClientRect().height:e.min,S=Number.isFinite(f)?f:g,A=Y(S,e.min,e.max),M=Ao(A,e.min,e.max),F=t.style[e.property],k=n?"Mixed":F||`${pe(S)}${e.unit}`,P=yo(k,e),[T,q]=p.useState(k),[H,ae]=p.useState(!1),[v,U]=p.useState(!1),[B,W]=p.useState(!1),G=p.useRef(null),K=p.useRef(null),te=p.useRef(!1),E=p.useMemo(()=>xo(e),[e]),fe={left:`max(5px, ${M}% - 9px)`,"--chisel-handle-opacity":M<18?"0.18":"1","--chisel-handle-scale":M<18?"0.25":"1"};p.useEffect(()=>{H||(q(k),U(!1))},[k,H]),p.useEffect(()=>{if(!B)return;let m=()=>{W(!1),window.requestAnimationFrame(()=>G.current?.focus())},I=j=>{j.target instanceof Node&&G.current?.parentElement?.contains(j.target)||m()},Z=j=>{j.key==="Escape"&&(m(),j.preventDefault())};return document.addEventListener("pointerdown",I,!0),document.addEventListener("keydown",Z),()=>{document.removeEventListener("pointerdown",I,!0),document.removeEventListener("keydown",Z)}},[B]);let oe=(m=T)=>{let I=da(m,e,t,P);if(!I){U(!0);return}q(I),U(!1),r(I)},re=()=>{G.current?.focus(),G.current?.select()},le=(m,I)=>{let Z=vo(m,I,e);q(`${pe(Z)}${e.unit}`),U(!1),o(Z)},$=()=>{E.length<=1||(W(!0),window.requestAnimationFrame(()=>G.current?.parentElement?.querySelector('[role="option"][aria-selected="true"]')?.focus()))},ee=m=>{let I=Io(T,m,e,t,P);if(!I){U(!0);return}q(I),U(!1),r(I),W(!1),G.current?.focus()};return w("div",{className:"chisel-slider","data-units-open":B,onDoubleClick:m=>{m.preventDefault(),m.stopPropagation(),$()},onClick:()=>{if(te.current){te.current=!1;return}window.setTimeout(re,0)},onMouseUp:()=>{te.current||window.setTimeout(re,0)},onPointerCancel:m=>{K.current?.pointerId===m.pointerId&&(K.current=null)},onPointerDown:m=>{m.preventDefault(),K.current={pointerId:m.pointerId,startX:m.clientX,rect:m.currentTarget.getBoundingClientRect(),dragging:!1},m.currentTarget.setPointerCapture(m.pointerId),window.setTimeout(re,0)},onPointerMove:m=>{let I=K.current;!I||I.pointerId!==m.pointerId||!I.dragging&&Math.abs(m.clientX-I.startX)<4||(I.dragging=!0,G.current?.blur(),m.preventDefault(),le(m.clientX,I.rect))},onPointerUp:m=>{let I=K.current;!I||I.pointerId!==m.pointerId||(I.dragging&&(te.current=!0,window.setTimeout(()=>{te.current=!1},250),le(m.clientX,I.rect)),I.dragging||window.setTimeout(re,0),K.current=null)},children:[u("span",{className:"chisel-slider-label",children:e.label}),u("span",{className:"chisel-slider-hashmarks","aria-hidden":"true",children:Array.from({length:9},(m,I)=>u("span",{className:"chisel-slider-hashmark",style:{left:`${(I+1)*10}%`}},I))}),u("span",{className:"chisel-slider-fill",style:{width:`${M}%`}}),u("span",{className:"chisel-slider-handle",style:fe}),u("input",{type:"range",tabIndex:-1,"aria-hidden":"true",min:e.min,max:e.max,step:e.step,value:A,onChange:m=>o(Number(m.target.value))}),u("input",{ref:G,className:"chisel-slider-value-input","aria-label":`${e.label} value`,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off","data-invalid":v,spellCheck:!1,value:T,onBlur:m=>{oe(),ae(!1),m.relatedTarget instanceof HTMLElement&&m.currentTarget.parentElement?.contains(m.relatedTarget)||W(!1)},onChange:m=>{let I=m.target.value;q(I);let Z=da(I,e,t,P);if(!Z){U(I.trim().length>0);return}U(!1),r(Z),Z!==I&&Lo(I)&&q(Z)},onFocus:m=>{ae(!0),m.currentTarget.select()},onMouseDown:m=>{window.setTimeout(()=>{m.currentTarget.focus(),m.currentTarget.select()},0)},onMouseUp:m=>{window.setTimeout(()=>{m.currentTarget.focus(),m.currentTarget.select()},0)},onDoubleClick:m=>{m.preventDefault(),m.stopPropagation(),$()},onKeyDown:m=>{if(m.key==="Enter"&&(m.preventDefault(),oe(),m.currentTarget.blur()),ra(m.key)){let I=Po(T,e,t,P,m.shiftKey?10:1,Ca(m.key));if(!I)return;m.preventDefault(),q(I),U(!1),r(I)}m.key==="Escape"&&(m.preventDefault(),q(k),U(!1),W(!1),m.currentTarget.blur())}}),B?u("div",{className:"chisel-unit-menu",role:"listbox","aria-label":`${e.label} units`,onKeyDown:ka,children:E.map(m=>u("button",{className:"chisel-unit-option","data-active":m===P,"aria-selected":m===P,onClick:I=>{I.preventDefault(),ee(m)},onPointerDown:I=>{I.preventDefault(),I.stopPropagation()},role:"option",type:"button",children:m||"unitless"},m||"unitless"))}):null]})}function zt(){return u("style",{children:`
|
|
10
|
+
${Wa}
|
|
863
11
|
.chisel-root, .chisel-root * { box-sizing: border-box; }
|
|
864
|
-
.chisel-root
|
|
12
|
+
.chisel-root :where(button, input, textarea, select) { margin: 0; font: inherit; color: inherit; text-transform: none; }
|
|
13
|
+
.chisel-root button { appearance: none; min-width: var(--chisel-ui-control); min-height: var(--chisel-ui-control); }
|
|
14
|
+
.chisel-root { --chisel-surface: rgba(0, 0, 0, 0.04); --chisel-surface-hover: rgba(0, 0, 0, 0.08); --chisel-surface-active: rgba(0, 0, 0, 0.1); --chisel-surface-subtle: rgba(0, 0, 0, 0.06); --chisel-text-root: #000; --chisel-text-section: rgba(0, 0, 0, 0.65); --chisel-text-label: rgba(0, 0, 0, 0.6); --chisel-text-focus: #000; --chisel-text-primary: rgba(0, 0, 0, 0.9); --chisel-text-secondary: rgba(0, 0, 0, 0.55); --chisel-text-tertiary: rgba(0, 0, 0, 0.55); --chisel-border: rgba(0, 0, 0, 0.1); --chisel-border-hover: rgba(0, 0, 0, 0.15); --chisel-glass-bg: rgba(250, 250, 250, 0.88); --chisel-radius: 8px; --chisel-row-height: 40px; --chisel-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); --chisel-motion: 150ms cubic-bezier(0.2, 0.8, 0.2, 1); position: fixed; inset: 0; height: 100dvh; z-index: 2147483647; pointer-events: none; font-family: var(--chisel-ui-font); color: var(--chisel-text-primary); letter-spacing: 0; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
|
|
15
|
+
.chisel-root { color-scheme: light; --chisel-warning-color: #805b12; --chisel-danger-color: #8a1f1f; }
|
|
16
|
+
@media (prefers-color-scheme: dark) {
|
|
17
|
+
.chisel-root { color-scheme: dark; --chisel-warning-color: #e2c78c; --chisel-danger-color: #ffa5a5; --chisel-surface: #303030; --chisel-surface-hover: #393939; --chisel-surface-active: #41413e; --chisel-surface-subtle: #383838; --chisel-text-root: #e8e8e5; --chisel-text-section: #b4b4ae; --chisel-text-label: #b4b4ae; --chisel-text-focus: #efeee9; --chisel-text-primary: #e8e8e5; --chisel-text-secondary: #b4b4ae; --chisel-text-tertiary: #9b9b93; --chisel-border: #41413e; --chisel-border-hover: #62625b; --chisel-glass-bg: #262626; --chisel-shadow: 0 4px 20px #0003; }
|
|
18
|
+
}
|
|
19
|
+
.chisel-root {--chisel-surface:var(--chisel-ui-raised); --chisel-surface-hover:var(--chisel-ui-hover); --chisel-surface-active:var(--chisel-ui-selected); --chisel-surface-subtle:var(--chisel-ui-border); --chisel-text-root:var(--chisel-ui-text); --chisel-text-section:var(--chisel-ui-secondary); --chisel-text-label:var(--chisel-ui-secondary); --chisel-text-focus:var(--chisel-ui-text); --chisel-text-primary:var(--chisel-ui-text); --chisel-text-secondary:var(--chisel-ui-secondary); --chisel-text-tertiary:var(--chisel-ui-muted); --chisel-border:var(--chisel-ui-border); --chisel-border-hover:var(--chisel-ui-border-strong); --chisel-glass-bg:var(--chisel-ui-surface); --chisel-radius:var(--chisel-ui-radius); --chisel-row-height:var(--chisel-ui-control); --chisel-shadow:var(--chisel-ui-panel-shadow); --chisel-motion:var(--chisel-ui-motion);}
|
|
20
|
+
.chisel-inspection-layer { position: fixed; inset: 0; pointer-events: auto; touch-action: pan-y pinch-zoom; }
|
|
21
|
+
.chisel-visually-hidden { position: fixed; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
865
22
|
.chisel-box { position: fixed; left: 0; top: 0; border-radius: 0; pointer-events: none; transition: none; }
|
|
866
|
-
.chisel-box-hover { border: 1px solid
|
|
867
|
-
.chisel-box-selected { border: 2px solid
|
|
868
|
-
.chisel-panel { position: fixed; top: 16px; max-height: calc(
|
|
23
|
+
.chisel-box-hover { border: 1px solid var(--chisel-ui-focus); background: color-mix(in srgb,var(--chisel-ui-focus) 8%,transparent); }
|
|
24
|
+
.chisel-box-selected { border: 2px solid var(--chisel-ui-focus); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.92), 0 0 0 4px color-mix(in srgb,var(--chisel-ui-focus) 18%,transparent); }
|
|
25
|
+
.chisel-panel { position: fixed; top: max(16px, env(safe-area-inset-top)); max-height: calc(100dvh - 32px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); width: 280px; pointer-events: auto; overflow: visible; }
|
|
869
26
|
.chisel-panel-right { right: 16px; }
|
|
870
27
|
.chisel-panel-left { left: 16px; }
|
|
871
28
|
.chisel-panel-wrapper { display: inline-flex; flex-direction: column; width: 100%; }
|
|
872
|
-
.chisel-panel-inner { width: 280px; max-height: calc(100vh - 32px); overflow-y: auto; padding:
|
|
29
|
+
.chisel-panel-inner { width: 280px; max-height: calc(100vh - 32px); overflow-y: auto; padding: 12px 16px 0; border: 0; border-radius: 16px; background: var(--chisel-glass-bg); box-shadow: var(--chisel-ui-popover-shadow); transform: translateZ(0); -ms-overflow-style: none; scrollbar-width: none; }
|
|
873
30
|
.chisel-panel-inner::-webkit-scrollbar { display: none; }
|
|
874
|
-
.chisel-folder { border
|
|
31
|
+
.chisel-folder { border: 0; margin-bottom: 16px; padding-bottom: 0; }
|
|
875
32
|
.chisel-folder-root { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
|
|
876
|
-
.chisel-panel-header { border
|
|
33
|
+
.chisel-panel-header { border: 0; margin-bottom: 16px; padding-bottom: 0; }
|
|
877
34
|
.chisel-folder-header { user-select: none; }
|
|
878
35
|
.chisel-folder-header-top { display: flex; align-items: center; justify-content: space-between; height: var(--chisel-row-height); padding: 0; }
|
|
879
36
|
.chisel-folder-title-row { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; overflow: hidden; white-space: nowrap; }
|
|
@@ -882,37 +39,41 @@ function ChiselStyles() {
|
|
|
882
39
|
.chisel-folder-count { color: var(--chisel-text-tertiary); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; font-weight: 500; }
|
|
883
40
|
.chisel-folder-content { position: relative; }
|
|
884
41
|
.chisel-folder-inner, .chisel-content, .chisel-empty { display: flex; flex-direction: column; gap: 6px; padding-bottom: 10px; }
|
|
885
|
-
.chisel-folder:not(.chisel-folder-root) { border
|
|
886
|
-
.chisel-folder:not(.chisel-folder-root) + .chisel-folder:not(.chisel-folder-root) {
|
|
42
|
+
.chisel-folder:not(.chisel-folder-root) { border: 0; margin-top: 16px; margin-bottom: 0; padding-bottom: 0; }
|
|
43
|
+
.chisel-folder:not(.chisel-folder-root) + .chisel-folder:not(.chisel-folder-root) { margin-top: 16px; }
|
|
887
44
|
.chisel-panel-toolbar { display: flex; align-items: center; gap: 6px; height: var(--chisel-row-height); min-width: 0; margin-bottom: 6px; overflow: visible; }
|
|
888
45
|
.chisel-toolbar-add { width: var(--chisel-row-height); height: var(--chisel-row-height); flex-shrink: 0; display: flex; align-items: center; justify-content: center; padding: 0; border: none; border-radius: var(--chisel-radius); background: var(--chisel-surface); color: var(--chisel-text-label); font: inherit; font-size: 16px; font-weight: 500; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
889
|
-
.chisel-toolbar-add:hover, .chisel-preset-trigger:hover, .chisel-button:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary);
|
|
890
|
-
.chisel-toolbar-add:active, .chisel-preset-trigger:active, .chisel-button:active { transform:
|
|
46
|
+
.chisel-toolbar-add:hover, .chisel-preset-trigger:hover, .chisel-button:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary); }
|
|
47
|
+
.chisel-toolbar-add:active, .chisel-preset-trigger:active, .chisel-button:active { transform: scale(0.96); }
|
|
891
48
|
.chisel-preset-manager { position: relative; flex: 1; min-width: 0; }
|
|
892
49
|
.chisel-preset-trigger { width: 100%; min-width: 0; height: var(--chisel-row-height); display: flex; align-items: center; justify-content: space-between; padding: 0 12px; border: none; border-radius: var(--chisel-radius); background: var(--chisel-surface); color: var(--chisel-text-label); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); overflow: hidden; }
|
|
893
50
|
.chisel-preset-trigger[aria-expanded="true"] { background: var(--chisel-surface-active); }
|
|
894
51
|
.chisel-preset-trigger-label, .chisel-font-trigger-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
895
|
-
.chisel-chevron { width:
|
|
896
|
-
.chisel-preset-trigger[aria-expanded="true"] .chisel-chevron, .chisel-font-trigger[aria-expanded="true"] .chisel-chevron { opacity: 1; transform: rotate(
|
|
897
|
-
.chisel-preset-dropdown { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 2147483647; padding: 4px; border:
|
|
52
|
+
.chisel-chevron { width: 16px; height: 16px; flex-shrink: 0; margin-left: 8px; opacity: 0.72; transition: transform var(--chisel-motion), opacity var(--chisel-motion); }
|
|
53
|
+
.chisel-preset-trigger[aria-expanded="true"] .chisel-chevron, .chisel-font-trigger[aria-expanded="true"] .chisel-chevron { opacity: 1; transform: rotate(180deg); }
|
|
54
|
+
.chisel-preset-dropdown { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 2147483647; padding: 4px; border: 0; border-radius: 12px; background: var(--chisel-glass-bg); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); animation: chisel-pop-in var(--chisel-motion); transform-origin: top center; }
|
|
898
55
|
.chisel-preset-list { display: flex; flex-direction: column; gap: 2px; }
|
|
899
56
|
.chisel-preset-item { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; border: none; border-radius: 8px; background: transparent; color: var(--chisel-text-label); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
900
|
-
.chisel-preset-item:hover { background: var(--chisel-surface-hover);
|
|
57
|
+
.chisel-preset-item:hover { background: var(--chisel-surface-hover); }
|
|
901
58
|
.chisel-preset-item[data-active="true"] { background: var(--chisel-surface-active); color: var(--chisel-text-primary); }
|
|
902
59
|
.chisel-preset-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
903
60
|
.chisel-preset-count { color: var(--chisel-text-tertiary); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 11px; }
|
|
904
61
|
.chisel-text-control, .chisel-color-control, .chisel-font-control { min-height: var(--chisel-row-height); display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 12px; border-radius: var(--chisel-radius); background: var(--chisel-surface); }
|
|
905
62
|
.chisel-text-label, .chisel-color-label, .chisel-font-label, .chisel-slider-label { color: var(--chisel-text-label); flex-shrink: 0; font-size: 13px; font-weight: 500; line-height: 17px; transform: translateY(-0.5px); }
|
|
906
63
|
.chisel-text-code, .chisel-text-value, .chisel-selector, .chisel-warning, .chisel-color-value-input, .chisel-slider-value-input { min-width: 0; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--chisel-text-label); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 13px; font-weight: 500; text-align: right; }
|
|
64
|
+
.chisel-context-row { background: transparent; padding-inline: 0; }
|
|
907
65
|
.chisel-selector-row { min-height: var(--chisel-row-height); }
|
|
908
66
|
.chisel-selector { max-width: 168px; line-height: 1.25; }
|
|
909
|
-
.chisel-warning { color:
|
|
67
|
+
.chisel-warning { color: var(--chisel-warning-color); font-family: inherit; }
|
|
910
68
|
.chisel-textarea-control { height: auto; align-items: flex-start; padding-top: 10px; padding-bottom: 10px; }
|
|
911
69
|
.chisel-text-input { min-width: 0; width: 100%; flex: 1; resize: vertical; border: none; outline: none; background: transparent; color: var(--chisel-text-label); text-align: right; font: inherit; font-size: 13px; font-weight: 500; line-height: 1.35; }
|
|
912
|
-
.chisel-text-input::selection, .chisel-color-value-input::selection, .chisel-slider-value-input::selection { background:
|
|
913
|
-
.chisel-text-input:focus { color: var(--chisel-text-focus); }
|
|
70
|
+
.chisel-text-input::selection, .chisel-color-value-input::selection, .chisel-slider-value-input::selection { background: color-mix(in srgb,var(--chisel-ui-focus) 22%,transparent); color: var(--chisel-text-focus); }
|
|
914
71
|
.chisel-text-input:disabled { color: var(--chisel-text-tertiary); cursor: not-allowed; }
|
|
915
|
-
.chisel-note-row { min-height: var(--chisel-row-height); display: flex; align-items: center; padding:
|
|
72
|
+
.chisel-note-row { min-height: var(--chisel-row-height); display: flex; align-items: center; padding: 8px 0; border-radius: var(--chisel-radius); background: transparent; color: var(--chisel-text-tertiary); font-size: 12px; font-weight: 400; line-height: 1.5; }
|
|
73
|
+
.chisel-toolbar-add { background: transparent; }
|
|
74
|
+
.chisel-actions .chisel-button { background: transparent; }
|
|
75
|
+
.chisel-actions .chisel-button-primary { background: var(--chisel-ui-action); color: var(--chisel-ui-action-text); }
|
|
76
|
+
.chisel-actions .chisel-button-primary:hover { background: var(--chisel-ui-action); opacity: .9; }
|
|
916
77
|
.chisel-button:disabled { color: var(--chisel-text-tertiary); cursor: not-allowed; transform: none; }
|
|
917
78
|
.chisel-font-control { position: relative; overflow: visible; cursor: default; }
|
|
918
79
|
.chisel-font-picker { min-width: 0; flex: 0 1 150px; }
|
|
@@ -924,15 +85,16 @@ function ChiselStyles() {
|
|
|
924
85
|
.chisel-font-item { justify-content: flex-start; text-align: left; font-size: 14px; }
|
|
925
86
|
.chisel-color-control { position: relative; overflow: visible; flex-wrap: wrap; }
|
|
926
87
|
.chisel-color-control[data-picker-open="true"] { z-index: 25; padding-bottom: 0; }
|
|
927
|
-
.chisel-color-inputs { display: inline-flex; align-items: center; gap:
|
|
928
|
-
.chisel-color-swatch { position: relative; width:
|
|
929
|
-
.chisel-color-
|
|
88
|
+
.chisel-color-inputs { display: inline-flex; align-items: center; gap: 10px; min-width: 0; flex: 0 0 auto; justify-content: flex-end; }
|
|
89
|
+
.chisel-root .chisel-color-swatch { position: relative; width: 24px; height: 24px; min-width:24px; min-height:24px; flex-shrink: 0; padding: 0; border: 0; border-radius: 4.5px; box-shadow: inset 0 0 0 1px var(--chisel-border); cursor: pointer; transition: transform var(--chisel-motion), box-shadow var(--chisel-motion); }
|
|
90
|
+
.chisel-color-swatch:after { content:""; position:absolute; inset:-8px; border-radius:inherit; }
|
|
91
|
+
@media(pointer:coarse) { .chisel-color-swatch:after { inset:-10px; } }
|
|
92
|
+
.chisel-color-control:hover .chisel-color-swatch { box-shadow: 0 0 0 2px var(--chisel-surface-hover); }
|
|
930
93
|
.chisel-color-swatch:active { transform: scale(0.96); }
|
|
931
94
|
.chisel-color-value-input { width: 7.5ch; max-width: 150px; padding: 0; border: 0; outline: none; background: transparent; font-variant-numeric: tabular-nums; text-align: right; }
|
|
932
|
-
.chisel-color-value-input
|
|
933
|
-
.chisel-color-
|
|
934
|
-
.chisel-color-
|
|
935
|
-
.chisel-color-tabs { height: 32px; display: flex; align-items: flex-start; gap: 14px; border-bottom: 1px solid var(--chisel-surface-subtle); }
|
|
95
|
+
.chisel-color-value-input[data-invalid="true"] { color: var(--chisel-danger-color); }
|
|
96
|
+
.chisel-color-popover { flex: 0 0 calc(100% + 24px); width: calc(100% + 24px); display: flex; flex-direction: column; gap: 8px; margin: 4px -12px 0; padding: 8px 12px 0; border-top: 1px solid var(--chisel-surface-subtle); animation: chisel-pop-in var(--chisel-motion); }
|
|
97
|
+
.chisel-color-tabs { min-height:40px; height: 32px; display: flex; align-items: flex-start; gap: 14px; border-bottom: 1px solid var(--chisel-surface-subtle); }
|
|
936
98
|
.chisel-color-tab, .chisel-color-close, .chisel-color-saved-row button { border: none; background: transparent; color: var(--chisel-text-label); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
|
|
937
99
|
.chisel-color-tab { height: 32px; padding: 0; border-bottom: 2px solid transparent; }
|
|
938
100
|
.chisel-color-tab[data-active="true"] { color: var(--chisel-text-primary); border-bottom-color: var(--chisel-text-primary); }
|
|
@@ -950,21 +112,19 @@ function ChiselStyles() {
|
|
|
950
112
|
.chisel-color-gradient-preview { height: 28px; border: 1px solid var(--chisel-border); border-radius: var(--chisel-radius); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28); }
|
|
951
113
|
.chisel-color-stop-buttons { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
|
|
952
114
|
.chisel-color-stop-button { min-width: 0; height: 32px; display: flex; align-items: center; justify-content: center; gap: 7px; padding: 0 9px; border: none; border-radius: var(--chisel-radius); background: var(--chisel-surface); color: var(--chisel-text-label); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
953
|
-
.chisel-color-stop-button:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary);
|
|
115
|
+
.chisel-color-stop-button:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary); }
|
|
954
116
|
.chisel-color-stop-button[data-active="true"] { background: var(--chisel-surface-active); color: var(--chisel-text-primary); }
|
|
955
|
-
.chisel-color-stop-swatch { width:
|
|
117
|
+
.chisel-color-stop-swatch { width: 10.5px; height: 10.5px; flex-shrink: 0; overflow: hidden; border: 1px solid var(--chisel-border-hover); border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28); }
|
|
956
118
|
.chisel-color-format-row { display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 6px; }
|
|
957
|
-
.chisel-color-format-select, .chisel-color-format-input { height:
|
|
119
|
+
.chisel-color-format-select, .chisel-color-format-input { height: 40px; min-width: 0; border: none; border-radius: var(--chisel-radius); outline: none; background: var(--chisel-surface); color: var(--chisel-text-label); font: inherit; font-size: 13px; font-weight: 500; }
|
|
958
120
|
.chisel-color-format-select { padding: 0 8px; cursor: pointer; }
|
|
959
121
|
.chisel-color-format-input { padding: 0 9px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
960
|
-
.chisel-color-format-input
|
|
961
|
-
.chisel-color-format-input[data-invalid="true"] { color: #8a1f1f; }
|
|
122
|
+
.chisel-color-format-input[data-invalid="true"] { color: var(--chisel-danger-color); }
|
|
962
123
|
.chisel-color-extra-row, .chisel-color-upload-row { position: relative; min-height: 32px; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 9px; border-radius: var(--chisel-radius); background: var(--chisel-surface); color: var(--chisel-text-label); font-size: 13px; font-weight: 500; }
|
|
963
124
|
.chisel-color-extra-row span, .chisel-color-upload-row span:first-child { flex-shrink: 0; }
|
|
964
125
|
.chisel-color-extra-row input { min-width: 0; flex: 1; border: none; outline: none; background: transparent; color: var(--chisel-text-label); font: inherit; text-align: right; }
|
|
965
|
-
.chisel-color-extra-row input:focus { color: var(--chisel-text-focus); }
|
|
966
126
|
.chisel-color-upload-row { cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
967
|
-
.chisel-color-upload-row:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary);
|
|
127
|
+
.chisel-color-upload-row:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary); }
|
|
968
128
|
.chisel-color-upload-row input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
|
|
969
129
|
.chisel-color-upload-name { min-width: 0; overflow: hidden; text-align: right; text-overflow: ellipsis; white-space: nowrap; color: var(--chisel-text-tertiary); }
|
|
970
130
|
.chisel-slider { position: relative; height: var(--chisel-row-height); display: block; overflow: hidden; border-radius: var(--chisel-radius); background: var(--chisel-surface); cursor: pointer; user-select: none; touch-action: none; }
|
|
@@ -972,17 +132,17 @@ function ChiselStyles() {
|
|
|
972
132
|
.chisel-slider input[type="range"] { position: absolute; inset: 0; z-index: 3; width: 100%; height: 100%; opacity: 0; pointer-events: none; cursor: pointer; }
|
|
973
133
|
.chisel-slider-label { position: absolute; top: 50%; left: 10px; pointer-events: none; transform: translateY(calc(-50% - 0.5px)); z-index: 2; }
|
|
974
134
|
.chisel-slider-value-input { position: absolute; inset: 0; z-index: 4; width: 100%; max-width: none; height: 100%; padding: 0 10px 0 92px; border: 1px solid transparent; border-radius: var(--chisel-radius); outline: none; background: transparent; font-variant-numeric: tabular-nums; cursor: pointer; }
|
|
975
|
-
.chisel-slider-value-input:focus {
|
|
976
|
-
.chisel-slider-value-input[data-invalid="true"] { border-color: rgba(170, 48, 48, 0.38); background: rgba(170, 48, 48, 0.08); color:
|
|
135
|
+
.chisel-root .chisel-slider-value-input:focus { cursor: text; }
|
|
136
|
+
.chisel-slider-value-input[data-invalid="true"] { border-color: rgba(170, 48, 48, 0.38); background: rgba(170, 48, 48, 0.08); color: var(--chisel-danger-color); }
|
|
977
137
|
.chisel-slider-hashmarks { position: absolute; inset: 0; pointer-events: none; }
|
|
978
138
|
.chisel-slider-hashmark { position: absolute; top: 50%; width: 1px; height: 8px; border-radius: 999px; background: transparent; transform: translate(-50%, -50%); transition: background 0.2s; }
|
|
979
|
-
.chisel-slider:hover .chisel-slider-hashmark
|
|
139
|
+
.chisel-slider:hover .chisel-slider-hashmark { background: var(--chisel-surface-hover); }
|
|
980
140
|
.chisel-slider-fill { position: absolute; top: 0; bottom: 0; left: 0; background: var(--chisel-surface-active); pointer-events: none; transition: background 0.15s; }
|
|
981
141
|
.chisel-slider-handle { position: absolute; top: 50%; z-index: 2; width: 3px; height: 20px; border-radius: 999px; background: var(--chisel-text-primary); pointer-events: none; opacity: 0; transform: translateY(-50%) scaleX(var(--chisel-handle-scale, 1)); transition: opacity 0.15s, transform 0.15s; }
|
|
982
142
|
.chisel-slider:hover .chisel-slider-handle { opacity: var(--chisel-handle-opacity, 1); }
|
|
983
|
-
.chisel-unit-menu { position: absolute; top: calc(100% + 4px); right: 6px; z-index: 30; display: grid; grid-template-columns: repeat(4, minmax(
|
|
143
|
+
.chisel-unit-menu { position: absolute; top: calc(100% + 4px); right: 6px; z-index: 30; display: grid; grid-template-columns: repeat(4, minmax(40px, 1fr)); gap: 2px; width: 186px; padding: 4px; border: 1px solid var(--chisel-border); border-radius: 10px; background: var(--chisel-glass-bg); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.1); animation: chisel-pop-in var(--chisel-motion); cursor: default; }
|
|
984
144
|
.chisel-unit-option { min-width: 0; height: 26px; border: none; border-radius: 7px; background: transparent; color: var(--chisel-text-label); font: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 11px; font-weight: 600; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
985
|
-
.chisel-unit-option:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary);
|
|
145
|
+
.chisel-unit-option:hover { background: var(--chisel-surface-hover); color: var(--chisel-text-primary); }
|
|
986
146
|
.chisel-unit-option[data-active="true"] { background: var(--chisel-surface-active); color: var(--chisel-text-primary); }
|
|
987
147
|
.chisel-actions { display: flex; flex-direction: column; gap: 6px; padding-bottom: 10px; }
|
|
988
148
|
.chisel-button { width: 100%; min-height: var(--chisel-row-height); border: none; border-radius: var(--chisel-radius); background: var(--chisel-surface); color: var(--chisel-text-secondary); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer; transition: background var(--chisel-motion), color var(--chisel-motion), transform var(--chisel-motion); }
|
|
@@ -991,711 +151,43 @@ function ChiselStyles() {
|
|
|
991
151
|
.chisel-root, .chisel-root * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
|
|
992
152
|
}
|
|
993
153
|
@media (max-width: 760px) {
|
|
994
|
-
.chisel-
|
|
995
|
-
.chisel-panel
|
|
154
|
+
.chisel-root { --chisel-row-height: 44px; }
|
|
155
|
+
.chisel-panel { top: auto; left: max(10px, env(safe-area-inset-left)); right: max(10px, env(safe-area-inset-right)); bottom: max(10px, env(safe-area-inset-bottom)); width: auto; max-height: 58dvh; touch-action: pan-y; }
|
|
156
|
+
.chisel-panel-inner { width: 100%; max-height: 58dvh; }
|
|
157
|
+
.chisel-color-tab, .chisel-color-close, .chisel-color-stop-button, .chisel-color-format-select, .chisel-color-format-input, .chisel-color-extra-row, .chisel-color-upload-row, .chisel-unit-option { min-width: 44px; min-height: 44px; }
|
|
158
|
+
.chisel-color-tabs { min-height:40px; height: 44px; }
|
|
159
|
+
.chisel-color-hue, .chisel-color-alpha { height: 44px; }
|
|
160
|
+
.chisel-unit-menu { grid-template-columns: repeat(4, minmax(44px, 1fr)); width: 206px; }
|
|
996
161
|
}
|
|
997
|
-
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
return `vse:versions:${window.location.pathname}${window.location.search}`;
|
|
1030
|
-
}
|
|
1031
|
-
function readStoredVersions(key) {
|
|
1032
|
-
try {
|
|
1033
|
-
const raw = window.localStorage.getItem(key);
|
|
1034
|
-
if (!raw)
|
|
1035
|
-
return [];
|
|
1036
|
-
const parsed = JSON.parse(raw);
|
|
1037
|
-
if (!Array.isArray(parsed))
|
|
1038
|
-
return [];
|
|
1039
|
-
return parsed.filter(isVersionState);
|
|
1040
|
-
}
|
|
1041
|
-
catch {
|
|
1042
|
-
return [];
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
function isVersionState(value) {
|
|
1046
|
-
if (!value || typeof value !== "object")
|
|
1047
|
-
return false;
|
|
1048
|
-
const version = value;
|
|
1049
|
-
return typeof version.id === "string" && typeof version.name === "string" && Boolean(version.elements) && typeof version.elements === "object";
|
|
1050
|
-
}
|
|
1051
|
-
function getElementKey(element) {
|
|
1052
|
-
return getSourceHint(element) ?? getBestSelector(element);
|
|
1053
|
-
}
|
|
1054
|
-
function ensureElementBaseline(element, key, baselines) {
|
|
1055
|
-
if (baselines.has(key))
|
|
1056
|
-
return;
|
|
1057
|
-
const styles = {};
|
|
1058
|
-
for (const property of STYLE_PROPERTIES) {
|
|
1059
|
-
styles[property] = element.style[property] ?? "";
|
|
1060
|
-
}
|
|
1061
|
-
baselines.set(key, {
|
|
1062
|
-
selector: getBestSelector(element),
|
|
1063
|
-
sourceHint: getSourceHint(element),
|
|
1064
|
-
text: element.textContent ?? "",
|
|
1065
|
-
styles
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
function applyVersionToDom(version, baselines) {
|
|
1069
|
-
for (const [key, baseline] of baselines) {
|
|
1070
|
-
const element = findVersionElement(baseline);
|
|
1071
|
-
if (!element)
|
|
1072
|
-
continue;
|
|
1073
|
-
element.textContent = baseline.text;
|
|
1074
|
-
for (const property of STYLE_PROPERTIES) {
|
|
1075
|
-
element.style[property] = baseline.styles[property] ?? "";
|
|
1076
|
-
}
|
|
1077
|
-
baselines.set(key, baseline);
|
|
1078
|
-
}
|
|
1079
|
-
for (const [key, change] of Object.entries(version.elements)) {
|
|
1080
|
-
const element = findVersionElement(change);
|
|
1081
|
-
if (!element)
|
|
1082
|
-
continue;
|
|
1083
|
-
ensureElementBaseline(element, key, baselines);
|
|
1084
|
-
if (typeof change.text === "string")
|
|
1085
|
-
element.textContent = change.text;
|
|
1086
|
-
for (const [property, value] of Object.entries(change.styles)) {
|
|
1087
|
-
element.style[property] = value;
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
function findVersionElement(change) {
|
|
1092
|
-
const hintedSelector = change.sourceHint
|
|
1093
|
-
? `[data-chisel-id="${cssEscape(change.sourceHint)}"], [data-ai-edit="${cssEscape(change.sourceHint)}"], [data-component="${cssEscape(change.sourceHint)}"]`
|
|
1094
|
-
: undefined;
|
|
1095
|
-
return queryHTMLElement(hintedSelector) ?? queryHTMLElement(change.selector);
|
|
1096
|
-
}
|
|
1097
|
-
function queryHTMLElement(selector) {
|
|
1098
|
-
if (!selector)
|
|
1099
|
-
return undefined;
|
|
1100
|
-
try {
|
|
1101
|
-
const element = document.querySelector(selector);
|
|
1102
|
-
return element instanceof HTMLElement ? element : undefined;
|
|
1103
|
-
}
|
|
1104
|
-
catch {
|
|
1105
|
-
return undefined;
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
function toggleElementSelection(current, target) {
|
|
1109
|
-
return current.includes(target) ? current.filter((element) => element !== target) : [...current, target];
|
|
1110
|
-
}
|
|
1111
|
-
function getChanges(element, snapshot) {
|
|
1112
|
-
const computed = getComputedStyle(element);
|
|
1113
|
-
const changes = [];
|
|
1114
|
-
const currentText = element.textContent ?? "";
|
|
1115
|
-
if (currentText !== snapshot.text) {
|
|
1116
|
-
changes.push({ property: "textContent", before: snapshot.text, after: currentText });
|
|
1117
|
-
}
|
|
1118
|
-
for (const property of STYLE_PROPERTIES) {
|
|
1119
|
-
const before = snapshot.styles[property];
|
|
1120
|
-
const authoredAfter = element.style[property] ?? "";
|
|
1121
|
-
const after = authoredAfter || computed[property];
|
|
1122
|
-
if (normalizeStyleValue(before) !== normalizeStyleValue(after)) {
|
|
1123
|
-
changes.push({ property, before, after });
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
return changes;
|
|
1127
|
-
}
|
|
1128
|
-
function buildAgentPrompt({ projectName, element, snapshot, rect, selector, sourceHint, changes }) {
|
|
1129
|
-
const intent = {
|
|
1130
|
-
route: window.location.href,
|
|
1131
|
-
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
1132
|
-
element: {
|
|
1133
|
-
tagName: element.tagName.toLowerCase(),
|
|
1134
|
-
selector,
|
|
1135
|
-
ancestry: getAncestry(element),
|
|
1136
|
-
boundingRect: rect,
|
|
1137
|
-
textBefore: snapshot.text,
|
|
1138
|
-
textAfter: element.textContent ?? "",
|
|
1139
|
-
sourceHint
|
|
1140
|
-
},
|
|
1141
|
-
changes
|
|
1142
|
-
};
|
|
1143
|
-
const lowConfidence = !sourceHint && !selector.includes("[data-chisel-id") && !selector.includes("#");
|
|
1144
|
-
return [
|
|
1145
|
-
`You are editing ${projectName}. Update the source files for this Next.js app to match the visual edit intent below.`,
|
|
1146
|
-
"",
|
|
1147
|
-
"Do not ship a broad global CSS override. Find the component, JSX, CSS module, Tailwind classes, or style object that owns the selected element and make the smallest source-level change.",
|
|
1148
|
-
lowConfidence ? "Selector confidence is low. Use the route, visible text, DOM ancestry, and nearby structure to find the matching source component before editing." : "A source hint is available. Prefer it when locating the component.",
|
|
1149
|
-
"",
|
|
1150
|
-
"Edit intent:",
|
|
1151
|
-
"```json",
|
|
1152
|
-
JSON.stringify(intent, null, 2),
|
|
1153
|
-
"```",
|
|
1154
|
-
"",
|
|
1155
|
-
"Acceptance criteria:",
|
|
1156
|
-
"- The selected element visually matches the requested text/style changes on the same route.",
|
|
1157
|
-
"- Existing responsive behavior is preserved.",
|
|
1158
|
-
"- No editor-only attributes or temporary inline preview styles are added unless they already belong to the app source."
|
|
1159
|
-
].join("\n");
|
|
1160
|
-
}
|
|
1161
|
-
function buildPageAgentPrompt({ projectName, version, baselines }) {
|
|
1162
|
-
const elements = Object.entries(version.elements).map(([key, change]) => {
|
|
1163
|
-
const baseline = baselines.get(key);
|
|
1164
|
-
const element = findVersionElement(change);
|
|
1165
|
-
return {
|
|
1166
|
-
selector: change.selector,
|
|
1167
|
-
sourceHint: change.sourceHint,
|
|
1168
|
-
tagName: element?.tagName.toLowerCase(),
|
|
1169
|
-
ancestry: element ? getAncestry(element) : undefined,
|
|
1170
|
-
textBefore: baseline?.text,
|
|
1171
|
-
textAfter: change.text,
|
|
1172
|
-
styleChanges: Object.fromEntries(Object.entries(change.styles).map(([property, after]) => [property, { before: baseline?.styles[property] ?? null, after }]))
|
|
1173
|
-
};
|
|
1174
|
-
});
|
|
1175
|
-
return [
|
|
1176
|
-
`You are editing ${projectName}. Update the source files for this Next.js app to match all page-level visual edit intents below.`,
|
|
1177
|
-
"",
|
|
1178
|
-
"Do not ship broad global CSS overrides. Find the owning components, JSX, CSS modules, Tailwind classes, or style objects and make the smallest source-level changes.",
|
|
1179
|
-
"",
|
|
1180
|
-
"Edit intent:",
|
|
1181
|
-
"```json",
|
|
1182
|
-
JSON.stringify({
|
|
1183
|
-
route: window.location.href,
|
|
1184
|
-
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
1185
|
-
elements
|
|
1186
|
-
}, null, 2),
|
|
1187
|
-
"```",
|
|
1188
|
-
"",
|
|
1189
|
-
"Acceptance criteria:",
|
|
1190
|
-
"- All changed elements visually match the requested page edits on the same route.",
|
|
1191
|
-
"- Existing responsive behavior is preserved.",
|
|
1192
|
-
"- No editor-only attributes or temporary inline preview styles are added unless they already belong to the app source."
|
|
1193
|
-
].join("\n");
|
|
1194
|
-
}
|
|
1195
|
-
function getSourceHint(element) {
|
|
1196
|
-
return element.dataset.chiselId ?? element.dataset.aiEdit ?? element.dataset.component ?? findClosestSourceHint(element);
|
|
1197
|
-
}
|
|
1198
|
-
function findClosestSourceHint(element) {
|
|
1199
|
-
const parent = element.closest("[data-chisel-id], [data-ai-edit], [data-component]");
|
|
1200
|
-
if (!(parent instanceof HTMLElement) || parent === element)
|
|
1201
|
-
return undefined;
|
|
1202
|
-
return parent.dataset.chiselId ?? parent.dataset.aiEdit ?? parent.dataset.component;
|
|
1203
|
-
}
|
|
1204
|
-
function getBestSelector(element) {
|
|
1205
|
-
const hint = getSourceHint(element);
|
|
1206
|
-
if (hint)
|
|
1207
|
-
return `[data-chisel-id="${cssEscape(hint)}"], [data-ai-edit="${cssEscape(hint)}"], [data-component="${cssEscape(hint)}"]`;
|
|
1208
|
-
if (element.id)
|
|
1209
|
-
return `#${cssEscape(element.id)}`;
|
|
1210
|
-
const parts = [];
|
|
1211
|
-
let current = element;
|
|
1212
|
-
while (current && current !== document.body && parts.length < 5) {
|
|
1213
|
-
let part = current.tagName.toLowerCase();
|
|
1214
|
-
const classNames = Array.from(current.classList).filter(Boolean).slice(0, 2);
|
|
1215
|
-
if (classNames.length)
|
|
1216
|
-
part += classNames.map((name) => `.${cssEscape(name)}`).join("");
|
|
1217
|
-
const parent = current.parentElement;
|
|
1218
|
-
if (parent) {
|
|
1219
|
-
const tagName = current.tagName;
|
|
1220
|
-
const siblings = Array.from(parent.children).filter((child) => child.tagName === tagName);
|
|
1221
|
-
if (siblings.length > 1)
|
|
1222
|
-
part += `:nth-of-type(${siblings.indexOf(current) + 1})`;
|
|
1223
|
-
}
|
|
1224
|
-
parts.unshift(part);
|
|
1225
|
-
current = parent;
|
|
1226
|
-
}
|
|
1227
|
-
return parts.join(" > ");
|
|
1228
|
-
}
|
|
1229
|
-
function getAncestry(element) {
|
|
1230
|
-
const ancestry = [];
|
|
1231
|
-
let current = element;
|
|
1232
|
-
while (current && current !== document.body && ancestry.length < 6) {
|
|
1233
|
-
const text = (current.textContent ?? "").trim().replace(/\s+/g, " ").slice(0, 80);
|
|
1234
|
-
ancestry.push(`${current.tagName.toLowerCase()}${current.id ? `#${current.id}` : ""}${text ? ` "${text}"` : ""}`);
|
|
1235
|
-
current = current.parentElement;
|
|
1236
|
-
}
|
|
1237
|
-
return ancestry;
|
|
1238
|
-
}
|
|
1239
|
-
function rectToJSON(rect) {
|
|
1240
|
-
return {
|
|
1241
|
-
x: round(rect.x),
|
|
1242
|
-
y: round(rect.y),
|
|
1243
|
-
width: round(rect.width),
|
|
1244
|
-
height: round(rect.height),
|
|
1245
|
-
top: round(rect.top),
|
|
1246
|
-
right: round(rect.right),
|
|
1247
|
-
bottom: round(rect.bottom),
|
|
1248
|
-
left: round(rect.left)
|
|
1249
|
-
};
|
|
1250
|
-
}
|
|
1251
|
-
function isEditorElement(element) {
|
|
1252
|
-
return Boolean(element.closest("[data-chisel-root='true']"));
|
|
1253
|
-
}
|
|
1254
|
-
function cssEscape(value) {
|
|
1255
|
-
if (typeof CSS !== "undefined" && CSS.escape)
|
|
1256
|
-
return CSS.escape(value);
|
|
1257
|
-
return value.replace(/["\\#.:,[\]>~+*^$|= ]/g, "\\$&");
|
|
1258
|
-
}
|
|
1259
|
-
function toHex(color) {
|
|
1260
|
-
const hex = normalizeHexColor(color);
|
|
1261
|
-
if (hex)
|
|
1262
|
-
return hex;
|
|
1263
|
-
const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
|
|
1264
|
-
if (match) {
|
|
1265
|
-
return `#${[match[1], match[2], match[3]]
|
|
1266
|
-
.map((value) => Number(value).toString(16).padStart(2, "0"))
|
|
1267
|
-
.join("")}`;
|
|
1268
|
-
}
|
|
1269
|
-
const computed = computeCSSColor(color);
|
|
1270
|
-
if (!computed || computed === color)
|
|
1271
|
-
return "#ffffff";
|
|
1272
|
-
const computedMatch = computed.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
|
|
1273
|
-
if (!computedMatch)
|
|
1274
|
-
return "#ffffff";
|
|
1275
|
-
return `#${[computedMatch[1], computedMatch[2], computedMatch[3]]
|
|
1276
|
-
.map((value) => Number(value).toString(16).padStart(2, "0"))
|
|
1277
|
-
.join("")}`;
|
|
1278
|
-
}
|
|
1279
|
-
function computeCSSColor(color) {
|
|
1280
|
-
if (typeof document === "undefined")
|
|
1281
|
-
return undefined;
|
|
1282
|
-
const probe = document.createElement("span");
|
|
1283
|
-
probe.style.color = color;
|
|
1284
|
-
if (!probe.style.color)
|
|
1285
|
-
return undefined;
|
|
1286
|
-
probe.style.position = "absolute";
|
|
1287
|
-
probe.style.visibility = "hidden";
|
|
1288
|
-
document.body.appendChild(probe);
|
|
1289
|
-
const computed = getComputedStyle(probe).color;
|
|
1290
|
-
probe.remove();
|
|
1291
|
-
return computed;
|
|
1292
|
-
}
|
|
1293
|
-
function normalizeHexColor(color) {
|
|
1294
|
-
const trimmed = color.trim();
|
|
1295
|
-
const shortHex = trimmed.match(/^#([0-9a-f]{3})$/i);
|
|
1296
|
-
if (shortHex) {
|
|
1297
|
-
return `#${shortHex[1]
|
|
1298
|
-
.split("")
|
|
1299
|
-
.map((value) => `${value}${value}`)
|
|
1300
|
-
.join("")}`.toUpperCase();
|
|
1301
|
-
}
|
|
1302
|
-
if (/^#[0-9a-f]{6}$/i.test(trimmed))
|
|
1303
|
-
return trimmed.toUpperCase();
|
|
1304
|
-
return undefined;
|
|
1305
|
-
}
|
|
1306
|
-
function hexToRgb(hex) {
|
|
1307
|
-
const normalized = normalizeHexColor(hex) ?? "#FFFFFF";
|
|
1308
|
-
const value = normalized.slice(1);
|
|
1309
|
-
return {
|
|
1310
|
-
r: Number.parseInt(value.slice(0, 2), 16),
|
|
1311
|
-
g: Number.parseInt(value.slice(2, 4), 16),
|
|
1312
|
-
b: Number.parseInt(value.slice(4, 6), 16)
|
|
1313
|
-
};
|
|
1314
|
-
}
|
|
1315
|
-
function rgbToHsv({ r, g, b }) {
|
|
1316
|
-
const red = r / 255;
|
|
1317
|
-
const green = g / 255;
|
|
1318
|
-
const blue = b / 255;
|
|
1319
|
-
const max = Math.max(red, green, blue);
|
|
1320
|
-
const min = Math.min(red, green, blue);
|
|
1321
|
-
const delta = max - min;
|
|
1322
|
-
let hue = 0;
|
|
1323
|
-
if (delta !== 0) {
|
|
1324
|
-
if (max === red)
|
|
1325
|
-
hue = ((green - blue) / delta) % 6;
|
|
1326
|
-
else if (max === green)
|
|
1327
|
-
hue = (blue - red) / delta + 2;
|
|
1328
|
-
else
|
|
1329
|
-
hue = (red - green) / delta + 4;
|
|
1330
|
-
}
|
|
1331
|
-
hue = Math.round(hue * 60);
|
|
1332
|
-
if (hue < 0)
|
|
1333
|
-
hue += 360;
|
|
1334
|
-
return {
|
|
1335
|
-
h: hue,
|
|
1336
|
-
s: max === 0 ? 0 : round((delta / max) * 100),
|
|
1337
|
-
v: round(max * 100)
|
|
1338
|
-
};
|
|
1339
|
-
}
|
|
1340
|
-
function rgbToHsl({ r, g, b }) {
|
|
1341
|
-
const red = r / 255;
|
|
1342
|
-
const green = g / 255;
|
|
1343
|
-
const blue = b / 255;
|
|
1344
|
-
const max = Math.max(red, green, blue);
|
|
1345
|
-
const min = Math.min(red, green, blue);
|
|
1346
|
-
const lightness = (max + min) / 2;
|
|
1347
|
-
const delta = max - min;
|
|
1348
|
-
if (delta === 0)
|
|
1349
|
-
return { h: 0, s: 0, l: Math.round(lightness * 100) };
|
|
1350
|
-
const saturation = delta / (1 - Math.abs(2 * lightness - 1));
|
|
1351
|
-
let hue = 0;
|
|
1352
|
-
if (max === red)
|
|
1353
|
-
hue = ((green - blue) / delta) % 6;
|
|
1354
|
-
else if (max === green)
|
|
1355
|
-
hue = (blue - red) / delta + 2;
|
|
1356
|
-
else
|
|
1357
|
-
hue = (red - green) / delta + 4;
|
|
1358
|
-
hue = Math.round(hue * 60);
|
|
1359
|
-
if (hue < 0)
|
|
1360
|
-
hue += 360;
|
|
1361
|
-
return { h: hue, s: Math.round(saturation * 100), l: Math.round(lightness * 100) };
|
|
1362
|
-
}
|
|
1363
|
-
function hsvToHex(hue, saturation, brightness) {
|
|
1364
|
-
const chroma = (brightness / 100) * (saturation / 100);
|
|
1365
|
-
const x = chroma * (1 - Math.abs(((hue / 60) % 2) - 1));
|
|
1366
|
-
const match = brightness / 100 - chroma;
|
|
1367
|
-
const sector = Math.floor(hue / 60) % 6;
|
|
1368
|
-
const channels = [
|
|
1369
|
-
[chroma, x, 0],
|
|
1370
|
-
[x, chroma, 0],
|
|
1371
|
-
[0, chroma, x],
|
|
1372
|
-
[0, x, chroma],
|
|
1373
|
-
[x, 0, chroma],
|
|
1374
|
-
[chroma, 0, x]
|
|
1375
|
-
][sector] ?? [chroma, 0, x];
|
|
1376
|
-
return `#${channels
|
|
1377
|
-
.map((channel) => Math.round((channel + match) * 255).toString(16).padStart(2, "0"))
|
|
1378
|
-
.join("")}`.toUpperCase();
|
|
1379
|
-
}
|
|
1380
|
-
function normalizeStyleValue(value) {
|
|
1381
|
-
return (value ?? "").replace(/\s+/g, " ").trim();
|
|
1382
|
-
}
|
|
1383
|
-
function getFontFamilyLabel(value) {
|
|
1384
|
-
const firstFamily = value
|
|
1385
|
-
.split(",")[0]
|
|
1386
|
-
?.replace(/^["']|["']$/g, "")
|
|
1387
|
-
.trim();
|
|
1388
|
-
return firstFamily;
|
|
1389
|
-
}
|
|
1390
|
-
function getFontFamilyOptions(value) {
|
|
1391
|
-
const options = [];
|
|
1392
|
-
const seen = new Set();
|
|
1393
|
-
const addOption = (option) => {
|
|
1394
|
-
const key = getFontFamilyLabel(option.value)?.toLowerCase() ?? option.label.toLowerCase();
|
|
1395
|
-
if (seen.has(key))
|
|
1396
|
-
return;
|
|
1397
|
-
seen.add(key);
|
|
1398
|
-
options.push(option);
|
|
1399
|
-
};
|
|
1400
|
-
for (const option of FONT_FAMILY_OPTIONS)
|
|
1401
|
-
addOption(option);
|
|
1402
|
-
if (value && !options.some((option) => isMatchingFontFamily(value, option.value))) {
|
|
1403
|
-
const label = getFontFamilyLabel(value);
|
|
1404
|
-
if (label)
|
|
1405
|
-
options.unshift({ label, value });
|
|
1406
|
-
}
|
|
1407
|
-
return options;
|
|
1408
|
-
}
|
|
1409
|
-
function getMatchingFontOption(value, options) {
|
|
1410
|
-
return options.find((option) => isMatchingFontFamily(value, option.value));
|
|
1411
|
-
}
|
|
1412
|
-
function isMatchingFontFamily(firstValue, secondValue) {
|
|
1413
|
-
const first = getFontFamilyLabel(firstValue)?.toLowerCase();
|
|
1414
|
-
const second = getFontFamilyLabel(secondValue)?.toLowerCase();
|
|
1415
|
-
if (first && second && first === second)
|
|
1416
|
-
return true;
|
|
1417
|
-
return normalizeStyleValue(firstValue) === normalizeStyleValue(secondValue);
|
|
1418
|
-
}
|
|
1419
|
-
function normalizeColorInput(value) {
|
|
1420
|
-
const trimmed = value.trim();
|
|
1421
|
-
if (!trimmed)
|
|
1422
|
-
return undefined;
|
|
1423
|
-
if (isSupportedCSSValue("color", trimmed))
|
|
1424
|
-
return trimmed;
|
|
1425
|
-
return undefined;
|
|
1426
|
-
}
|
|
1427
|
-
function getColorDisplayValue(value) {
|
|
1428
|
-
return normalizeHexColor(value) ?? value;
|
|
1429
|
-
}
|
|
1430
|
-
function parseGradientValue(value) {
|
|
1431
|
-
const trimmed = value.trim();
|
|
1432
|
-
if (!trimmed.toLowerCase().startsWith("linear-gradient(") || !trimmed.endsWith(")"))
|
|
1433
|
-
return undefined;
|
|
1434
|
-
const content = trimmed.slice(trimmed.indexOf("(") + 1, -1);
|
|
1435
|
-
const parts = splitCSSFunctionArgs(content);
|
|
1436
|
-
if (parts.length < 3)
|
|
1437
|
-
return undefined;
|
|
1438
|
-
return {
|
|
1439
|
-
start: parts[1].trim(),
|
|
1440
|
-
end: parts.slice(2).join(", ").trim()
|
|
1441
|
-
};
|
|
1442
|
-
}
|
|
1443
|
-
function parseImageUrlValue(value) {
|
|
1444
|
-
const trimmed = value.trim();
|
|
1445
|
-
if (!trimmed.toLowerCase().startsWith("url(") || !trimmed.endsWith(")"))
|
|
1446
|
-
return undefined;
|
|
1447
|
-
let content = trimmed.slice(trimmed.indexOf("(") + 1, -1).trim();
|
|
1448
|
-
const quote = content[0];
|
|
1449
|
-
if ((quote === "\"" || quote === "'") && content.endsWith(quote)) {
|
|
1450
|
-
content = content.slice(1, -1);
|
|
1451
|
-
}
|
|
1452
|
-
return content.replace(/\\(["'\\])/g, "$1");
|
|
1453
|
-
}
|
|
1454
|
-
function splitCSSFunctionArgs(value) {
|
|
1455
|
-
const parts = [];
|
|
1456
|
-
let current = "";
|
|
1457
|
-
let depth = 0;
|
|
1458
|
-
let quote;
|
|
1459
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
1460
|
-
const char = value[index];
|
|
1461
|
-
const previous = value[index - 1];
|
|
1462
|
-
if (quote) {
|
|
1463
|
-
current += char;
|
|
1464
|
-
if (char === quote && previous !== "\\")
|
|
1465
|
-
quote = undefined;
|
|
1466
|
-
continue;
|
|
1467
|
-
}
|
|
1468
|
-
if (char === "\"" || char === "'") {
|
|
1469
|
-
quote = char;
|
|
1470
|
-
current += char;
|
|
1471
|
-
continue;
|
|
1472
|
-
}
|
|
1473
|
-
if (char === "(")
|
|
1474
|
-
depth += 1;
|
|
1475
|
-
if (char === ")")
|
|
1476
|
-
depth = Math.max(0, depth - 1);
|
|
1477
|
-
if (char === "," && depth === 0) {
|
|
1478
|
-
parts.push(current.trim());
|
|
1479
|
-
current = "";
|
|
1480
|
-
continue;
|
|
1481
|
-
}
|
|
1482
|
-
current += char;
|
|
1483
|
-
}
|
|
1484
|
-
if (current.trim())
|
|
1485
|
-
parts.push(current.trim());
|
|
1486
|
-
return parts;
|
|
1487
|
-
}
|
|
1488
|
-
function inferColorFormat(value) {
|
|
1489
|
-
const normalized = value.trim().toLowerCase();
|
|
1490
|
-
if (normalized.startsWith("hsl"))
|
|
1491
|
-
return "HSL";
|
|
1492
|
-
if (normalized.startsWith("rgba"))
|
|
1493
|
-
return "RGBA";
|
|
1494
|
-
if (normalized.startsWith("rgb"))
|
|
1495
|
-
return "RGB";
|
|
1496
|
-
return "Hex";
|
|
1497
|
-
}
|
|
1498
|
-
function formatColorValue(hex, alpha, format) {
|
|
1499
|
-
const normalizedHex = (normalizeHexColor(hex) ?? toHex(hex)).toUpperCase();
|
|
1500
|
-
const { r, g, b } = hexToRgb(normalizedHex);
|
|
1501
|
-
if (format === "RGB")
|
|
1502
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
1503
|
-
if (format === "RGBA")
|
|
1504
|
-
return colorWithAlpha(normalizedHex, alpha);
|
|
1505
|
-
if (format === "HSL") {
|
|
1506
|
-
const { h, s, l } = rgbToHsl({ r, g, b });
|
|
1507
|
-
return alpha < 1 ? `hsl(${h} ${s}% ${l}% / ${formatNumber(alpha)})` : `hsl(${h} ${s}% ${l}%)`;
|
|
1508
|
-
}
|
|
1509
|
-
return normalizedHex;
|
|
1510
|
-
}
|
|
1511
|
-
function getColorAlpha(value) {
|
|
1512
|
-
const rgba = computeCSSColor(value) ?? value;
|
|
1513
|
-
const match = rgba.match(/rgba?\([^,]+,\s*[^,]+,\s*[^,]+(?:,\s*([^)]+))?\)/i);
|
|
1514
|
-
if (!match?.[1])
|
|
1515
|
-
return 1;
|
|
1516
|
-
const alpha = Number.parseFloat(match[1]);
|
|
1517
|
-
return Number.isFinite(alpha) ? clamp(alpha, 0, 1) : 1;
|
|
1518
|
-
}
|
|
1519
|
-
function colorWithAlpha(hex, alpha) {
|
|
1520
|
-
const { r, g, b } = hexToRgb(hex);
|
|
1521
|
-
return `rgba(${r}, ${g}, ${b}, ${formatNumber(alpha)})`;
|
|
1522
|
-
}
|
|
1523
|
-
function getGradientValue(start, end) {
|
|
1524
|
-
return `linear-gradient(135deg, ${start}, ${end})`;
|
|
1525
|
-
}
|
|
1526
|
-
function getImageValue(url) {
|
|
1527
|
-
return `url("${url.trim().replace(/["\\]/g, "\\$&")}")`;
|
|
1528
|
-
}
|
|
1529
|
-
function isBackgroundImageValue(value) {
|
|
1530
|
-
return value.startsWith("linear-gradient(") || value.startsWith("url(");
|
|
1531
|
-
}
|
|
1532
|
-
function normalizeStyleInput(value, control, element, inferredUnit = control.unit) {
|
|
1533
|
-
const trimmed = value.trim();
|
|
1534
|
-
if (!trimmed)
|
|
1535
|
-
return undefined;
|
|
1536
|
-
const converted = convertUnitExpression(trimmed, element);
|
|
1537
|
-
const candidate = converted ?? inferUnitForBareNumber(trimmed, control, inferredUnit);
|
|
1538
|
-
if (isSupportedCSSValue(control.cssProperty, candidate))
|
|
1539
|
-
return candidate;
|
|
1540
|
-
return undefined;
|
|
1541
|
-
}
|
|
1542
|
-
function isSupportedCSSValue(property, value) {
|
|
1543
|
-
if (typeof CSS === "undefined" || typeof CSS.supports !== "function")
|
|
1544
|
-
return true;
|
|
1545
|
-
return CSS.supports(property, value);
|
|
1546
|
-
}
|
|
1547
|
-
function isCompleteUnitConversion(value) {
|
|
1548
|
-
return /^-?(?:\d+|\d*\.\d+)(px|rem|em)(px|rem|em)$/i.test(value.trim());
|
|
1549
|
-
}
|
|
1550
|
-
function getSupportedUnits(control) {
|
|
1551
|
-
const units = [];
|
|
1552
|
-
if (isSupportedCSSValue(control.cssProperty, "1"))
|
|
1553
|
-
units.push("");
|
|
1554
|
-
for (const unit of CSS_NUMERIC_UNITS) {
|
|
1555
|
-
if (isSupportedCSSValue(control.cssProperty, `1${unit}`))
|
|
1556
|
-
units.push(unit);
|
|
1557
|
-
}
|
|
1558
|
-
return units;
|
|
1559
|
-
}
|
|
1560
|
-
function convertStyleInputToUnit(value, targetUnit, control, element, inferredUnit) {
|
|
1561
|
-
const normalized = normalizeStyleInput(value, control, element, inferredUnit);
|
|
1562
|
-
if (!normalized)
|
|
1563
|
-
return undefined;
|
|
1564
|
-
const parsed = parseNumericCSSValue(normalized);
|
|
1565
|
-
if (!parsed)
|
|
1566
|
-
return undefined;
|
|
1567
|
-
if (parsed.unit === targetUnit)
|
|
1568
|
-
return normalized;
|
|
1569
|
-
const pxValue = numericValueToPx(parsed.value, parsed.unit, control, element);
|
|
1570
|
-
if (pxValue === undefined)
|
|
1571
|
-
return undefined;
|
|
1572
|
-
const nextAmount = pxToNumericValue(pxValue, targetUnit, control, element);
|
|
1573
|
-
if (nextAmount === undefined)
|
|
1574
|
-
return undefined;
|
|
1575
|
-
const candidate = targetUnit ? `${formatNumber(round(nextAmount))}${targetUnit}` : formatNumber(round(nextAmount));
|
|
1576
|
-
return isSupportedCSSValue(control.cssProperty, candidate) ? candidate : undefined;
|
|
1577
|
-
}
|
|
1578
|
-
function parseNumericCSSValue(value) {
|
|
1579
|
-
const match = value.trim().match(/^(-?(?:\d+|\d*\.\d+))([a-z%]*)$/i);
|
|
1580
|
-
if (!match)
|
|
1581
|
-
return undefined;
|
|
1582
|
-
const numericValue = Number(match[1]);
|
|
1583
|
-
if (!Number.isFinite(numericValue))
|
|
1584
|
-
return undefined;
|
|
1585
|
-
return { value: numericValue, unit: match[2].toLowerCase() };
|
|
1586
|
-
}
|
|
1587
|
-
function numericValueToPx(value, unit, control, element) {
|
|
1588
|
-
if (!unit) {
|
|
1589
|
-
if (control.cssProperty === "line-height")
|
|
1590
|
-
return value * getElementFontSize(element);
|
|
1591
|
-
if (control.cssProperty === "opacity")
|
|
1592
|
-
return value;
|
|
1593
|
-
return undefined;
|
|
1594
|
-
}
|
|
1595
|
-
const unitSize = getUnitSizeInPx(unit, element, control);
|
|
1596
|
-
return unitSize === undefined ? undefined : value * unitSize;
|
|
1597
|
-
}
|
|
1598
|
-
function pxToNumericValue(pxValue, unit, control, element) {
|
|
1599
|
-
if (!unit) {
|
|
1600
|
-
if (control.cssProperty === "line-height")
|
|
1601
|
-
return pxValue / getElementFontSize(element);
|
|
1602
|
-
if (control.cssProperty === "opacity")
|
|
1603
|
-
return pxValue;
|
|
1604
|
-
return undefined;
|
|
1605
|
-
}
|
|
1606
|
-
const unitSize = getUnitSizeInPx(unit, element, control);
|
|
1607
|
-
return unitSize === undefined || unitSize === 0 ? undefined : pxValue / unitSize;
|
|
1608
|
-
}
|
|
1609
|
-
function convertUnitExpression(value, element) {
|
|
1610
|
-
const match = value.match(/^(-?(?:\d+|\d*\.\d+))(px|rem|em)(px|rem|em)$/i);
|
|
1611
|
-
if (!match)
|
|
1612
|
-
return undefined;
|
|
1613
|
-
const amount = Number(match[1]);
|
|
1614
|
-
const fromUnit = match[2].toLowerCase();
|
|
1615
|
-
const toUnit = match[3].toLowerCase();
|
|
1616
|
-
if (!Number.isFinite(amount) || fromUnit === toUnit)
|
|
1617
|
-
return undefined;
|
|
1618
|
-
const fromSize = getUnitSizeInPx(fromUnit, element);
|
|
1619
|
-
const toSize = getUnitSizeInPx(toUnit, element);
|
|
1620
|
-
if (!fromSize || !toSize)
|
|
1621
|
-
return undefined;
|
|
1622
|
-
const pxValue = amount * fromSize;
|
|
1623
|
-
const converted = pxValue / toSize;
|
|
1624
|
-
return `${formatNumber(round(converted))}${toUnit}`;
|
|
1625
|
-
}
|
|
1626
|
-
function inferUnitForBareNumber(value, control, inferredUnit) {
|
|
1627
|
-
if (!isBareNumber(value) || !inferredUnit)
|
|
1628
|
-
return value;
|
|
1629
|
-
if (isSupportedCSSValue(control.cssProperty, value) && control.unit === "")
|
|
1630
|
-
return value;
|
|
1631
|
-
return `${value}${inferredUnit}`;
|
|
1632
|
-
}
|
|
1633
|
-
function isBareNumber(value) {
|
|
1634
|
-
return /^-?(?:\d+|\d*\.\d+)$/.test(value);
|
|
1635
|
-
}
|
|
1636
|
-
function getInferredUnit(value, control) {
|
|
1637
|
-
const match = value.trim().match(/(-?(?:\d+|\d*\.\d+))([a-z%]+)$/i);
|
|
1638
|
-
return match?.[2] ?? control.unit;
|
|
1639
|
-
}
|
|
1640
|
-
function isArrowStepKey(key) {
|
|
1641
|
-
return key === "ArrowUp" || key === "ArrowRight" || key === "ArrowDown" || key === "ArrowLeft";
|
|
1642
|
-
}
|
|
1643
|
-
function isIncrementKey(key) {
|
|
1644
|
-
return key === "ArrowUp" || key === "ArrowRight";
|
|
1645
|
-
}
|
|
1646
|
-
function stepStyleInput(value, control, element, inferredUnit, step, increment) {
|
|
1647
|
-
const match = value.trim().match(/^(-?(?:\d+|\d*\.\d+))([a-z%]*)$/i);
|
|
1648
|
-
if (!match)
|
|
1649
|
-
return undefined;
|
|
1650
|
-
const current = Number(match[1]);
|
|
1651
|
-
if (!Number.isFinite(current))
|
|
1652
|
-
return undefined;
|
|
1653
|
-
const unit = match[2] || inferredUnit;
|
|
1654
|
-
const next = round(current + (increment ? step : -step));
|
|
1655
|
-
const candidate = unit ? `${formatNumber(next)}${unit}` : formatNumber(next);
|
|
1656
|
-
return normalizeStyleInput(candidate, control, element, unit);
|
|
1657
|
-
}
|
|
1658
|
-
function getUnitSizeInPx(unit, element, control) {
|
|
1659
|
-
if (unit === "px")
|
|
1660
|
-
return 1;
|
|
1661
|
-
if (unit === "rem") {
|
|
1662
|
-
const rootSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
1663
|
-
return Number.isFinite(rootSize) && rootSize > 0 ? rootSize : 16;
|
|
1664
|
-
}
|
|
1665
|
-
if (unit === "em") {
|
|
1666
|
-
const base = control?.cssProperty === "font-size" ? element.parentElement ?? element : element;
|
|
1667
|
-
const emSize = parseFloat(getComputedStyle(base).fontSize);
|
|
1668
|
-
return Number.isFinite(emSize) && emSize > 0 ? emSize : getUnitSizeInPx("rem", element);
|
|
1669
|
-
}
|
|
1670
|
-
return undefined;
|
|
1671
|
-
}
|
|
1672
|
-
function getElementFontSize(element) {
|
|
1673
|
-
const fontSize = parseFloat(getComputedStyle(element).fontSize);
|
|
1674
|
-
return Number.isFinite(fontSize) && fontSize > 0 ? fontSize : 16;
|
|
1675
|
-
}
|
|
1676
|
-
function clamp(value, min, max) {
|
|
1677
|
-
return Math.min(max, Math.max(min, value));
|
|
1678
|
-
}
|
|
1679
|
-
function getSliderPercent(value, min, max) {
|
|
1680
|
-
if (max <= min)
|
|
1681
|
-
return 0;
|
|
1682
|
-
return clamp(((value - min) / (max - min)) * 100, 0, 100);
|
|
1683
|
-
}
|
|
1684
|
-
function getSliderValueFromPointer(clientX, rect, control) {
|
|
1685
|
-
const percent = rect.width > 0 ? clamp((clientX - rect.left) / rect.width, 0, 1) : 0;
|
|
1686
|
-
const raw = control.min + percent * (control.max - control.min);
|
|
1687
|
-
return roundToStep(raw, control.step, control.min);
|
|
1688
|
-
}
|
|
1689
|
-
function roundToStep(value, step, min) {
|
|
1690
|
-
if (step <= 0)
|
|
1691
|
-
return value;
|
|
1692
|
-
const stepped = Math.round((value - min) / step) * step + min;
|
|
1693
|
-
const decimals = String(step).includes(".") ? String(step).split(".")[1].length : 0;
|
|
1694
|
-
return Number(stepped.toFixed(decimals));
|
|
1695
|
-
}
|
|
1696
|
-
function round(value) {
|
|
1697
|
-
return Math.round(value * 100) / 100;
|
|
1698
|
-
}
|
|
1699
|
-
function formatNumber(value) {
|
|
1700
|
-
return Number.isInteger(value) ? String(value) : value.toFixed(2);
|
|
1701
|
-
}
|
|
162
|
+
@media (forced-colors: active) {
|
|
163
|
+
.chisel-panel-inner, .chisel-preset-dropdown, .chisel-color-popover { forced-color-adjust: auto; border: 1px solid CanvasText; background: Canvas; }
|
|
164
|
+
.chisel-box { border-color: Highlight; }
|
|
165
|
+
}
|
|
166
|
+
`})}function Wt(e,a){if(a.has(e))return;let t=getComputedStyle(e),o={};for(let r of Sa)o[r]=t[r];a.set(e,{text:e.textContent??"",styles:o})}function pa(e){return{id:`version-${e}`,name:`Version ${e}`,elements:{}}}function Xt(e){return Object.fromEntries(Object.entries(e).map(([a,t])=>[a,{...t,styles:{...t.styles}}]))}function Kt(){return{pathname:window.location.pathname,search:window.location.search}}function $t(e){Zt(),ea+=1;let a=()=>{st(),e()};return window.addEventListener(La,a),window.addEventListener("popstate",a),()=>{window.removeEventListener(La,a),window.removeEventListener("popstate",a),ea-=1,ea<=0&&(ea=0,la?.(),la=void 0)}}function Zt(){if(la)return;let e=window.history.pushState,a=window.history.replaceState,t=()=>{st(),window.setTimeout(()=>window.dispatchEvent(new Event(La)),0)},o=function(...i){let c=e.apply(this,i);return t(),c},r=function(...i){let c=a.apply(this,i);return t(),c};window.history.pushState=o,window.history.replaceState=r,la=()=>{window.history.pushState===o&&(window.history.pushState=e),window.history.replaceState===r&&(window.history.replaceState=a)}}function st(){let e=++$a;Ke=!0,window.setTimeout(()=>{$a===e&&(Ke=!1)},0)}function jt(e=ut(window.location.pathname,window.location.search)){return`vse:versions:${e}`}function Jt(e,a){return`vse:versions:${e}${a}`}function ut(e,a){let t=new URLSearchParams(a);t.delete("editor");let o=Array.from(t.entries()).sort(([n,i],[c,f])=>n===c?i.localeCompare(f):n.localeCompare(c)),r=new URLSearchParams(o).toString();return r?`${e}?${r}`:e}function Qt(e,a=e){try{let t=window.localStorage.getItem(e),o=t??(a===e?null:window.localStorage.getItem(a)),r=Xa(o);return r.envelope&&xa.set(e,r.envelope),t===null&&o!==null?{...r,migrated:!r.warning}:r}catch{return{envelope:xa.get(e),migrated:!1,warning:"Browser storage is unavailable. Edits will be kept for this session."}}}function Ja(e,a,t){let o=ca(a,t);xa.set(e,o);try{window.localStorage.setItem(e,JSON.stringify(o));return}catch{return"Browser storage is unavailable or full. Edits will be kept for this session."}}function de(e){return De(e)??$e(e)}function ke(e,a,t){let o=t.get(a);if(o?.element===e||o?.element.isConnected)return;let r={};for(let n of Sa)r[n]=e.style[n]??"";t.set(a,{element:e,selector:$e(e),sourceHint:De(e),text:e.textContent??"",styles:r})}function ce(e){let a=(Xe.get(e)??0)+1;Xe.set(e,a),window.setTimeout(()=>{Xe.get(e)===a&&Xe.delete(e)},0)}function aa(e,a,t,o,r=!0){if(r)for(let[n,i]of t){let c=i.element.isConnected?i.element:null;if(!c)continue;let f=a.map(S=>S.elements[n]).filter(Boolean);if(!f.length)continue;ce(c),f.some(S=>typeof S.text=="string")&&c.textContent!==i.text&&(c.textContent=i.text);let g=new Set(f.flatMap(S=>Object.keys(S.styles)));f.some(S=>S.asset)&&g.add("backgroundImage");for(let S of g){let A=i.styles[S]??"";c.style[S]!==A&&(c.style[S]=A)}}for(let[n,i]of Object.entries(e.elements)){let c=dt(i);if(c){ke(c,n,t),ce(c),typeof i.text=="string"&&c.textContent!==i.text&&(c.textContent=i.text);for(let[f,g]of Object.entries(i.styles))c.style[f]!==g&&(c.style[f]=g);if(i.asset){let f=o.get(be(e.id,n)),g=f?Re(f):"";c.style.backgroundImage!==g&&(c.style.backgroundImage=g)}}}}function _t(e,a,t){let o=e.get(a);e.set(a,t),o&&o!==t&&!Array.from(e.values()).includes(o)&&URL.revokeObjectURL(o)}function ma(e,a){let t=e.get(a);e.delete(a),t&&!Array.from(e.values()).includes(t)&&URL.revokeObjectURL(t)}function ha(e){for(let a of new Set(e.values()))URL.revokeObjectURL(a);e.clear()}function be(e,a){return`${e}:${a}`}function Qa(e,a,t){for(let[o,r]of Object.entries(e.elements)){let n=a.get(o);if(!n)continue;let i=n.element.isConnected?n.element:null;if(i){ce(i),typeof r.text=="string"&&i.textContent===r.text&&(i.textContent=n.text);for(let[c,f]of Object.entries(r.styles)){if(c==="backgroundImage"&&r.asset)continue;let g=n.styles[c]??"";Yt(c,i.style[c],f)&&(i.style[c]=g)}if(r.asset){let c=t.get(be(e.id,o));c&&i.style.backgroundImage===Re(c)&&(i.style.backgroundImage=n.styles.backgroundImage??"")}}}}function Yt(e,a,t){if(a===t)return!0;let o=document.createElement("div").style;return o[e]=t,o[e]===a}function dt(e){let a=e.sourceHint?wa(e.sourceHint):void 0;return _a(a)??_a(e.selector)}function _a(e){if(e)try{let a=document.querySelector(e);return a instanceof HTMLElement?a:void 0}catch{return}}function Ya(e,a){return e.includes(a)?e.filter(t=>t!==a):[...e,a]}function eo(e,a){let t=getComputedStyle(e),o=[],r=e.textContent??"";r!==a.text&&o.push({property:"textContent",before:a.text,after:r});for(let n of Sa){let i=a.styles[n],f=(e.style[n]??"")||t[n];sa(i)!==sa(f)&&o.push({property:n,before:i,after:f})}return o}function ao(e){if(!e)return[];let a=[];e.text!==void 0&&a.push({property:"textContent",before:null,after:e.text});for(let[t,o]of Object.entries(e.styles))a.push({property:t,before:null,after:o??""});return e.asset&&a.push({property:"localAsset",before:null,after:e.asset.fileName}),a}function to({projectName:e,element:a,snapshot:t,rect:o,selector:r,sourceHint:n,changes:i}){let c={route:window.location.href,viewport:{width:window.innerWidth,height:window.innerHeight},element:{tagName:a.tagName.toLowerCase(),selector:r,ancestry:it(a),boundingRect:o,textBefore:t.text,textAfter:a.textContent??"",sourceHint:n},changes:i},f=!n&&!r.includes("[data-chisel-id")&&!r.includes("#");return[`You are editing ${e}. Update the source files for this Next.js app to match the visual edit intent below.`,"","Do not ship a broad global CSS override. Find the component, JSX, CSS module, Tailwind classes, or style object that owns the selected element and make the smallest source-level change.",f?"Selector confidence is low. Use the route, visible text, DOM ancestry, and nearby structure to find the matching source component before editing.":"A source hint is available. Prefer it when locating the component.","","Edit intent:","```json",JSON.stringify(c,null,2),"```","","Acceptance criteria:","- The selected element visually matches the requested text/style changes on the same route.","- Existing responsive behavior is preserved.","- No editor-only attributes or temporary inline preview styles are added unless they already belong to the app source."].join(`
|
|
167
|
+
`)}function oo({projectName:e,version:a,baselines:t}){let o=Object.entries(a.elements).sort(([r],[n])=>r.localeCompare(n)).map(([r,n])=>{let i=t.get(r),c=dt(n);return{selector:n.selector,sourceHint:n.sourceHint,tagName:c?.tagName.toLowerCase(),ancestry:c?it(c):void 0,textBefore:i?.text,textAfter:n.text,asset:n.asset,styleChanges:Object.fromEntries(Object.entries(n.styles).map(([f,g])=>[f,{before:i?.styles[f]??null,after:g}]))}});return[`You are editing ${e}. Update the source files for this Next.js app to match all page-level visual edit intents below.`,"","Do not ship broad global CSS overrides. Find the owning components, JSX, CSS modules, Tailwind classes, or style objects and make the smallest source-level changes.","","Edit intent:","```json",JSON.stringify({route:window.location.href,viewport:{width:window.innerWidth,height:window.innerHeight},elements:o},null,2),"```","","Acceptance criteria:","- All changed elements visually match the requested page edits on the same route.","- Existing responsive behavior is preserved.","- No editor-only attributes or temporary inline preview styles are added unless they already belong to the app source."].join(`
|
|
168
|
+
`)}function De(e){let a=ft(e);if(a)return et(a)?a:void 0;let t=ro(e);if(t)return et(t)?t:void 0}function ro(e){let a=e.parentElement?.closest("[data-chisel-id], [data-ai-edit], [data-component]");if(!(!(a instanceof HTMLElement)||a===e))return ft(a)}function ft(e){return e.dataset.chiselId??e.dataset.aiEdit??e.dataset.component}function et(e){return document.querySelectorAll(wa(e)).length===1}function wa(e){let a=Ia(e);return`[data-chisel-id="${a}"], [data-ai-edit="${a}"], [data-component="${a}"]`}function $e(e){let a=De(e);if(a)return wa(a);if(e.id)return`#${Ia(e.id)}`;let t=[],o=e;for(;o&&o!==document.body&&t.length<5;){let r=o.tagName.toLowerCase(),n=Array.from(o.classList).filter(Boolean).slice(0,2);n.length&&(r+=n.map(c=>`.${Ia(c)}`).join(""));let i=o.parentElement;if(i){let c=o.tagName,f=Array.from(i.children).filter(g=>g.tagName===c);f.length>1&&(r+=`:nth-of-type(${f.indexOf(o)+1})`)}t.unshift(r),o=i}return t.join(" > ")}function it(e){let a=[],t=e;for(;t&&t!==document.body&&a.length<6;){let o=(t.textContent??"").trim().replace(/\s+/g," ").slice(0,80);a.push(`${t.tagName.toLowerCase()}${t.id?`#${t.id}`:""}${o?` "${o}"`:""}`),t=t.parentElement}return a}function ie(e){return{x:J(e.x),y:J(e.y),width:J(e.width),height:J(e.height),top:J(e.top),right:J(e.right),bottom:J(e.bottom),left:J(e.left)}}function Be(e){return!!e.closest("[data-chisel-root='true']")}function lo(e){let a=e.closest("[data-chisel-id], [data-ai-edit], [data-component]");return a instanceof HTMLElement?a:e}function so(){return Array.from(document.body.querySelectorAll("*")).filter(e=>{if(Be(e)||e.closest("nextjs-portal")||["script","style","link","meta","noscript"].includes(e.tagName.toLowerCase()))return!1;let a=e.getBoundingClientRect(),t=getComputedStyle(e);return a.width>0&&a.height>0&&t.display!=="none"&&t.visibility!=="hidden"})}function at(e){let a=De(e),t=a?`source hint ${a}`:`selector confidence ${e.id?"high":"low"}`,o=(e.textContent??"").trim().replace(/\s+/g," ").slice(0,60);return`${e.tagName.toLowerCase()}, ${t}${o?`, ${o}`:""}`}function ka(e){let a=Array.from(e.currentTarget.querySelectorAll('[role="option"]')).filter(r=>r.getAttribute("aria-disabled")!=="true");if(!a.length)return;let t=Math.max(0,a.indexOf(document.activeElement)),o;if(e.key==="ArrowDown"||e.key==="ArrowRight")o=(t+1)%a.length;else if(e.key==="ArrowUp"||e.key==="ArrowLeft")o=(t-1+a.length)%a.length;else if(e.key==="Home")o=0;else if(e.key==="End")o=a.length-1;else if(e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey){let r=a.find(n=>(n.textContent??"").trim().toLowerCase().startsWith(e.key.toLowerCase()));r&&(o=a.indexOf(r))}o!==void 0&&(a[o]?.focus(),e.preventDefault())}function tt(e){return!(e.children.length>0||Nt.has(e.tagName.toLowerCase()))}function Ia(e){return typeof CSS<"u"&&CSS.escape?CSS.escape(e):e.replace(/["\\#.:,[\]>~+*^$|= ]/g,"\\$&")}function Me(e){let a=Te(e);if(a)return a;let t=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);if(t)return`#${[t[1],t[2],t[3]].map(n=>Number(n).toString(16).padStart(2,"0")).join("")}`;let o=nt(e);if(!o||o===e)return"#ffffff";let r=o.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);return r?`#${[r[1],r[2],r[3]].map(n=>Number(n).toString(16).padStart(2,"0")).join("")}`:"#ffffff"}function nt(e){if(typeof document>"u")return;let a=document.createElement("span");if(a.style.color=e,!a.style.color)return;a.style.position="absolute",a.style.visibility="hidden",document.body.appendChild(a);let t=getComputedStyle(a).color;return a.remove(),t}function Te(e){let a=e.trim(),t=a.match(/^#([0-9a-f]{3})$/i);if(t)return`#${t[1].split("").map(o=>`${o}${o}`).join("")}`.toUpperCase();if(/^#[0-9a-f]{6}$/i.test(a))return a.toUpperCase()}function ba(e){let t=(Te(e)??"#FFFFFF").slice(1);return{r:Number.parseInt(t.slice(0,2),16),g:Number.parseInt(t.slice(2,4),16),b:Number.parseInt(t.slice(4,6),16)}}function uo({r:e,g:a,b:t}){let o=e/255,r=a/255,n=t/255,i=Math.max(o,r,n),c=Math.min(o,r,n),f=i-c,g=0;return f!==0&&(i===o?g=(r-n)/f%6:i===r?g=(n-o)/f+2:g=(o-r)/f+4),g=Math.round(g*60),g<0&&(g+=360),{h:g,s:i===0?0:J(f/i*100),v:J(i*100)}}function fo({r:e,g:a,b:t}){let o=e/255,r=a/255,n=t/255,i=Math.max(o,r,n),c=Math.min(o,r,n),f=(i+c)/2,g=i-c;if(g===0)return{h:0,s:0,l:Math.round(f*100)};let S=g/(1-Math.abs(2*f-1)),A=0;return i===o?A=(r-n)/g%6:i===r?A=(n-o)/g+2:A=(o-r)/g+4,A=Math.round(A*60),A<0&&(A+=360),{h:A,s:Math.round(S*100),l:Math.round(f*100)}}function ta(e,a,t){let o=t/100*(a/100),r=o*(1-Math.abs(e/60%2-1)),n=t/100-o,i=Math.floor(e/60)%6;return`#${([[o,r,0],[r,o,0],[0,o,r],[0,r,o],[r,0,o],[o,0,r]][i]??[o,0,r]).map(f=>Math.round((f+n)*255).toString(16).padStart(2,"0")).join("")}`.toUpperCase()}function sa(e){return(e??"").replace(/\s+/g," ").trim()}function Ze(e){return e.split(",")[0]?.replace(/^["']|["']$/g,"").trim()}function io(e){let a=[],t=new Set,o=r=>{let n=Ze(r.value)?.toLowerCase()??r.label.toLowerCase();t.has(n)||(t.add(n),a.push(r))};for(let r of Ut)o(r);if(e&&!a.some(r=>ua(e,r.value))){let r=Ze(e);r&&a.unshift({label:r,value:e})}return a}function no(e,a){return a.find(t=>ua(e,t.value))}function ua(e,a){let t=Ze(e)?.toLowerCase(),o=Ze(a)?.toLowerCase();return t&&o&&t===o?!0:sa(e)===sa(a)}function ot(e){let a=e.trim();if(a&&qe("color",a))return a}function rt(e){return Te(e)??e}function lt(e){let a=e.trim();if(!a.toLowerCase().startsWith("linear-gradient(")||!a.endsWith(")"))return;let t=a.slice(a.indexOf("(")+1,-1),o=co(t);if(!(o.length<3))return{start:o[1].trim(),end:o.slice(2).join(", ").trim()}}function ga(e){let a=e.trim();if(!a.toLowerCase().startsWith("url(")||!a.endsWith(")"))return;let t=a.slice(a.indexOf("(")+1,-1).trim(),o=t[0];return(o==='"'||o==="'")&&t.endsWith(o)&&(t=t.slice(1,-1)),t.replace(/\\(["'\\])/g,"$1")}function co(e){let a=[],t="",o=0,r;for(let n=0;n<e.length;n+=1){let i=e[n],c=e[n-1];if(r){t+=i,i===r&&c!=="\\"&&(r=void 0);continue}if(i==='"'||i==="'"){r=i,t+=i;continue}if(i==="("&&(o+=1),i===")"&&(o=Math.max(0,o-1)),i===","&&o===0){a.push(t.trim()),t="";continue}t+=i}return t.trim()&&a.push(t.trim()),a}function Fe(e){let a=e.trim().toLowerCase();return a.startsWith("hsl")?"HSL":a.startsWith("rgba")?"RGBA":a.startsWith("rgb")?"RGB":"Hex"}function po(e,a,t){let o=(Te(e)??Me(e)).toUpperCase(),{r,g:n,b:i}=ba(o);if(t==="RGB")return`rgb(${r}, ${n}, ${i})`;if(t==="RGBA")return ct(o,a);if(t==="HSL"){let{h:c,s:f,l:g}=fo({r,g:n,b:i});return a<1?`hsl(${c} ${f}% ${g}% / ${pe(a)})`:`hsl(${c} ${f}% ${g}%)`}return o}function mo(e){let t=(nt(e)??e).match(/rgba?\([^,]+,\s*[^,]+,\s*[^,]+(?:,\s*([^)]+))?\)/i);if(!t?.[1])return 1;let o=Number.parseFloat(t[1]);return Number.isFinite(o)?Y(o,0,1):1}function ct(e,a){let{r:t,g:o,b:r}=ba(e);return`rgba(${t}, ${o}, ${r}, ${pe(a)})`}function oa(e,a){return`linear-gradient(135deg, ${e}, ${a})`}function Re(e){return`url("${e.trim().replace(/["\\]/g,"\\$&")}")`}function ho(e){return e.startsWith("linear-gradient(")||e.startsWith("url(")}function da(e,a,t,o=a.unit){let r=e.trim();if(!r)return;let i=wo(r,t)??ko(r,a,o);if(qe(a.cssProperty,i))return i}function qe(e,a){return typeof CSS>"u"||typeof CSS.supports!="function"?!0:CSS.supports(e,a)}function Lo(e){return/^-?(?:\d+|\d*\.\d+)(px|rem|em)(px|rem|em)$/i.test(e.trim())}function xo(e){let a=[];qe(e.cssProperty,"1")&&a.push("");for(let t of qt)qe(e.cssProperty,`1${t}`)&&a.push(t);return a}function Io(e,a,t,o,r){let n=da(e,t,o,r);if(!n)return;let i=go(n);if(!i)return;if(i.unit===a)return n;let c=Co(i.value,i.unit,t,o);if(c===void 0)return;let f=So(c,a,t,o);if(f===void 0)return;let g=a?`${pe(J(f))}${a}`:pe(J(f));return qe(t.cssProperty,g)?g:void 0}function go(e){let a=e.trim().match(/^(-?(?:\d+|\d*\.\d+))([a-z%]*)$/i);if(!a)return;let t=Number(a[1]);if(Number.isFinite(t))return{value:t,unit:a[2].toLowerCase()}}function Co(e,a,t,o){if(!a)return t.cssProperty==="line-height"?e*pt(o):t.cssProperty==="opacity"?e:void 0;let r=je(a,o,t);return r===void 0?void 0:e*r}function So(e,a,t,o){if(!a)return t.cssProperty==="line-height"?e/pt(o):t.cssProperty==="opacity"?e:void 0;let r=je(a,o,t);return r===void 0||r===0?void 0:e/r}function wo(e,a){let t=e.match(/^(-?(?:\d+|\d*\.\d+))(px|rem|em)(px|rem|em)$/i);if(!t)return;let o=Number(t[1]),r=t[2].toLowerCase(),n=t[3].toLowerCase();if(!Number.isFinite(o)||r===n)return;let i=je(r,a),c=je(n,a);if(!i||!c)return;let g=o*i/c;return`${pe(J(g))}${n}`}function ko(e,a,t){return!bo(e)||!t||qe(a.cssProperty,e)&&a.unit===""?e:`${e}${t}`}function bo(e){return/^-?(?:\d+|\d*\.\d+)$/.test(e)}function yo(e,a){return e.trim().match(/(-?(?:\d+|\d*\.\d+))([a-z%]+)$/i)?.[2]??a.unit}function ra(e){return e==="ArrowUp"||e==="ArrowRight"||e==="ArrowDown"||e==="ArrowLeft"}function Ca(e){return e==="ArrowUp"||e==="ArrowRight"}function Po(e,a,t,o,r,n){let i=e.trim().match(/^(-?(?:\d+|\d*\.\d+))([a-z%]*)$/i);if(!i)return;let c=Number(i[1]);if(!Number.isFinite(c))return;let f=i[2]||o,g=J(c+(n?r:-r)),S=f?`${pe(g)}${f}`:pe(g);return da(S,a,t,f)}function je(e,a,t){if(e==="px")return 1;if(e==="rem"){let o=parseFloat(getComputedStyle(document.documentElement).fontSize);return Number.isFinite(o)&&o>0?o:16}if(e==="em"){let o=t?.cssProperty==="font-size"?a.parentElement??a:a,r=parseFloat(getComputedStyle(o).fontSize);return Number.isFinite(r)&&r>0?r:je("rem",a)}}function pt(e){let a=parseFloat(getComputedStyle(e).fontSize);return Number.isFinite(a)&&a>0?a:16}function Y(e,a,t){return Math.min(t,Math.max(a,e))}function Ao(e,a,t){return t<=a?0:Y((e-a)/(t-a)*100,0,100)}function vo(e,a,t){let o=a.width>0?Y((e-a.left)/a.width,0,1):0,r=t.min+o*(t.max-t.min);return Fo(r,t.step,t.min)}function Fo(e,a,t){if(a<=0)return e;let o=Math.round((e-t)/a)*a+t,r=String(a).includes(".")?String(a).split(".")[1].length:0;return Number(o.toFixed(r))}function J(e){return Math.round(e*100)/100}function pe(e){return Number.isInteger(e)?String(e):e.toFixed(2)}export{wr as Chisel,Sr as EditableRegion};
|
|
169
|
+
/*! Bundled license information:
|
|
170
|
+
|
|
171
|
+
lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs:
|
|
172
|
+
lucide-react/dist/esm/shared/src/utils/toLucideIconData.mjs:
|
|
173
|
+
lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs:
|
|
174
|
+
lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs:
|
|
175
|
+
lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs:
|
|
176
|
+
lucide-react/dist/esm/shared/src/build/defaultAttributes.mjs:
|
|
177
|
+
lucide-react/dist/esm/shared/src/build/buildLucideIconNode.mjs:
|
|
178
|
+
lucide-react/dist/esm/shared/src/build/buildLucideIconForReact.mjs:
|
|
179
|
+
lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs:
|
|
180
|
+
lucide-react/dist/esm/context.mjs:
|
|
181
|
+
lucide-react/dist/esm/Icon.mjs:
|
|
182
|
+
lucide-react/dist/esm/createLucideIcon.mjs:
|
|
183
|
+
lucide-react/dist/esm/icons/chevron-down.mjs:
|
|
184
|
+
lucide-react/dist/esm/icons/plus.mjs:
|
|
185
|
+
lucide-react/dist/esm/icons/x.mjs:
|
|
186
|
+
lucide-react/dist/esm/lucide-react.mjs:
|
|
187
|
+
(**
|
|
188
|
+
* @license lucide-react v1.61.0 - ISC
|
|
189
|
+
*
|
|
190
|
+
* This source code is licensed under the ISC license.
|
|
191
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
192
|
+
*)
|
|
193
|
+
*/
|