@weasel-js/labkit 1.1.0 → 1.2.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 (79) hide show
  1. package/README.md +27 -0
  2. package/dist/_dts/{DrawCommand-BkZztJsW.d.ts → DrawCommand-C_XboUpz.d.ts} +48 -6
  3. package/dist/_dts/{index-iAP6XbH3.d.ts → index-JFAYj5Tv.d.ts} +12 -0
  4. package/dist/_dts/types-DJ79Tg5J.d.ts +56 -0
  5. package/dist/_dts/{useTrialState-DYe2vUwN.d.ts → useTrialState-BMNIx3Cy.d.ts} +5 -9
  6. package/dist/canvas/index.d.ts +2 -1
  7. package/dist/{chunk-C6GJKPUI.js → chunk-73KA7WBO.js} +69 -63
  8. package/dist/chunk-73KA7WBO.js.map +1 -0
  9. package/dist/{chunk-DJLDIRFN.js → chunk-BOHF3PQO.js} +4375 -3720
  10. package/dist/chunk-BOHF3PQO.js.map +1 -0
  11. package/dist/{chunk-NRKWVTVT.js → chunk-G5TJVQQT.js} +3 -3
  12. package/dist/{chunk-NRKWVTVT.js.map → chunk-G5TJVQQT.js.map} +1 -1
  13. package/dist/chunk-LN6JDUGB.js +106 -0
  14. package/dist/chunk-LN6JDUGB.js.map +1 -0
  15. package/dist/chunk-THBG7FQZ.js +167 -0
  16. package/dist/chunk-THBG7FQZ.js.map +1 -0
  17. package/dist/{chunk-3TYUJR7Z.js → chunk-VUU5UXHE.js} +6 -3
  18. package/dist/chunk-VUU5UXHE.js.map +1 -0
  19. package/dist/dragdrop/index.d.ts +2 -1
  20. package/dist/index.d.ts +71 -11
  21. package/dist/index.js +165 -22
  22. package/dist/index.js.map +1 -1
  23. package/dist/job/index.d.ts +13 -0
  24. package/dist/job/index.js +3 -0
  25. package/dist/job/index.js.map +1 -0
  26. package/dist/layers/index.d.ts +3 -2
  27. package/dist/passthrough/weasel-canvas.d.ts +1 -1
  28. package/dist/passthrough/weasel-canvas.js +1 -1
  29. package/dist/passthrough/weasel-ui.d.ts +20 -4
  30. package/dist/passthrough/weasel-ui.js +2 -2
  31. package/dist/state/index.d.ts +2 -2
  32. package/dist/state/index.js +2 -2
  33. package/dist/styles.css +10 -0
  34. package/dist/surface/index.d.ts +77 -0
  35. package/dist/surface/index.js +3 -0
  36. package/dist/surface/index.js.map +1 -0
  37. package/dist/ui/layers/index.js +3 -3
  38. package/dist/undo/index.d.ts +2 -1
  39. package/package.json +9 -1
  40. package/src/canvas/AGENTS.md +8 -0
  41. package/src/canvas/useOrbit.test.ts +71 -0
  42. package/src/canvas/useOrbit.ts +149 -0
  43. package/src/index.test.ts +18 -0
  44. package/src/index.ts +13 -0
  45. package/src/instrument/SineWave.smoke.test.tsx +2 -1
  46. package/src/instrument/types.ts +13 -1
  47. package/src/job/index.ts +3 -0
  48. package/src/job/types.ts +47 -0
  49. package/src/job/useJob.test.tsx +210 -0
  50. package/src/job/useJob.ts +134 -0
  51. package/src/lab/Lab.stories.tsx +1 -2
  52. package/src/lab/Workspace.surface.test.tsx +49 -0
  53. package/src/lab/Workspace.tsx +14 -1
  54. package/src/state/store.ts +8 -2
  55. package/src/state/types.ts +4 -2
  56. package/src/state/view.test.ts +127 -0
  57. package/src/state/view.ts +18 -0
  58. package/src/surface/AGENTS.md +64 -0
  59. package/src/surface/SurfaceContext.ts +5 -0
  60. package/src/surface/composeRects.test.ts +50 -0
  61. package/src/surface/composeRects.ts +19 -0
  62. package/src/surface/deviceRect.test.ts +40 -0
  63. package/src/surface/deviceRect.ts +19 -0
  64. package/src/surface/index.ts +7 -0
  65. package/src/surface/rect.ts +16 -0
  66. package/src/surface/useSurfaceTile.test.tsx +67 -0
  67. package/src/surface/useSurfaceTile.ts +32 -0
  68. package/src/surface/useTiledSurface.test.tsx +231 -0
  69. package/src/surface/useTiledSurface.ts +157 -0
  70. package/src/trial/DefaultStatusBar.tsx +2 -2
  71. package/src/trial/Trial.job.test.tsx +75 -0
  72. package/src/trial/Trial.less +12 -0
  73. package/src/trial/Trial.stories.tsx +8 -1
  74. package/src/trial/Trial.tsx +32 -6
  75. package/src/trial/TrialChrome.tsx +33 -6
  76. package/src/trial/slotTypes.ts +2 -1
  77. package/dist/chunk-3TYUJR7Z.js.map +0 -1
  78. package/dist/chunk-C6GJKPUI.js.map +0 -1
  79. package/dist/chunk-DJLDIRFN.js.map +0 -1
package/README.md CHANGED
@@ -59,6 +59,33 @@ import { ThemeProvider } from '@weasel-js/theme/react';
59
59
  `"light"` or `"dark"`. Only `styles.css` needs importing — the token values
60
60
  arrive through the provider.
61
61
 
62
+ ## Driving your own renderer
63
+
64
+ `CanvasStack` is 2D. For three.js or raw WebGL, take rects and dirtiness from
65
+ labkit and keep the GL yourself:
66
+
67
+ ```tsx
68
+ import { toDeviceRect, useSurfaceTile, useTiledSurface } from '@weasel-js/labkit/surface';
69
+ ```
70
+
71
+ A trial's `view` is opaque to labkit — it is persisted, restored on Reset and
72
+ handed to the instrument without being read into — so a 3D lab stores an orbit
73
+ there and gets all three. `useOrbit` is the 3D peer of `usePanZoom`.
74
+
75
+ See `src/surface/AGENTS.md` for the contract and the traps.
76
+
77
+ ## Long-running work
78
+
79
+ An instrument with work too slow for a render declares a `job`. labkit starts it,
80
+ aborts it on unmount and on a key change, discards results from a superseded run,
81
+ and renders progress and a cancel control into the trial chrome. Per-item failure
82
+ is an event rather than a thrown error, so a run with two failed items is a
83
+ partial success.
84
+
85
+ ```tsx
86
+ import type { JobCapability } from '@weasel-js/labkit/job';
87
+ ```
88
+
62
89
  ## Development
63
90
 
64
91
  ```bash
@@ -88,6 +88,8 @@ interface SerializedHistoryEntry {
88
88
  label: string;
89
89
  forwardOps: SerializedOp[];
90
90
  baseOps: SerializedOp[];
91
+ selectionBefore?: readonly string[];
92
+ selectionAfter?: readonly string[];
91
93
  }
92
94
  /** Snapshot of an entire `History` instance. Designed to live alongside the
93
95
  * scene snapshot in IDB so a reload restores the undo / redo stacks to
@@ -119,6 +121,10 @@ interface HistoryEntry {
119
121
  * contribute nothing. May be `undefined` for deserialized entries
120
122
  * restored from an older snapshot that predates this field. */
121
123
  touchedIds?: ReadonlySet<string>;
124
+ /** Selection restored when this entry is undone. */
125
+ selectionBefore?: readonly string[];
126
+ /** Selection restored when this entry is redone. */
127
+ selectionAfter?: readonly string[];
122
128
  }
123
129
  /** Op-batched undo/redo controller returned by `createHistory`. */
124
130
  interface History {
@@ -170,7 +176,7 @@ interface History {
170
176
  * Unlike `applyOps`, does NOT call `op.apply()`. Used by Journal.commit
171
177
  * to flush a session's net forward ops to the parent as one entry without
172
178
  * re-mutating the scene. */
173
- recordEntry(ops: Op[], label: string): void;
179
+ recordEntry(ops: Op[], label: string, options?: RecordEntryOptions): void;
174
180
  /** Concatenated forwardOps of every undo-stack entry, in order. Snapshot
175
181
  * of "what changes are currently applied via this history" — useful for
176
182
  * Journal.commit to flush to a parent, and for any caller that wants to
@@ -193,6 +199,14 @@ interface History {
193
199
  * to resume or discard before calling this. */
194
200
  resumeJournal(journal: Journal): void;
195
201
  }
202
+ /** Options for `recordEntry`. */
203
+ interface RecordEntryOptions {
204
+ /** Selection as of before the already-applied ops ran. `recordEntry` is
205
+ * called after the fact, so the live selection has moved on by then and
206
+ * the engine cannot sample it — a caller that wants undo to restore the
207
+ * selection captures it when the batch opens and passes it here. */
208
+ selectionBefore?: readonly string[];
209
+ }
196
210
 
197
211
  /** Fill rule used by polygon path hit-testing and `ctx.fill()`. */
198
212
  type PathFillRule = 'nonzero' | 'evenodd';
@@ -500,6 +514,14 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
500
514
  * `SceneCanvasAdapter`). Pass `this` from `sceneToAdapter` or a compatible
501
515
  * adapter. */
502
516
  applyBatch(ops: Op[], label: string, adapter: unknown): void;
517
+ /** The transient set of active ids — "operate on these N as a unit".
518
+ * Shared by every view over this scene unless a view supplies its own
519
+ * (see `CanvasView.selection`). Not document content: it never appears
520
+ * in `toJSON`. It does ride on history entries, so undo and redo put
521
+ * back the selection an edit was made under; changing it is never an
522
+ * undo step of its own. */
523
+ getSelection(): readonly NodeId[];
524
+ setSelection(ids: readonly NodeId[]): void;
503
525
  undo(): boolean;
504
526
  redo(): boolean;
505
527
  canUndo(): boolean;
@@ -792,17 +814,22 @@ type StrokeAlign = 'center' | 'inner' | 'outer';
792
814
  /** Stroke style: a FillStyle plus structural line parameters. */
793
815
  interface Stroke {
794
816
  paint: FillStyle;
795
- width?: number;
817
+ /** World units, or `{ px }` for screen pixels — resolved against the
818
+ * accumulated transform scale at draw time, so it holds its on-screen
819
+ * thickness as the view zooms. */
820
+ width?: number | {
821
+ px: number;
822
+ };
796
823
  /** Per `CanvasRenderingContext2D.setLineDash` — empty/omitted = solid. */
797
824
  dash?: number[];
798
825
  cap?: 'butt' | 'round' | 'square';
799
826
  join?: 'miter' | 'round' | 'bevel';
800
827
  /**
801
828
  * Miter join fallback threshold. When the miter length exceeds
802
- * `miterLimit * width / 2`, the join falls back to a bevel. Default 10
803
- * (matching Canvas2D). SVG's default is 4; consumers that want SVG
804
- * fidelity should set this explicitly when constructing strokes from
805
- * SVG sources where the attribute was omitted.
829
+ * `miterLimit * width / 2`, the join falls back to a bevel. Default 4,
830
+ * matching SVG which is also what the kit's own serializer implies when
831
+ * it omits the attribute for an unset field. Canvas2D's 10 lets an acute
832
+ * corner throw a spike four times the half-width.
806
833
  */
807
834
  miterLimit?: number;
808
835
  /** Where the stroke sits relative to the geometric edge. Default `'center'`. */
@@ -1063,6 +1090,21 @@ interface ImageDrawCommand {
1063
1090
  * device pixels as hard squares — required by anything magnifying a
1064
1091
  * framebuffer readback, where blur destroys the point of the readback. */
1065
1092
  sampling?: 'linear' | 'nearest';
1093
+ /** Sub-rectangle of `image` to draw, in bitmap pixels from the top-left.
1094
+ * Omitted draws the whole bitmap. Not range-checked: a rect past the edge
1095
+ * samples outside [0..1], which CLAMP_TO_EDGE smears. With
1096
+ * `sampling: 'linear'` the filter reaches half a texel beyond `source`, so
1097
+ * atlas frames need a gutter (see `SpriteSheet.spacing`) or `'nearest'`. */
1098
+ source?: {
1099
+ x: number;
1100
+ y: number;
1101
+ w: number;
1102
+ h: number;
1103
+ };
1104
+ /** Mirror the sampled region within the destination rect. The quad does not
1105
+ * move — a flipped draw covers exactly the pixels an unflipped one does. */
1106
+ flipX?: boolean;
1107
+ flipY?: boolean;
1066
1108
  }
1067
1109
  /**
1068
1110
  * Custom shader draw command. The renderer generates a quad over `bounds`
@@ -1,5 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { C as ConfigField } from './types-x92Kfeme.js';
3
+ import { J as JobHandle, a as JobCapability } from './types-DJ79Tg5J.js';
3
4
 
4
5
  /** What an instrument's `render` is handed: its state and config, the setters
5
6
  * for both, the trial it is mounted in, and a way to emit named events. */
@@ -10,10 +11,18 @@ interface RenderContext<TS = unknown, TC = unknown> {
10
11
  setConfig: (key: keyof TC, value: unknown) => void;
11
12
  trial: {
12
13
  id: string;
14
+ /** The trial's view, in whatever shape this instrument chose. labkit persists
15
+ * it and restores it on Reset without ever reading into it. */
16
+ view: unknown;
17
+ setView: (next: unknown) => void;
18
+ /** 2D convenience over `view`. Reads 1 and writes nothing when the trial holds
19
+ * a view that is not the 2D one. */
13
20
  zoom: number;
14
21
  setZoom: (z: number) => void;
15
22
  };
16
23
  emit: (event: string) => void;
24
+ /** Present only when the instrument declares a `job`. */
25
+ job?: JobHandle;
17
26
  }
18
27
  /** One 2D canvas layer of an instrument, drawn in declaration order.
19
28
  *
@@ -123,6 +132,9 @@ interface Instrument<TS = unknown, TC = unknown> {
123
132
  layers?: LayerCapability;
124
133
  dragDrop?: DragDropCapability<TS, TC>;
125
134
  undo?: UndoCapability;
135
+ /** Work too slow to do during a render. The runtime starts it, aborts it on
136
+ * unmount and on a `key` change, and renders progress into the trial. */
137
+ job?: JobCapability<TS, TC, never>;
126
138
  }
127
139
  /** Instruments as a lab receives them. `any` rather than `unknown` because
128
140
  * parameter contravariance keeps a `defineInstrument<TS, TC>` result out of
@@ -0,0 +1,56 @@
1
+ /** What a running job reports as it goes. `total` may arrive at any point and may
2
+ * arrive more than once; a job that cannot count up front simply never sends it.
3
+ *
4
+ * `failed` is a first-class event rather than a thrown error because these
5
+ * failures are per item: a run with two failed items is a partial success, and
6
+ * its other items are worth showing. */
7
+ type JobEvent<T> = {
8
+ kind: 'total';
9
+ total: number;
10
+ } | {
11
+ kind: 'item';
12
+ item: T;
13
+ } | {
14
+ kind: 'failed';
15
+ index: number;
16
+ error: string;
17
+ };
18
+ /** Where a job is. `idle` before its first run and after a cancel; `done` when the
19
+ * iterable finished, whether or not items failed along the way. */
20
+ type JobStatus = 'idle' | 'running' | 'done' | 'error';
21
+ /** Declares that an instrument has work too slow to do during a render: what to
22
+ * run, when to re-run it, and how each result folds into state. */
23
+ interface JobCapability<TS = unknown, TC = unknown, TItem = unknown> {
24
+ /** Re-run whenever this value changes, compared element-wise. A job with no
25
+ * `key` runs only when something calls `start()`. */
26
+ key?: (config: TC, state: TS) => readonly unknown[];
27
+ /** Start on mount and on every `key` change. Default false. */
28
+ auto?: boolean;
29
+ run: (args: {
30
+ config: TC;
31
+ state: TS;
32
+ signal: AbortSignal;
33
+ }) => AsyncIterable<JobEvent<TItem>>;
34
+ /** Fold one result into state. Called once per `item` event, in arrival order. */
35
+ onItem: (item: TItem, state: TS) => TS;
36
+ }
37
+ /** One item that failed, and why. */
38
+ interface JobFailure {
39
+ index: number;
40
+ error: string;
41
+ }
42
+ /** What `RenderContext.job` exposes. Present only when the instrument declares the
43
+ * capability; `undefined` otherwise. */
44
+ interface JobHandle {
45
+ status: JobStatus;
46
+ done: number;
47
+ /** Null until the job reports a total, and forever if it never does. */
48
+ total: number | null;
49
+ failures: readonly JobFailure[];
50
+ /** The error that ended the run, when `status` is `'error'`. */
51
+ error: string | null;
52
+ start: () => void;
53
+ cancel: () => void;
54
+ }
55
+
56
+ export type { JobHandle as J, JobCapability as a, JobEvent as b, JobFailure as c, JobStatus as d };
@@ -10,18 +10,14 @@ interface UndoStack {
10
10
  }
11
11
  /** One trial as the store holds it: which instrument it runs, that
12
12
  * instrument's config and state, the camera, and the undo history. */
13
- interface TrialRecord<TS = unknown, TC = unknown> {
13
+ interface TrialRecord<TS = unknown, TC = unknown, TV = unknown> {
14
14
  id: string;
15
15
  instrumentName: string;
16
16
  config: TC;
17
17
  state: TS;
18
- view: {
19
- zoom: number;
20
- pan: {
21
- x: number;
22
- y: number;
23
- };
24
- };
18
+ /** Opaque to labkit: persisted, restored on Reset and handed to the instrument,
19
+ * but never read into. A 3D lab puts an orbit here and keeps all three. */
20
+ view: TV;
25
21
  undoStack: UndoStack;
26
22
  }
27
23
  /** A named, saved copy of a trial's config and state, restorable into any
@@ -112,7 +108,7 @@ interface LabStoreActions {
112
108
  removeTrial: (id: string) => void;
113
109
  updateTrialState: <TS>(id: string, next: TS | ((prev: TS) => TS)) => void;
114
110
  updateTrialConfig: <TC>(id: string, key: keyof TC, value: TC[keyof TC]) => void;
115
- updateTrialView: (id: string, view: TrialRecord['view']) => void;
111
+ updateTrialView: (id: string, view: unknown) => void;
116
112
  updateTrialUndoStack: (id: string, next: TrialRecord['undoStack'] | ((prev: TrialRecord['undoStack']) => TrialRecord['undoStack'])) => void;
117
113
  setTrialInstrument: (id: string, instrumentName: string) => void;
118
114
  saveSnapshot: (trialId: string, name: string) => void;
@@ -1,8 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { V as ViewTransform, e as Point } from '../_dts/index-iAP6XbH3.js';
4
+ import { V as ViewTransform, e as Point } from '../_dts/index-JFAYj5Tv.js';
5
5
  import '../_dts/types-x92Kfeme.js';
6
+ import '../_dts/types-DJ79Tg5J.js';
6
7
 
7
8
  /** One layer of a canvas stack: its id, whether it is currently shown, and how
8
9
  * it paints itself. */
@@ -1,4 +1,4 @@
1
- import { useActionsRegistry, useOptionalDepRegistry, evaluateEnabled, eligibleContribution, oklchToOklab, oklabToSrgbU8, rgbaToHex, UnknownIcon } from './chunk-DJLDIRFN.js';
1
+ import { useActionsRegistry, useOptionalDepRegistry, evaluateEnabled, eligibleContribution, oklchToOklab, oklabToSrgbU8, rgbaToHex, UnknownIcon } from './chunk-BOHF3PQO.js';
2
2
  import { forwardRef, useRef, useMemo, useCallback, useEffect, useImperativeHandle, useSyncExternalStore, useState, useLayoutEffect, useId, Fragment as Fragment$1 } from 'react';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
  import { Checkbox, TextField, Label, Input, Text, FieldError, NumberField, Group, Button, Switch, Focusable, RadioGroup, Radio, Slider, SliderOutput, SliderTrack, SliderThumb, Select, SelectValue, Popover, ListBox, ListBoxItem, ModalOverlay, Modal, Dialog, Heading, Tabs, TabList, Tab, TabPanel, ComboBox, TooltipTrigger, Tooltip, OverlayArrow } from 'react-aria-components';
@@ -2248,11 +2248,12 @@ function ot(e19) {
2248
2248
  var st = 240;
2249
2249
  var ct = {
2250
2250
  Component: ({ sampler: e19, boxW: n30, boxH: r28, variant: i24, params: c16 }) => {
2251
+ let l17 = useId();
2251
2252
  if (i24 !== "solid" && i24 !== "subtle") return null;
2252
- let l17 = {
2253
+ let u15 = {
2253
2254
  ...it,
2254
2255
  ...c16
2255
- }, u15 = useId(), d12 = 100 / n30, f12 = 100 / r28, p11 = ot(l17.lightFrom), m9 = e19.totalCss, h7 = [], g6 = [];
2256
+ }, d12 = 100 / n30, f12 = 100 / r28, p11 = ot(u15.lightFrom), m9 = e19.totalCss, h7 = [], g6 = [];
2256
2257
  for (let t25 = 0; t25 < st; t25++) {
2257
2258
  let n31 = e19.perimeterAt(t25 / st * m9);
2258
2259
  h7.push({
@@ -2260,8 +2261,8 @@ var ct = {
2260
2261
  y: n31.y,
2261
2262
  side: at(n31.nx, n31.ny)
2262
2263
  }), g6.push({
2263
- x: n31.x - n31.nx * l17.bevelWidth * d12,
2264
- y: n31.y - n31.ny * l17.bevelWidth * f12
2264
+ x: n31.x - n31.nx * u15.bevelWidth * d12,
2265
+ y: n31.y - n31.ny * u15.bevelWidth * f12
2265
2266
  });
2266
2267
  }
2267
2268
  let _7 = [], v4 = null;
@@ -2281,10 +2282,10 @@ var ct = {
2281
2282
  return i25 + " Z";
2282
2283
  };
2283
2284
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", {
2284
- id: u15,
2285
+ id: l17,
2285
2286
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
2286
2287
  }) }), /* @__PURE__ */ jsx("g", {
2287
- clipPath: `url(#${u15})`,
2288
+ clipPath: `url(#${l17})`,
2288
2289
  children: _7.map((e20, t25) => /* @__PURE__ */ jsx("path", {
2289
2290
  className: p11[e20.side],
2290
2291
  d: y4(e20)
@@ -2326,17 +2327,18 @@ var ut = {
2326
2327
  };
2327
2328
  var dt = {
2328
2329
  Component: ({ sampler: e19, variant: n30, params: r28 }) => {
2330
+ let i24 = useId(), c16 = useId();
2329
2331
  if (n30 !== "solid" && n30 !== "subtle") return null;
2330
- let i24 = {
2332
+ let l17 = {
2331
2333
  ...lt,
2332
2334
  ...r28
2333
- }, c16 = useId(), l17 = useId(), u15 = Math.max(0, Math.min(i24.intensity, 1));
2335
+ }, u15 = Math.max(0, Math.min(l17.intensity, 1));
2334
2336
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("defs", { children: [/* @__PURE__ */ jsx("clipPath", {
2335
- id: l17,
2337
+ id: c16,
2336
2338
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
2337
2339
  }), /* @__PURE__ */ jsxs("linearGradient", {
2338
- id: c16,
2339
- ...ut[i24.lightFrom],
2340
+ id: i24,
2341
+ ...ut[l17.lightFrom],
2340
2342
  children: [
2341
2343
  /* @__PURE__ */ jsx("stop", {
2342
2344
  offset: "0%",
@@ -2360,12 +2362,12 @@ var dt = {
2360
2362
  })
2361
2363
  ]
2362
2364
  })] }), /* @__PURE__ */ jsx("rect", {
2363
- clipPath: `url(#${l17})`,
2365
+ clipPath: `url(#${c16})`,
2364
2366
  x: "0",
2365
2367
  y: "0",
2366
2368
  width: "100",
2367
2369
  height: "100",
2368
- fill: `url(#${c16})`,
2370
+ fill: `url(#${i24})`,
2369
2371
  style: { pointerEvents: "none" }
2370
2372
  })] });
2371
2373
  },
@@ -2448,26 +2450,27 @@ function _t(e19) {
2448
2450
  }
2449
2451
  var vt = {
2450
2452
  Component: ({ sampler: e19, variant: n30, params: r28 }) => {
2453
+ let i24 = useId();
2451
2454
  if (n30 !== "solid" && n30 !== "subtle") return null;
2452
- let i24 = {
2455
+ let c16 = {
2453
2456
  ...gt,
2454
2457
  ...r28
2455
- }, c16 = useId(), l17 = [];
2456
- for (let e20 = 0; e20 < i24.lines; e20++) {
2457
- let t25 = (e20 + 1) / (i24.lines + 1) * 100, n31 = _t(e20 * 2 + 1) * 4, r29 = _t(e20 * 2 + 2) * 4;
2458
+ }, l17 = [];
2459
+ for (let e20 = 0; e20 < c16.lines; e20++) {
2460
+ let t25 = (e20 + 1) / (c16.lines + 1) * 100, n31 = _t(e20 * 2 + 1) * 4, r29 = _t(e20 * 2 + 2) * 4;
2458
2461
  l17.push(`M -5 ${t25.toFixed(2)} Q 35 ${(t25 + n31).toFixed(2)} 60 ${t25.toFixed(2)} T 105 ${(t25 + r29).toFixed(2)}`);
2459
2462
  }
2460
2463
  let u15 = [];
2461
- for (let e20 = 0; e20 < i24.knots; e20++) {
2464
+ for (let e20 = 0; e20 < c16.knots; e20++) {
2462
2465
  let t25 = 30 + _t(e20 * 3 + 0.7) * 30 + 20, n31 = 50 + _t(e20 * 3 + 1.3) * 30;
2463
2466
  u15.push([t25, n31]);
2464
2467
  }
2465
2468
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", {
2466
- id: c16,
2469
+ id: i24,
2467
2470
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
2468
2471
  }) }), /* @__PURE__ */ jsxs("g", {
2469
- clipPath: `url(#${c16})`,
2470
- opacity: Math.max(0, Math.min(i24.intensity, 1)),
2472
+ clipPath: `url(#${i24})`,
2473
+ opacity: Math.max(0, Math.min(c16.intensity, 1)),
2471
2474
  style: { pointerEvents: "none" },
2472
2475
  children: [l17.map((e20, t25) => /* @__PURE__ */ jsx("path", {
2473
2476
  className: "badge-stroke",
@@ -2546,11 +2549,12 @@ function Ct(e19) {
2546
2549
  }
2547
2550
  var wt = {
2548
2551
  Component: ({ sampler: e19, boxW: n30, boxH: r28, variant: i24, params: c16 }) => {
2552
+ let l17 = useId();
2549
2553
  if (i24 !== "solid" && i24 !== "subtle") return null;
2550
- let l17 = {
2554
+ let u15 = {
2551
2555
  ...xt,
2552
2556
  ...c16
2553
- }, u15 = useId(), d12 = 100 / n30, f12 = 100 / r28, p11 = e19.totalCss, { lx: m9, ly: h7 } = Ct(l17.lightFrom), g6 = [], _7 = [];
2557
+ }, d12 = 100 / n30, f12 = 100 / r28, p11 = e19.totalCss, { lx: m9, ly: h7 } = Ct(u15.lightFrom), g6 = [], _7 = [];
2554
2558
  for (let t25 = 0; t25 < Q; t25++) {
2555
2559
  let n31 = e19.perimeterAt(t25 / Q * p11), r29 = -(n31.nx * m9 + n31.ny * h7), i25 = Math.max(0, Math.min((r29 + 1) / 2, 0.9999)), a22 = Math.floor(i25 * St.length);
2556
2560
  g6.push({
@@ -2558,8 +2562,8 @@ var wt = {
2558
2562
  y: n31.y,
2559
2563
  bucket: a22
2560
2564
  }), _7.push({
2561
- x: n31.x - n31.nx * l17.bevelWidth * d12,
2562
- y: n31.y - n31.ny * l17.bevelWidth * f12
2565
+ x: n31.x - n31.nx * u15.bevelWidth * d12,
2566
+ y: n31.y - n31.ny * u15.bevelWidth * f12
2563
2567
  });
2564
2568
  }
2565
2569
  let v4 = [], y4 = null;
@@ -2581,10 +2585,10 @@ var wt = {
2581
2585
  return l18 + " Z";
2582
2586
  };
2583
2587
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", {
2584
- id: u15,
2588
+ id: l17,
2585
2589
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
2586
2590
  }) }), /* @__PURE__ */ jsx("g", {
2587
- clipPath: `url(#${u15})`,
2591
+ clipPath: `url(#${l17})`,
2588
2592
  children: v4.map((e20, t25) => /* @__PURE__ */ jsx("path", {
2589
2593
  className: St[e20.bucket],
2590
2594
  d: b3(e20)
@@ -2751,11 +2755,12 @@ var kt = {
2751
2755
  var At = 240;
2752
2756
  var jt = {
2753
2757
  Component: ({ sampler: e19, boxW: n30, boxH: r28, variant: i24, params: c16 }) => {
2758
+ let l17 = useId(), u15 = useId(), d12 = useId();
2754
2759
  if (i24 !== "solid" && i24 !== "subtle" && i24 !== "outline") return null;
2755
- let l17 = {
2760
+ let f12 = {
2756
2761
  ...kt,
2757
2762
  ...c16
2758
- }, u15 = useId(), d12 = useId(), f12 = useId(), p11 = e19.totalCss, m9 = [], h7 = null;
2763
+ }, p11 = e19.totalCss, m9 = [], h7 = null;
2759
2764
  for (let t25 = 0; t25 < At; t25++) {
2760
2765
  let n31 = t25 / At * p11, r29 = e19.perimeterAt(n31);
2761
2766
  r29.ny < 0 ? (h7 || (h7 = [], m9.push(h7)), h7.push({
@@ -2777,11 +2782,11 @@ var jt = {
2777
2782
  for (let n31 = 1; n31 < e20.length; n31++) t25 += ` L ${e20[n31].x.toFixed(3)} ${e20[n31].y.toFixed(3)}`;
2778
2783
  g6.push(t25);
2779
2784
  }
2780
- let _7 = 100 / n30, v4 = 100 / r28, y4 = Math.max(_7, v4), b3 = l17.bezelWidth * y4, x3 = l17.rimWidth * y4, S3 = Math.max(0, l17.equator - l17.equatorSpread), C3 = Math.min(100, l17.equator + l17.equatorSpread * 1.6), w3 = `color-mix(in srgb, ${l17.accent} ${l17.equatorTint}%, white)`, T3 = `color-mix(in srgb, ${l17.accent} ${l17.baseTint}%, black)`;
2785
+ let _7 = 100 / n30, v4 = 100 / r28, y4 = Math.max(_7, v4), b3 = f12.bezelWidth * y4, x3 = f12.rimWidth * y4, S3 = Math.max(0, f12.equator - f12.equatorSpread), C3 = Math.min(100, f12.equator + f12.equatorSpread * 1.6), w3 = `color-mix(in srgb, ${f12.accent} ${f12.equatorTint}%, white)`, T3 = `color-mix(in srgb, ${f12.accent} ${f12.baseTint}%, black)`;
2781
2786
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2782
2787
  /* @__PURE__ */ jsxs("defs", { children: [
2783
2788
  /* @__PURE__ */ jsxs("linearGradient", {
2784
- id: u15,
2789
+ id: l17,
2785
2790
  x1: "0%",
2786
2791
  y1: "0%",
2787
2792
  x2: "0%",
@@ -2790,19 +2795,19 @@ var jt = {
2790
2795
  /* @__PURE__ */ jsx("stop", {
2791
2796
  offset: "0%",
2792
2797
  style: {
2793
- stopColor: l17.accent,
2794
- stopOpacity: l17.topAlpha
2798
+ stopColor: f12.accent,
2799
+ stopOpacity: f12.topAlpha
2795
2800
  }
2796
2801
  }),
2797
2802
  /* @__PURE__ */ jsx("stop", {
2798
2803
  offset: `${S3}%`,
2799
2804
  style: {
2800
- stopColor: l17.accent,
2801
- stopOpacity: l17.upperAlpha
2805
+ stopColor: f12.accent,
2806
+ stopOpacity: f12.upperAlpha
2802
2807
  }
2803
2808
  }),
2804
2809
  /* @__PURE__ */ jsx("stop", {
2805
- offset: `${l17.equator}%`,
2810
+ offset: `${f12.equator}%`,
2806
2811
  style: {
2807
2812
  stopColor: w3,
2808
2813
  stopOpacity: 1
@@ -2811,7 +2816,7 @@ var jt = {
2811
2816
  /* @__PURE__ */ jsx("stop", {
2812
2817
  offset: `${C3}%`,
2813
2818
  style: {
2814
- stopColor: l17.accent,
2819
+ stopColor: f12.accent,
2815
2820
  stopOpacity: 1
2816
2821
  }
2817
2822
  }),
@@ -2825,24 +2830,24 @@ var jt = {
2825
2830
  ]
2826
2831
  }),
2827
2832
  /* @__PURE__ */ jsxs("linearGradient", {
2828
- id: d12,
2833
+ id: u15,
2829
2834
  x1: "0%",
2830
2835
  y1: "0%",
2831
2836
  x2: "0%",
2832
- y2: `${l17.glossExtent}%`,
2837
+ y2: `${f12.glossExtent}%`,
2833
2838
  children: [
2834
2839
  /* @__PURE__ */ jsx("stop", {
2835
2840
  offset: "0%",
2836
2841
  style: {
2837
2842
  stopColor: "white",
2838
- stopOpacity: l17.glossTopAlpha
2843
+ stopOpacity: f12.glossTopAlpha
2839
2844
  }
2840
2845
  }),
2841
2846
  /* @__PURE__ */ jsx("stop", {
2842
2847
  offset: "60%",
2843
2848
  style: {
2844
2849
  stopColor: "white",
2845
- stopOpacity: l17.glossMidAlpha
2850
+ stopOpacity: f12.glossMidAlpha
2846
2851
  }
2847
2852
  }),
2848
2853
  /* @__PURE__ */ jsx("stop", {
@@ -2855,29 +2860,29 @@ var jt = {
2855
2860
  ]
2856
2861
  }),
2857
2862
  /* @__PURE__ */ jsx("clipPath", {
2858
- id: f12,
2863
+ id: d12,
2859
2864
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
2860
2865
  })
2861
2866
  ] }),
2862
2867
  /* @__PURE__ */ jsx("path", {
2863
2868
  d: e19.bodyPath,
2864
- fill: `url(#${u15})`,
2869
+ fill: `url(#${l17})`,
2865
2870
  style: { pointerEvents: "none" }
2866
2871
  }),
2867
2872
  /* @__PURE__ */ jsx("rect", {
2868
2873
  x: "0",
2869
2874
  y: "0",
2870
2875
  width: "100",
2871
- height: l17.glossExtent,
2872
- fill: `url(#${d12})`,
2873
- clipPath: `url(#${f12})`,
2876
+ height: f12.glossExtent,
2877
+ fill: `url(#${u15})`,
2878
+ clipPath: `url(#${d12})`,
2874
2879
  style: { pointerEvents: "none" }
2875
2880
  }),
2876
2881
  g6.map((e20, t25) => /* @__PURE__ */ jsx("path", {
2877
2882
  d: e20,
2878
2883
  fill: "none",
2879
2884
  stroke: "white",
2880
- strokeOpacity: l17.bezelAlpha,
2885
+ strokeOpacity: f12.bezelAlpha,
2881
2886
  strokeWidth: b3,
2882
2887
  strokeLinecap: "round",
2883
2888
  vectorEffect: "non-scaling-stroke",
@@ -2887,7 +2892,7 @@ var jt = {
2887
2892
  d: e19.bodyPath,
2888
2893
  fill: "none",
2889
2894
  stroke: "black",
2890
- strokeOpacity: l17.rimAlpha,
2895
+ strokeOpacity: f12.rimAlpha,
2891
2896
  strokeWidth: x3,
2892
2897
  vectorEffect: "non-scaling-stroke",
2893
2898
  style: { pointerEvents: "none" }
@@ -2929,11 +2934,12 @@ var $ = {
2929
2934
  aqua: jt,
2930
2935
  metal: {
2931
2936
  Component: ({ sampler: e19, boxW: n30, boxH: r28, variant: i24, params: c16 }) => {
2937
+ let l17 = useId(), u15 = useId(), d12 = useId();
2932
2938
  if (i24 !== "solid" && i24 !== "subtle" && i24 !== "outline") return null;
2933
- let l17 = {
2939
+ let f12 = {
2934
2940
  ...Mt,
2935
2941
  ...c16
2936
- }, u15 = Math.max(0, Math.min(l17.specularity, 1)), d12 = useId(), f12 = useId(), p11 = useId(), m9 = e19.totalCss, h7 = [], g6 = null;
2942
+ }, p11 = Math.max(0, Math.min(f12.specularity, 1)), m9 = e19.totalCss, h7 = [], g6 = null;
2937
2943
  for (let t25 = 0; t25 < Nt; t25++) {
2938
2944
  let n31 = t25 / Nt * m9, r29 = e19.perimeterAt(n31);
2939
2945
  r29.ny < 0 ? (g6 || (g6 = [], h7.push(g6)), g6.push({
@@ -2955,11 +2961,11 @@ var $ = {
2955
2961
  for (let n31 = 1; n31 < e20.length; n31++) t25 += ` L ${e20[n31].x.toFixed(3)} ${e20[n31].y.toFixed(3)}`;
2956
2962
  _7.push(t25);
2957
2963
  }
2958
- let v4 = 100 / n30, y4 = 100 / r28, b3 = Math.max(v4, y4), x3 = l17.bezelWidth * b3, S3 = l17.rimWidth * b3, C3 = Math.max(0, l17.equator - l17.equatorSpread), w3 = Math.min(100, l17.equator + l17.equatorSpread), T3 = 100 - Math.round(u15 * 85), E3 = `color-mix(in srgb, ${l17.accent} ${T3}%, white)`, D3 = `color-mix(in srgb, ${l17.accent} ${l17.topDarkness}%, black)`, O3 = `color-mix(in srgb, ${l17.accent} ${l17.baseDarkness}%, black)`, k3 = 100 - Math.round(u15 * 50), A3 = 100 - Math.round(u15 * 30), j3 = `color-mix(in srgb, ${l17.accent} ${k3}%, white)`, M3 = `color-mix(in srgb, ${l17.accent} ${A3}%, white)`, N3 = l17.glossAlphaTop * u15, P3 = l17.bezelAlpha * (0.4 + 0.6 * u15), F3 = l17.rimAlpha * (0.6 + 0.4 * u15);
2964
+ let v4 = 100 / n30, y4 = 100 / r28, b3 = Math.max(v4, y4), x3 = f12.bezelWidth * b3, S3 = f12.rimWidth * b3, C3 = Math.max(0, f12.equator - f12.equatorSpread), w3 = Math.min(100, f12.equator + f12.equatorSpread), T3 = 100 - Math.round(p11 * 85), E3 = `color-mix(in srgb, ${f12.accent} ${T3}%, white)`, D3 = `color-mix(in srgb, ${f12.accent} ${f12.topDarkness}%, black)`, O3 = `color-mix(in srgb, ${f12.accent} ${f12.baseDarkness}%, black)`, k3 = 100 - Math.round(p11 * 50), A3 = 100 - Math.round(p11 * 30), j3 = `color-mix(in srgb, ${f12.accent} ${k3}%, white)`, M3 = `color-mix(in srgb, ${f12.accent} ${A3}%, white)`, N3 = f12.glossAlphaTop * p11, P3 = f12.bezelAlpha * (0.4 + 0.6 * p11), F3 = f12.rimAlpha * (0.6 + 0.4 * p11);
2959
2965
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2960
2966
  /* @__PURE__ */ jsxs("defs", { children: [
2961
2967
  /* @__PURE__ */ jsxs("linearGradient", {
2962
- id: d12,
2968
+ id: l17,
2963
2969
  x1: "0%",
2964
2970
  y1: "0%",
2965
2971
  x2: "0%",
@@ -2974,7 +2980,7 @@ var $ = {
2974
2980
  style: { stopColor: j3 }
2975
2981
  }),
2976
2982
  /* @__PURE__ */ jsx("stop", {
2977
- offset: `${l17.equator}%`,
2983
+ offset: `${f12.equator}%`,
2978
2984
  style: { stopColor: E3 }
2979
2985
  }),
2980
2986
  /* @__PURE__ */ jsx("stop", {
@@ -2988,11 +2994,11 @@ var $ = {
2988
2994
  ]
2989
2995
  }),
2990
2996
  /* @__PURE__ */ jsxs("linearGradient", {
2991
- id: f12,
2997
+ id: u15,
2992
2998
  x1: "0%",
2993
2999
  y1: "0%",
2994
3000
  x2: "0%",
2995
- y2: `${l17.glossExtent}%`,
3001
+ y2: `${f12.glossExtent}%`,
2996
3002
  children: [/* @__PURE__ */ jsx("stop", {
2997
3003
  offset: "0%",
2998
3004
  style: {
@@ -3008,22 +3014,22 @@ var $ = {
3008
3014
  })]
3009
3015
  }),
3010
3016
  /* @__PURE__ */ jsx("clipPath", {
3011
- id: p11,
3017
+ id: d12,
3012
3018
  children: /* @__PURE__ */ jsx("path", { d: e19.bodyPath })
3013
3019
  })
3014
3020
  ] }),
3015
3021
  /* @__PURE__ */ jsx("path", {
3016
3022
  d: e19.bodyPath,
3017
- fill: `url(#${d12})`,
3023
+ fill: `url(#${l17})`,
3018
3024
  style: { pointerEvents: "none" }
3019
3025
  }),
3020
3026
  N3 > 0 && /* @__PURE__ */ jsx("rect", {
3021
3027
  x: "0",
3022
3028
  y: "0",
3023
3029
  width: "100",
3024
- height: l17.glossExtent,
3025
- fill: `url(#${f12})`,
3026
- clipPath: `url(#${p11})`,
3030
+ height: f12.glossExtent,
3031
+ fill: `url(#${u15})`,
3032
+ clipPath: `url(#${d12})`,
3027
3033
  style: { pointerEvents: "none" }
3028
3034
  }),
3029
3035
  _7.map((e20, t25) => /* @__PURE__ */ jsx("path", {
@@ -5982,5 +5988,5 @@ function He2(e19, t25) {
5982
5988
  }
5983
5989
 
5984
5990
  export { F2 as F, Ft, He2 as He, Ve2 as Ve, _, _4 as _2, a4 as a, a8 as a2, a15 as a3, c4 as c, c5 as c2, c12 as c3, c13 as c4, d4 as d, d8 as d2, e7 as e, f, f6 as f2, h4 as h, l9 as l, l10 as l2, l13 as l3, m2 as m, m7 as m2, n15 as n, n23 as n2, n26 as n3, n29 as n4, o5 as o, o6 as o2, o7 as o3, o14 as o4, o15 as o5, o17 as o6, p, p4 as p2, p6 as p3, p8 as p4, p10 as p5, qe, r10 as r, r11 as r2, r12 as r3, r13 as r4, r15 as r5, s6 as s, s7 as s2, s15 as s3, u4 as u, u5 as u2, u7 as u3, u9 as u4, u11 as u5, v2 as v };
5985
- //# sourceMappingURL=chunk-C6GJKPUI.js.map
5986
- //# sourceMappingURL=chunk-C6GJKPUI.js.map
5991
+ //# sourceMappingURL=chunk-73KA7WBO.js.map
5992
+ //# sourceMappingURL=chunk-73KA7WBO.js.map