@clipkit/editor 1.0.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.
Files changed (248) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +51 -0
  3. package/dist/Editor.d.ts +3 -0
  4. package/dist/Editor.d.ts.map +1 -0
  5. package/dist/Editor.js +73 -0
  6. package/dist/Editor.js.map +1 -0
  7. package/dist/ExportDialog.d.ts +12 -0
  8. package/dist/ExportDialog.d.ts.map +1 -0
  9. package/dist/ExportDialog.js +30 -0
  10. package/dist/ExportDialog.js.map +1 -0
  11. package/dist/MotionPathOverlay.d.ts +5 -0
  12. package/dist/MotionPathOverlay.d.ts.map +1 -0
  13. package/dist/MotionPathOverlay.js +156 -0
  14. package/dist/MotionPathOverlay.js.map +1 -0
  15. package/dist/PerfHud.d.ts +2 -0
  16. package/dist/PerfHud.d.ts.map +1 -0
  17. package/dist/PerfHud.js +85 -0
  18. package/dist/PerfHud.js.map +1 -0
  19. package/dist/Stage.d.ts +2 -0
  20. package/dist/Stage.d.ts.map +1 -0
  21. package/dist/Stage.js +406 -0
  22. package/dist/Stage.js.map +1 -0
  23. package/dist/StageOverlay.d.ts +7 -0
  24. package/dist/StageOverlay.d.ts.map +1 -0
  25. package/dist/StageOverlay.js +508 -0
  26. package/dist/StageOverlay.js.map +1 -0
  27. package/dist/commands.d.ts +18 -0
  28. package/dist/commands.d.ts.map +1 -0
  29. package/dist/commands.js +103 -0
  30. package/dist/commands.js.map +1 -0
  31. package/dist/configuration.d.ts +9 -0
  32. package/dist/configuration.d.ts.map +1 -0
  33. package/dist/configuration.js +21 -0
  34. package/dist/configuration.js.map +1 -0
  35. package/dist/controls/AnimationsStack.d.ts +8 -0
  36. package/dist/controls/AnimationsStack.d.ts.map +1 -0
  37. package/dist/controls/AnimationsStack.js +188 -0
  38. package/dist/controls/AnimationsStack.js.map +1 -0
  39. package/dist/controls/CameraControl.d.ts +19 -0
  40. package/dist/controls/CameraControl.d.ts.map +1 -0
  41. package/dist/controls/CameraControl.js +47 -0
  42. package/dist/controls/CameraControl.js.map +1 -0
  43. package/dist/controls/CaptionLengthControl.d.ts +5 -0
  44. package/dist/controls/CaptionLengthControl.d.ts.map +1 -0
  45. package/dist/controls/CaptionLengthControl.js +11 -0
  46. package/dist/controls/CaptionLengthControl.js.map +1 -0
  47. package/dist/controls/CaptionTranscribe.d.ts +2 -0
  48. package/dist/controls/CaptionTranscribe.d.ts.map +1 -0
  49. package/dist/controls/CaptionTranscribe.js +95 -0
  50. package/dist/controls/CaptionTranscribe.js.map +1 -0
  51. package/dist/controls/ColorPicker.d.ts +17 -0
  52. package/dist/controls/ColorPicker.d.ts.map +1 -0
  53. package/dist/controls/ColorPicker.js +354 -0
  54. package/dist/controls/ColorPicker.js.map +1 -0
  55. package/dist/controls/ControlRenderer.d.ts +20 -0
  56. package/dist/controls/ControlRenderer.d.ts.map +1 -0
  57. package/dist/controls/ControlRenderer.js +106 -0
  58. package/dist/controls/ControlRenderer.js.map +1 -0
  59. package/dist/controls/CropControl.d.ts +2 -0
  60. package/dist/controls/CropControl.d.ts.map +1 -0
  61. package/dist/controls/CropControl.js +177 -0
  62. package/dist/controls/CropControl.js.map +1 -0
  63. package/dist/controls/EffectsStack.d.ts +8 -0
  64. package/dist/controls/EffectsStack.d.ts.map +1 -0
  65. package/dist/controls/EffectsStack.js +89 -0
  66. package/dist/controls/EffectsStack.js.map +1 -0
  67. package/dist/controls/GradeControl.d.ts +2 -0
  68. package/dist/controls/GradeControl.d.ts.map +1 -0
  69. package/dist/controls/GradeControl.js +120 -0
  70. package/dist/controls/GradeControl.js.map +1 -0
  71. package/dist/controls/KeyframeDiamond.d.ts +11 -0
  72. package/dist/controls/KeyframeDiamond.d.ts.map +1 -0
  73. package/dist/controls/KeyframeDiamond.js +87 -0
  74. package/dist/controls/KeyframeDiamond.js.map +1 -0
  75. package/dist/controls/LightingControls.d.ts +24 -0
  76. package/dist/controls/LightingControls.d.ts.map +1 -0
  77. package/dist/controls/LightingControls.js +108 -0
  78. package/dist/controls/LightingControls.js.map +1 -0
  79. package/dist/controls/ShapePresetControl.d.ts +4 -0
  80. package/dist/controls/ShapePresetControl.d.ts.map +1 -0
  81. package/dist/controls/ShapePresetControl.js +30 -0
  82. package/dist/controls/ShapePresetControl.js.map +1 -0
  83. package/dist/controls/ValueField.d.ts +10 -0
  84. package/dist/controls/ValueField.d.ts.map +1 -0
  85. package/dist/controls/ValueField.js +158 -0
  86. package/dist/controls/ValueField.js.map +1 -0
  87. package/dist/controls/VolumeControl.d.ts +10 -0
  88. package/dist/controls/VolumeControl.d.ts.map +1 -0
  89. package/dist/controls/VolumeControl.js +75 -0
  90. package/dist/controls/VolumeControl.js.map +1 -0
  91. package/dist/controls/compound.d.ts +46 -0
  92. package/dist/controls/compound.d.ts.map +1 -0
  93. package/dist/controls/compound.js +160 -0
  94. package/dist/controls/compound.js.map +1 -0
  95. package/dist/controls/layout.d.ts +38 -0
  96. package/dist/controls/layout.d.ts.map +1 -0
  97. package/dist/controls/layout.js +162 -0
  98. package/dist/controls/layout.js.map +1 -0
  99. package/dist/controls/primitives.d.ts +83 -0
  100. package/dist/controls/primitives.d.ts.map +1 -0
  101. package/dist/controls/primitives.js +194 -0
  102. package/dist/controls/primitives.js.map +1 -0
  103. package/dist/controls/transcribe.worker.d.ts +2 -0
  104. package/dist/controls/transcribe.worker.d.ts.map +1 -0
  105. package/dist/controls/transcribe.worker.js +22 -0
  106. package/dist/controls/transcribe.worker.js.map +1 -0
  107. package/dist/frame/AddElementBar.d.ts +2 -0
  108. package/dist/frame/AddElementBar.d.ts.map +1 -0
  109. package/dist/frame/AddElementBar.js +103 -0
  110. package/dist/frame/AddElementBar.js.map +1 -0
  111. package/dist/frame/Breadcrumbs.d.ts +2 -0
  112. package/dist/frame/Breadcrumbs.d.ts.map +1 -0
  113. package/dist/frame/Breadcrumbs.js +32 -0
  114. package/dist/frame/Breadcrumbs.js.map +1 -0
  115. package/dist/frame/GroupFlash.d.ts +2 -0
  116. package/dist/frame/GroupFlash.d.ts.map +1 -0
  117. package/dist/frame/GroupFlash.js +65 -0
  118. package/dist/frame/GroupFlash.js.map +1 -0
  119. package/dist/frame/Resizable.d.ts +12 -0
  120. package/dist/frame/Resizable.d.ts.map +1 -0
  121. package/dist/frame/Resizable.js +37 -0
  122. package/dist/frame/Resizable.js.map +1 -0
  123. package/dist/frame/Section.d.ts +23 -0
  124. package/dist/frame/Section.d.ts.map +1 -0
  125. package/dist/frame/Section.js +23 -0
  126. package/dist/frame/Section.js.map +1 -0
  127. package/dist/frame/ZoomControl.d.ts +9 -0
  128. package/dist/frame/ZoomControl.d.ts.map +1 -0
  129. package/dist/frame/ZoomControl.js +15 -0
  130. package/dist/frame/ZoomControl.js.map +1 -0
  131. package/dist/index.d.ts +9 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +13 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/lib/camera-gizmo.d.ts +15 -0
  136. package/dist/lib/camera-gizmo.d.ts.map +1 -0
  137. package/dist/lib/camera-gizmo.js +57 -0
  138. package/dist/lib/camera-gizmo.js.map +1 -0
  139. package/dist/lib/camera-tool.d.ts +43 -0
  140. package/dist/lib/camera-tool.d.ts.map +1 -0
  141. package/dist/lib/camera-tool.js +80 -0
  142. package/dist/lib/camera-tool.js.map +1 -0
  143. package/dist/lib/caption-segments.d.ts +17 -0
  144. package/dist/lib/caption-segments.d.ts.map +1 -0
  145. package/dist/lib/caption-segments.js +50 -0
  146. package/dist/lib/caption-segments.js.map +1 -0
  147. package/dist/lib/group.d.ts +12 -0
  148. package/dist/lib/group.d.ts.map +1 -0
  149. package/dist/lib/group.js +61 -0
  150. package/dist/lib/group.js.map +1 -0
  151. package/dist/lib/keyframes.d.ts +29 -0
  152. package/dist/lib/keyframes.d.ts.map +1 -0
  153. package/dist/lib/keyframes.js +92 -0
  154. package/dist/lib/keyframes.js.map +1 -0
  155. package/dist/lib/sfx-preview.d.ts +18 -0
  156. package/dist/lib/sfx-preview.d.ts.map +1 -0
  157. package/dist/lib/sfx-preview.js +74 -0
  158. package/dist/lib/sfx-preview.js.map +1 -0
  159. package/dist/lib/shape-presets.d.ts +35 -0
  160. package/dist/lib/shape-presets.d.ts.map +1 -0
  161. package/dist/lib/shape-presets.js +81 -0
  162. package/dist/lib/shape-presets.js.map +1 -0
  163. package/dist/lib/ungroup.d.ts +12 -0
  164. package/dist/lib/ungroup.d.ts.map +1 -0
  165. package/dist/lib/ungroup.js +40 -0
  166. package/dist/lib/ungroup.js.map +1 -0
  167. package/dist/lib/utils.d.ts +3 -0
  168. package/dist/lib/utils.d.ts.map +1 -0
  169. package/dist/lib/utils.js +9 -0
  170. package/dist/lib/utils.js.map +1 -0
  171. package/dist/panels/AssetsPanel.d.ts +2 -0
  172. package/dist/panels/AssetsPanel.d.ts.map +1 -0
  173. package/dist/panels/AssetsPanel.js +108 -0
  174. package/dist/panels/AssetsPanel.js.map +1 -0
  175. package/dist/panels/InspectorPanel.d.ts +2 -0
  176. package/dist/panels/InspectorPanel.d.ts.map +1 -0
  177. package/dist/panels/InspectorPanel.js +286 -0
  178. package/dist/panels/InspectorPanel.js.map +1 -0
  179. package/dist/panels/InterpolationPanel.d.ts +2 -0
  180. package/dist/panels/InterpolationPanel.d.ts.map +1 -0
  181. package/dist/panels/InterpolationPanel.js +226 -0
  182. package/dist/panels/InterpolationPanel.js.map +1 -0
  183. package/dist/panels/LayersTree.d.ts +4 -0
  184. package/dist/panels/LayersTree.d.ts.map +1 -0
  185. package/dist/panels/LayersTree.js +137 -0
  186. package/dist/panels/LayersTree.js.map +1 -0
  187. package/dist/panels/LeftRail.d.ts +6 -0
  188. package/dist/panels/LeftRail.d.ts.map +1 -0
  189. package/dist/panels/LeftRail.js +35 -0
  190. package/dist/panels/LeftRail.js.map +1 -0
  191. package/dist/panels/SourcePanel.d.ts +2 -0
  192. package/dist/panels/SourcePanel.d.ts.map +1 -0
  193. package/dist/panels/SourcePanel.js +470 -0
  194. package/dist/panels/SourcePanel.js.map +1 -0
  195. package/dist/panels/TimelinePanel.d.ts +11 -0
  196. package/dist/panels/TimelinePanel.d.ts.map +1 -0
  197. package/dist/panels/TimelinePanel.js +98 -0
  198. package/dist/panels/TimelinePanel.js.map +1 -0
  199. package/dist/panels/assets/SfxBrowser.d.ts +2 -0
  200. package/dist/panels/assets/SfxBrowser.d.ts.map +1 -0
  201. package/dist/panels/assets/SfxBrowser.js +49 -0
  202. package/dist/panels/assets/SfxBrowser.js.map +1 -0
  203. package/dist/panels/assets/use-assets.d.ts +11 -0
  204. package/dist/panels/assets/use-assets.d.ts.map +1 -0
  205. package/dist/panels/assets/use-assets.js +84 -0
  206. package/dist/panels/assets/use-assets.js.map +1 -0
  207. package/dist/panels/assets/use-sfx.d.ts +6 -0
  208. package/dist/panels/assets/use-sfx.d.ts.map +1 -0
  209. package/dist/panels/assets/use-sfx.js +47 -0
  210. package/dist/panels/assets/use-sfx.js.map +1 -0
  211. package/dist/panels/timeline/CanvasTimeline.d.ts +7 -0
  212. package/dist/panels/timeline/CanvasTimeline.d.ts.map +1 -0
  213. package/dist/panels/timeline/CanvasTimeline.js +1536 -0
  214. package/dist/panels/timeline/CanvasTimeline.js.map +1 -0
  215. package/dist/panels/timeline/Clip.d.ts +37 -0
  216. package/dist/panels/timeline/Clip.d.ts.map +1 -0
  217. package/dist/panels/timeline/Clip.js +176 -0
  218. package/dist/panels/timeline/Clip.js.map +1 -0
  219. package/dist/panels/timeline/CurveEditor.d.ts +2 -0
  220. package/dist/panels/timeline/CurveEditor.d.ts.map +1 -0
  221. package/dist/panels/timeline/CurveEditor.js +233 -0
  222. package/dist/panels/timeline/CurveEditor.js.map +1 -0
  223. package/dist/panels/timeline/MixerRail.d.ts +7 -0
  224. package/dist/panels/timeline/MixerRail.d.ts.map +1 -0
  225. package/dist/panels/timeline/MixerRail.js +295 -0
  226. package/dist/panels/timeline/MixerRail.js.map +1 -0
  227. package/dist/panels/timeline/Waveform.d.ts +11 -0
  228. package/dist/panels/timeline/Waveform.d.ts.map +1 -0
  229. package/dist/panels/timeline/Waveform.js +63 -0
  230. package/dist/panels/timeline/Waveform.js.map +1 -0
  231. package/dist/panels/timeline/clip-style.d.ts +10 -0
  232. package/dist/panels/timeline/clip-style.d.ts.map +1 -0
  233. package/dist/panels/timeline/clip-style.js +20 -0
  234. package/dist/panels/timeline/clip-style.js.map +1 -0
  235. package/dist/panels/timeline/filmstrip.d.ts +7 -0
  236. package/dist/panels/timeline/filmstrip.d.ts.map +1 -0
  237. package/dist/panels/timeline/filmstrip.js +135 -0
  238. package/dist/panels/timeline/filmstrip.js.map +1 -0
  239. package/dist/panels/timeline/timeline-layout.d.ts +65 -0
  240. package/dist/panels/timeline/timeline-layout.d.ts.map +1 -0
  241. package/dist/panels/timeline/timeline-layout.js +118 -0
  242. package/dist/panels/timeline/timeline-layout.js.map +1 -0
  243. package/dist/types.d.ts +68 -0
  244. package/dist/types.d.ts.map +1 -0
  245. package/dist/types.js +3 -0
  246. package/dist/types.js.map +1 -0
  247. package/package.json +56 -0
  248. package/src/styles.css +185 -0
@@ -0,0 +1,194 @@
1
+ // Control kit primitives — the flat, compact knobs every registry-
2
+ // rendered row uses (design/refs: small mono numerals, drag-scrub
3
+ // number fields, hairline inputs, no cards).
4
+ //
5
+ // Scrub contract (shared with stage drags): onScrubStart() snapshots
6
+ // history ONCE, every live change dispatches with skipHistory, so one
7
+ // scrub = one undo step.
8
+ 'use client';
9
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { useEffect, useRef, useState, } from 'react';
11
+ import { cn } from '../lib/utils.js';
12
+ import { ColorPickerPopover } from './ColorPicker.js';
13
+ /* Filled "well" fields per the Figma mock (ruled by Ian 2026-06-11):
14
+ chip lighter than the panel, no border, ring on focus, optional
15
+ muted prefix glyph (X / Y / W / H / ∠) inside the well. */
16
+ const FIELD_WRAP_CLS = 'h-6 flex items-center gap-1 bg-field hover:bg-field-hover focus-within:ring-1 focus-within:ring-ring rounded-md px-1.5 transition-colors';
17
+ const FIELD_INNER_CLS = 'flex-1 min-w-0 w-full bg-transparent text-[11px] font-mono tabular-nums text-foreground/90 outline-none text-right';
18
+ const FIELD_CLS = 'h-6 w-[72px] bg-field hover:bg-field-hover focus:ring-1 focus:ring-ring rounded-md px-1.5 text-[11px] font-mono tabular-nums text-foreground/90 outline-none text-right transition-colors';
19
+ const clamp = (v, min, max) => Math.min(max ?? Infinity, Math.max(min ?? -Infinity, v));
20
+ const roundTo = (v, step) => {
21
+ const inv = 1 / step;
22
+ return Math.round(v * inv) / inv;
23
+ };
24
+ /** Partial numeric input — what's allowed WHILE typing ("-", "1.").
25
+ * Letters never enter number fields (ruled by Ian 2026-06-11). */
26
+ const NUMERIC_PARTIAL = /^-?\d*\.?\d*$/;
27
+ /** Joined −/+ pair, same 24px well treatment as the inputs. */
28
+ export function Stepper({ onStep, fluid, }) {
29
+ return (_jsx("div", { className: cn('flex h-6 gap-px rounded-md overflow-hidden shrink-0', fluid && 'flex-1 w-full min-w-0'), children: [-1, 1].map((dir) => (_jsx("button", { type: "button", className: cn('h-6 grid place-items-center text-[12px] bg-field text-muted-foreground hover:text-foreground hover:bg-field-hover transition-colors', fluid ? 'flex-1' : 'w-6'), onClick: () => onStep(dir), "aria-label": dir === -1 ? 'Decrease' : 'Increase', children: dir === -1 ? '−' : '+' }, dir))) }));
30
+ }
31
+ /** Drag-scrub number field: horizontal pointer drag scrubs (step per
32
+ * 2px, ×10 with shift), click-through to type (numeric chars only),
33
+ * ↑/↓ arrow steps, optional unit label + built-in stepper. */
34
+ export function NumberControl({ value, onChange, min, max, step = 1, suffix, prefix, trailing, stepper, fluid, width, onScrubStart, onScrubEnd, }) {
35
+ const [text, setText] = useState(null);
36
+ const dragRef = useRef(null);
37
+ const display = text ?? String(roundTo(value, Math.min(step, 0.01)));
38
+ const stepBy = (dir, factor = 1) => {
39
+ onChange(clamp(roundTo(value + dir * step * factor, step), min, max), false);
40
+ setText(null);
41
+ };
42
+ const onPointerDown = (e) => {
43
+ // Only scrub from an unfocused field — focused = typing mode.
44
+ if (document.activeElement === e.currentTarget)
45
+ return;
46
+ dragRef.current = { startX: e.clientX, startV: value, scrubbed: false };
47
+ e.currentTarget.setPointerCapture(e.pointerId);
48
+ };
49
+ const onPointerMove = (e) => {
50
+ const d = dragRef.current;
51
+ if (!d)
52
+ return;
53
+ const dx = e.clientX - d.startX;
54
+ if (!d.scrubbed && Math.abs(dx) < 3)
55
+ return;
56
+ if (!d.scrubbed) {
57
+ d.scrubbed = true;
58
+ onScrubStart?.();
59
+ }
60
+ const factor = e.shiftKey ? 10 : 1;
61
+ const next = clamp(roundTo(d.startV + (dx / 2) * step * factor, step), min, max);
62
+ onChange(next, true);
63
+ };
64
+ const onPointerUp = (e) => {
65
+ const d = dragRef.current;
66
+ dragRef.current = null;
67
+ if (d?.scrubbed) {
68
+ e.preventDefault();
69
+ onScrubEnd?.();
70
+ e.currentTarget.blur();
71
+ }
72
+ };
73
+ const scrubProps = {
74
+ onPointerDown,
75
+ onPointerMove,
76
+ onPointerUp,
77
+ };
78
+ const commitText = (raw) => {
79
+ const parsed = parseFloat(raw);
80
+ if (Number.isFinite(parsed))
81
+ onChange(clamp(parsed, min, max), false);
82
+ setText(null);
83
+ };
84
+ const needsWrap = Boolean(prefix || trailing || suffix || stepper);
85
+ const input = (_jsx("input", { className: cn(needsWrap ? FIELD_INNER_CLS : FIELD_CLS, !needsWrap && fluid && 'w-full flex-1 min-w-0', 'cursor-ew-resize focus:cursor-text select-none'), style: !needsWrap && !fluid && width ? { width } : undefined, value: display, onChange: (e) => {
86
+ // Reject non-numeric characters at the keystroke level.
87
+ if (NUMERIC_PARTIAL.test(e.target.value))
88
+ setText(e.target.value);
89
+ }, onFocus: () => setText(String(roundTo(value, Math.min(step, 0.01)))), onBlur: (e) => text !== null && commitText(e.target.value), onKeyDown: (e) => {
90
+ if (e.key === 'Enter')
91
+ e.target.blur();
92
+ if (e.key === 'Escape') {
93
+ setText(null);
94
+ e.target.blur();
95
+ }
96
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
97
+ e.preventDefault();
98
+ stepBy(e.key === 'ArrowUp' ? 1 : -1, e.shiftKey ? 10 : 1);
99
+ }
100
+ }, ...scrubProps, inputMode: "decimal", spellCheck: false }));
101
+ if (!needsWrap)
102
+ return input;
103
+ const well = (_jsxs("span", { className: cn(FIELD_WRAP_CLS,
104
+ // flex-1 ONLY beside the stepper (horizontal flex = shares
105
+ // width). In vertical stacks flex-1 would override h-6 and
106
+ // collapse the well, so plain fluid uses w-full.
107
+ stepper ? 'flex-1 min-w-0' : (fluid || undefined) && 'w-full min-w-0'), style: fluid || stepper ? undefined : { width: width ?? 72 }, children: [prefix && (_jsx("span", { className: "text-[10px] text-muted-foreground/70 hover:text-foreground select-none shrink-0 cursor-ew-resize transition-colors", ...scrubProps, children: prefix })), input, suffix && (_jsx("span", { className: "text-[10px] text-muted-foreground/70 select-none shrink-0", children: suffix })), trailing && _jsx("span", { className: "shrink-0 flex items-center pl-1 -mr-0.5", children: trailing })] }));
108
+ if (!stepper)
109
+ return well;
110
+ return (_jsxs("span", { className: cn('flex items-center gap-2', fluid && 'w-full flex-1 min-w-0'), style: fluid ? undefined : { width: width ?? 72 }, children: [well, _jsx(Stepper, { onStep: (dir) => stepBy(dir) })] }));
111
+ }
112
+ /** Length values: number (px) or string with a unit ("50%", "10vw").
113
+ * The numeric part scrubs/edits; an existing unit suffix is kept. */
114
+ export function LengthControl({ value, onChange, step = 1, prefix, trailing, stepper, fluid, onScrubStart, onScrubEnd, }) {
115
+ const str = typeof value === 'string' ? value : null;
116
+ const match = str?.match(/^(-?\d*\.?\d+)\s*(px|%|vw|vh|vmin|vmax)$/);
117
+ const num = match ? parseFloat(match[1]) : typeof value === 'number' ? value : 0;
118
+ const unit = match?.[2] === 'px' ? '' : match?.[2] ?? '';
119
+ // Unparseable strings ('auto', 'end', keywords) edit as raw text.
120
+ if (str !== null && !match) {
121
+ return (_jsx(TextControl, { value: str, onChange: (v) => onChange(v, false), width: 72, fluid: fluid }));
122
+ }
123
+ return (_jsx(NumberControl, { value: num,
124
+ // Numeric lengths are pixels — show it (writes stay plain numbers).
125
+ suffix: unit === '' ? 'px' : unit, prefix: prefix, trailing: trailing, stepper: stepper, fluid: fluid, step: step, onScrubStart: onScrubStart, onScrubEnd: onScrubEnd, onChange: (n, live) => onChange(unit ? `${n}${unit}` : n, live) }));
126
+ }
127
+ export function TextControl({ value, onChange, width = 120, fluid, live, onScrubStart, onScrubEnd, }) {
128
+ // Same controlled pattern as TextareaControl: a local draft that adopts
129
+ // external updates only when we're not the one editing. In `live` mode
130
+ // we commit per keystroke (skip-history while typing, flush on blur);
131
+ // otherwise we commit once on blur/Enter.
132
+ const [draft, setDraft] = useState(value);
133
+ const editing = useRef(false);
134
+ useEffect(() => {
135
+ if (!editing.current)
136
+ setDraft(value);
137
+ }, [value]);
138
+ return (_jsx("input", { className: cn(FIELD_CLS, 'text-left cursor-text', fluid && 'w-full flex-1 min-w-0'), style: fluid ? undefined : { width }, value: draft, onFocus: () => {
139
+ editing.current = true;
140
+ if (live)
141
+ onScrubStart?.();
142
+ }, onChange: (e) => {
143
+ setDraft(e.target.value);
144
+ if (live)
145
+ onChange(e.target.value, true); // live preview per keystroke
146
+ }, onBlur: () => {
147
+ editing.current = false;
148
+ if (live)
149
+ onScrubEnd?.();
150
+ else if (draft !== value)
151
+ onChange(draft);
152
+ }, onKeyDown: (e) => {
153
+ if (e.key === 'Enter')
154
+ e.target.blur();
155
+ if (e.key === 'Escape') {
156
+ editing.current = false;
157
+ setDraft(value);
158
+ e.target.blur();
159
+ }
160
+ }, spellCheck: false }));
161
+ }
162
+ export function SelectControl({ value, options, onChange, fluid, }) {
163
+ return (_jsx("select", { className: cn('h-6 bg-field hover:bg-field-hover rounded-md px-1 text-[11px] text-foreground/90 outline-none cursor-pointer transition-colors', fluid ? 'w-full flex-1 min-w-0' : 'max-w-[120px]'), value: value, onChange: (e) => onChange(e.target.value), children: options.map((o) => (_jsx("option", { value: o, children: o }, o))) }));
164
+ }
165
+ export function ToggleControl({ value, onChange, }) {
166
+ return (_jsx("button", { type: "button", role: "switch", "aria-checked": value, onClick: () => onChange(!value), className: cn('relative w-7 h-4 rounded-full transition-colors', value ? 'bg-primary' : 'bg-ring hover:bg-muted-foreground/40'), children: _jsx("span", { className: cn('absolute top-0.5 w-3 h-3 rounded-full transition-transform',
167
+ // The thumb must read on BOTH track states (it was
168
+ // background-on-border before: invisible in dark mode).
169
+ value
170
+ ? 'translate-x-3.5 bg-background'
171
+ : 'translate-x-0.5 bg-muted-foreground') }) }));
172
+ }
173
+ export function ColorControl({ value, onChange, fluid, onScrubStart, onScrubEnd, }) {
174
+ const [open, setOpen] = useState(false);
175
+ const swatchRef = useRef(null);
176
+ return (_jsxs("div", { className: cn('flex items-center gap-1', fluid && 'w-full min-w-0'), children: [_jsxs("button", { ref: swatchRef, type: "button", className: "relative w-[18px] h-[18px] rounded border border-border overflow-hidden cursor-pointer shrink-0", title: "Open color picker", "aria-label": "Open color picker", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [_jsx("span", { className: "absolute inset-0", style: {
177
+ background: 'repeating-conic-gradient(rgba(255,255,255,0.18) 0% 25%, transparent 0% 50%) 0 0 / 8px 8px',
178
+ } }), _jsx("span", { className: "absolute inset-0", style: { background: value } })] }), _jsx(TextControl, { value: value, onChange: (v) => onChange(v), width: 68, fluid: fluid }), open && swatchRef.current && (_jsx(ColorPickerPopover, { anchor: swatchRef.current, value: value, onChange: onChange, onClose: () => setOpen(false), onScrubStart: onScrubStart, onScrubEnd: onScrubEnd }))] }));
179
+ }
180
+ /** 9-dot anchor grid — the composite claiming x_anchor / y_anchor. */
181
+ export function AnchorGridControl({ x, y, onChange, }) {
182
+ const stops = [0, 0.5, 1];
183
+ return (_jsx("div", { className: "grid grid-cols-3 gap-px p-0.5 border border-border rounded", children: stops.flatMap((ay) => stops.map((ax) => {
184
+ const active = Math.abs(ax - x) < 0.01 && Math.abs(ay - y) < 0.01;
185
+ return (_jsx("button", { type: "button", className: "w-3.5 h-3.5 grid place-items-center group", onClick: () => onChange(ax, ay), "aria-label": `Anchor ${ax * 100}% ${ay * 100}%`, "aria-pressed": active, children: _jsx("span", { className: cn('w-1 h-1 rounded-full transition-colors', active
186
+ ? 'bg-primary scale-150'
187
+ : 'bg-muted-foreground/40 group-hover:bg-muted-foreground') }) }, `${ax}-${ay}`));
188
+ })) }));
189
+ }
190
+ /** Hydration-safe wrapper for values currently driven by keyframes. */
191
+ export function KeyframedChip() {
192
+ return (_jsx("span", { className: "text-[10px] italic text-muted-foreground/70 px-1", children: "keyframed" }));
193
+ }
194
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/controls/primitives.tsx"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kEAAkE;AAClE,6CAA6C;AAC7C,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,yBAAyB;AAEzB,YAAY,CAAC;;AAEb,OAAO,EACL,SAAS,EACT,MAAM,EACN,QAAQ,GAGT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;6DAE6D;AAC7D,MAAM,cAAc,GAClB,0IAA0I,CAAC;AAC7I,MAAM,eAAe,GACnB,oHAAoH,CAAC;AACvH,MAAM,SAAS,GACb,2LAA2L,CAAC;AA4B9L,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,GAAY,EAAE,GAAY,EAAU,EAAE,CAC9D,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;AAE3D,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,IAAY,EAAU,EAAE;IAClD,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;IACrB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACnC,CAAC,CAAC;AAEF;kEACkE;AAClE,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC,+DAA+D;AAC/D,MAAM,UAAU,OAAO,CAAC,EACtB,MAAM,EACN,KAAK,GAKN;IACC,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,qDAAqD,EACrD,KAAK,IAAI,uBAAuB,CACjC,YAEC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC/B,iBAEE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,EAAE,CACX,qIAAqI,EACrI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CACzB,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,gBACd,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,YAE/C,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IATlB,GAAG,CAUD,CACV,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED;;8DAE8D;AAC9D,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,GAAG,EACH,GAAG,EACH,IAAI,GAAG,CAAC,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,YAAY,EACZ,UAAU,GACS;IACnB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,MAAM,CAA+D,IAAI,CAAC,CAAC;IAE3F,MAAM,OAAO,GAAG,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAErE,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,MAAM,GAAG,CAAC,EAAQ,EAAE;QAC/C,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,GAAG,GAAG,GAAG,IAAI,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,CAAiC,EAAQ,EAAE;QAChE,8DAA8D;QAC9D,IAAI,QAAQ,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;YAAE,OAAO;QACvD,OAAO,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACxE,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,MAAM,aAAa,GAAG,CAAC,CAAiC,EAAQ,EAAE;QAChE,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;QAChC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC;YAAE,OAAO;QAC5C,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChB,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC;YAClB,YAAY,EAAE,EAAE,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,CAAiC,EAAQ,EAAE;QAC9D,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;YAChB,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,UAAU,EAAE,EAAE,CAAC;YACd,CAAC,CAAC,aAA6B,CAAC,IAAI,EAAE,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC;IACF,MAAM,UAAU,GAAG;QACjB,aAAa;QACb,aAAa;QACb,WAAW;KACZ,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,GAAW,EAAQ,EAAE;QACvC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,IAAI,QAAQ,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,CACZ,gBACE,SAAS,EAAE,EAAE,CACX,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,EACvC,CAAC,SAAS,IAAI,KAAK,IAAI,uBAAuB,EAC9C,gDAAgD,CACjD,EACD,KAAK,EAAE,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,EAC5D,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;YACd,wDAAwD;YACxD,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpE,CAAC,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EACpE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC1D,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO;gBAAG,CAAC,CAAC,MAA2B,CAAC,IAAI,EAAE,CAAC;YAC7D,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,CAAC;gBACb,CAAC,CAAC,MAA2B,CAAC,IAAI,EAAE,CAAC;YACxC,CAAC;YACD,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;gBACjD,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC,KACG,UAAU,EACd,SAAS,EAAC,SAAS,EACnB,UAAU,EAAE,KAAK,GACjB,CACH,CAAC;IACF,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,CACX,gBACE,SAAS,EAAE,EAAE,CACX,cAAc;QACd,2DAA2D;QAC3D,2DAA2D;QAC3D,iDAAiD;QACjD,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,gBAAgB,CACtE,EACD,KAAK,EAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,aAE3D,MAAM,IAAI,CACT,eACE,SAAS,EAAC,oHAAoH,KAC1H,UAAU,YAEb,MAAM,GACF,CACR,EACA,KAAK,EAEL,MAAM,IAAI,CACT,eAAM,SAAS,EAAC,2DAA2D,YACxE,MAAM,GACF,CACR,EAEA,QAAQ,IAAI,eAAM,SAAS,EAAC,yCAAyC,YAAE,QAAQ,GAAQ,IACnF,CACR,CAAC;IACF,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CACL,gBACE,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,uBAAuB,CAAC,EAC1E,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,aAEhD,IAAI,EACL,KAAC,OAAO,IAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAI,IACpC,CACR,CAAC;AACJ,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,IAAI,GAAG,CAAC,EACR,MAAM,EACN,QAAQ,EACR,OAAO,EACP,KAAK,EACL,YAAY,EACZ,UAAU,GASX;IACC,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACrD,MAAM,KAAK,GAAG,GAAG,EAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,kEAAkE;IAClE,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAC,WAAW,IACV,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,EACnC,KAAK,EAAE,EAAE,EACT,KAAK,EAAE,KAAK,GACZ,CACH,CAAC;IACJ,CAAC;IACD,OAAO,CACL,KAAC,aAAa,IACZ,KAAK,EAAE,GAAG;QACV,oEAAoE;QACpE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAC/D,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,KAAK,GAAG,GAAG,EACX,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,UAAU,GAWX;IACC,wEAAwE;IACxE,uEAAuE;IACvE,sEAAsE;IACtE,0CAA0C;IAC1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACZ,OAAO,CACL,gBACE,SAAS,EAAE,EAAE,CACX,SAAS,EACT,uBAAuB,EACvB,KAAK,IAAI,uBAAuB,CACjC,EACD,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EACpC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;YACvB,IAAI,IAAI;gBAAE,YAAY,EAAE,EAAE,CAAC;QAC7B,CAAC,EACD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;YACd,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,IAAI;gBAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,6BAA6B;QACzE,CAAC,EACD,MAAM,EAAE,GAAG,EAAE;YACX,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;YACxB,IAAI,IAAI;gBAAE,UAAU,EAAE,EAAE,CAAC;iBACpB,IAAI,KAAK,KAAK,KAAK;gBAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC,EACD,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO;gBAAG,CAAC,CAAC,MAA2B,CAAC,IAAI,EAAE,CAAC;YAC7D,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACvB,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;gBACxB,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACf,CAAC,CAAC,MAA2B,CAAC,IAAI,EAAE,CAAC;YACxC,CAAC;QACH,CAAC,EACD,UAAU,EAAE,KAAK,GACjB,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,EACP,QAAQ,EACR,KAAK,GAMN;IACC,OAAO,CACL,iBACE,SAAS,EAAE,EAAE,CACX,gIAAgI,EAChI,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,eAAe,CAClD,EACD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAiC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,YAExE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,iBAAgB,KAAK,EAAE,CAAC,YACrB,CAAC,IADS,CAAC,CAEL,CACV,CAAC,GACK,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,GAIT;IACC,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,kBACC,KAAK,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAC/B,SAAS,EAAE,EAAE,CACX,iDAAiD,EACjD,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,sCAAsC,CAC9D,YAED,eACE,SAAS,EAAE,EAAE,CACX,4DAA4D;YAC5D,mDAAmD;YACnD,wDAAwD;YACxD,KAAK;gBACH,CAAC,CAAC,+BAA+B;gBACjC,CAAC,CAAC,qCAAqC,CAC1C,GACD,GACK,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,UAAU,GAOX;IACC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAClD,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,gBAAgB,CAAC,aACtE,kBACE,GAAG,EAAE,SAAS,EACd,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,iGAAiG,EAC3G,KAAK,EAAC,mBAAmB,gBACd,mBAAmB,mBACf,IAAI,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAGjC,eACE,SAAS,EAAC,kBAAkB,EAC5B,KAAK,EAAE;4BACL,UAAU,EACR,2FAA2F;yBAC9F,GACD,EACF,eAAM,SAAS,EAAC,kBAAkB,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,GAAI,IAC5D,EACT,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC5B,KAAK,EAAE,EAAE,EACT,KAAK,EAAE,KAAK,GACZ,EACD,IAAI,IAAI,SAAS,CAAC,OAAO,IAAI,CAC5B,KAAC,kBAAkB,IACjB,MAAM,EAAE,SAAS,CAAC,OAAO,EACzB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAC7B,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,UAAU,GACtB,CACH,IACG,CACP,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,EAChC,CAAC,EACD,CAAC,EACD,QAAQ,GAKT;IACC,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IAC1B,OAAO,CACL,cAAK,SAAS,EAAC,4DAA4D,YACxE,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CACpB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YACf,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;YAClE,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,2CAA2C,EACrD,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,gBACnB,UAAU,EAAE,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,GAAG,kBAChC,MAAM,YAEpB,eACE,SAAS,EAAE,EAAE,CACX,wCAAwC,EACxC,MAAM;wBACJ,CAAC,CAAC,sBAAsB;wBACxB,CAAC,CAAC,wDAAwD,CAC7D,GACD,IAdG,GAAG,EAAE,IAAI,EAAE,EAAE,CAeX,CACV,CAAC;QACJ,CAAC,CAAC,CACH,GACG,CACP,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,aAAa;IAC3B,OAAO,CACL,eAAM,SAAS,EAAC,kDAAkD,0BAE3D,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transcribe.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcribe.worker.d.ts","sourceRoot":"","sources":["../../src/controls/transcribe.worker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ // Transcription Web Worker — runs Whisper (Transformers.js) OFF the main thread
2
+ // so the editor UI stays responsive during inference. The main thread decodes
3
+ // the audio (WebAudio) and transfers the PCM samples here (zero-copy); we run
4
+ // the model and post the transcript back.
5
+ //
6
+ // Bundlers (webpack/Next) pick this up via `new Worker(new URL('./transcribe.
7
+ // worker.js', import.meta.url), { type: 'module' })` — see CaptionTranscribe.
8
+ import { transcribe } from '@clipkit/speech-to-text';
9
+ // `self` typed loosely to avoid pulling the webworker lib into the editor's
10
+ // DOM-typed project (the two libs conflict on shared globals).
11
+ const ctx = self;
12
+ ctx.onmessage = async (e) => {
13
+ const { samples, sampleRate, model } = e.data;
14
+ try {
15
+ const result = await transcribe({ samples, sampleRate }, { model, onProgress: (info) => ctx.postMessage({ type: 'progress', info }) });
16
+ ctx.postMessage({ type: 'result', result });
17
+ }
18
+ catch (err) {
19
+ ctx.postMessage({ type: 'error', message: err instanceof Error ? err.message : String(err) });
20
+ }
21
+ };
22
+ //# sourceMappingURL=transcribe.worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcribe.worker.js","sourceRoot":"","sources":["../../src/controls/transcribe.worker.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,0CAA0C;AAC1C,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,4EAA4E;AAC5E,+DAA+D;AAC/D,MAAM,GAAG,GAAG,IAGX,CAAC;AAQF,GAAG,CAAC,SAAS,GAAG,KAAK,EAAE,CAAe,EAAiB,EAAE;IACvD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,IAAe,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,EAAE,OAAO,EAAE,UAAU,EAAE,EACvB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAC7E,CAAC;QACF,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function AddElementBar(): import("react").JSX.Element;
2
+ //# sourceMappingURL=AddElementBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddElementBar.d.ts","sourceRoot":"","sources":["../../src/frame/AddElementBar.tsx"],"names":[],"mappings":"AAkDA,wBAAgB,aAAa,gCAwF5B"}
@@ -0,0 +1,103 @@
1
+ // Add-element bar — a floating, vertical toolbar centered on the LEFT of the
2
+ // stage.
3
+ //
4
+ // Tools: Select (click / marquee) and Hand (drag to pan) — the active one is
5
+ // highlighted. Below the divider: one button per element type you can add.
6
+ // Visual primitives add at the playhead; media (image / video / music) open a
7
+ // file picker and import through the AssetStore.
8
+ //
9
+ // Styling mirrors the stage's floating clusters: `bg-background/90 backdrop-blur
10
+ // border border-border rounded-md`, shadcn tokens, the editor `cn` helper.
11
+ 'use client';
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { useCallback, useRef } from 'react';
14
+ import { useEditor, useEditorContext, useEditorStore } from '@clipkit/editor-core';
15
+ import { cn } from '../lib/utils.js';
16
+ // ── icons (inline, currentColor, lucide-flavored 24-grid) ────────────────────
17
+ const ic = 'shrink-0';
18
+ const Cursor = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: cn(ic, 'size-4'), children: _jsx("path", { d: "M6.75 5.97a1.12 1.12 0 0 1 1.81-.89l10.13 7.88c.85.66.38 2.01-.69 2.01h-5.14c-.38 0-.73.17-.97.47l-3.14 3.97c-.66.84-2.01.37-2.01-.7z" }) }));
19
+ const sk = { fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round' };
20
+ const Hand = () => _jsx("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: _jsx("path", { d: "M7 11V6.5a1.5 1.5 0 0 1 3 0V11m0-.5V5a1.5 1.5 0 0 1 3 0v6m0-.5V6a1.5 1.5 0 0 1 3 0v6.5m0-2.5a1.5 1.5 0 0 1 3 0V15a5 5 0 0 1-5 5h-1.5a5 5 0 0 1-4-2L7 14.5c-.8-1-.3-2 .8-2.2L10 12" }) });
21
+ const Square = () => _jsx("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: _jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2.5" }) });
22
+ const TypeI = () => _jsx("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: _jsx("path", { d: "M5 6.5V5h14v1.5M12 5v14M9 19h6" }) });
23
+ const ImageI = () => _jsxs("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: [_jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2.5" }), _jsx("circle", { cx: "8.5", cy: "9.5", r: "1.5" }), _jsx("path", { d: "m4 18 5-5 4 4 3-3 4 4" })] });
24
+ const VideoI = () => _jsxs("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: [_jsx("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2.5" }), _jsx("path", { d: "M10 9.5v5l4-2.5z" })] });
25
+ const MusicI = () => _jsxs("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: [_jsx("path", { d: "M9 18V7l10-2v9" }), _jsx("circle", { cx: "6.5", cy: "18", r: "2.5" }), _jsx("circle", { cx: "16.5", cy: "16", r: "2.5" })] });
26
+ const CaptionI = () => _jsxs("svg", { viewBox: "0 0 24 24", ...sk, className: cn(ic, 'size-4'), children: [_jsx("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2.5" }), _jsx("path", { d: "M7 11h4M7 14h7M14 11h3" })] });
27
+ const TOOLS = [
28
+ { kind: 'shape', label: 'Shape', Icon: Square },
29
+ { kind: 'text', label: 'Text', Icon: TypeI },
30
+ { kind: 'caption', label: 'Captions', Icon: CaptionI },
31
+ { kind: 'image', label: 'Image', Icon: ImageI, media: 'image' },
32
+ { kind: 'video', label: 'Video', Icon: VideoI, media: 'video' },
33
+ { kind: 'audio', label: 'Music', Icon: MusicI, media: 'audio' },
34
+ ];
35
+ const FILL = '#6366f1';
36
+ const num = (v, d) => (typeof v === 'number' && Number.isFinite(v) ? v : d);
37
+ let addCounter = 0;
38
+ const uid = (k) => `${k}-${(addCounter++).toString(36)}`;
39
+ const iconBtn = 'flex items-center justify-center w-7 h-7 rounded-sm text-muted-foreground transition-colors hover:text-foreground hover:bg-accent';
40
+ const activeBtn = 'flex items-center justify-center w-7 h-7 rounded-sm bg-primary text-primary-foreground transition-colors';
41
+ export function AddElementBar() {
42
+ const { addElement, setUiState } = useEditor();
43
+ const { assetStore } = useEditorContext();
44
+ const tool = useEditorStore((s) => s.ui.tool);
45
+ const playhead = useEditorStore((s) => s.playback.time);
46
+ const elements = useEditorStore((s) => s.source.elements);
47
+ const compW = useEditorStore((s) => num(s.source.width, 1920));
48
+ const compH = useEditorStore((s) => num(s.source.height, 1080));
49
+ const fileRef = useRef(null);
50
+ const pendingMedia = useRef('image');
51
+ const ctx = () => {
52
+ const time = Math.max(0, playhead);
53
+ // layer is assigned on add — the store places new elements on top (layer 1).
54
+ return { time, layer: 1, cx: compW / 2, cy: compH / 2 };
55
+ };
56
+ const center = { x_anchor: '50%', y_anchor: '50%' };
57
+ const addByKind = useCallback((kind) => {
58
+ const c = ctx();
59
+ let el = null;
60
+ if (kind === 'shape') {
61
+ el = { id: uid('shape'), name: 'Shape', type: 'shape', shape: 'rectangle', x: c.cx, y: c.cy, ...center, width: 400, height: 280, fill_color: FILL, border_radius: 8, time: c.time, duration: 3, layer: c.layer };
62
+ }
63
+ else if (kind === 'text') {
64
+ el = { id: uid('text'), name: 'Text', type: 'text', text: 'Text', x: c.cx, y: c.cy, ...center, width: 600, height: 160, font_family: 'Inter', font_size: 'auto', font_weight: 700, fill_color: '#ffffff', text_align: 'center', time: c.time, duration: 3, layer: c.layer };
65
+ }
66
+ else if (kind === 'caption') {
67
+ // A starter caption with an explicit box (like text) — transcribe a source
68
+ // in the inspector to fill the words, or edit them by hand.
69
+ el = { id: uid('caption'), name: 'Captions', type: 'caption', x: c.cx, y: c.cy, ...center, width: 900, height: 200, font_family: 'Inter', font_size: 72, font_weight: 800, fill_color: '#ffffff', text_align: 'center', style: 'tiktok_bounce', highlight_color: '#ffd60a', max_length: 16, words: [{ text: 'Caption', start: 0, end: 1 }], time: c.time, duration: 'auto', layer: c.layer };
70
+ }
71
+ if (el)
72
+ addElement(el);
73
+ }, [addElement, elements, playhead, compW, compH]);
74
+ const pickMedia = useCallback((media) => {
75
+ pendingMedia.current = media;
76
+ const input = fileRef.current;
77
+ if (!input)
78
+ return;
79
+ input.accept = media === 'image' ? 'image/*' : media === 'video' ? 'video/*' : 'audio/*';
80
+ input.click();
81
+ }, []);
82
+ const onFile = useCallback(async (e) => {
83
+ const file = e.target.files?.[0];
84
+ e.target.value = '';
85
+ if (!file)
86
+ return;
87
+ const asset = await assetStore.upload(file);
88
+ const c = ctx();
89
+ const media = pendingMedia.current;
90
+ let el;
91
+ if (media === 'audio') {
92
+ el = { id: uid('audio'), name: asset.name, type: 'audio', source: asset.url, duration: asset.duration ?? 5, volume: 100, time: c.time, layer: c.layer };
93
+ }
94
+ else {
95
+ const iw = num(asset.width, compW), ih = num(asset.height, compH);
96
+ const scale = Math.min(1, compW / iw, compH / ih);
97
+ el = { id: uid(media), name: asset.name, type: media, source: asset.url, x: c.cx, y: c.cy, ...center, width: Math.round(iw * scale), height: Math.round(ih * scale), duration: media === 'video' ? asset.duration ?? 5 : 3, time: c.time, layer: c.layer };
98
+ }
99
+ addElement(el);
100
+ }, [assetStore, addElement, playhead, compW, compH, elements]);
101
+ return (_jsxs("div", { className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 flex flex-col items-center gap-1 bg-background/90 backdrop-blur-sm border border-border rounded-md p-1", children: [_jsx("button", { type: "button", title: "Select (click / marquee)", "aria-pressed": tool === 'select', onClick: () => setUiState({ tool: 'select' }), className: tool === 'select' ? activeBtn : iconBtn, children: _jsx(Cursor, {}) }), _jsx("button", { type: "button", title: "Hand (drag to pan)", "aria-pressed": tool === 'hand', onClick: () => setUiState({ tool: 'hand' }), className: tool === 'hand' ? activeBtn : iconBtn, children: _jsx(Hand, {}) }), _jsx("div", { className: "h-px w-5 bg-border my-0.5", "aria-orientation": "horizontal" }), TOOLS.map((t) => (_jsx("button", { type: "button", title: `Add ${t.label.toLowerCase()}`, onClick: () => (t.media ? pickMedia(t.media) : addByKind(t.kind)), className: iconBtn, children: _jsx(t.Icon, {}) }, t.kind))), _jsx("input", { ref: fileRef, type: "file", hidden: true, onChange: onFile })] }));
102
+ }
103
+ //# sourceMappingURL=AddElementBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddElementBar.js","sourceRoot":"","sources":["../../src/frame/AddElementBar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function Breadcrumbs(): import("react").JSX.Element | null;
2
+ //# sourceMappingURL=Breadcrumbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../src/frame/Breadcrumbs.tsx"],"names":[],"mappings":"AAYA,wBAAgB,WAAW,uCA6C1B"}
@@ -0,0 +1,32 @@
1
+ // Group drill-down breadcrumbs — a floating box on the stage's bottom-LEFT
2
+ // (mirrors the zoom box on the bottom-right). Shows the path into nested groups,
3
+ // e.g. "Composition › Group". Click any crumb to pop back out to that level.
4
+ // Only renders while inside a group.
5
+ 'use client';
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { useEffect } from 'react';
8
+ import { resolveGroupPath, useEditor, useEditorStore } from '@clipkit/editor-core';
9
+ import { cn } from '../lib/utils.js';
10
+ export function Breadcrumbs() {
11
+ const groupPath = useEditorStore((s) => s.ui.groupPath);
12
+ const elements = useEditorStore((s) => s.source.elements);
13
+ const groupFlashId = useEditorStore((s) => s.ui.groupFlashId);
14
+ const { setUiState, clearSelection } = useEditor();
15
+ // On entering a group, flash this control's border, then clear the flag.
16
+ useEffect(() => {
17
+ if (!groupFlashId)
18
+ return;
19
+ const t = setTimeout(() => setUiState({ groupFlashId: null }), 1000);
20
+ return () => clearTimeout(t);
21
+ }, [groupFlashId, setUiState]);
22
+ if (groupPath.length === 0)
23
+ return null;
24
+ const { crumbs } = resolveGroupPath(elements, groupPath);
25
+ const go = (depth) => {
26
+ setUiState({ groupPath: groupPath.slice(0, depth) });
27
+ clearSelection();
28
+ };
29
+ const label = (g) => (typeof g.name === 'string' && g.name) || (typeof g.id === 'string' ? g.id : 'Group');
30
+ return (_jsxs("div", { style: groupFlashId ? { animation: 'clipkit-crumb-flash 1s ease-out' } : undefined, className: "flex items-center gap-1 h-7 px-2 bg-background/90 backdrop-blur-sm border border-border rounded-md text-[11px]", children: [_jsx("button", { type: "button", onClick: () => go(0), className: "text-muted-foreground hover:text-foreground transition-colors", children: "Composition" }), crumbs.map((g, i) => (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx("span", { className: "text-muted-foreground/50", children: "\u203A" }), _jsx("button", { type: "button", onClick: () => go(i + 1), className: cn('transition-colors', i === crumbs.length - 1 ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground'), children: label(g) })] }, typeof g.id === 'string' ? g.id : i)))] }, groupFlashId ?? 'crumbs'));
31
+ }
32
+ //# sourceMappingURL=Breadcrumbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../../src/frame/Breadcrumbs.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function GroupFlash(): import("react").JSX.Element | null;
2
+ //# sourceMappingURL=GroupFlash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupFlash.d.ts","sourceRoot":"","sources":["../../src/frame/GroupFlash.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,UAAU,uCA6CzB"}
@@ -0,0 +1,65 @@
1
+ // GroupFlash — a transient, over-emphasized outline around a group's content on
2
+ // the stage, shown briefly when you ENTER the group (so you can see where it is).
3
+ // Reads `ui.groupFlashId`, draws a fading box around the union of the group's
4
+ // children, and clears the flag once the animation finishes. Never permanent.
5
+ 'use client';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ import { useEffect } from 'react';
8
+ import { elementSourceBox, useEditor, useEditorStore } from '@clipkit/editor-core';
9
+ function findGroup(els, id) {
10
+ for (const e of els) {
11
+ if (e.id === id && e.type === 'group')
12
+ return e;
13
+ if (e.type === 'group') {
14
+ const nested = e.elements;
15
+ if (Array.isArray(nested)) {
16
+ const r = findGroup(nested, id);
17
+ if (r)
18
+ return r;
19
+ }
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ export function GroupFlash() {
25
+ const flashId = useEditorStore((s) => s.ui.groupFlashId);
26
+ const source = useEditorStore((s) => s.source);
27
+ const pan = useEditorStore((s) => s.ui.stagePan);
28
+ const zoom = useEditorStore((s) => s.ui.stageZoom);
29
+ const time = useEditorStore((s) => s.playback.time);
30
+ const { setUiState } = useEditor();
31
+ useEffect(() => {
32
+ if (!flashId)
33
+ return;
34
+ const t = setTimeout(() => setUiState({ groupFlashId: null }), 1100);
35
+ return () => clearTimeout(t);
36
+ }, [flashId, setUiState]);
37
+ if (!flashId)
38
+ return null;
39
+ const group = findGroup(source.elements, flashId);
40
+ const children = group && Array.isArray(group.elements) ? group.elements : null;
41
+ if (!children)
42
+ return null;
43
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
44
+ for (const c of children) {
45
+ const b = elementSourceBox(c, source, { time });
46
+ if (!b)
47
+ continue;
48
+ minX = Math.min(minX, b.x);
49
+ minY = Math.min(minY, b.y);
50
+ maxX = Math.max(maxX, b.x + b.w);
51
+ maxY = Math.max(maxY, b.y + b.h);
52
+ }
53
+ if (!Number.isFinite(minX))
54
+ return null;
55
+ const pad = 10;
56
+ return (_jsx("div", { className: "absolute pointer-events-none rounded-md border-2 border-foreground", style: {
57
+ left: pan.x + minX * zoom - pad,
58
+ top: pan.y + minY * zoom - pad,
59
+ width: (maxX - minX) * zoom + pad * 2,
60
+ height: (maxY - minY) * zoom + pad * 2,
61
+ animation: 'clipkit-group-flash 1.1s ease-out forwards',
62
+ zIndex: 20,
63
+ } }, flashId));
64
+ }
65
+ //# sourceMappingURL=GroupFlash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupFlash.js","sourceRoot":"","sources":["../../src/frame/GroupFlash.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ /** Which panel edge this gutter drags. */
3
+ direction: 'left' | 'right' | 'bottom';
4
+ /** Current size (width for left/right, height for bottom), px. */
5
+ size: number;
6
+ min: number;
7
+ max: number;
8
+ onResize: (next: number) => void;
9
+ }
10
+ export declare function PanelGutter({ direction, size, min, max, onResize }: Props): import("react").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=Resizable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Resizable.d.ts","sourceRoot":"","sources":["../../src/frame/Resizable.tsx"],"names":[],"mappings":"AASA,UAAU,KAAK;IACb,0CAA0C;IAC1C,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvC,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,KAAK,+BAsDzE"}
@@ -0,0 +1,37 @@
1
+ // Resizable panel gutter — a 1px hairline that grows a hit area on
2
+ // hover and drags a panel dimension. Flat per the design refs: no
3
+ // visible chrome until hovered.
4
+ 'use client';
5
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
+ import { useRef } from 'react';
7
+ import { cn } from './../lib/utils.js';
8
+ export function PanelGutter({ direction, size, min, max, onResize }) {
9
+ const startRef = useRef(0);
10
+ const sizeRef = useRef(size);
11
+ sizeRef.current = size;
12
+ const horizontal = direction === 'bottom';
13
+ const onMouseDown = (e) => {
14
+ if (e.button !== 0)
15
+ return;
16
+ e.preventDefault();
17
+ startRef.current = horizontal ? e.clientY : e.clientX;
18
+ const startSize = sizeRef.current;
19
+ const onMove = (ev) => {
20
+ const delta = (horizontal ? ev.clientY : ev.clientX) - startRef.current;
21
+ // Left panel grows rightward; right panel + bottom grow toward
22
+ // the center, i.e. against the cursor delta.
23
+ const signed = direction === 'left' ? delta : -delta;
24
+ onResize(Math.max(min, Math.min(max, startSize + signed)));
25
+ };
26
+ const onUp = () => {
27
+ window.removeEventListener('mousemove', onMove);
28
+ window.removeEventListener('mouseup', onUp);
29
+ document.body.style.cursor = '';
30
+ };
31
+ document.body.style.cursor = horizontal ? 'row-resize' : 'col-resize';
32
+ window.addEventListener('mousemove', onMove);
33
+ window.addEventListener('mouseup', onUp);
34
+ };
35
+ return (_jsxs("div", { className: cn('relative shrink-0 group/gutter z-10', horizontal ? 'h-px w-full cursor-row-resize' : 'w-px h-full cursor-col-resize'), onMouseDown: onMouseDown, role: "separator", "aria-orientation": horizontal ? 'horizontal' : 'vertical', children: [_jsx("div", { className: cn('absolute bg-border transition-colors group-hover/gutter:bg-primary/40', horizontal ? 'inset-x-0 top-0 h-px' : 'inset-y-0 left-0 w-px') }), _jsx("div", { className: cn('absolute', horizontal ? '-top-1.5 -bottom-1.5 inset-x-0' : '-left-1.5 -right-1.5 inset-y-0') })] }));
36
+ }
37
+ //# sourceMappingURL=Resizable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Resizable.js","sourceRoot":"","sources":["../../src/frame/Resizable.tsx"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,kEAAkE;AAClE,gCAAgC;AAEhC,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,EAAsC,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAYvC,MAAM,UAAU,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAS;IACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAEvB,MAAM,UAAU,GAAG,SAAS,KAAK,QAAQ,CAAC;IAE1C,MAAM,WAAW,GAAG,CAAC,CAAkC,EAAQ,EAAE;QAC/D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC3B,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACtD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;QAClC,MAAM,MAAM,GAAG,CAAC,EAAc,EAAQ,EAAE;YACtC,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;YACxE,+DAA+D;YAC/D,6CAA6C;YAC7C,MAAM,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,GAAS,EAAE;YACtB,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC5C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;QAClC,CAAC,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACtE,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC,CAAC;IAEF,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,qCAAqC,EACrC,UAAU,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,+BAA+B,CAC/E,EACD,WAAW,EAAE,WAAW,EACxB,IAAI,EAAC,WAAW,sBACE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,aAExD,cACE,SAAS,EAAE,EAAE,CACX,uEAAuE,EACvE,UAAU,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,uBAAuB,CAC9D,GACD,EAEF,cACE,SAAS,EAAE,EAAE,CACX,UAAU,EACV,UAAU,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,gCAAgC,CACjF,GACD,IACE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type ReactNode } from 'react';
2
+ interface Props {
3
+ title: string;
4
+ /** Right-aligned header slot (a `+` add button, a toggle, …). */
5
+ action?: ReactNode;
6
+ defaultOpen?: boolean;
7
+ children?: ReactNode;
8
+ className?: string;
9
+ }
10
+ export declare function Section({ title, action, defaultOpen, children, className, }: Props): import("react").JSX.Element;
11
+ /** A label-left / value-right row inside a Section.
12
+ *
13
+ * THE GRID RHYTHM (ruled by Ian 2026-06-11): every row is 32px — a
14
+ * 24px well + 8px breathing room. The label column is FIXED (64px,
15
+ * matching the reference HTML) and the value area is FLUID — controls
16
+ * stretch to fill it, so every well's left and right edges align
17
+ * panel-wide regardless of panel width. */
18
+ export declare function FieldRow({ label, children, }: {
19
+ label: string;
20
+ children?: ReactNode;
21
+ }): import("react").JSX.Element;
22
+ export {};
23
+ //# sourceMappingURL=Section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Section.d.ts","sourceRoot":"","sources":["../../src/frame/Section.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,MAAM,EACN,WAAkB,EAClB,QAAQ,EACR,SAAS,GACV,EAAE,KAAK,+BA8BP;AAED;;;;;;2CAM2C;AAC3C,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,+BAUA"}