@agent-native/toolkit 0.11.2 → 0.12.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.
Files changed (75) hide show
  1. package/README.md +19 -0
  2. package/agent-native.eject.json +38 -0
  3. package/dist/canvas-annotations/CanvasCommentPins.d.ts +68 -0
  4. package/dist/canvas-annotations/CanvasCommentPins.d.ts.map +1 -0
  5. package/dist/canvas-annotations/CanvasCommentPins.js +513 -0
  6. package/dist/canvas-annotations/CanvasCommentPins.js.map +1 -0
  7. package/dist/canvas-annotations/DrawOverlay.d.ts +108 -0
  8. package/dist/canvas-annotations/DrawOverlay.d.ts.map +1 -0
  9. package/dist/canvas-annotations/DrawOverlay.js +746 -0
  10. package/dist/canvas-annotations/DrawOverlay.js.map +1 -0
  11. package/dist/canvas-annotations/DrawOverlay.spec.d.ts +2 -0
  12. package/dist/canvas-annotations/DrawOverlay.spec.d.ts.map +1 -0
  13. package/dist/canvas-annotations/DrawOverlay.spec.js +111 -0
  14. package/dist/canvas-annotations/DrawOverlay.spec.js.map +1 -0
  15. package/dist/canvas-annotations/index.d.ts +4 -0
  16. package/dist/canvas-annotations/index.d.ts.map +1 -0
  17. package/dist/canvas-annotations/index.js +3 -0
  18. package/dist/canvas-annotations/index.js.map +1 -0
  19. package/dist/canvas-annotations/types.d.ts +8 -0
  20. package/dist/canvas-annotations/types.d.ts.map +1 -0
  21. package/dist/canvas-annotations/types.js +2 -0
  22. package/dist/canvas-annotations/types.js.map +1 -0
  23. package/dist/canvas-interactions/canvas-interactions.d.ts +334 -0
  24. package/dist/canvas-interactions/canvas-interactions.d.ts.map +1 -0
  25. package/dist/canvas-interactions/canvas-interactions.js +451 -0
  26. package/dist/canvas-interactions/canvas-interactions.js.map +1 -0
  27. package/dist/canvas-interactions/canvas-interactions.spec.d.ts +2 -0
  28. package/dist/canvas-interactions/canvas-interactions.spec.d.ts.map +1 -0
  29. package/dist/canvas-interactions/canvas-interactions.spec.js +538 -0
  30. package/dist/canvas-interactions/canvas-interactions.spec.js.map +1 -0
  31. package/dist/canvas-interactions/index.d.ts +2 -0
  32. package/dist/canvas-interactions/index.d.ts.map +1 -0
  33. package/dist/canvas-interactions/index.js +2 -0
  34. package/dist/canvas-interactions/index.js.map +1 -0
  35. package/dist/composer/runtime-adapters.d.ts.map +1 -1
  36. package/dist/composer/runtime-adapters.js +13 -10
  37. package/dist/composer/runtime-adapters.js.map +1 -1
  38. package/dist/composer/runtime-adapters.spec.d.ts +2 -0
  39. package/dist/composer/runtime-adapters.spec.d.ts.map +1 -0
  40. package/dist/composer/runtime-adapters.spec.js +54 -0
  41. package/dist/composer/runtime-adapters.spec.js.map +1 -0
  42. package/dist/design-tweaks/scrub-input-utils.d.ts +61 -0
  43. package/dist/design-tweaks/scrub-input-utils.d.ts.map +1 -0
  44. package/dist/design-tweaks/scrub-input-utils.js +235 -0
  45. package/dist/design-tweaks/scrub-input-utils.js.map +1 -0
  46. package/dist/design-tweaks/scrub-input.d.ts +66 -0
  47. package/dist/design-tweaks/scrub-input.d.ts.map +1 -0
  48. package/dist/design-tweaks/scrub-input.js +313 -0
  49. package/dist/design-tweaks/scrub-input.js.map +1 -0
  50. package/dist/design-tweaks/visual-style-controls.d.ts +2 -12
  51. package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -1
  52. package/dist/design-tweaks/visual-style-controls.js +3 -107
  53. package/dist/design-tweaks/visual-style-controls.js.map +1 -1
  54. package/dist/design-tweaks/visual-style-controls.spec.js +26 -0
  55. package/dist/design-tweaks/visual-style-controls.spec.js.map +1 -1
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +1 -0
  59. package/dist/index.js.map +1 -1
  60. package/package.json +29 -1
  61. package/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
  62. package/src/canvas-annotations/DrawOverlay.spec.tsx +145 -0
  63. package/src/canvas-annotations/DrawOverlay.tsx +1233 -0
  64. package/src/canvas-annotations/index.ts +15 -0
  65. package/src/canvas-annotations/types.ts +14 -0
  66. package/src/canvas-interactions/canvas-interactions.spec.ts +688 -0
  67. package/src/canvas-interactions/canvas-interactions.ts +933 -0
  68. package/src/canvas-interactions/index.ts +67 -0
  69. package/src/composer/runtime-adapters.spec.tsx +83 -0
  70. package/src/composer/runtime-adapters.tsx +16 -11
  71. package/src/design-tweaks/scrub-input-utils.ts +311 -0
  72. package/src/design-tweaks/scrub-input.tsx +491 -0
  73. package/src/design-tweaks/visual-style-controls.spec.tsx +60 -0
  74. package/src/design-tweaks/visual-style-controls.tsx +23 -168
  75. package/src/index.ts +1 -0
@@ -0,0 +1,313 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconArrowsHorizontal } from "@tabler/icons-react";
3
+ import { useEffect, useId, useRef, useState, } from "react";
4
+ import { Input } from "../ui/input.js";
5
+ import { Label } from "../ui/label.js";
6
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../ui/tooltip.js";
7
+ import { cn } from "../utils.js";
8
+ import { formatScrubValue, getScrubStepFromEvent, normalizeScrubNumber, parseScrubExpression, roundScrubDragValue, startScrubDrag, updateScrubDrag, } from "./scrub-input-utils.js";
9
+ export function resolvePendingScrubCommit(pending, incomingValue, options) {
10
+ if (pending === null)
11
+ return "none";
12
+ const incoming = normalizeScrubNumber(incomingValue, options);
13
+ if (incoming === pending.value)
14
+ return "confirmed";
15
+ return incoming === pending.baseline ? "hold" : "superseded";
16
+ }
17
+ export function VisualScrubInput({ label, value, onChange, id, step = 1, unit, min, max, precision, icon: Icon = IconArrowsHorizontal, prefix = "label", disabled = false, placeholder, mixed = false, mixedLabel, className, inputClassName, labelClassName, ariaLabel, tooltipLabel, }) {
18
+ const resolvedMixedLabel = mixedLabel ?? "Mixed";
19
+ const generatedId = useId();
20
+ const inputId = id ?? generatedId;
21
+ const [draft, setDraft] = useState(() => mixed ? resolvedMixedLabel : formatScrubValue(value, { unit, precision }));
22
+ // Track the latest draft in a ref so commitDraft always reads the most
23
+ // up-to-date value even if the blur event fires before the React state
24
+ // update has been committed to the render tree (concurrent mode / batching).
25
+ const draftRef = useRef(draft);
26
+ const [focused, setFocused] = useState(false);
27
+ const [dragging, setDragging] = useState(false);
28
+ const inputRef = useRef(null);
29
+ const skipNextBlurCommitRef = useRef(false);
30
+ const dragRef = useRef({
31
+ pointerId: -1,
32
+ drag: startScrubDrag(0),
33
+ });
34
+ // The last normalized value emitted as a "preview" scrub tick, so endDrag
35
+ // can re-emit it once as the gesture's authoritative "commit" — without
36
+ // recomputing from stale pointer deltas after pointer capture is released.
37
+ const lastScrubValueRef = useRef(value);
38
+ // The most recent value THIS input committed (typed Enter/blur, keyboard
39
+ // nudge, or scrub release) that the host hasn't echoed back yet. While this
40
+ // is set, the resync effect below must hold the optimistic committed
41
+ // display instead of snapping back to the still-stale incoming `value`
42
+ // prop — otherwise a round-trip slower than one React render (host commit
43
+ // -> computedStyles update -> fresh `value` prop) clobbers the just-typed
44
+ // value back to the old one the instant focus leaves the input, which
45
+ // reads as "Enter resets to the old value". Cleared as soon as a fresh
46
+ // `value` prop confirms (or supersedes) the pending commit.
47
+ const pendingCommitRef = useRef(null);
48
+ const options = { unit, min, max, precision };
49
+ useEffect(() => {
50
+ if (mixed)
51
+ pendingCommitRef.current = null;
52
+ const resolution = resolvePendingScrubCommit(pendingCommitRef.current, value, options);
53
+ if (resolution !== "none") {
54
+ if (resolution === "confirmed" || resolution === "superseded") {
55
+ // The host either echoed exactly what we committed or returned a new,
56
+ // authoritative normalized/rejected value. In both cases resume prop
57
+ // synchronization. The old equality-only logic held forever on the
58
+ // second path, leaving the field permanently stuck on a value the
59
+ // canvas never accepted.
60
+ pendingCommitRef.current = null;
61
+ }
62
+ else {
63
+ // Still seeing the exact pre-commit prop — don't stomp the optimistic
64
+ // draft while the source-write round trip is pending.
65
+ return;
66
+ }
67
+ }
68
+ if (!focused) {
69
+ const formatted = mixed
70
+ ? resolvedMixedLabel
71
+ : formatScrubValue(value, { unit, precision });
72
+ draftRef.current = formatted;
73
+ setDraft(formatted);
74
+ }
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- `options` is a fresh object every render; the individual fields it's built from (unit/min/max/precision) are already listed below.
76
+ }, [focused, max, min, mixed, precision, resolvedMixedLabel, unit, value]);
77
+ const resolvedTooltipLabel = tooltipLabel ?? ariaLabel ?? label;
78
+ const setNextValue = (nextValue, meta) => {
79
+ const normalized = normalizeScrubNumber(nextValue, options);
80
+ // Mark commit-phase writes as pending confirmation so the resync effect
81
+ // holds this optimistic display instead of reverting to a stale `value`
82
+ // prop before the host's round-trip lands (see pendingCommitRef above).
83
+ // Preview ticks don't need this: they're expected to be superseded by
84
+ // the next tick or the gesture's own final commit almost immediately.
85
+ if (meta.phase === "commit") {
86
+ pendingCommitRef.current = {
87
+ value: normalized,
88
+ baseline: normalizeScrubNumber(value, options),
89
+ };
90
+ }
91
+ onChange(normalized, meta);
92
+ const formatted = formatScrubValue(normalized, options);
93
+ draftRef.current = formatted;
94
+ setDraft(formatted);
95
+ return normalized;
96
+ };
97
+ const commitDraft = () => {
98
+ // Always read from the ref so we use the latest typed value even if the
99
+ // React render with the updated draft state hasn't committed yet (e.g.
100
+ // when blur fires in the same synchronous batch as the last onChange).
101
+ const currentDraft = draftRef.current;
102
+ if (mixed && currentDraft === resolvedMixedLabel)
103
+ return;
104
+ const parsed = parseScrubExpression(currentDraft, value, options);
105
+ if (!parsed) {
106
+ const reverted = mixed
107
+ ? resolvedMixedLabel
108
+ : formatScrubValue(value, options);
109
+ draftRef.current = reverted;
110
+ setDraft(reverted);
111
+ return;
112
+ }
113
+ draftRef.current = parsed.normalized;
114
+ setDraft(parsed.normalized);
115
+ // From a mixed selection every explicitly typed value must commit, even
116
+ // when it equals the placeholder `value` prop (e.g. typing "0"): the
117
+ // selected objects hold differing values, so "no change" is meaningless.
118
+ if (parsed.value !== value || mixed) {
119
+ // See setNextValue's pendingCommitRef comment — this text-commit path
120
+ // (Enter/blur) bypasses setNextValue, so mark it pending here too.
121
+ pendingCommitRef.current = {
122
+ value: parsed.value,
123
+ baseline: normalizeScrubNumber(value, options),
124
+ };
125
+ onChange(parsed.value, {
126
+ source: "commit",
127
+ expression: currentDraft,
128
+ phase: "commit",
129
+ });
130
+ }
131
+ };
132
+ const handleKeyDown = (event) => {
133
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
134
+ event.preventDefault();
135
+ const direction = event.key === "ArrowUp" ? 1 : -1;
136
+ // getScrubStepFromEvent handles shiftKey (×10) and altKey (÷10).
137
+ // Cmd (metaKey) mirrors Shift for ×10 — editor convention on macOS.
138
+ const baseStep = getScrubStepFromEvent(event, step);
139
+ const cmdMultiplier = event.metaKey && !event.shiftKey ? 10 : 1;
140
+ const delta = direction * baseStep * cmdMultiplier;
141
+ // Mixed selection: the `value` prop is only a placeholder (typically 0)
142
+ // — there's no single current value to step from, and there's no
143
+ // typed draft either (mixed keeps the draft as the literal "Mixed"
144
+ // string, see commitDraft's guard). Figma's behavior here is a
145
+ // *relative* nudge: apply the same +/-delta to each selected object's
146
+ // own value rather than snapping every object to one absolute number.
147
+ // ScrubInput itself can't resolve each target's individual value, so
148
+ // emit the delta via `onChange` (as both `value` and
149
+ // `meta.relativeDelta`) and let the consumer apply it per-target. Do
150
+ // NOT route through setNextValue: that formats/displays one absolute
151
+ // number in the draft, which would incorrectly replace the "Mixed"
152
+ // placeholder text with a single value that was never actually common
153
+ // to the whole selection.
154
+ if (mixed) {
155
+ onChange(delta, {
156
+ source: "keyboard",
157
+ phase: "commit",
158
+ relativeDelta: delta,
159
+ });
160
+ return;
161
+ }
162
+ // Step from the currently typed draft, not the last-committed `value`
163
+ // prop — otherwise an in-progress, uncommitted edit (typed but not yet
164
+ // blurred/entered) is silently discarded the moment an arrow key is
165
+ // pressed. Parse the draft the same way commitDraft does, falling back
166
+ // to `value` only when the draft doesn't parse (e.g. empty/invalid).
167
+ const draftParsed = parseScrubExpression(draftRef.current, value, options);
168
+ const base = draftParsed ? draftParsed.value : value;
169
+ setNextValue(base + delta, {
170
+ source: "keyboard",
171
+ phase: "commit",
172
+ });
173
+ return;
174
+ }
175
+ if (event.key === "Enter") {
176
+ event.preventDefault();
177
+ commitDraft();
178
+ skipNextBlurCommitRef.current = true;
179
+ event.currentTarget.blur();
180
+ return;
181
+ }
182
+ if (event.key === "Escape") {
183
+ event.preventDefault();
184
+ const reverted = mixed
185
+ ? resolvedMixedLabel
186
+ : formatScrubValue(value, options);
187
+ draftRef.current = reverted;
188
+ setDraft(reverted);
189
+ skipNextBlurCommitRef.current = true;
190
+ event.currentTarget.blur();
191
+ }
192
+ };
193
+ const handlePointerDown = (event) => {
194
+ if (disabled || event.button !== 0)
195
+ return;
196
+ event.preventDefault();
197
+ dragRef.current = {
198
+ pointerId: event.pointerId,
199
+ drag: startScrubDrag(event.clientX),
200
+ };
201
+ // Re-seed the gesture's running base from the current prop right as the
202
+ // drag starts. Without this, a stale `lastScrubValueRef` left over from a
203
+ // previous gesture (or from an out-of-band prop update that arrived while
204
+ // not dragging) would silently become this gesture's starting point
205
+ // instead of the value actually displayed when the user grabbed the
206
+ // control.
207
+ lastScrubValueRef.current = value;
208
+ event.currentTarget.setPointerCapture(event.pointerId);
209
+ setDragging(true);
210
+ };
211
+ const handlePointerMove = (event) => {
212
+ if (!dragging || dragRef.current.pointerId !== event.pointerId)
213
+ return;
214
+ // Mixed selection: scrubbing has no meaningful base value (the `value`
215
+ // prop is a placeholder), so committing drag deltas would snap every
216
+ // selected object to a step-from-0 value. Keep the drag inert; releasing
217
+ // without a committed drag focuses the input so the user can type an
218
+ // explicit value that then applies to all.
219
+ if (mixed)
220
+ return;
221
+ // updateScrubDrag mirrors the jitter-threshold + hasDragged bookkeeping
222
+ // (see scrub-input-utils.ts) so it can be unit tested in isolation from
223
+ // real DOM pointer events.
224
+ const tick = updateScrubDrag(dragRef.current.drag, event.clientX);
225
+ dragRef.current.drag = tick.state;
226
+ if (tick.deltaX === null)
227
+ return;
228
+ // Use incremental deltas from the last move so that clamped/rounded values
229
+ // committed by onChange are respected. A total-delta approach would create
230
+ // a dead zone equal to the amount dragged past the clamp boundary.
231
+ //
232
+ // Accumulate from this gesture's OWN last emitted value
233
+ // (lastScrubValueRef), not the `value` prop. The prop only reflects
234
+ // whatever the host last echoed back through computedStyles — a "preview"
235
+ // phase commit is not guaranteed to round-trip before the next
236
+ // pointermove tick fires (the host may debounce/throttle/skip preview
237
+ // writes), so re-reading `value` here would recompute every tick from a
238
+ // stale, pre-drag base plus one tiny incremental delta: the displayed
239
+ // number barely creeps from the original value instead of following the
240
+ // cursor, which reads as jittery/near-random rather than a smooth
241
+ // continuum. The gesture's own running total is always current because
242
+ // this component sets it itself on every tick below.
243
+ const next = lastScrubValueRef.current +
244
+ tick.deltaX *
245
+ getScrubStepFromEvent({ altKey: event.altKey, shiftKey: event.shiftKey }, step);
246
+ // Px-type fields snap to whole numbers while scrubbing (see
247
+ // roundScrubDragValue) even though `precision` — which also governs typed
248
+ // input and keyboard nudges — allows a decimal. Rounding here, before
249
+ // setNextValue's own normalizeScrubNumber pass, keeps every subsequent
250
+ // incremental delta measured from an already-whole value instead of
251
+ // drifting on fractional leftovers.
252
+ lastScrubValueRef.current = setNextValue(roundScrubDragValue(next, unit), {
253
+ source: "scrub",
254
+ phase: "preview",
255
+ });
256
+ };
257
+ const endDrag = (event) => {
258
+ if (dragRef.current.pointerId !== event.pointerId)
259
+ return;
260
+ event.currentTarget.releasePointerCapture(event.pointerId);
261
+ const wasDrag = dragRef.current.drag.hasDragged;
262
+ setDragging(false);
263
+ // A real scrub drag emitted only "preview" ticks via handlePointerMove.
264
+ // Emit exactly one authoritative "commit" here with the final value so a
265
+ // downstream consumer can distinguish "gesture finished" from "still
266
+ // dragging" — without this, the last preview tick would be the only
267
+ // signal, and a consumer that ignores preview ticks would never commit.
268
+ if (wasDrag && !mixed) {
269
+ // See setNextValue's pendingCommitRef comment — mark this gesture's
270
+ // authoritative value as pending confirmation so releasing the drag
271
+ // can't be clobbered back to the pre-drag value by a slow host
272
+ // round-trip (same class of bug as the Enter/blur text-commit case).
273
+ pendingCommitRef.current = {
274
+ value: lastScrubValueRef.current,
275
+ baseline: normalizeScrubNumber(value, options),
276
+ };
277
+ onChange(lastScrubValueRef.current, {
278
+ source: "scrub",
279
+ phase: "commit",
280
+ });
281
+ }
282
+ // If the pointer was released without dragging (a plain click), focus the
283
+ // input so the user can type immediately — mirrors the design editor's label click
284
+ // behaviour (the event.preventDefault() in handlePointerDown blocks the
285
+ // native label→input focus transfer).
286
+ if (!wasDrag && !disabled) {
287
+ inputRef.current?.focus();
288
+ }
289
+ };
290
+ return (_jsxs("div", { className: cn("flex min-w-0 items-center gap-1.5", className), children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Label, { htmlFor: inputId, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, className: cn("flex h-6 shrink-0 cursor-ew-resize select-none items-center gap-1 truncate whitespace-nowrap rounded-sm !text-[11px] text-muted-foreground transition-colors", prefix === "icon" ? "w-8 justify-center gap-0" : "w-20", "hover:bg-[var(--design-editor-control-bg)] hover:text-foreground", dragging &&
291
+ "bg-[var(--design-editor-control-bg)] text-foreground", disabled && "pointer-events-none cursor-not-allowed opacity-50", labelClassName), children: [Icon ? (_jsx(Icon, { className: "size-3 shrink-0", "aria-hidden": true })) : null, _jsx("span", { className: cn("truncate", prefix === "icon" && "sr-only"), children: label })] }) }), _jsx(TooltipContent, { children: resolvedTooltipLabel })] }) }), _jsx(Input, { ref: inputRef, id: inputId, value: draft, disabled: disabled, placeholder: placeholder, inputMode: "decimal", "aria-label": ariaLabel ?? label, onFocus: (event) => {
292
+ setFocused(true);
293
+ if (mixed && mixedLabel !== undefined) {
294
+ const formatted = formatScrubValue(value, options);
295
+ draftRef.current = formatted;
296
+ setDraft(formatted);
297
+ }
298
+ event.currentTarget.select();
299
+ }, onBlur: () => {
300
+ setFocused(false);
301
+ if (skipNextBlurCommitRef.current) {
302
+ skipNextBlurCommitRef.current = false;
303
+ return;
304
+ }
305
+ commitDraft();
306
+ }, onChange: (event) => {
307
+ draftRef.current = event.target.value;
308
+ setDraft(event.target.value);
309
+ }, onKeyDown: handleKeyDown, className: cn(
310
+ // Compact design-editor: h-6, 11px tabular text, ring-1 with no offset.
311
+ "h-6 w-0 min-w-0 flex-1 !text-[11px] tabular-nums", "focus-visible:ring-1 focus-visible:ring-offset-0", inputClassName, mixed && "text-muted-foreground") })] }));
312
+ }
313
+ //# sourceMappingURL=scrub-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrub-input.js","sourceRoot":"","sources":["../../src/design-tweaks/scrub-input.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { type ComponentPropsWithoutRef, type ReactNode } from "react";
2
2
  import { PopoverContent } from "../ui/popover.js";
3
+ export { VisualScrubInput, resolvePendingScrubCommit, type PendingScrubCommit, type ScrubInputChangeMeta, type ScrubInputProps, } from "./scrub-input.js";
4
+ export { formatScrubValue, getScrubStepFromEvent, normalizeScrubNumber, parseScrubExpression, roundScrubDragValue, scrubSnapsToInteger, SCRUB_DRAG_THRESHOLD_PX, startScrubDrag, updateScrubDrag, type ParsedScrubExpression, type ScrubDragState, type ScrubDragTick, type ScrubExpressionOptions, } from "./scrub-input-utils.js";
3
5
  export type VisualControlValue = string | number | boolean;
4
6
  export interface VisualControlOption {
5
7
  label: string;
@@ -76,18 +78,6 @@ export declare function VisualSliderControl({ value, onChange, min, max, step, u
76
78
  step?: number;
77
79
  unit?: string;
78
80
  }): import("react").JSX.Element;
79
- export declare function VisualScrubInput({ label, value, onChange, min, max, step, unit, disabled, mixed, mixedLabel, }: {
80
- label: string;
81
- value: number;
82
- onChange: (value: number) => void;
83
- min?: number;
84
- max?: number;
85
- step?: number;
86
- unit?: string;
87
- disabled?: boolean;
88
- mixed?: boolean;
89
- mixedLabel?: string;
90
- }): import("react").JSX.Element;
91
81
  export declare function VisualTweakControl({ tweak, value, onChange, className, }: {
92
82
  tweak: VisualTweakDefinition;
93
83
  value: VisualControlValue;
@@ -1 +1 @@
1
- {"version":3,"file":"visual-style-controls.d.ts","sourceRoot":"","sources":["../../src/design-tweaks/visual-style-controls.tsx"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,wBAAwB,EAC7B,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAW,cAAc,EAAkB,MAAM,kBAAkB,CAAC;AAG3E,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,GAAG,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1E,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,kBAAkB,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAoMD,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAY,GACb,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B,+BA0BA;AAED,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BASA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAOA;AAED,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,KAAK,EACL,QAAQ,EACR,OAAW,EACX,SAAS,GACV,EAAE;IACD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAmCA;AAED,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,KAAK,EACL,QAAQ,EACR,cAAmB,EACnB,gBAAwB,EACxB,QAAgB,EAChB,mBAAuC,EACvC,gBAAgC,EAChC,SAAS,EACT,YAAY,EACZ,KAAa,EACb,UAAoB,EACpB,OAAmB,GACpB,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,IAAI,CACjB,wBAAwB,CAAC,OAAO,cAAc,CAAC,EAC/C,UAAU,CACX,GACC,MAAM,CAAC,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAChC,+BAqPA;AA8KD,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAuBA;AAED,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,QAAQ,EACR,KAAK,GACN,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,+BAoBA;AAED,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,+BAkBA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,GAAG,EACH,GAAG,EACH,IAAQ,EACR,IAAI,EACJ,QAAgB,EAChB,KAAa,EACb,UAAoB,GACrB,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,+BAyIA;AAED,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE;IACD,KAAK,EAAE,qBAAqB,CAAC;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BA4DA"}
1
+ {"version":3,"file":"visual-style-controls.d.ts","sourceRoot":"","sources":["../../src/design-tweaks/visual-style-controls.tsx"],"names":[],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { IconColorPicker } from "@tabler/icons-react";
3
- import { useEffect, useId, useRef, useState, } from "react";
3
+ import { useEffect, useRef, useState, } from "react";
4
4
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
5
5
  import { cn } from "../utils.js";
6
+ export { VisualScrubInput, resolvePendingScrubCommit, } from "./scrub-input.js";
7
+ export { formatScrubValue, getScrubStepFromEvent, normalizeScrubNumber, parseScrubExpression, roundScrubDragValue, scrubSnapsToInteger, SCRUB_DRAG_THRESHOLD_PX, startScrubDrag, updateScrubDrag, } from "./scrub-input-utils.js";
6
8
  function clampNumber(value, min, max) {
7
9
  let next = value;
8
10
  if (typeof min === "number")
@@ -15,13 +17,6 @@ function formatNumber(value, unit) {
15
17
  const rounded = Number.isInteger(value) ? value : Number(value.toFixed(2));
16
18
  return unit ? `${rounded}${unit}` : String(rounded);
17
19
  }
18
- function parseDraftNumber(value, fallback) {
19
- const match = value.trim().match(/-?\d+(?:\.\d+)?/);
20
- if (!match)
21
- return fallback;
22
- const next = Number(match[0]);
23
- return Number.isFinite(next) ? next : fallback;
24
- }
25
20
  const CHECKERBOARD_IMAGE = "linear-gradient(45deg, #d4d4d4 25%, transparent 25%), linear-gradient(-45deg, #d4d4d4 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #d4d4d4 75%), linear-gradient(-45deg, transparent 75%, #d4d4d4 75%)";
26
21
  const FALLBACK_RGBA = { r: 0, g: 0, b: 0, a: 1 };
27
22
  function normalizeRgba(color) {
@@ -409,105 +404,6 @@ export function VisualSliderControl({ value, onChange, min = 0, max = 100, step
409
404
  const safeValue = clampNumber(Number.isFinite(value) ? value : min, min, max);
410
405
  return (_jsxs("div", { className: "flex h-7 items-center gap-2", children: [_jsx("input", { type: "range", min: min, max: max, step: step, value: safeValue, onChange: (event) => onChange(Number(event.currentTarget.value)), className: "min-w-0 flex-1 cursor-pointer accent-foreground" }), _jsx("span", { className: "w-9 text-right text-[11px] tabular-nums text-muted-foreground", children: formatNumber(safeValue, unit) })] }));
411
406
  }
412
- export function VisualScrubInput({ label, value, onChange, min, max, step = 1, unit, disabled = false, mixed = false, mixedLabel = "Mixed", }) {
413
- const id = useId();
414
- const [draft, setDraft] = useState(() => mixed ? mixedLabel : formatNumber(value, unit));
415
- const [focused, setFocused] = useState(false);
416
- const [hasInteracted, setHasInteracted] = useState(false);
417
- const dragRef = useRef(null);
418
- useEffect(() => {
419
- if (!focused) {
420
- setDraft(mixed && !hasInteracted ? mixedLabel : formatNumber(value, unit));
421
- }
422
- }, [focused, hasInteracted, mixed, mixedLabel, unit, value]);
423
- useEffect(() => {
424
- if (mixed)
425
- setHasInteracted(false);
426
- }, [mixed]);
427
- const startInteraction = () => {
428
- if (!hasInteracted) {
429
- setHasInteracted(true);
430
- setDraft(formatNumber(value, unit));
431
- }
432
- };
433
- const commit = (nextDraft = draft) => {
434
- const parsed = parseDraftNumber(nextDraft, value);
435
- const next = clampNumber(parsed, min, max);
436
- onChange(next);
437
- setDraft(formatNumber(next, unit));
438
- };
439
- const setNext = (next) => {
440
- const clamped = clampNumber(next, min, max);
441
- onChange(clamped);
442
- setDraft(formatNumber(clamped, unit));
443
- };
444
- const onKeyDown = (event) => {
445
- startInteraction();
446
- if (event.key === "Enter") {
447
- event.preventDefault();
448
- commit();
449
- event.currentTarget.blur();
450
- return;
451
- }
452
- if (event.key === "Escape") {
453
- event.preventDefault();
454
- setDraft(formatNumber(value, unit));
455
- event.currentTarget.blur();
456
- return;
457
- }
458
- if (event.key === "ArrowUp" || event.key === "ArrowDown") {
459
- event.preventDefault();
460
- const mult = event.shiftKey || event.metaKey ? 10 : event.altKey ? 0.1 : 1;
461
- const direction = event.key === "ArrowUp" ? 1 : -1;
462
- const base = parseDraftNumber(draft, value);
463
- setNext(base + direction * step * mult);
464
- }
465
- };
466
- const onPointerDown = (event) => {
467
- if (disabled || event.button !== 0)
468
- return;
469
- event.preventDefault();
470
- startInteraction();
471
- dragRef.current = {
472
- pointerId: event.pointerId,
473
- prevX: event.clientX,
474
- dragged: false,
475
- };
476
- event.currentTarget.setPointerCapture(event.pointerId);
477
- };
478
- const onPointerMove = (event) => {
479
- const drag = dragRef.current;
480
- if (!drag || drag.pointerId !== event.pointerId)
481
- return;
482
- const delta = event.clientX - drag.prevX;
483
- if (delta === 0)
484
- return;
485
- drag.prevX = event.clientX;
486
- drag.dragged = true;
487
- const mult = event.shiftKey || event.metaKey ? 10 : event.altKey ? 0.1 : 1;
488
- setNext(value + delta * step * mult);
489
- };
490
- const onPointerUp = (event) => {
491
- const drag = dragRef.current;
492
- if (!drag || drag.pointerId !== event.pointerId)
493
- return;
494
- event.currentTarget.releasePointerCapture(event.pointerId);
495
- dragRef.current = null;
496
- if (!drag.dragged) {
497
- document.getElementById(id)?.focus();
498
- }
499
- };
500
- return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("label", { htmlFor: id, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, className: cn("flex w-8 shrink-0 cursor-ew-resize select-none items-center justify-center rounded border border-transparent px-1 text-[10px] font-semibold text-muted-foreground hover:border-border hover:bg-accent/60", disabled && "cursor-not-allowed opacity-50"), children: label }), _jsx("input", { id: id, value: draft, disabled: disabled, onFocus: () => {
501
- setFocused(true);
502
- startInteraction();
503
- }, onBlur: () => {
504
- setFocused(false);
505
- commit();
506
- }, onChange: (event) => {
507
- startInteraction();
508
- setDraft(event.currentTarget.value);
509
- }, onKeyDown: onKeyDown, className: "h-7 min-w-0 flex-1 rounded-md border border-input bg-background/70 px-2 text-right text-[11px] tabular-nums text-foreground outline-none transition-colors focus:border-ring focus:ring-1 focus:ring-ring disabled:opacity-50" })] }));
510
- }
511
407
  export function VisualTweakControl({ tweak, value, onChange, className, }) {
512
408
  if (tweak.type === "toggle") {
513
409
  return (_jsxs("div", { className: cn("flex h-7 items-center justify-between gap-2", className), children: [_jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: tweak.label }), _jsx(VisualToggleControl, { checked: Boolean(value), onChange: onChange, label: tweak.label })] }));