hyperframes 0.8.81 → 0.8.83

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 (61) hide show
  1. package/dist/backgroundChecksWorker.js +890 -0
  2. package/dist/cli.js +4272 -2792
  3. package/dist/commands/layout-audit.browser.js +55 -25
  4. package/dist/fontLocalizeCli.js +714 -344
  5. package/dist/hyperframe-runtime.js +83 -58
  6. package/dist/hyperframe.manifest.json +1 -1
  7. package/dist/hyperframe.runtime.iife.js +83 -58
  8. package/dist/hyperframes-player.global.js +3 -3
  9. package/dist/registry/localSemantic.js +7 -3
  10. package/dist/renderSetupWorker.js +62 -32
  11. package/dist/sherpaWorker.js +179 -0
  12. package/dist/skills/hyperframes/SKILL.md +2 -0
  13. package/dist/skills/hyperframes/references/plugin-installation.md +43 -0
  14. package/dist/skills/hyperframes/references/skill-lifecycle.md +2 -0
  15. package/dist/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
  16. package/dist/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
  17. package/dist/skills/hyperframes-cli/SKILL.md +2 -0
  18. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +1 -0
  19. package/dist/skills/media-use/SKILL.md +2 -0
  20. package/dist/skills/media-use/references/operations.md +7 -5
  21. package/dist/skills/media-use/references/setup-providers.md +9 -9
  22. package/dist/skills/media-use/registry/localSemantic.js +7 -3
  23. package/dist/skills/media-use/scripts/lib/ff-binaries.mjs +37 -0
  24. package/dist/skills/media-use/scripts/lib/probe.mjs +3 -1
  25. package/dist/skills/media-use/scripts/lib/probe.test.mjs +118 -1
  26. package/dist/skills/media-use/scripts/lib/tts-local-provider.mjs +5 -3
  27. package/dist/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
  28. package/dist/skills/media-use/scripts/resolve.mjs +45 -19
  29. package/dist/skills/media-use/scripts/transcribe.mjs +39 -25
  30. package/dist/skills/media-use/scripts/transcribe.test.mjs +112 -0
  31. package/dist/skills/registry/localSemantic.js +7 -3
  32. package/dist/studio/assets/{hyperframes-player-C68UawR3.js → hyperframes-player-BAerMCex.js} +1 -1
  33. package/dist/studio/assets/{index-CMzPGv9P.js → index-BUhcVhNy.js} +1 -1
  34. package/dist/studio/assets/{index-hNVM9Pd2.js → index-BYhK_KMc.js} +187 -187
  35. package/dist/studio/assets/{index-CS5SImRT.js → index-Iv0HI7eM.js} +1 -1
  36. package/dist/studio/{chunk-I7XNAIOF.js → chunk-3IOCVWB6.js} +6 -97
  37. package/dist/studio/chunk-3IOCVWB6.js.map +1 -0
  38. package/dist/studio/chunk-62DDWOSH.js +189 -0
  39. package/dist/studio/chunk-62DDWOSH.js.map +1 -0
  40. package/dist/studio/chunk-LPZMAGS7.js +1871 -0
  41. package/dist/studio/chunk-LPZMAGS7.js.map +1 -0
  42. package/dist/studio/chunk-QZ6HNNFG.js +934 -0
  43. package/dist/studio/chunk-QZ6HNNFG.js.map +1 -0
  44. package/dist/studio/chunk-S65AQH6M.js +101 -0
  45. package/dist/studio/chunk-S65AQH6M.js.map +1 -0
  46. package/dist/studio/{domEditingLayers-MHFDKAQ7.js → domEditingLayers-ZOOMN7CQ.js} +3 -2
  47. package/dist/studio/index.d.ts +834 -330
  48. package/dist/studio/index.html +1 -1
  49. package/dist/studio/index.js +26378 -28802
  50. package/dist/studio/index.js.map +1 -1
  51. package/dist/studio/player.d.ts +30 -0
  52. package/dist/studio/player.js +10 -0
  53. package/dist/studio/player.js.map +1 -0
  54. package/dist/studio/ui.d.ts +294 -0
  55. package/dist/studio/ui.js +66 -0
  56. package/dist/studio/ui.js.map +1 -0
  57. package/dist/templates/_shared/AGENTS.md +5 -1
  58. package/dist/templates/_shared/CLAUDE.md +5 -1
  59. package/package.json +1 -1
  60. package/dist/studio/chunk-I7XNAIOF.js.map +0 -1
  61. /package/dist/studio/{domEditingLayers-MHFDKAQ7.js.map → domEditingLayers-ZOOMN7CQ.js.map} +0 -0
@@ -0,0 +1,934 @@
1
+ // src/components/ui/cn.ts
2
+ import { createCn } from "cn/config";
3
+ var isTypeStep = (value) => /^step-\d+$/.test(value);
4
+ var isControlSize = (value) => /^ctl(-sm|-lg)?$/.test(value);
5
+ var cn = createCn({
6
+ extend: {
7
+ classGroups: {
8
+ "font-size": [{ text: [isTypeStep] }],
9
+ h: [{ h: [isControlSize] }],
10
+ w: [{ w: [isControlSize] }],
11
+ size: [{ size: [isControlSize] }],
12
+ "min-h": [{ "min-h": [isControlSize] }],
13
+ "min-w": [{ "min-w": [isControlSize] }]
14
+ }
15
+ }
16
+ });
17
+
18
+ // src/components/ui/Button.tsx
19
+ import { forwardRef } from "react";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ var buttonBase = cn(
22
+ "inline-flex items-center justify-center select-none cursor-pointer whitespace-nowrap",
23
+ "transition-[background-color,border-color,color,filter,transform] ease-out-quint duration-press",
24
+ "disabled:opacity-40 disabled:cursor-not-allowed",
25
+ "outline-hidden",
26
+ "focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent",
27
+ "data-[preview-state=focus]:outline-solid data-[preview-state=focus]:outline-2 data-[preview-state=focus]:outline-offset-1 data-[preview-state=focus]:outline-accent"
28
+ );
29
+ var buttonVariants = {
30
+ primary: cn(
31
+ "bg-accent text-bg-0 font-semibold",
32
+ "enabled:hover:brightness-110 data-[preview-state=hover]:brightness-110",
33
+ "enabled:active:scale-[0.98] data-[preview-state=active]:scale-[0.98]"
34
+ ),
35
+ secondary: cn(
36
+ "bg-transparent text-text-1 font-medium border border-border-strong",
37
+ "enabled:hover:bg-hover enabled:hover:text-text-0 data-[preview-state=hover]:bg-hover data-[preview-state=hover]:text-text-0",
38
+ "enabled:active:scale-[0.98] data-[preview-state=active]:scale-[0.98]"
39
+ ),
40
+ danger: cn(
41
+ "bg-danger text-text-0 font-medium",
42
+ "enabled:hover:brightness-110 data-[preview-state=hover]:brightness-110",
43
+ "enabled:active:scale-[0.98] data-[preview-state=active]:scale-[0.98]"
44
+ ),
45
+ ghost: cn(
46
+ "bg-transparent text-text-2 font-medium",
47
+ "enabled:hover:bg-hover enabled:hover:text-text-0 data-[preview-state=hover]:bg-hover data-[preview-state=hover]:text-text-0",
48
+ "enabled:active:scale-[0.98] data-[preview-state=active]:scale-[0.98]"
49
+ )
50
+ };
51
+ var buttonSizes = {
52
+ sm: "h-ctl-sm px-2 gap-1 rounded-sm text-step-11",
53
+ md: "h-ctl px-3 gap-1.5 rounded-md text-step-12",
54
+ lg: "h-ctl-lg px-4 gap-2 rounded-md text-step-13"
55
+ };
56
+ function Spinner() {
57
+ return /* @__PURE__ */ jsxs("svg", { className: "animate-spin size-3.5", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
58
+ /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
59
+ /* @__PURE__ */ jsx(
60
+ "path",
61
+ {
62
+ className: "opacity-75",
63
+ fill: "currentColor",
64
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
65
+ }
66
+ )
67
+ ] });
68
+ }
69
+ var Button = forwardRef(
70
+ ({ variant = "secondary", size = "md", loading, icon, children, className, disabled, ...props }, ref) => {
71
+ const isDisabled = disabled || loading;
72
+ let leading = null;
73
+ if (loading) leading = /* @__PURE__ */ jsx(Spinner, {});
74
+ else if (icon) leading = /* @__PURE__ */ jsx("span", { className: "shrink-0", children: icon });
75
+ return /* @__PURE__ */ jsxs(
76
+ "button",
77
+ {
78
+ ref,
79
+ disabled: isDisabled,
80
+ "aria-disabled": isDisabled || void 0,
81
+ className: cn(buttonBase, buttonVariants[variant], buttonSizes[size], className),
82
+ ...props,
83
+ children: [
84
+ leading,
85
+ children
86
+ ]
87
+ }
88
+ );
89
+ }
90
+ );
91
+ Button.displayName = "Button";
92
+
93
+ // src/components/ui/IconButton.tsx
94
+ import { forwardRef as forwardRef2 } from "react";
95
+ import { jsx as jsx2 } from "react/jsx-runtime";
96
+ var iconSizeStyles = {
97
+ sm: "size-ctl-sm rounded-sm",
98
+ md: "size-ctl rounded-md",
99
+ lg: "size-ctl-lg rounded-md"
100
+ };
101
+ var IconButton = forwardRef2(
102
+ ({ icon, size = "md", variant = "ghost", className, disabled, ...props }, ref) => {
103
+ return /* @__PURE__ */ jsx2(
104
+ "button",
105
+ {
106
+ ref,
107
+ disabled,
108
+ "aria-disabled": disabled || void 0,
109
+ className: cn(buttonBase, buttonVariants[variant], iconSizeStyles[size], className),
110
+ ...props,
111
+ children: icon
112
+ }
113
+ );
114
+ }
115
+ );
116
+ IconButton.displayName = "IconButton";
117
+
118
+ // src/components/ui/Tabs.tsx
119
+ import { Tabs as BaseTabs } from "@base-ui/react/tabs";
120
+ import { jsx as jsx3 } from "react/jsx-runtime";
121
+ function Tabs(props) {
122
+ return /* @__PURE__ */ jsx3(BaseTabs.Root, { ...props });
123
+ }
124
+ function TabsList({ className, ...props }) {
125
+ return /* @__PURE__ */ jsx3(
126
+ BaseTabs.List,
127
+ {
128
+ activateOnFocus: true,
129
+ className: cn("inline-flex items-center gap-0.5 rounded-lg bg-surface-alt p-1", className),
130
+ ...props
131
+ }
132
+ );
133
+ }
134
+ function Tab({ value, className, ...props }) {
135
+ return /* @__PURE__ */ jsx3(
136
+ BaseTabs.Tab,
137
+ {
138
+ value,
139
+ "data-tab-id": value,
140
+ className: cn(
141
+ "inline-flex h-ctl-sm cursor-pointer select-none items-center justify-center rounded-sm px-2.5",
142
+ "text-step-11 font-semibold whitespace-nowrap text-text-3",
143
+ "transition-[background-color,color] ease-out-quint duration-hover",
144
+ "hover:text-text-1 data-[preview-state=hover]:text-text-1",
145
+ "aria-selected:bg-hover aria-selected:text-text-0",
146
+ "outline-hidden focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent",
147
+ "data-[preview-state=focus]:outline-solid data-[preview-state=focus]:outline-2 data-[preview-state=focus]:outline-offset-1 data-[preview-state=focus]:outline-accent",
148
+ className
149
+ ),
150
+ ...props
151
+ }
152
+ );
153
+ }
154
+ function TabPanel({ className, ...props }) {
155
+ return /* @__PURE__ */ jsx3(BaseTabs.Panel, { className: cn("outline-hidden", className), ...props });
156
+ }
157
+
158
+ // src/components/ui/HyperframesMark.tsx
159
+ import { useId } from "react";
160
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
161
+ function HyperframesMark({ viewBox = "0 0 100 100", ...props }) {
162
+ const gradientId = useId();
163
+ const leftGradient = `${gradientId}-left`;
164
+ const rightGradient = `${gradientId}-right`;
165
+ return /* @__PURE__ */ jsxs2(
166
+ "svg",
167
+ {
168
+ viewBox,
169
+ fill: "none",
170
+ xmlns: "http://www.w3.org/2000/svg",
171
+ "aria-hidden": "true",
172
+ ...props,
173
+ children: [
174
+ /* @__PURE__ */ jsx4("g", { transform: "translate(50 50)", opacity: ".92", children: /* @__PURE__ */ jsxs2("g", { transform: "translate(-50 -50)", children: [
175
+ /* @__PURE__ */ jsx4(
176
+ "path",
177
+ {
178
+ d: "M10.1851 57.8021L33.1145 73.8313C36.2202 75.9978 41.5173 73.5433 42.4816 69.4984L51.7611 30.4271C52.7253 26.3822 48.5802 23.9277 44.4602 26.0942L13.917 42.1235C6.96677 45.7676 4.97564 54.1579 10.1851 57.8021Z",
179
+ fill: `url(#${leftGradient})`
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsx4(
183
+ "path",
184
+ {
185
+ d: "M87.5129 57.5141L56.9696 73.5433C52.8371 75.7098 48.7046 73.2553 49.6688 69.2104L58.9483 30.1391C59.9125 26.0942 65.2097 23.6397 68.3154 25.8062L91.2447 41.8354C96.4668 45.4796 94.4631 53.8699 87.5129 57.5141Z",
186
+ fill: `url(#${rightGradient})`
187
+ }
188
+ )
189
+ ] }) }),
190
+ /* @__PURE__ */ jsxs2("defs", { children: [
191
+ /* @__PURE__ */ jsxs2(
192
+ "linearGradient",
193
+ {
194
+ id: leftGradient,
195
+ x1: "48.5676",
196
+ y1: "25",
197
+ x2: "44.7804",
198
+ y2: "71.9384",
199
+ gradientUnits: "userSpaceOnUse",
200
+ children: [
201
+ /* @__PURE__ */ jsx4("stop", { stopColor: "#06E3FA" }),
202
+ /* @__PURE__ */ jsx4("stop", { offset: "1", stopColor: "#4FDB5E" })
203
+ ]
204
+ }
205
+ ),
206
+ /* @__PURE__ */ jsxs2(
207
+ "linearGradient",
208
+ {
209
+ id: rightGradient,
210
+ x1: "54.8282",
211
+ y1: "73.8392",
212
+ x2: "72.0989",
213
+ y2: "32.8932",
214
+ gradientUnits: "userSpaceOnUse",
215
+ children: [
216
+ /* @__PURE__ */ jsx4("stop", { stopColor: "#06E3FA" }),
217
+ /* @__PURE__ */ jsx4("stop", { offset: "1", stopColor: "#4FDB5E" })
218
+ ]
219
+ }
220
+ )
221
+ ] })
222
+ ]
223
+ }
224
+ );
225
+ }
226
+
227
+ // src/components/ui/HyperframesLoader.tsx
228
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
229
+ function HyperframesLoader({
230
+ title,
231
+ detail,
232
+ mono,
233
+ size = 64,
234
+ progress
235
+ }) {
236
+ const boundedProgress = typeof progress === "number" && Number.isFinite(progress) ? Math.min(1, Math.max(0, progress)) : void 0;
237
+ const markFrameSize = Math.round(size * 1.16);
238
+ return /* @__PURE__ */ jsxs3("div", { className: "hf-loader", role: "status", draggable: false, children: [
239
+ /* @__PURE__ */ jsx5(
240
+ "div",
241
+ {
242
+ className: "hf-loader-mark-frame",
243
+ style: { width: markFrameSize, height: markFrameSize },
244
+ draggable: false,
245
+ children: /* @__PURE__ */ jsx5(HyperframesMark, { className: "hf-loader-mark", width: size, height: size })
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsx5("div", { className: "hf-loader-title", children: title }),
249
+ detail && /* @__PURE__ */ jsx5("div", { className: "hf-loader-detail", children: detail }),
250
+ boundedProgress !== void 0 && /* @__PURE__ */ jsx5(
251
+ "div",
252
+ {
253
+ className: "hf-loader-progress",
254
+ role: "progressbar",
255
+ "aria-valuemin": 0,
256
+ "aria-valuemax": 100,
257
+ "aria-valuenow": Math.round(boundedProgress * 100),
258
+ children: /* @__PURE__ */ jsx5(
259
+ "div",
260
+ {
261
+ className: "hf-loader-progress__fill",
262
+ style: { transform: `scaleX(${boundedProgress})` }
263
+ }
264
+ )
265
+ }
266
+ ),
267
+ mono && /* @__PURE__ */ jsx5("div", { className: "hf-loader-mono", children: mono })
268
+ ] });
269
+ }
270
+
271
+ // src/components/ui/Menu.tsx
272
+ import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
273
+ import { Menu as BaseMenu } from "@base-ui/react/menu";
274
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
275
+ var SIDE_OFFSET = 6;
276
+ var VIEWPORT_MARGIN = 8;
277
+ function floatingMotion(openDuration) {
278
+ return cn(
279
+ "origin-[var(--transform-origin)] outline-hidden",
280
+ "transition-[opacity,transform] ease-out-quint",
281
+ openDuration,
282
+ "data-[ending-style]:duration-close data-[ending-style]:ease-in",
283
+ "data-[starting-style]:[opacity:var(--popup-enter-opacity)]",
284
+ "data-[starting-style]:[scale:var(--popup-enter-scale)]",
285
+ "data-[ending-style]:opacity-0"
286
+ );
287
+ }
288
+ var popupSurface = cn(
289
+ "rounded-lg border border-border-input bg-surface",
290
+ floatingMotion("duration-open"),
291
+ "data-[preview-state=open]:opacity-100 data-[preview-state=open]:scale-100"
292
+ );
293
+ var POPUP_LAYER = "z-200";
294
+ var menuPopup = cn(popupSurface, "min-w-36 p-1 shadow-menu");
295
+ var itemBase = cn(
296
+ "flex cursor-default select-none items-center justify-between gap-6 rounded-sm px-2 py-1.5",
297
+ "text-step-11 whitespace-nowrap text-text-1",
298
+ "outline-hidden transition-colors ease-out-quint duration-hover",
299
+ "data-[highlighted]:bg-hover data-[highlighted]:text-text-0",
300
+ "data-[preview-state=hover]:bg-hover data-[preview-state=hover]:text-text-0",
301
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-40"
302
+ );
303
+ var itemDanger = cn("text-danger data-[highlighted]:bg-danger/15 data-[highlighted]:text-danger");
304
+ function Menu({
305
+ trigger,
306
+ children,
307
+ side = "bottom",
308
+ align = "start",
309
+ sideOffset = SIDE_OFFSET,
310
+ container,
311
+ className,
312
+ "aria-label": ariaLabel,
313
+ "data-preview-state": previewState,
314
+ ...root
315
+ }) {
316
+ return /* @__PURE__ */ jsxs4(BaseMenu.Root, { ...root, children: [
317
+ /* @__PURE__ */ jsx6(BaseMenu.Trigger, { render: trigger }),
318
+ /* @__PURE__ */ jsx6(BaseMenu.Portal, { container, children: /* @__PURE__ */ jsx6(
319
+ BaseMenu.Positioner,
320
+ {
321
+ side,
322
+ align,
323
+ sideOffset,
324
+ collisionPadding: VIEWPORT_MARGIN,
325
+ className: POPUP_LAYER,
326
+ children: /* @__PURE__ */ jsx6(
327
+ BaseMenu.Popup,
328
+ {
329
+ "aria-label": ariaLabel,
330
+ "data-preview-state": previewState,
331
+ className: cn(menuPopup, className),
332
+ children
333
+ }
334
+ )
335
+ }
336
+ ) })
337
+ ] });
338
+ }
339
+ function ContextMenu({
340
+ trigger,
341
+ children,
342
+ container,
343
+ className,
344
+ "aria-label": ariaLabel,
345
+ "data-preview-state": previewState,
346
+ ...root
347
+ }) {
348
+ return /* @__PURE__ */ jsxs4(BaseContextMenu.Root, { ...root, children: [
349
+ /* @__PURE__ */ jsx6(BaseContextMenu.Trigger, { render: trigger }),
350
+ /* @__PURE__ */ jsx6(BaseContextMenu.Portal, { container, children: /* @__PURE__ */ jsx6(BaseContextMenu.Positioner, { collisionPadding: VIEWPORT_MARGIN, className: POPUP_LAYER, children: /* @__PURE__ */ jsx6(
351
+ BaseContextMenu.Popup,
352
+ {
353
+ "aria-label": ariaLabel,
354
+ "data-preview-state": previewState,
355
+ className: cn(menuPopup, className),
356
+ children
357
+ }
358
+ ) }) })
359
+ ] });
360
+ }
361
+ function MenuShortcut({ className, ...props }) {
362
+ return /* @__PURE__ */ jsx6(
363
+ "span",
364
+ {
365
+ className: cn("shrink-0 font-mono text-step-10 tabular-nums text-text-4", className),
366
+ "aria-hidden": "true",
367
+ ...props
368
+ }
369
+ );
370
+ }
371
+ function MenuItem({ shortcut, tone, className, children, ...props }) {
372
+ return /* @__PURE__ */ jsxs4(BaseMenu.Item, { className: cn(itemBase, tone === "danger" && itemDanger, className), ...props, children: [
373
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children }),
374
+ shortcut ? /* @__PURE__ */ jsx6(MenuShortcut, { children: shortcut }) : null
375
+ ] });
376
+ }
377
+ function MenuRadioGroup(props) {
378
+ return /* @__PURE__ */ jsx6(BaseMenu.RadioGroup, { ...props });
379
+ }
380
+ function MenuRadioItem({ className, children, ...props }) {
381
+ return /* @__PURE__ */ jsxs4(BaseMenu.RadioItem, { className: cn(itemBase, className), ...props, children: [
382
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children }),
383
+ /* @__PURE__ */ jsx6("span", { className: "flex size-3 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx6(BaseMenu.RadioItemIndicator, { className: "size-1.5 rounded-full bg-accent" }) })
384
+ ] });
385
+ }
386
+ function MenuCheckboxItem({
387
+ className,
388
+ children,
389
+ ...props
390
+ }) {
391
+ return /* @__PURE__ */ jsxs4(BaseMenu.CheckboxItem, { className: cn(itemBase, className), ...props, children: [
392
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children }),
393
+ /* @__PURE__ */ jsx6("span", { className: "flex size-3 shrink-0 items-center justify-center text-accent", children: /* @__PURE__ */ jsx6(BaseMenu.CheckboxItemIndicator, { children: "\u2713" }) })
394
+ ] });
395
+ }
396
+ function MenuSeparator({ className, ...props }) {
397
+ return /* @__PURE__ */ jsx6(BaseMenu.Separator, { className: cn("my-1 h-px bg-hairline", className), ...props });
398
+ }
399
+
400
+ // src/components/ui/Tooltip.tsx
401
+ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
402
+ import { cloneElement, useId as useId2, useRef, useState } from "react";
403
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
404
+ var SIDE_OFFSET2 = 6;
405
+ var VIEWPORT_MARGIN2 = 8;
406
+ function Tooltip({ label, children, delay = 400, side = "top" }) {
407
+ const [open, setOpen] = useState(false);
408
+ const boxRef = useRef(null);
409
+ const tooltipId = useId2();
410
+ return /* @__PURE__ */ jsxs5(BaseTooltip.Root, { open, onOpenChange: setOpen, children: [
411
+ /* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay, render: /* @__PURE__ */ jsx7("span", { ref: boxRef, className: "contents" }), children: cloneElement(children, {
412
+ "aria-describedby": open ? tooltipId : children.props["aria-describedby"]
413
+ }) }),
414
+ /* @__PURE__ */ jsx7(BaseTooltip.Portal, { children: /* @__PURE__ */ jsx7(
415
+ BaseTooltip.Positioner,
416
+ {
417
+ anchor: () => boxRef.current?.firstElementChild ?? null,
418
+ side,
419
+ sideOffset: SIDE_OFFSET2,
420
+ collisionPadding: VIEWPORT_MARGIN2,
421
+ className: "z-200",
422
+ children: /* @__PURE__ */ jsx7(
423
+ BaseTooltip.Popup,
424
+ {
425
+ id: tooltipId,
426
+ role: "tooltip",
427
+ className: cn(
428
+ "pointer-events-none rounded-md border border-border-input bg-surface px-2 py-1 text-step-10 font-medium text-text-1 whitespace-nowrap shadow-menu",
429
+ floatingMotion("duration-tooltip")
430
+ ),
431
+ children: label
432
+ }
433
+ )
434
+ }
435
+ ) })
436
+ ] });
437
+ }
438
+
439
+ // src/components/ui/Popover.tsx
440
+ import { Popover as BasePopover } from "@base-ui/react/popover";
441
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
442
+ var SIDE_OFFSET3 = 6;
443
+ var VIEWPORT_MARGIN3 = 8;
444
+ function Popover({
445
+ trigger,
446
+ children,
447
+ side = "bottom",
448
+ align = "center",
449
+ sideOffset = SIDE_OFFSET3,
450
+ container,
451
+ className,
452
+ initialFocus,
453
+ "aria-label": ariaLabel,
454
+ "data-preview-state": previewState,
455
+ ...root
456
+ }) {
457
+ return /* @__PURE__ */ jsxs6(BasePopover.Root, { ...root, children: [
458
+ /* @__PURE__ */ jsx8(BasePopover.Trigger, { render: trigger }),
459
+ /* @__PURE__ */ jsx8(BasePopover.Portal, { container, children: /* @__PURE__ */ jsx8(
460
+ BasePopover.Positioner,
461
+ {
462
+ side,
463
+ align,
464
+ sideOffset,
465
+ collisionPadding: VIEWPORT_MARGIN3,
466
+ className: "z-200",
467
+ children: /* @__PURE__ */ jsx8(
468
+ BasePopover.Popup,
469
+ {
470
+ "aria-label": ariaLabel,
471
+ initialFocus,
472
+ "data-preview-state": previewState,
473
+ className: cn(popupSurface, "p-3 text-step-11 text-text-1 shadow-popover", className),
474
+ children
475
+ }
476
+ )
477
+ }
478
+ ) })
479
+ ] });
480
+ }
481
+
482
+ // src/components/ui/Input.tsx
483
+ import { Input as BaseInput } from "@base-ui/react/input";
484
+ import { useEffect, useRef as useRef2, useState as useState2 } from "react";
485
+ import { jsx as jsx9 } from "react/jsx-runtime";
486
+ var fieldBase = cn(
487
+ "flex min-w-0 items-center gap-1.5 h-ctl px-2 rounded-md",
488
+ "bg-input border border-border-input text-step-11 font-medium text-text-1",
489
+ "transition-[border-color,background-color] ease-standard duration-focus",
490
+ "hover:border-border-strong data-[preview-state=hover]:border-border-strong",
491
+ "outline-hidden",
492
+ "focus-within:outline-solid focus-within:outline-2 focus-within:outline-offset-1 focus-within:outline-accent",
493
+ "data-[preview-state=focus]:outline-solid data-[preview-state=focus]:outline-2 data-[preview-state=focus]:outline-offset-1 data-[preview-state=focus]:outline-accent",
494
+ // `aria-invalid` is not one of Tailwind's built-in aria variants, so the
495
+ // arbitrary form is the one that compiles. The token gate would have caught
496
+ // the bare `aria-invalid:` spelling as a class that resolves to nothing.
497
+ "aria-[invalid]:border-danger",
498
+ "has-[:disabled]:opacity-40 has-[:disabled]:cursor-not-allowed"
499
+ );
500
+ var fieldText = cn(
501
+ "min-w-0 w-full bg-transparent text-inherit outline-hidden",
502
+ "placeholder:text-text-5 disabled:cursor-not-allowed"
503
+ );
504
+ function Input({
505
+ value,
506
+ onCommit,
507
+ onTrack,
508
+ invalid,
509
+ disabled,
510
+ className,
511
+ "data-preview-state": previewState,
512
+ ...props
513
+ }) {
514
+ const [draft, setDraft] = useState2(value);
515
+ const valueRef = useRef2(value);
516
+ valueRef.current = value;
517
+ const dirtyRef = useRef2(false);
518
+ useEffect(() => {
519
+ if (!dirtyRef.current) setDraft(value);
520
+ }, [value]);
521
+ const commit = (next) => {
522
+ dirtyRef.current = false;
523
+ if (next === valueRef.current) return;
524
+ onCommit(next);
525
+ onTrack?.();
526
+ };
527
+ return /* @__PURE__ */ jsx9(
528
+ "div",
529
+ {
530
+ className: cn(fieldBase, className),
531
+ "aria-invalid": invalid || void 0,
532
+ "data-preview-state": previewState,
533
+ children: /* @__PURE__ */ jsx9(
534
+ BaseInput,
535
+ {
536
+ value: draft,
537
+ disabled,
538
+ "aria-invalid": invalid || void 0,
539
+ className: fieldText,
540
+ onValueChange: (next) => {
541
+ dirtyRef.current = true;
542
+ setDraft(next);
543
+ },
544
+ onBlur: () => commit(draft),
545
+ onKeyDown: (event) => {
546
+ if (event.key === "Enter") {
547
+ event.preventDefault();
548
+ commit(draft);
549
+ return;
550
+ }
551
+ if (event.key === "Escape") {
552
+ event.preventDefault();
553
+ event.stopPropagation();
554
+ dirtyRef.current = false;
555
+ setDraft(valueRef.current);
556
+ event.currentTarget.blur();
557
+ }
558
+ },
559
+ ...props
560
+ }
561
+ )
562
+ }
563
+ );
564
+ }
565
+
566
+ // src/components/ui/NumberField.tsx
567
+ import { NumberField as BaseNumberField } from "@base-ui/react/number-field";
568
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
569
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
570
+ function NumberField({
571
+ label,
572
+ value,
573
+ onCommit,
574
+ onTrack,
575
+ unit,
576
+ min,
577
+ max,
578
+ step,
579
+ disabled,
580
+ className,
581
+ "data-preview-state": previewState
582
+ }) {
583
+ const [draft, setDraft] = useState3(value);
584
+ const [invalid, setInvalid] = useState3(false);
585
+ const inputRef = useRef3(null);
586
+ const committedRef = useRef3(value);
587
+ const valueRef = useRef3(value);
588
+ valueRef.current = value;
589
+ useEffect2(() => {
590
+ committedRef.current = value;
591
+ setDraft(value);
592
+ setInvalid(false);
593
+ }, [value]);
594
+ const commit = (next) => {
595
+ if (next === null || !Number.isFinite(next)) {
596
+ setInvalid(true);
597
+ return;
598
+ }
599
+ setInvalid(false);
600
+ if (next === committedRef.current) return;
601
+ committedRef.current = next;
602
+ onCommit(next);
603
+ onTrack?.();
604
+ };
605
+ const commitFromText = () => {
606
+ const text = inputRef.current?.value.trim() ?? "";
607
+ commit(text === "" ? null : Number(text));
608
+ };
609
+ return /* @__PURE__ */ jsx10(
610
+ BaseNumberField.Root,
611
+ {
612
+ value: draft,
613
+ min,
614
+ max,
615
+ step,
616
+ disabled,
617
+ onValueChange: (next) => {
618
+ setDraft(next);
619
+ if (next !== null) setInvalid(false);
620
+ },
621
+ onValueCommitted: (next) => commit(next),
622
+ children: /* @__PURE__ */ jsxs7(
623
+ BaseNumberField.Group,
624
+ {
625
+ className: cn(fieldBase, className),
626
+ "aria-invalid": invalid || void 0,
627
+ "data-preview-state": previewState,
628
+ children: [
629
+ /* @__PURE__ */ jsx10(
630
+ BaseNumberField.Input,
631
+ {
632
+ ref: inputRef,
633
+ "aria-label": label,
634
+ "aria-invalid": invalid || void 0,
635
+ className: cn(fieldText, "tabular-nums"),
636
+ onKeyDown: (event) => {
637
+ if (event.key !== "Enter") return;
638
+ event.preventDefault();
639
+ commitFromText();
640
+ },
641
+ onBlur: () => {
642
+ const text = inputRef.current?.value.trim() ?? "";
643
+ if (text === "" || !Number.isFinite(Number(text))) setInvalid(true);
644
+ }
645
+ }
646
+ ),
647
+ unit && /* @__PURE__ */ jsx10("span", { className: "shrink-0 select-none text-step-10 text-text-4", "aria-hidden": "true", children: unit })
648
+ ]
649
+ }
650
+ )
651
+ }
652
+ );
653
+ }
654
+
655
+ // src/components/ui/Select.tsx
656
+ import { Select as BaseSelect } from "@base-ui/react/select";
657
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
658
+ function Select({
659
+ label,
660
+ value,
661
+ options,
662
+ onCommit,
663
+ onTrack,
664
+ disabled,
665
+ className,
666
+ "data-preview-state": previewState
667
+ }) {
668
+ return /* @__PURE__ */ jsxs8(
669
+ BaseSelect.Root,
670
+ {
671
+ value,
672
+ disabled,
673
+ items: options,
674
+ onValueChange: (next) => {
675
+ const chosen = String(next);
676
+ if (chosen === value) return;
677
+ onCommit(chosen);
678
+ onTrack?.();
679
+ },
680
+ children: [
681
+ /* @__PURE__ */ jsxs8(
682
+ BaseSelect.Trigger,
683
+ {
684
+ "aria-label": label,
685
+ className: cn(
686
+ fieldBase,
687
+ "w-full cursor-pointer justify-between text-left",
688
+ "data-[popup-open]:border-border-strong",
689
+ className
690
+ ),
691
+ "data-preview-state": previewState,
692
+ children: [
693
+ /* @__PURE__ */ jsx11(BaseSelect.Value, { className: "truncate" }),
694
+ /* @__PURE__ */ jsx11(BaseSelect.Icon, { className: "shrink-0 text-text-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx11("svg", { width: "8", height: "5", viewBox: "0 0 8 5", fill: "none", children: /* @__PURE__ */ jsx11(
695
+ "path",
696
+ {
697
+ d: "M1 1L4 4L7 1",
698
+ stroke: "currentColor",
699
+ strokeWidth: "1.5",
700
+ strokeLinecap: "round",
701
+ strokeLinejoin: "round"
702
+ }
703
+ ) }) })
704
+ ]
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsx11(BaseSelect.Portal, { children: /* @__PURE__ */ jsx11(BaseSelect.Positioner, { sideOffset: 4, alignItemWithTrigger: false, children: /* @__PURE__ */ jsx11(
708
+ BaseSelect.Popup,
709
+ {
710
+ className: cn(
711
+ "min-w-[var(--anchor-width)] rounded-md border border-border bg-surface py-1 shadow-menu",
712
+ floatingMotion("duration-open")
713
+ ),
714
+ children: /* @__PURE__ */ jsx11(BaseSelect.List, { children: options.map((option) => /* @__PURE__ */ jsx11(
715
+ BaseSelect.Item,
716
+ {
717
+ value: option.value,
718
+ disabled: option.disabled,
719
+ className: cn(
720
+ "flex h-ctl-sm cursor-pointer select-none items-center gap-2 px-2.5",
721
+ "text-step-11 text-text-2 outline-hidden",
722
+ "data-[highlighted]:bg-hover data-[highlighted]:text-text-0",
723
+ "data-[selected]:text-text-0",
724
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-40"
725
+ ),
726
+ children: /* @__PURE__ */ jsx11(BaseSelect.ItemText, { className: "truncate", children: option.label })
727
+ },
728
+ option.value
729
+ )) })
730
+ }
731
+ ) }) })
732
+ ]
733
+ }
734
+ );
735
+ }
736
+
737
+ // src/components/ui/Slider.tsx
738
+ import { Slider as BaseSlider } from "@base-ui/react/slider";
739
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
740
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
741
+ var first = (next) => Array.isArray(next) ? next[0] : next;
742
+ function Slider({
743
+ label,
744
+ value,
745
+ min,
746
+ max,
747
+ step,
748
+ onPreview,
749
+ onCommit,
750
+ onTrack,
751
+ disabled,
752
+ className,
753
+ "data-preview-state": previewState
754
+ }) {
755
+ const [draft, setDraft] = useState4(value);
756
+ const draggingRef = useRef4(false);
757
+ const abortedRef = useRef4(false);
758
+ const dragStartRef = useRef4(value);
759
+ const committedRef = useRef4(value);
760
+ const valueRef = useRef4(value);
761
+ valueRef.current = value;
762
+ useEffect3(() => {
763
+ if (draggingRef.current) return;
764
+ committedRef.current = value;
765
+ setDraft(value);
766
+ }, [value]);
767
+ const commit = (next) => {
768
+ if (next === committedRef.current) return;
769
+ committedRef.current = next;
770
+ onCommit(next);
771
+ };
772
+ const abort = () => {
773
+ if (!draggingRef.current) return;
774
+ abortedRef.current = true;
775
+ const start = dragStartRef.current;
776
+ setDraft(start);
777
+ onPreview?.(start);
778
+ commit(start);
779
+ };
780
+ return /* @__PURE__ */ jsx12(
781
+ BaseSlider.Root,
782
+ {
783
+ value: draft,
784
+ min,
785
+ max,
786
+ step,
787
+ disabled,
788
+ onValueChange: (next, details) => {
789
+ if (abortedRef.current) {
790
+ details.cancel();
791
+ return;
792
+ }
793
+ const n = first(next);
794
+ setDraft(n);
795
+ onPreview?.(n);
796
+ },
797
+ onValueCommitted: (next) => {
798
+ draggingRef.current = false;
799
+ if (abortedRef.current) {
800
+ abortedRef.current = false;
801
+ return;
802
+ }
803
+ commit(first(next));
804
+ onTrack?.();
805
+ },
806
+ className: cn("flex min-w-0 items-center", className),
807
+ "data-preview-state": previewState,
808
+ children: /* @__PURE__ */ jsx12(
809
+ BaseSlider.Control,
810
+ {
811
+ "data-slider-control": "true",
812
+ className: "flex h-6 w-full min-w-0 touch-none select-none items-center",
813
+ onPointerDown: () => {
814
+ draggingRef.current = true;
815
+ abortedRef.current = false;
816
+ dragStartRef.current = valueRef.current;
817
+ },
818
+ onContextMenu: (event) => {
819
+ if (!draggingRef.current) return;
820
+ event.preventDefault();
821
+ abort();
822
+ },
823
+ onKeyDown: (event) => {
824
+ if (event.key !== "Escape" || !draggingRef.current) return;
825
+ event.preventDefault();
826
+ abort();
827
+ },
828
+ children: /* @__PURE__ */ jsxs9(BaseSlider.Track, { className: "h-0.5 w-full rounded-full bg-hover", children: [
829
+ /* @__PURE__ */ jsx12(BaseSlider.Indicator, { className: "rounded-full bg-text-5" }),
830
+ /* @__PURE__ */ jsx12(
831
+ BaseSlider.Thumb,
832
+ {
833
+ "aria-label": label,
834
+ className: cn(
835
+ // The ring separates the thumb from the track behind it. A drop
836
+ // shadow would need a raw colour literal, which R5 does not allow
837
+ // outside the token file, and no shadow token fits a 10px dot.
838
+ "size-2.5 rounded-full bg-text-0 ring-2 ring-bg-1",
839
+ "cursor-grab active:cursor-grabbing data-[preview-state=active]:cursor-grabbing",
840
+ "hover:scale-110 data-[preview-state=hover]:scale-110",
841
+ "transition-transform ease-standard duration-hover",
842
+ "has-[:focus-visible]:outline-solid has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-accent",
843
+ "data-[preview-state=focus]:outline-solid data-[preview-state=focus]:outline-2 data-[preview-state=focus]:outline-offset-2 data-[preview-state=focus]:outline-accent"
844
+ )
845
+ }
846
+ )
847
+ ] })
848
+ }
849
+ )
850
+ }
851
+ );
852
+ }
853
+
854
+ // src/components/ui/Toggle.tsx
855
+ import { Switch } from "@base-ui/react/switch";
856
+ import { jsx as jsx13 } from "react/jsx-runtime";
857
+ function Toggle({
858
+ label,
859
+ checked,
860
+ onCommit,
861
+ onTrack,
862
+ disabled,
863
+ className,
864
+ "data-preview-state": previewState
865
+ }) {
866
+ return /* @__PURE__ */ jsx13(
867
+ Switch.Root,
868
+ {
869
+ "aria-label": label,
870
+ checked,
871
+ disabled,
872
+ onCheckedChange: (next) => {
873
+ onCommit(next);
874
+ onTrack?.();
875
+ },
876
+ "data-preview-state": previewState,
877
+ className: cn(
878
+ "relative inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full p-0.5",
879
+ "border border-border-input bg-input",
880
+ "transition-[background-color,border-color] ease-standard duration-press",
881
+ "hover:border-border-strong data-[preview-state=hover]:border-border-strong",
882
+ "data-[checked]:border-accent data-[checked]:bg-accent",
883
+ "outline-hidden focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent",
884
+ "data-[preview-state=focus]:outline-solid data-[preview-state=focus]:outline-2 data-[preview-state=focus]:outline-offset-1 data-[preview-state=focus]:outline-accent",
885
+ "disabled:cursor-not-allowed disabled:opacity-40",
886
+ className
887
+ ),
888
+ children: /* @__PURE__ */ jsx13(
889
+ Switch.Thumb,
890
+ {
891
+ className: cn(
892
+ "size-3 rounded-full bg-text-3",
893
+ "transition-[transform,background-color] ease-standard duration-press",
894
+ "data-[checked]:translate-x-3 data-[checked]:bg-bg-0"
895
+ )
896
+ }
897
+ )
898
+ }
899
+ );
900
+ }
901
+
902
+ export {
903
+ cn,
904
+ buttonBase,
905
+ buttonVariants,
906
+ buttonSizes,
907
+ Button,
908
+ IconButton,
909
+ Tabs,
910
+ TabsList,
911
+ Tab,
912
+ TabPanel,
913
+ HyperframesMark,
914
+ HyperframesLoader,
915
+ popupSurface,
916
+ Menu,
917
+ ContextMenu,
918
+ MenuShortcut,
919
+ MenuItem,
920
+ MenuRadioGroup,
921
+ MenuRadioItem,
922
+ MenuCheckboxItem,
923
+ MenuSeparator,
924
+ Tooltip,
925
+ Popover,
926
+ fieldBase,
927
+ fieldText,
928
+ Input,
929
+ NumberField,
930
+ Select,
931
+ Slider,
932
+ Toggle
933
+ };
934
+ //# sourceMappingURL=chunk-QZ6HNNFG.js.map