@agent-native/toolkit 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/agent-native.eject.json +38 -0
- package/dist/canvas-annotations/CanvasCommentPins.d.ts +68 -0
- package/dist/canvas-annotations/CanvasCommentPins.d.ts.map +1 -0
- package/dist/canvas-annotations/CanvasCommentPins.js +513 -0
- package/dist/canvas-annotations/CanvasCommentPins.js.map +1 -0
- package/dist/canvas-annotations/DrawOverlay.d.ts +108 -0
- package/dist/canvas-annotations/DrawOverlay.d.ts.map +1 -0
- package/dist/canvas-annotations/DrawOverlay.js +746 -0
- package/dist/canvas-annotations/DrawOverlay.js.map +1 -0
- package/dist/canvas-annotations/DrawOverlay.spec.d.ts +2 -0
- package/dist/canvas-annotations/DrawOverlay.spec.d.ts.map +1 -0
- package/dist/canvas-annotations/DrawOverlay.spec.js +111 -0
- package/dist/canvas-annotations/DrawOverlay.spec.js.map +1 -0
- package/dist/canvas-annotations/index.d.ts +4 -0
- package/dist/canvas-annotations/index.d.ts.map +1 -0
- package/dist/canvas-annotations/index.js +3 -0
- package/dist/canvas-annotations/index.js.map +1 -0
- package/dist/canvas-annotations/types.d.ts +8 -0
- package/dist/canvas-annotations/types.d.ts.map +1 -0
- package/dist/canvas-annotations/types.js +2 -0
- package/dist/canvas-annotations/types.js.map +1 -0
- package/dist/canvas-interactions/canvas-interactions.d.ts +334 -0
- package/dist/canvas-interactions/canvas-interactions.d.ts.map +1 -0
- package/dist/canvas-interactions/canvas-interactions.js +451 -0
- package/dist/canvas-interactions/canvas-interactions.js.map +1 -0
- package/dist/canvas-interactions/canvas-interactions.spec.d.ts +2 -0
- package/dist/canvas-interactions/canvas-interactions.spec.d.ts.map +1 -0
- package/dist/canvas-interactions/canvas-interactions.spec.js +538 -0
- package/dist/canvas-interactions/canvas-interactions.spec.js.map +1 -0
- package/dist/canvas-interactions/index.d.ts +2 -0
- package/dist/canvas-interactions/index.d.ts.map +1 -0
- package/dist/canvas-interactions/index.js +2 -0
- package/dist/canvas-interactions/index.js.map +1 -0
- package/dist/design-tweaks/scrub-input-utils.d.ts +61 -0
- package/dist/design-tweaks/scrub-input-utils.d.ts.map +1 -0
- package/dist/design-tweaks/scrub-input-utils.js +235 -0
- package/dist/design-tweaks/scrub-input-utils.js.map +1 -0
- package/dist/design-tweaks/scrub-input.d.ts +66 -0
- package/dist/design-tweaks/scrub-input.d.ts.map +1 -0
- package/dist/design-tweaks/scrub-input.js +313 -0
- package/dist/design-tweaks/scrub-input.js.map +1 -0
- package/dist/design-tweaks/visual-style-controls.d.ts +2 -12
- package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -1
- package/dist/design-tweaks/visual-style-controls.js +3 -107
- package/dist/design-tweaks/visual-style-controls.js.map +1 -1
- package/dist/design-tweaks/visual-style-controls.spec.js +26 -0
- package/dist/design-tweaks/visual-style-controls.spec.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +29 -1
- package/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
- package/src/canvas-annotations/DrawOverlay.spec.tsx +145 -0
- package/src/canvas-annotations/DrawOverlay.tsx +1233 -0
- package/src/canvas-annotations/index.ts +15 -0
- package/src/canvas-annotations/types.ts +14 -0
- package/src/canvas-interactions/canvas-interactions.spec.ts +688 -0
- package/src/canvas-interactions/canvas-interactions.ts +933 -0
- package/src/canvas-interactions/index.ts +67 -0
- package/src/design-tweaks/scrub-input-utils.ts +311 -0
- package/src/design-tweaks/scrub-input.tsx +491 -0
- package/src/design-tweaks/visual-style-controls.spec.tsx +60 -0
- package/src/design-tweaks/visual-style-controls.tsx +23 -168
- 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;
|
|
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,
|
|
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 })] }));
|