@kitlangton/knobs 0.0.0-stage → 0.1.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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1270 -2
  3. package/dist/dev/chunk-e13znr7c.js +155 -0
  4. package/dist/dev/chunk-kdewv0mt.js +1334 -0
  5. package/dist/dev/chunk-ktsn42p7.js +15668 -0
  6. package/dist/dev/chunk-qtt698hp.js +1118 -0
  7. package/dist/dev/index.js +1389 -0
  8. package/dist/index.js +2367 -0
  9. package/dist/panel.js +23635 -0
  10. package/dist/react.js +326 -0
  11. package/dist/solid.js +336 -0
  12. package/dist/themes.js +235 -0
  13. package/dist/types/core/adapter.d.ts +21 -0
  14. package/dist/types/core/code.d.ts +3 -0
  15. package/dist/types/core/color.d.ts +27 -0
  16. package/dist/types/core/easing.d.ts +21 -0
  17. package/dist/types/core/internal.d.ts +18 -0
  18. package/dist/types/core/keys.d.ts +21 -0
  19. package/dist/types/core/mutate.d.ts +21 -0
  20. package/dist/types/core/ramp.d.ts +150 -0
  21. package/dist/types/core/random.d.ts +2 -0
  22. package/dist/types/core/readout.d.ts +73 -0
  23. package/dist/types/core/remote.d.ts +258 -0
  24. package/dist/types/core/schema.d.ts +526 -0
  25. package/dist/types/core/spring.d.ts +38 -0
  26. package/dist/types/core/storage.d.ts +8 -0
  27. package/dist/types/core/store.d.ts +474 -0
  28. package/dist/types/core/theme.d.ts +27 -0
  29. package/dist/types/core/variants.d.ts +17 -0
  30. package/dist/types/index.d.ts +13 -0
  31. package/dist/types/panel/attach.d.ts +5 -0
  32. package/dist/types/panel/choice.d.ts +56 -0
  33. package/dist/types/panel/die.d.ts +121 -0
  34. package/dist/types/panel/editors.d.ts +159 -0
  35. package/dist/types/panel/folds.d.ts +14 -0
  36. package/dist/types/panel/give.d.ts +73 -0
  37. package/dist/types/panel/gpu/atlas.d.ts +40 -0
  38. package/dist/types/panel/gpu/color.d.ts +128 -0
  39. package/dist/types/panel/gpu/die.wgsl.d.ts +1 -0
  40. package/dist/types/panel/gpu/renderer.d.ts +712 -0
  41. package/dist/types/panel/gpu/shader.wgsl.d.ts +2 -0
  42. package/dist/types/panel/haptics.d.ts +8 -0
  43. package/dist/types/panel/has.d.ts +14 -0
  44. package/dist/types/panel/hints.d.ts +45 -0
  45. package/dist/types/panel/icons.d.ts +30 -0
  46. package/dist/types/panel/index.d.ts +10 -0
  47. package/dist/types/panel/inspector.d.ts +20 -0
  48. package/dist/types/panel/measure.d.ts +6 -0
  49. package/dist/types/panel/menu.d.ts +38 -0
  50. package/dist/types/panel/morph.d.ts +38 -0
  51. package/dist/types/panel/motion.d.ts +77 -0
  52. package/dist/types/panel/page-hints.d.ts +82 -0
  53. package/dist/types/panel/page.d.ts +423 -0
  54. package/dist/types/panel/panel.d.ts +43 -0
  55. package/dist/types/panel/position.d.ts +5 -0
  56. package/dist/types/panel/prefs.d.ts +28 -0
  57. package/dist/types/panel/presets.d.ts +48 -0
  58. package/dist/types/panel/ramps.d.ts +14 -0
  59. package/dist/types/panel/readout-row.d.ts +21 -0
  60. package/dist/types/panel/reveal.d.ts +15 -0
  61. package/dist/types/panel/rolling-css.d.ts +2 -0
  62. package/dist/types/panel/search.d.ts +36 -0
  63. package/dist/types/panel/seg.d.ts +15 -0
  64. package/dist/types/panel/session.d.ts +21 -0
  65. package/dist/types/panel/slider.d.ts +92 -0
  66. package/dist/types/panel/smear.d.ts +7 -0
  67. package/dist/types/panel/spin.d.ts +13 -0
  68. package/dist/types/panel/styles.d.ts +11 -0
  69. package/dist/types/panel/swipe.d.ts +114 -0
  70. package/dist/types/panel/switcher.d.ts +20 -0
  71. package/dist/types/panel/tabs.d.ts +31 -0
  72. package/dist/types/panel/thumb.d.ts +36 -0
  73. package/dist/types/react/Knobs.d.ts +15 -0
  74. package/dist/types/react/VariantSwitcher.d.ts +10 -0
  75. package/dist/types/react/index.d.ts +3 -0
  76. package/dist/types/react/useControls.d.ts +11 -0
  77. package/dist/types/solid/index.d.ts +50 -0
  78. package/dist/types/themes/index.d.ts +1 -0
  79. package/dist/types/ui/bento-css.d.ts +1 -0
  80. package/dist/types/ui/bento-model.d.ts +96 -0
  81. package/dist/types/ui/bento.d.ts +77 -0
  82. package/dist/types/ui/commands.d.ts +11 -0
  83. package/dist/types/ui/confirm.d.ts +13 -0
  84. package/dist/types/ui/index.d.ts +20 -0
  85. package/dist/types/ui/layer.d.ts +70 -0
  86. package/dist/types/ui/look.d.ts +53 -0
  87. package/dist/types/ui/menu.d.ts +63 -0
  88. package/dist/types/ui/overlay-css.d.ts +1 -0
  89. package/dist/types/ui/overlay-model.d.ts +87 -0
  90. package/dist/types/ui/palette.d.ts +38 -0
  91. package/dist/types/ui/popover.d.ts +35 -0
  92. package/dist/types/ui/react.d.ts +45 -0
  93. package/dist/types/ui/readout-css.d.ts +1 -0
  94. package/dist/types/ui/readout-model.d.ts +137 -0
  95. package/dist/types/ui/readouts.d.ts +85 -0
  96. package/dist/types/ui/rgba.d.ts +6 -0
  97. package/dist/types/ui/solid.d.ts +40 -0
  98. package/dist/types/ui/split-model.d.ts +81 -0
  99. package/dist/types/ui/split.d.ts +75 -0
  100. package/dist/types/ui/timeline-model.d.ts +83 -0
  101. package/dist/types/ui/timeline.d.ts +76 -0
  102. package/dist/types/ui/toast.d.ts +19 -0
  103. package/dist/types/ui/tooltip.d.ts +19 -0
  104. package/dist/types/ui/tree-model.d.ts +125 -0
  105. package/dist/types/ui/tree.d.ts +95 -0
  106. package/dist/ui-react.js +6558 -0
  107. package/dist/ui-solid.js +6511 -0
  108. package/dist/ui.js +9238 -0
  109. package/package.json +99 -4
@@ -0,0 +1,1389 @@
1
+ import {
2
+ __preload,
3
+ __chunks,
4
+ maxChroma,
5
+ oklchToRgb,
6
+ parseColor2,
7
+ colorHex2,
8
+ EASINGS2,
9
+ EASING_Y,
10
+ bezierPoint2,
11
+ bezierCss2,
12
+ normalizeCombo2,
13
+ letterOf2,
14
+ comboFromEvent2,
15
+ matchesCombo2,
16
+ comboParts2,
17
+ comboLabel2,
18
+ sampleGradient2,
19
+ gradientCss2,
20
+ sampleCurve2,
21
+ CURVE_SHAPES2,
22
+ randomStops,
23
+ mutateStops,
24
+ randomPoints,
25
+ mutatePoints,
26
+ pickMeta,
27
+ isReadout2,
28
+ hasValue2,
29
+ SPRING2,
30
+ valueKeys,
31
+ knob2,
32
+ choice2,
33
+ action2,
34
+ flatSpring2,
35
+ toggle2,
36
+ spring2,
37
+ color2,
38
+ point2,
39
+ easing2,
40
+ vec22,
41
+ vec32,
42
+ range2,
43
+ angle2,
44
+ seed2,
45
+ keybind2,
46
+ gradient2,
47
+ curve2,
48
+ toolbarShortcut2,
49
+ toolbar2,
50
+ watch2,
51
+ sparkline2,
52
+ graph2,
53
+ meter2,
54
+ table2,
55
+ log2,
56
+ wrapAngle2,
57
+ normalizeField,
58
+ normalize,
59
+ isRecord,
60
+ same,
61
+ equal,
62
+ springMotion2,
63
+ springCss2,
64
+ RESHAPE,
65
+ RESET_KEYS,
66
+ REFRESHES,
67
+ readoutState,
68
+ pushReadout,
69
+ READOUT,
70
+ memoryStorage2,
71
+ browserStorage,
72
+ urlFlag2,
73
+ storageKey
74
+ } from "./chunk-qtt698hp.js";
75
+ __chunks(import.meta.url,["yfpdrfyw","ktsn42p7","e13znr7c","qtt698hp","kdewv0mt"],[["./index.js",3],["./chunk-ktsn42p7.js",3,4],["./chunk-e13znr7c.js",3,4],["./chunk-qtt698hp.js"],["./chunk-kdewv0mt.js",3]],0);
76
+ // src/core/code.ts
77
+ var literal = (value) => Array.isArray(value) ? `[${value.map(literal).join(", ")}]` : typeof value === "object" && value !== null ? `{ ${Object.entries(value).map(([k, v]) => `${k}: ${literal(v)}`).join(", ")} }` : JSON.stringify(value);
78
+ function formatCode(values, format = "ts") {
79
+ if (format === "json")
80
+ return JSON.stringify(values, null, 2);
81
+ if (format === "jsx")
82
+ return Object.entries(values).map(([key, value]) => {
83
+ if (!/^[A-Za-z_$][\w$-]*$/.test(key))
84
+ throw Error(`Cannot serialize JSX prop: ${key}`);
85
+ return `${key}={${literal(value)}}`;
86
+ }).join(" ");
87
+ return `{ ${Object.entries(values).map(([key, value]) => `${/^[A-Za-z_$][\w$]*$/.test(key) && key !== "__proto__" ? key : `[${JSON.stringify(key)}]`}: ${literal(value)}`).join(", ")} }`;
88
+ }
89
+
90
+ // src/core/mutate.ts
91
+ var MUTATE = {
92
+ min: 0.08,
93
+ max: 0.12,
94
+ flip: 0.15,
95
+ hue: [4, 12],
96
+ chroma: 0.02,
97
+ lightness: [0.015, 0.045],
98
+ bezier: [0.03, 0.06]
99
+ }, between = (min, max, r) => min + (max - min) * r, signed = (random) => random() < 0.5 ? -1 : 1;
100
+ function nudge(v, min, max, step, random, reach = max - min) {
101
+ let span = max - min;
102
+ if (!(span > 0))
103
+ return v;
104
+ let sign = signed(random), by = reach * between(MUTATE.min, MUTATE.max, random()), next = v + sign * by;
105
+ if (next > max || next < min)
106
+ next = v - sign * by;
107
+ let top = Math.floor(span / step + 0.000000001), at = (n) => Number((min + n * step).toPrecision(14)), steps = Math.max(0, Math.min(top, Math.round((next - min) / step)));
108
+ if (at(steps) === v) {
109
+ let dir = next >= v ? 1 : -1;
110
+ steps = Math.max(0, Math.min(top, steps + (steps + dir > top || steps + dir < 0 ? -dir : dir)));
111
+ }
112
+ return at(steps);
113
+ }
114
+ function shift(field, value, random) {
115
+ switch (field.kind) {
116
+ case "knob":
117
+ return nudge(value, field.min, field.max, field.step, random);
118
+ case "point": {
119
+ let p = value;
120
+ return {
121
+ x: nudge(p.x, field.min.x, field.max.x, field.step.x, random),
122
+ y: nudge(p.y, field.min.y, field.max.y, field.step.y, random)
123
+ };
124
+ }
125
+ case "spring": {
126
+ let s = value, d = SPRING2.duration, b = SPRING2.bounce;
127
+ return {
128
+ duration: nudge(s.duration, d.min, d.max, d.step, random, 0.7),
129
+ bounce: nudge(s.bounce, b.min, b.max, b.step, random, 0.45)
130
+ };
131
+ }
132
+ case "color": {
133
+ let c = parseColor2(value) ?? { l: 0.7, c: 0.1, h: 0 }, max0 = maxChroma(c.l, c.h), rel0 = max0 > 0.0001 ? Math.min(1, Math.max(0, c.c / max0)) : 0.5, h = (c.h + signed(random) * between(MUTATE.hue[0], MUTATE.hue[1], random()) + 360) % 360, l = Math.min(1, Math.max(0, c.l + signed(random) * between(MUTATE.lightness[0], MUTATE.lightness[1], random())));
134
+ return { l, c: nudge(rel0, 0, 1, 0.01, random) * maxChroma(l, h), h };
135
+ }
136
+ case "easing":
137
+ return value.map((v, i) => {
138
+ let [lo, hi] = i % 2 === 0 ? [0, 1] : EASING_Y, next = v + signed(random) * between(MUTATE.bezier[0], MUTATE.bezier[1], random());
139
+ return Math.min(hi, Math.max(lo, next));
140
+ });
141
+ case "choice": {
142
+ if (random() >= MUTATE.flip || field.options.length < 2)
143
+ return value;
144
+ return other(field.options, value, random);
145
+ }
146
+ case "toggle":
147
+ return random() < MUTATE.flip ? !value : value;
148
+ case "vec": {
149
+ let v = value, axis = (n) => nudge(n, field.min, field.max, field.step, random);
150
+ return field.axes === 3 ? { x: axis(v.x), y: axis(v.y), z: axis(v.z ?? 0) } : { x: axis(v.x), y: axis(v.y) };
151
+ }
152
+ case "range": {
153
+ let [a, b] = value;
154
+ return [
155
+ nudge(a, field.min, field.max, field.step, random),
156
+ nudge(b, field.min, field.max, field.step, random)
157
+ ];
158
+ }
159
+ case "angle": {
160
+ let v = value;
161
+ if (!field.wrap)
162
+ return nudge(v, field.min, field.max, field.step, random);
163
+ let span = field.max - field.min;
164
+ return v + signed(random) * span * between(MUTATE.min, MUTATE.max, random());
165
+ }
166
+ case "seed":
167
+ return nudge(value, field.min, field.max, 1, random);
168
+ case "keybind":
169
+ return value;
170
+ case "gradient":
171
+ return mutateStops(value, random, MUTATE.hue, MUTATE.lightness);
172
+ case "curve":
173
+ return mutatePoints(value, field.range, random, [
174
+ MUTATE.min,
175
+ MUTATE.max
176
+ ]);
177
+ }
178
+ }
179
+ var other = (options, value, random) => {
180
+ let rest = options.filter((o) => o !== value);
181
+ return rest[Math.floor(Math.min(0.999999, random()) * rest.length)] ?? value;
182
+ };
183
+ function mutateValues(schema, current, keys = valueKeys(schema), random = Math.random) {
184
+ let out = {}, changed = !1;
185
+ for (let key of keys) {
186
+ let field = schema[key];
187
+ if (!field || !hasValue2(field))
188
+ continue;
189
+ let before = current[key] ?? field.value, next = normalizeField(field, shift(field, before, random));
190
+ if (out[key] = next, !same(before, next))
191
+ changed = !0;
192
+ }
193
+ if (!changed) {
194
+ let discrete = keys.filter((k) => {
195
+ let f = schema[k];
196
+ return f?.kind === "toggle" || f?.kind === "choice" && f.options.length > 1;
197
+ }), key = discrete[Math.floor(Math.min(0.999999, random()) * discrete.length)], field = key ? schema[key] : void 0;
198
+ if (key && field?.kind === "toggle")
199
+ out[key] = !(current[key] ?? field.value);
200
+ else if (key && field?.kind === "choice")
201
+ out[key] = other(field.options, String(current[key] ?? field.value), random);
202
+ }
203
+ return out;
204
+ }
205
+
206
+ // src/core/random.ts
207
+ var lattice = (min, max, step, r) => min + Math.floor(r * (Math.floor((max - min) / step + 0.000000001) + 1)) * step, between2 = (min, max, r) => min + (max - min) * r;
208
+ function pick(field, random) {
209
+ let r = () => Math.max(0, Math.min(1 - Number.EPSILON, random()));
210
+ switch (field.kind) {
211
+ case "knob":
212
+ return lattice(field.min, field.max, field.step, r());
213
+ case "choice":
214
+ return field.options[Math.floor(r() * field.options.length)];
215
+ case "toggle":
216
+ return r() >= 0.5;
217
+ case "spring":
218
+ return { duration: between2(0.2, 0.9, r()), bounce: between2(0, 0.45, r()) };
219
+ case "color": {
220
+ let l = between2(0.5, 0.85, r()), h = between2(0, 360, r());
221
+ return { l, c: between2(0.25, 0.85, r()) * maxChroma(l, h), h };
222
+ }
223
+ case "point":
224
+ return {
225
+ x: lattice(field.min.x, field.max.x, field.step.x, r()),
226
+ y: lattice(field.min.y, field.max.y, field.step.y, r())
227
+ };
228
+ case "easing": {
229
+ let curves = Object.values(EASINGS2);
230
+ return curves[Math.floor(r() * curves.length)];
231
+ }
232
+ case "vec": {
233
+ let axis = () => lattice(field.min, field.max, field.step, r());
234
+ return field.axes === 3 ? { x: axis(), y: axis(), z: axis() } : { x: axis(), y: axis() };
235
+ }
236
+ case "range":
237
+ return [
238
+ lattice(field.min, field.max, field.step, r()),
239
+ lattice(field.min, field.max, field.step, r())
240
+ ];
241
+ case "angle": {
242
+ let top = field.wrap ? field.max - field.step : field.max;
243
+ return lattice(field.min, Math.max(field.min, top), field.step, r());
244
+ }
245
+ case "seed":
246
+ return lattice(field.min, field.max, 1, r());
247
+ case "keybind":
248
+ return field.value;
249
+ case "gradient":
250
+ return randomStops(field.value.length, r);
251
+ case "curve":
252
+ return randomPoints(field.range, r);
253
+ }
254
+ }
255
+ function randomValues(schema, random = Math.random) {
256
+ return normalize(schema, Object.fromEntries(Object.entries(schema).flatMap(([key, field]) => hasValue2(field) ? [[key, pick(field, random)]] : [])));
257
+ }
258
+
259
+ // src/core/variants.ts
260
+ function createVariants(schema, id, key, storage, get, set, notify, enabled) {
261
+ let ready = !1, list = Object.freeze([]);
262
+ function parse(json) {
263
+ let data = JSON.parse(json);
264
+ if (!isRecord(data) || data.version !== 1 || data.controls !== id || !Array.isArray(data.variants))
265
+ throw Error("Expected a version 1 export for these controls.");
266
+ let ids = /* @__PURE__ */ new Set;
267
+ return Object.freeze(data.variants.map((item) => {
268
+ if (!isRecord(item) || typeof item.id !== "string" || !item.id || ids.has(item.id))
269
+ throw Error("Variant IDs must be unique nonempty strings.");
270
+ if (ids.add(item.id), item.name !== void 0 && (typeof item.name !== "string" || item.name.length > 100))
271
+ throw Error("Variant names must be at most 100 characters.");
272
+ if (!isRecord(item.values))
273
+ throw Error("Invalid variant values.");
274
+ let values = normalize(schema(), item.values);
275
+ if (!equal(values, item.values))
276
+ throw Error("Variant values do not match the schema, bounds, or step.");
277
+ return Object.freeze({
278
+ id: item.id,
279
+ ...typeof item.name === "string" ? { name: item.name } : {},
280
+ values
281
+ });
282
+ }));
283
+ }
284
+ let encode = (variants) => JSON.stringify({ version: 1, controls: id, variants }, null, 2);
285
+ function read() {
286
+ if (ready || !enabled())
287
+ return;
288
+ let json = storage()?.getItem(key);
289
+ list = json ? parse(json) : Object.freeze([]), ready = !0;
290
+ }
291
+ function persist(next) {
292
+ if (!enabled())
293
+ throw Error("Controls are disabled.");
294
+ if (!ready)
295
+ throw Error("Read variants with list() before writing; unread storage will not be overwritten.");
296
+ storage()?.setItem(key, encode(next)), list = Object.freeze(next), notify();
297
+ }
298
+ return {
299
+ get ready() {
300
+ return ready;
301
+ },
302
+ list() {
303
+ return read(), list;
304
+ },
305
+ save(name) {
306
+ if (read(), name !== void 0 && name.length > 100)
307
+ throw Error("Variant names must be at most 100 characters.");
308
+ let variant = Object.freeze({
309
+ id: crypto.randomUUID(),
310
+ ...name?.trim() ? { name: name.trim() } : {},
311
+ values: get()
312
+ });
313
+ return persist([...list, variant]), variant;
314
+ },
315
+ load(id) {
316
+ read();
317
+ let variant = list.find((v) => v.id === id);
318
+ if (!variant)
319
+ throw Error(`Unknown variant: ${id}`);
320
+ set(variant.values);
321
+ },
322
+ remove(id) {
323
+ read(), persist(list.filter((v) => v.id !== id));
324
+ },
325
+ export() {
326
+ return read(), encode(list);
327
+ },
328
+ import(json) {
329
+ if (!ready)
330
+ throw Error("Read variants with list() before importing; unread storage will not be overwritten.");
331
+ let incoming = parse(json), ids = new Set(list.map((v) => v.id));
332
+ persist([...list, ...incoming.filter((v) => !ids.has(v.id))]);
333
+ }
334
+ };
335
+ }
336
+
337
+ // src/core/store.ts
338
+ var devBuild = () => !0;
339
+ function sameField(a, b) {
340
+ if (a === b)
341
+ return !0;
342
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
343
+ return !1;
344
+ let ka = Object.keys(a).filter((k) => k !== "run"), kb = Object.keys(b).filter((k) => k !== "run");
345
+ if (ka.length !== kb.length)
346
+ return !1;
347
+ return ka.every((k) => {
348
+ let x = a[k], y = b[k];
349
+ if (typeof x === "function" && typeof y === "function")
350
+ return !0;
351
+ return Array.isArray(x) && Array.isArray(y) ? x.length === y.length && x.every((v, i) => same(v, y[i]) || sameField(v, y[i])) : same(x, y) || typeof x === "object" && sameField(x, y);
352
+ });
353
+ }
354
+ function defineControls(id, input, options = {}) {
355
+ if (!id.trim())
356
+ throw Error("Controls need a stable, nonempty id.");
357
+ let schema = Object.freeze({ ...input }), locked = normalize(schema, {}), actions = Object.freeze([...options.actions ?? []]), theme = options.theme ?? "dark", density = options.density ?? "default", renderer = options.renderer ?? "auto", enabled = () => typeof options.enabled === "function" ? options.enabled() : options.enabled ?? (Boolean(options.ship) || typeof location < "u" && ["localhost", "127.0.0.1", "[::1]"].includes(location.hostname)), storage = () => options.storage === void 0 ? browserStorage() : options.storage, persistMode = options.persist ?? "all", valueStorage = () => persistMode === "all" ? storage() : null, variantStorage = () => persistMode === "none" ? null : storage(), draw = options.random ?? Math.random, hostHistory = options.history, unsubscribeHistory, listeners = /* @__PURE__ */ new Set, refreshes = 0, notify = () => {
358
+ for (let cb of [...listeners])
359
+ cb();
360
+ }, mixed = /* @__PURE__ */ new Set, current = locked, read = !1, error = null, locks = /* @__PURE__ */ new Set, comparing = null, landing = !1, echo = Math.max(0, options.echo ?? 0), grabbed = /* @__PURE__ */ new Set, changedAt = /* @__PURE__ */ new Map, sent = /* @__PURE__ */ new Map, pending = /* @__PURE__ */ new Map, echoTimer, now = () => typeof performance < "u" ? performance.now() : Date.now(), isHeld = (key) => grabbed.has(key) || echo > 0 && now() - (changedAt.get(key) ?? -1 / 0) < echo, past = [], future = [], HISTORY = 100, stateKey = storageKey(id, "state"), buildPresets = () => Object.freeze(Object.fromEntries([
361
+ ["default", locked],
362
+ ...Object.entries(options.presets ?? {}).map(([id, patch]) => {
363
+ if (id === "default" || id === "custom")
364
+ throw Error(`Reserved preset id: ${id}`);
365
+ return [id, normalize(schema, { ...locked, ...patch })];
366
+ })
367
+ ])), presets = buildPresets(), buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
368
+ let named = list.flatMap((p) => Object.keys(p.values).filter((k) => Object.hasOwn(schema, k))), covered = new Set((named.length ? named : Object.keys(schema).filter((k) => schema[k].group === group)).filter((k) => hasValue2(schema[k])));
369
+ return [
370
+ group,
371
+ Object.freeze(list.map((p) => Object.freeze({
372
+ name: p.name,
373
+ values: Object.freeze(Object.fromEntries([...covered].map((k) => [
374
+ k,
375
+ normalizeField(schema[k], p.values[k] ?? locked[k])
376
+ ])))
377
+ })))
378
+ ];
379
+ }))), groupPresets = buildGroupPresets(), labelsOf, fieldLabels = () => {
380
+ if (labelsOf?.schema === schema)
381
+ return labelsOf;
382
+ let group = /* @__PURE__ */ new Map, section = /* @__PURE__ */ new Map, groupText = /* @__PURE__ */ new Map, sectionText = /* @__PURE__ */ new Map, first = (map, id, text) => {
383
+ if (id !== void 0 && text !== void 0 && !map.has(id))
384
+ map.set(id, text);
385
+ };
386
+ for (let f of Object.values(schema))
387
+ first(group, f.group, f.groupLabel), first(section, f.section, f.sectionLabel), first(groupText, f.group, f.groupDescription), first(sectionText, f.section, f.sectionDescription);
388
+ return labelsOf = { schema, group, section, groupText, sectionText }, labelsOf;
389
+ };
390
+ function load() {
391
+ if (!read) {
392
+ read = !0;
393
+ try {
394
+ let raw = valueStorage()?.getItem(stateKey);
395
+ if (raw) {
396
+ let data = JSON.parse(raw);
397
+ if (data?.version === 1) {
398
+ if (current = normalize(schema, data.values), Array.isArray(data.locks))
399
+ locks = new Set(data.locks.filter((k) => typeof k === "string" && Object.hasOwn(schema, k)));
400
+ }
401
+ }
402
+ } catch (cause) {
403
+ error = String(cause);
404
+ }
405
+ }
406
+ return current;
407
+ }
408
+ function get() {
409
+ if (!enabled())
410
+ return locked;
411
+ return comparing ?? load();
412
+ }
413
+ function persist() {
414
+ try {
415
+ valueStorage()?.setItem(stateKey, JSON.stringify({
416
+ version: 1,
417
+ values: current,
418
+ ...locks.size ? { locks: [...locks] } : {}
419
+ })), error = null;
420
+ } catch (cause) {
421
+ error = String(cause);
422
+ }
423
+ }
424
+ function commit(next) {
425
+ current = next, persist(), notify();
426
+ }
427
+ let fieldKeys = () => valueKeys(schema), valueField = (k) => {
428
+ let field = Object.hasOwn(schema, k) ? schema[k] : void 0;
429
+ return field && hasValue2(field) ? field : void 0;
430
+ };
431
+ function changes(from, to) {
432
+ let diff = {};
433
+ for (let k of fieldKeys())
434
+ if (!same(from[k], to[k]))
435
+ diff[k] = to[k];
436
+ return diff;
437
+ }
438
+ function release() {
439
+ if (!comparing)
440
+ return;
441
+ let shown = comparing;
442
+ comparing = null, options.onChange?.(changes(shown, current), current, { source: "compare" }), notify();
443
+ }
444
+ let flag = (k, name) => {
445
+ let v = valueField(k)?.[name];
446
+ return typeof v === "function" ? Boolean(v(get())) : Boolean(v);
447
+ }, blocked = (k) => flag(k, "disabled") || flag(k, "readOnly"), rollable = (k) => {
448
+ let field = valueField(k);
449
+ return Boolean(field && !locks.has(k) && field.random !== !1 && !blocked(k) && (!options.tunable || options.tunable(k, get())));
450
+ }, pool = (keys) => (load(), (keys ?? fieldKeys()).filter(rollable));
451
+ function applyPatch(base, previous, patch) {
452
+ let out = { ...base }, diff = {}, changed = !1;
453
+ if (base === previous) {
454
+ for (let k of Object.keys(patch)) {
455
+ let field = valueField(k);
456
+ if (!field)
457
+ continue;
458
+ let raw = patch[k], val = raw === void 0 ? previous[k] : normalizeField(field, raw);
459
+ if (!same(previous[k], val))
460
+ out[k] = val, diff[k] = val, changed = !0;
461
+ }
462
+ return changed ? { next: Object.freeze(out), diff } : null;
463
+ }
464
+ for (let k of Object.keys(patch)) {
465
+ let field = valueField(k);
466
+ if (!field)
467
+ continue;
468
+ let raw = patch[k], val = raw === void 0 ? base[k] : normalizeField(field, raw);
469
+ out[k] = same(previous[k], val) ? previous[k] : val;
470
+ }
471
+ for (let k of fieldKeys())
472
+ if (!same(previous[k], out[k]))
473
+ diff[k] = out[k], changed = !0;
474
+ else
475
+ out[k] = previous[k];
476
+ return changed ? { next: Object.freeze(out), diff } : null;
477
+ }
478
+ let markChanged = (diff) => {
479
+ if (echo > 0) {
480
+ let at = now();
481
+ for (let k of Object.keys(diff))
482
+ changedAt.set(k, at), sent.set(k, diff[k]);
483
+ scheduleEcho();
484
+ }
485
+ for (let k of Object.keys(diff))
486
+ pending.delete(k);
487
+ };
488
+ function set(patch, setOpts) {
489
+ if (!enabled())
490
+ return;
491
+ release();
492
+ let previous = load(), forced = mixed.size ? Object.keys(patch).filter((k) => mixed.has(k) && valueField(k)) : [];
493
+ for (let k of forced)
494
+ mixed.delete(k);
495
+ let applied = applyPatch(previous, previous, patch) ?? {
496
+ next: previous,
497
+ diff: {}
498
+ }, { next, diff } = applied;
499
+ for (let k of forced)
500
+ if (!(k in diff))
501
+ diff[k] = next[k];
502
+ if (Object.keys(diff).length === 0)
503
+ return;
504
+ if (next === previous) {
505
+ notify(), options.onChange?.(diff, next, {
506
+ source: setOpts?.source ?? "local",
507
+ ...setOpts?.key ? { key: setOpts.key } : {}
508
+ });
509
+ return;
510
+ }
511
+ if (!setOpts?.coalesce || past.length === 0) {
512
+ if (past.push(previous), past.length > HISTORY)
513
+ past.shift();
514
+ }
515
+ future.length = 0, markChanged(diff), commit(next), options.onChange?.(diff, next, {
516
+ source: setOpts?.source ?? "local",
517
+ ...setOpts?.coalesce ? { coalesce: !0 } : {},
518
+ ...setOpts?.key ? { key: setOpts.key } : {},
519
+ ...setOpts?.group ? { group: setOpts.group } : {}
520
+ });
521
+ }
522
+ function place(values, replace, land) {
523
+ let previous = load(), applied = applyPatch(replace ? locked : previous, previous, values);
524
+ if (!applied)
525
+ return;
526
+ landing = land;
527
+ try {
528
+ commit(applied.next), options.onChange?.(applied.diff, applied.next, { source: "remote" });
529
+ } finally {
530
+ landing = !1;
531
+ }
532
+ }
533
+ function acknowledges(key, value) {
534
+ if (!sent.has(key))
535
+ return !1;
536
+ let was = sent.get(key), field = schema[key];
537
+ if (field?.kind === "knob" && typeof value === "number" && typeof was === "number")
538
+ return Math.abs(value - was) <= (field.step ?? 0) / 2 + 0.000000001;
539
+ return same(value, was);
540
+ }
541
+ function incoming(values, replace) {
542
+ let current = load(), out = {};
543
+ for (let k of replace ? fieldKeys() : Object.keys(values)) {
544
+ if (!valueField(k))
545
+ continue;
546
+ let target = Object.hasOwn(values, k) ? values[k] : locked[k];
547
+ if (!grabbed.has(k) && changedAt.has(k) && acknowledges(k, target))
548
+ changedAt.delete(k), sent.delete(k);
549
+ if (isHeld(k))
550
+ pending.set(k, target), out[k] = current[k];
551
+ else
552
+ pending.delete(k), out[k] = target;
553
+ }
554
+ if (pending.size)
555
+ scheduleEcho();
556
+ return out;
557
+ }
558
+ function replaceMixed(keys) {
559
+ if (!keys)
560
+ return !1;
561
+ let next = new Set(keys.filter((k) => valueField(k)));
562
+ if (next.size === mixed.size && [...next].every((k) => mixed.has(k)))
563
+ return !1;
564
+ mixed.clear();
565
+ for (let k of next)
566
+ mixed.add(k);
567
+ return !0;
568
+ }
569
+ function sync(values, syncOpts) {
570
+ if (!enabled())
571
+ return;
572
+ release();
573
+ let land = Boolean(syncOpts?.land);
574
+ if (land)
575
+ settle();
576
+ let before = current, remixed = replaceMixed(syncOpts?.mixed);
577
+ if (place(incoming(values, Boolean(syncOpts?.replace)), !1, land), (land || remixed) && current === before)
578
+ announce(land);
579
+ }
580
+ function settle() {
581
+ past.length = 0, future.length = 0, changedAt.clear(), sent.clear();
582
+ for (let k of [...pending.keys()])
583
+ if (!grabbed.has(k))
584
+ pending.delete(k);
585
+ scheduleEcho();
586
+ }
587
+ function announce(land) {
588
+ landing = land;
589
+ try {
590
+ notify();
591
+ } finally {
592
+ landing = !1;
593
+ }
594
+ }
595
+ function flush() {
596
+ let ready = {};
597
+ for (let [k, v] of pending)
598
+ if (!isHeld(k))
599
+ ready[k] = v, pending.delete(k);
600
+ if (Object.keys(ready).length)
601
+ place(ready, !1, !1);
602
+ scheduleEcho();
603
+ }
604
+ function scheduleEcho() {
605
+ if (clearTimeout(echoTimer), echoTimer = void 0, echo <= 0 || pending.size === 0)
606
+ return;
607
+ let soonest = 1 / 0, t = now();
608
+ for (let k of pending.keys()) {
609
+ if (grabbed.has(k))
610
+ continue;
611
+ soonest = Math.min(soonest, (changedAt.get(k) ?? -1 / 0) + echo - t);
612
+ }
613
+ if (soonest === 1 / 0)
614
+ return;
615
+ echoTimer = setTimeout(flush, Math.max(0, soonest) + 1);
616
+ }
617
+ let reshape = (next, values, reshapeOpts) => {
618
+ if (!enabled())
619
+ return;
620
+ release();
621
+ let before = schema, changed = Object.keys(before).length !== Object.keys(next).length || Object.keys(next).some((k) => !sameField(before[k], next[k])), land = Boolean(reshapeOpts?.land), fresh = !changed && Object.keys(next).some((k) => {
622
+ let a = before[k], b = next[k];
623
+ return Object.keys(b).some((p) => typeof b[p] === "function" && a[p] !== b[p]);
624
+ });
625
+ if (fresh)
626
+ schema = Object.freeze({ ...next });
627
+ if (changed) {
628
+ let previous = load();
629
+ schema = Object.freeze({ ...next }), locked = normalize(schema, {}), presets = buildPresets(), groupPresets = buildGroupPresets();
630
+ for (let k of [...locks])
631
+ if (!valueField(k))
632
+ locks.delete(k);
633
+ for (let k of [...pending.keys()])
634
+ if (!valueField(k))
635
+ pending.delete(k);
636
+ for (let k of [...mixed])
637
+ if (!valueField(k))
638
+ mixed.delete(k);
639
+ let kept = {};
640
+ for (let k of fieldKeys())
641
+ kept[k] = Object.hasOwn(previous, k) ? previous[k] : locked[k];
642
+ current = normalize(schema, kept);
643
+ }
644
+ if (land)
645
+ settle();
646
+ else if (changed)
647
+ past.length = 0, future.length = 0;
648
+ let remixed = replaceMixed(reshapeOpts?.mixed), target = incoming(values, !0), before2 = current;
649
+ if (place(target, !1, land), current === before2 && (changed || fresh || land || remixed))
650
+ announce(land);
651
+ }, readouts = /* @__PURE__ */ new Map, readoutListeners = /* @__PURE__ */ new Set, readoutOf = (key) => {
652
+ let field = Object.hasOwn(schema, key) ? schema[key] : void 0;
653
+ if (!field || !isReadout2(field))
654
+ return;
655
+ let shape = `${field.kind}\x00${"history" in field ? field.history : ""}\x00${field.kind === "graph" ? field.series.map((s) => s.id).join("\x00") : ""}\x00${field.kind === "log" ? field.max : ""}`, entry = readouts.get(key);
656
+ if (!entry || entry.shape !== shape)
657
+ entry = { shape, state: readoutState(field) }, readouts.set(key, entry);
658
+ return { field, state: entry.state };
659
+ }, readoutPort = {
660
+ state: (key) => readoutOf(key)?.state,
661
+ listen(cb) {
662
+ return readoutListeners.add(cb), () => readoutListeners.delete(cb);
663
+ }
664
+ }, controls = {
665
+ id,
666
+ get schema() {
667
+ return schema;
668
+ },
669
+ get locked() {
670
+ return locked;
671
+ },
672
+ get presets() {
673
+ return presets;
674
+ },
675
+ actions,
676
+ theme,
677
+ density,
678
+ renderer,
679
+ keys: options.keys,
680
+ marks: options.marks !== !1,
681
+ chip: Object.freeze({
682
+ ...options.chip,
683
+ reveal: options.chip?.reveal ?? (devBuild() ? "hover" : "shortcut"),
684
+ shortcut: options.chip?.shortcut ?? "Alt+Shift+D"
685
+ }),
686
+ groupPresetDisplay: options.groupPresetDisplay ?? "auto",
687
+ groupLabel: (group) => options.groupLabels?.[group] ?? fieldLabels().group.get(group),
688
+ sectionLabel: (section) => options.sectionLabels?.[section] ?? fieldLabels().section.get(section),
689
+ groupDescription: (group) => options.groupDescriptions?.[group] ?? fieldLabels().groupText.get(group),
690
+ sectionDescription: (section) => options.sectionDescriptions?.[section] ?? fieldLabels().sectionText.get(section),
691
+ groupFolded: options.groupFolded,
692
+ sectionFolded: options.sectionFolded,
693
+ presetLabel: (presetId) => options.presetLabels?.[presetId] ?? (presetId === "default" ? options.defaultLabel : void 0) ?? presetId,
694
+ get,
695
+ set,
696
+ sync,
697
+ get enabled() {
698
+ return enabled();
699
+ },
700
+ get storage() {
701
+ return storage();
702
+ },
703
+ get error() {
704
+ return error;
705
+ },
706
+ get canUndo() {
707
+ return hostHistory ? hostHistory.canUndo() : past.length > 0;
708
+ },
709
+ get canRedo() {
710
+ return hostHistory ? hostHistory.canRedo() : future.length > 0;
711
+ },
712
+ persist: persistMode,
713
+ get comparing() {
714
+ return comparing !== null;
715
+ },
716
+ get landing() {
717
+ return landing;
718
+ },
719
+ [RESHAPE]: reshape,
720
+ [READOUT]: readoutPort,
721
+ watch(key, value) {
722
+ let found = readoutOf(key);
723
+ if (!found)
724
+ return;
725
+ pushReadout(found.field, found.state, value);
726
+ for (let cb of readoutListeners)
727
+ cb(key);
728
+ },
729
+ watched(key) {
730
+ let state = readouts.get(key)?.state;
731
+ return state && state.seq > 0 ? state.value : void 0;
732
+ },
733
+ hold(key, on = !0) {
734
+ if (on) {
735
+ if (grabbed.has(key))
736
+ return;
737
+ grabbed.add(key), options.onGesture?.({ key, phase: "start" });
738
+ return;
739
+ }
740
+ if (!grabbed.delete(key))
741
+ return;
742
+ options.onGesture?.({ key, phase: "end" }), flush();
743
+ },
744
+ isHeld,
745
+ action(key, item) {
746
+ let field = schema[key];
747
+ if (field?.kind === "toolbar") {
748
+ let found = field.items.find((i) => (i.id ?? i.label) === item);
749
+ if (!found)
750
+ throw Error(`Unknown toolbar item: ${key} ${item}`);
751
+ if (found.disabled)
752
+ return;
753
+ found.run?.(), options.onAction?.(found.id ?? found.label);
754
+ return;
755
+ }
756
+ if (!field || field.kind !== "action")
757
+ throw Error(`Unknown action: ${key}`);
758
+ field.run?.(), options.onAction?.(key);
759
+ },
760
+ undo() {
761
+ if (release(), hostHistory)
762
+ return hostHistory.undo();
763
+ let previous = past.pop();
764
+ if (!previous)
765
+ return;
766
+ let before = load(), diff = changes(before, previous);
767
+ future.push(before), markChanged(diff), commit(previous), options.onChange?.(diff, previous, { source: "undo" });
768
+ },
769
+ redo() {
770
+ if (release(), hostHistory)
771
+ return hostHistory.redo();
772
+ let next = future.pop();
773
+ if (!next)
774
+ return;
775
+ let before = load(), diff = changes(before, next);
776
+ past.push(before), markChanged(diff), commit(next), options.onChange?.(diff, next, { source: "redo" });
777
+ },
778
+ getServerSnapshot: () => locked,
779
+ subscribe(cb) {
780
+ if (listeners.add(cb), hostHistory?.subscribe && !unsubscribeHistory)
781
+ unsubscribeHistory = hostHistory.subscribe(notify);
782
+ return () => {
783
+ if (listeners.delete(cb), !listeners.size && unsubscribeHistory)
784
+ unsubscribeHistory(), unsubscribeHistory = void 0;
785
+ };
786
+ },
787
+ reset(keys) {
788
+ if (!enabled())
789
+ return;
790
+ let skipped = fieldKeys().some(blocked);
791
+ if (!keys && !skipped) {
792
+ set(locked, { source: "reset" }), options.onReset?.({});
793
+ return;
794
+ }
795
+ let patch = {};
796
+ for (let k of keys ?? fieldKeys())
797
+ if (valueField(k) && !blocked(k))
798
+ patch[k] = locked[k];
799
+ set(patch, { source: "reset" });
800
+ let resetKeys = options[RESET_KEYS];
801
+ if (resetKeys)
802
+ resetKeys(Object.keys(patch));
803
+ else
804
+ for (let key of Object.keys(patch))
805
+ options.onReset?.({ key });
806
+ },
807
+ resetKey(key) {
808
+ if (!enabled())
809
+ return;
810
+ if (!valueField(key))
811
+ throw Error(`Unknown control key: ${key}`);
812
+ if (blocked(key))
813
+ return;
814
+ set({ [key]: locked[key] }, { source: "reset", key }), options.onReset?.({ key });
815
+ },
816
+ resetGroup(group) {
817
+ if (!enabled())
818
+ return;
819
+ let keys = Object.keys(schema).filter((k) => schema[k].group === group && hasValue2(schema[k])), open = keys.filter((k) => !blocked(k));
820
+ if (open.length < keys.length)
821
+ return controls.reset(open);
822
+ let patch = {};
823
+ for (let k of keys)
824
+ patch[k] = locked[k];
825
+ set(patch, { source: "reset", group }), options.onReset?.({ group });
826
+ },
827
+ isModified(key) {
828
+ let cur = get();
829
+ if (key !== void 0)
830
+ return !same(cur[key], locked[key]);
831
+ return !equal(cur, locked);
832
+ },
833
+ modified() {
834
+ let cur = get(), out = {};
835
+ for (let k of fieldKeys())
836
+ if (!same(cur[k], locked[k]))
837
+ out[k] = cur[k];
838
+ return Object.freeze(out);
839
+ },
840
+ randomize(keys) {
841
+ if (!enabled())
842
+ return;
843
+ let chosen = pool(keys);
844
+ if (chosen.length === 0)
845
+ return;
846
+ let sub = Object.fromEntries(chosen.map((k) => [k, schema[k]]));
847
+ set(randomValues(sub, draw), { source: "randomize" });
848
+ },
849
+ mutate(keys) {
850
+ if (!enabled())
851
+ return;
852
+ release();
853
+ let chosen = pool(keys);
854
+ if (chosen.length === 0)
855
+ return;
856
+ set(mutateValues(schema, load(), chosen, draw), { source: "mutate" });
857
+ },
858
+ lock(keys, on = !0) {
859
+ if (!enabled())
860
+ return;
861
+ load();
862
+ let changed = !1;
863
+ for (let key of typeof keys === "string" ? [keys] : keys) {
864
+ if (!valueField(key))
865
+ throw Error(`Unknown control key: ${key}`);
866
+ if (locks.has(key) === on)
867
+ continue;
868
+ if (on)
869
+ locks.add(key);
870
+ else
871
+ locks.delete(key);
872
+ changed = !0;
873
+ }
874
+ if (!changed)
875
+ return;
876
+ persist(), notify();
877
+ },
878
+ isLocked(key) {
879
+ if (!enabled())
880
+ return !1;
881
+ return load(), locks.has(key);
882
+ },
883
+ canRoll(key) {
884
+ if (!enabled())
885
+ return !1;
886
+ return load(), rollable(key);
887
+ },
888
+ isDisabled: (key) => flag(key, "disabled"),
889
+ isReadOnly: (key) => flag(key, "readOnly"),
890
+ refresh() {
891
+ refreshes++, notify();
892
+ },
893
+ get [REFRESHES]() {
894
+ return refreshes;
895
+ },
896
+ setMixed(keys, on = !0) {
897
+ let changed = !1;
898
+ for (let key of typeof keys === "string" ? [keys] : keys) {
899
+ if (!valueField(key) || mixed.has(key) === on)
900
+ continue;
901
+ if (on)
902
+ mixed.add(key);
903
+ else
904
+ mixed.delete(key);
905
+ changed = !0;
906
+ }
907
+ if (changed)
908
+ notify();
909
+ },
910
+ isMixed: (key) => mixed.has(key),
911
+ compare(hold) {
912
+ if (!enabled())
913
+ return;
914
+ if (!hold)
915
+ return release();
916
+ let before = past.at(-1), now = load();
917
+ if (comparing || !before || equal(before, now))
918
+ return;
919
+ comparing = before, options.onChange?.(changes(now, before), before, { source: "compare" }), notify();
920
+ },
921
+ preset(id) {
922
+ if (!Object.hasOwn(presets, id))
923
+ throw Error(`Unknown preset: ${id}`);
924
+ set(presets[id], { source: "preset" });
925
+ },
926
+ matchingPreset: () => Object.keys(presets).find((id) => equal(get(), presets[id])) ?? "custom",
927
+ get groupPresets() {
928
+ return groupPresets;
929
+ },
930
+ groupPreset(group, index, presetOptions) {
931
+ let preset = groupPresets[group]?.[index];
932
+ if (!preset)
933
+ throw Error(`Unknown preset ${index + 1} for group ${group}`);
934
+ if (!enabled())
935
+ return;
936
+ set(preset.values, { source: "preset", group, coalesce: presetOptions?.coalesce }), options.onPreset?.({ group, index, name: preset.name });
937
+ },
938
+ matchingGroupPreset(group) {
939
+ let cur = get();
940
+ return (groupPresets[group] ?? []).findIndex((p) => Object.entries(p.values).every(([k, v]) => same(cur[k], v)));
941
+ },
942
+ code: (format, values) => formatCode(values ?? get(), format),
943
+ variants: createVariants(() => schema, id, storageKey(id, "variants"), variantStorage, get, (v) => set(v, { source: "variant" }), notify, enabled),
944
+ attach(element, chip) {
945
+ let load = options.ship ? () => options.ship().then((m) => m.attach) : () => (__preload("e13znr7c"), import("./chunk-e13znr7c.js")).then((m) => m.attach);
946
+ if (!load || !enabled())
947
+ return () => {};
948
+ let disposed = !1, detach;
949
+ return load().then((attach) => {
950
+ if (!disposed && enabled())
951
+ detach = attach(controls, element, chip);
952
+ }).catch((cause) => {
953
+ error = String(cause), notify();
954
+ }), () => {
955
+ disposed = !0, detach?.();
956
+ };
957
+ },
958
+ mount(container, mountOptions) {
959
+ let load = options.ship ? () => options.ship().then((m) => m.mountPanel) : () => (__preload("ktsn42p7"), import("./chunk-ktsn42p7.js")).then((m) => m.mountPanel);
960
+ if (!load || !enabled())
961
+ return () => {};
962
+ let disposed = !1, panel;
963
+ return load().then((mountPanel) => {
964
+ if (!disposed && enabled())
965
+ panel = mountPanel(controls, container, mountOptions), mountOptions?.onReady?.(panel);
966
+ }).catch((cause) => {
967
+ error = String(cause), notify();
968
+ }), () => {
969
+ disposed = !0, panel?.dispose();
970
+ };
971
+ }
972
+ };
973
+ return Object.freeze(controls);
974
+ }
975
+ // src/core/remote.ts
976
+ var readoutDescriptor = (d) => isReadout2(d);
977
+ function readoutField(d) {
978
+ let { key: _key, kind, default: _d, bind: _b, ...rest } = d, opts = Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== void 0));
979
+ if (kind === "watch")
980
+ return watch2(opts);
981
+ if (kind === "sparkline")
982
+ return sparkline2(opts);
983
+ if (kind === "graph")
984
+ return graph2(opts);
985
+ if (kind === "meter")
986
+ return meter2(opts);
987
+ if (kind === "table")
988
+ return table2(opts);
989
+ return log2(opts);
990
+ }
991
+ var optionId = (o) => typeof o === "string" ? o : String(o.id ?? o.value ?? o.label ?? "");
992
+ function descriptorToField(d) {
993
+ let meta = pickMeta(d);
994
+ if (d.kind === "action")
995
+ return action2(d.label, meta);
996
+ if (readoutDescriptor(d))
997
+ return readoutField(d);
998
+ if (d.kind === "toolbar")
999
+ return toolbar2(d.items.map(({ key, ...item }) => ({ ...item, id: key })), meta);
1000
+ if (d.bind)
1001
+ return flatSpring2({}, { ...meta, id: d.key }).duration;
1002
+ if (d.kind === "knob" || d.kind === "number") {
1003
+ let def = typeof d.default === "number" && Number.isFinite(d.default) ? d.default : 0, min = d.min ?? Math.min(0, def * 2), max = d.max ?? Math.max(1, def * 2), step = d.step ?? (d.swiftType === "Int" ? 1 : (max - min) / 100 || 1);
1004
+ return knob2(def, {
1005
+ min,
1006
+ max,
1007
+ step,
1008
+ ...d.unit !== void 0 ? { unit: d.unit } : {},
1009
+ ...d.decimals !== void 0 ? { decimals: d.decimals } : {},
1010
+ ...meta
1011
+ });
1012
+ }
1013
+ if (d.kind === "choice") {
1014
+ let given = d.options ?? d.choices ?? [String(d.default)];
1015
+ if (given.length === 0)
1016
+ throw Error(`Choice descriptor ${d.key} needs options.`);
1017
+ let list = given.map(optionId), labels = Object.fromEntries(given.flatMap((o) => typeof o === "string" || o.label === void 0 ? [] : [[optionId(o), o.label]])), def = list.includes(String(d.default)) ? String(d.default) : list[0];
1018
+ return choice2(def, list, {
1019
+ ...meta,
1020
+ labels,
1021
+ ...d.display ? { display: d.display } : {}
1022
+ });
1023
+ }
1024
+ if (d.kind === "spring")
1025
+ return spring2(d.default, meta);
1026
+ if (d.kind === "color")
1027
+ return color2(parseColor2(d.default) ? d.default : "#808080", meta);
1028
+ if (d.kind === "point")
1029
+ return point2(d.default, { min: d.min ?? 0, max: d.max ?? 1, step: d.step, ...meta });
1030
+ if (d.kind === "easing")
1031
+ return easing2(d.default, meta);
1032
+ let numbers = {
1033
+ ...d.unit !== void 0 ? { unit: d.unit } : {},
1034
+ ...d.decimals !== void 0 ? { decimals: d.decimals } : {},
1035
+ ...d.step !== void 0 ? { step: d.step } : {}
1036
+ };
1037
+ if (d.kind === "vec2" || d.kind === "vec3") {
1038
+ let v = d.default ?? {}, opts = {
1039
+ min: d.min ?? -1,
1040
+ max: d.max ?? 1,
1041
+ ...numbers,
1042
+ ...d.link ? { link: !0 } : {},
1043
+ ...d.linked ? { linked: !0 } : {},
1044
+ ...d.axes ? { axes: d.axes } : {},
1045
+ ...meta
1046
+ };
1047
+ return d.kind === "vec3" ? vec32({ x: v.x ?? 0, y: v.y ?? 0, z: v.z ?? 0 }, opts) : vec22({ x: v.x ?? 0, y: v.y ?? 0 }, opts);
1048
+ }
1049
+ if (d.kind === "range") {
1050
+ let v = Array.isArray(d.default) ? d.default : [d.min ?? 0, d.max ?? 1];
1051
+ return range2([Number(v[0]), Number(v[1])], {
1052
+ min: d.min ?? 0,
1053
+ max: d.max ?? 1,
1054
+ ...numbers,
1055
+ ...meta
1056
+ });
1057
+ }
1058
+ if (d.kind === "angle")
1059
+ return angle2(typeof d.default === "number" ? d.default : 0, {
1060
+ ...d.min !== void 0 ? { min: d.min } : {},
1061
+ ...d.max !== void 0 ? { max: d.max } : {},
1062
+ ...d.step !== void 0 ? { step: d.step } : {},
1063
+ ...d.wrap !== void 0 ? { wrap: d.wrap } : {},
1064
+ ...meta
1065
+ });
1066
+ if (d.kind === "seed")
1067
+ return seed2(typeof d.default === "number" ? d.default : 0, {
1068
+ ...d.min !== void 0 ? { min: d.min } : {},
1069
+ ...d.max !== void 0 ? { max: d.max } : {},
1070
+ ...meta
1071
+ });
1072
+ if (d.kind === "keybind")
1073
+ return keybind2(typeof d.default === "string" ? d.default : "", meta);
1074
+ if (d.kind === "gradient") {
1075
+ let fallback = [
1076
+ { at: 0, color: "#000000" },
1077
+ { at: 1, color: "#ffffff" }
1078
+ ], stops = Array.isArray(d.default) ? d.default : fallback, opts = {
1079
+ ...d.space ? { space: d.space } : {},
1080
+ ...d.presets ? { presets: d.presets } : {},
1081
+ ...meta
1082
+ };
1083
+ try {
1084
+ return gradient2(stops, opts);
1085
+ } catch {
1086
+ return gradient2(fallback, opts);
1087
+ }
1088
+ }
1089
+ if (d.kind === "curve") {
1090
+ let opts = {
1091
+ range: d.range ?? [d.min ?? 0, d.max ?? 1],
1092
+ ...d.interp ? { interp: d.interp } : {},
1093
+ ...d.shapes !== void 0 ? { shapes: d.shapes } : {},
1094
+ ...d.presets ? { presets: d.presets } : {},
1095
+ ...meta
1096
+ }, points = Array.isArray(d.default) ? d.default : [];
1097
+ return points.length >= 2 ? curve2(points, opts) : curve2("linear", opts);
1098
+ }
1099
+ return toggle2(Boolean(d.default), meta);
1100
+ }
1101
+ function fromDescriptors(descriptors) {
1102
+ let byKey = new Map(descriptors.map((d) => [d.key, d])), bound = /* @__PURE__ */ new Set;
1103
+ for (let d of descriptors)
1104
+ if (d.bind) {
1105
+ if (d.bind.duration === d.bind.bounce)
1106
+ throw Error(`Spring ${d.key} binds one key twice.`);
1107
+ bound.add(d.bind.duration).add(d.bind.bounce);
1108
+ }
1109
+ let entries = [];
1110
+ for (let d of descriptors) {
1111
+ if (bound.has(d.key) && !d.bind)
1112
+ continue;
1113
+ if (!d.bind) {
1114
+ entries.push([d.key, descriptorToField(d)]);
1115
+ continue;
1116
+ }
1117
+ let half = (part) => {
1118
+ let own = byKey.get(d.bind[part]);
1119
+ if (own && !own.bind && (own.kind === "number" || own.kind === "knob"))
1120
+ return descriptorToField({
1121
+ ...own,
1122
+ group: d.group ?? own.group,
1123
+ groupLabel: d.groupLabel ?? own.groupLabel
1124
+ });
1125
+ return d.default?.[part] ?? (part === "duration" ? 0.5 : 0);
1126
+ }, pair = flatSpring2({ duration: half("duration"), bounce: half("bounce") }, { id: d.key, ...pickMeta(d, ["shortcut"]) });
1127
+ entries.push([d.bind.duration, pair.duration], [d.bind.bounce, pair.bounce]);
1128
+ }
1129
+ return Object.freeze(Object.fromEntries(entries));
1130
+ }
1131
+ var decimal = (n) => String(Math.round(n * 1e4) / 1e4), swiftLiteral = (d, v) => {
1132
+ if (d.kind === "color") {
1133
+ let [r, g, b] = oklchToRgb(parseColor2(v) ?? { l: 0, c: 0, h: 0 }).map(decimal);
1134
+ return `Color(red: ${r}, green: ${g}, blue: ${b})`;
1135
+ }
1136
+ if (d.kind === "point") {
1137
+ let p = v;
1138
+ return `CGPoint(x: ${decimal(p.x)}, y: ${decimal(p.y)})`;
1139
+ }
1140
+ if (d.kind === "easing") {
1141
+ let [x1, y1, x2, y2] = v.map(decimal);
1142
+ return `.bezier(startControlPoint: UnitPoint(x: ${x1}, y: ${y1}), endControlPoint: UnitPoint(x: ${x2}, y: ${y2}))`;
1143
+ }
1144
+ if (d.kind === "vec2" || d.kind === "vec3") {
1145
+ let p = v;
1146
+ return d.kind === "vec3" ? `SIMD3<Double>(${decimal(p.x)}, ${decimal(p.y)}, ${decimal(p.z)})` : `SIMD2<Double>(${decimal(p.x)}, ${decimal(p.y)})`;
1147
+ }
1148
+ if (d.kind === "range") {
1149
+ let [a, b] = v;
1150
+ return `${decimal(a)}...${decimal(b)}`;
1151
+ }
1152
+ if (d.kind === "keybind")
1153
+ return JSON.stringify(v);
1154
+ if (d.kind === "gradient")
1155
+ return `Gradient(stops: [${(Array.isArray(v) ? v : []).map((s) => {
1156
+ let [r, g, b] = oklchToRgb(parseColor2(s.color) ?? { l: 0, c: 0, h: 0 }).map(decimal);
1157
+ return `.init(color: Color(red: ${r}, green: ${g}, blue: ${b}), location: ${decimal(s.at)})`;
1158
+ }).join(", ")}])`;
1159
+ if (d.kind === "curve")
1160
+ return `[${(Array.isArray(v) ? v : []).map((p) => `CGPoint(x: ${decimal(p.x)}, y: ${decimal(p.y)})`).join(", ")}]`;
1161
+ if (d.kind === "seed")
1162
+ return String(Math.round(v));
1163
+ if (typeof v === "boolean")
1164
+ return String(v);
1165
+ if (typeof v === "string")
1166
+ return `.${v}`;
1167
+ if (typeof v !== "number")
1168
+ return JSON.stringify(v);
1169
+ if (d.swiftType === "Int")
1170
+ return String(Math.round(v));
1171
+ return decimal(v);
1172
+ }, swiftTypes = {
1173
+ color: "Color",
1174
+ point: "CGPoint",
1175
+ easing: "UnitCurve",
1176
+ vec2: "SIMD2<Double>",
1177
+ vec3: "SIMD3<Double>",
1178
+ range: "ClosedRange<Double>",
1179
+ seed: "Int",
1180
+ keybind: "String",
1181
+ gradient: "Gradient",
1182
+ curve: "[CGPoint]"
1183
+ };
1184
+ function formatSwift(descriptors, values, group) {
1185
+ let byKey = new Map(descriptors.map((d) => [d.key, d])), done = /* @__PURE__ */ new Set, lines = [];
1186
+ for (let d of descriptors) {
1187
+ if (d.kind === "action" || d.kind === "toolbar" || d.bind)
1188
+ continue;
1189
+ if (readoutDescriptor(d))
1190
+ continue;
1191
+ if (!((d.key in values) && !same(values[d.key], d.default)) || done.has(d.key) || group && d.group !== group)
1192
+ continue;
1193
+ let base = d.key.replace(/\.(duration|bounce)$/, ""), duration = byKey.get(`${base}.duration`), bounce = byKey.get(`${base}.bounce`);
1194
+ if (base !== d.key && duration && bounce) {
1195
+ done.add(duration.key).add(bounce.key);
1196
+ let label = (duration.label ?? duration.key).replace(/ duration$/i, ""), dv = values[duration.key] ?? duration.default, bv = values[bounce.key] ?? bounce.default;
1197
+ lines.push(`TunableSpring(${JSON.stringify(base)}, ${JSON.stringify(label)}, duration: ${swiftLiteral(duration, dv)}, bounce: ${swiftLiteral(bounce, bv)}) // was duration: ${swiftLiteral(duration, duration.default)}, bounce: ${swiftLiteral(bounce, bounce.default)}`);
1198
+ continue;
1199
+ }
1200
+ if (done.add(d.key), d.kind === "spring") {
1201
+ let v = values[d.key], was = d.default;
1202
+ lines.push(`TunableSpring(${JSON.stringify(d.key)}, ${JSON.stringify(d.label ?? d.key)}, duration: ${decimal(v.duration)}, bounce: ${decimal(v.bounce)}) // was duration: ${decimal(was.duration)}, bounce: ${decimal(was.bounce)}`);
1203
+ continue;
1204
+ }
1205
+ let call = `Tunable<${d.swiftType ?? (d.kind === "bool" || d.kind === "toggle" ? "Bool" : (d.kind in swiftTypes) ? swiftTypes[d.kind] : "Double")}>(${JSON.stringify(d.key)}, ${JSON.stringify(d.label ?? d.key)}, default: ${swiftLiteral(d, values[d.key])}`;
1206
+ if (d.kind === "knob" || d.kind === "number") {
1207
+ if (d.min !== void 0 && d.max !== void 0)
1208
+ call += `, in: ${decimal(d.min)}...${decimal(d.max)}`;
1209
+ if (d.step !== void 0)
1210
+ call += `, step: ${decimal(d.step)}`;
1211
+ }
1212
+ let note = d.kind === "color" ? `${colorHex2(values[d.key])} · ` : "";
1213
+ lines.push(`${call}) // ${note}was ${swiftLiteral(d, d.default)}`);
1214
+ }
1215
+ return lines.join(`
1216
+ `);
1217
+ }
1218
+ var ECHO_MS = 600;
1219
+ function extend(source, extra) {
1220
+ return Object.freeze(Object.defineProperties({}, {
1221
+ ...Object.getOwnPropertyDescriptors(source),
1222
+ ...Object.getOwnPropertyDescriptors(extra)
1223
+ }));
1224
+ }
1225
+ function createRemoteControls(id, descriptors, options = {}) {
1226
+ let frozenDescriptors = Object.freeze([...descriptors]), given = descriptors, nullDefaults = options.nullDefaults !== !1, send = (changes, meta) => {
1227
+ if (changes.length === 0)
1228
+ return;
1229
+ if (options.onSetBatch && (changes.length > 1 || !options.onSet))
1230
+ return options.onSetBatch(changes, meta);
1231
+ for (let { key, value } of changes)
1232
+ options.onSet?.(key, value, meta);
1233
+ }, onReset = (target) => {
1234
+ if (target.key && nullDefaults)
1235
+ send([{ key: target.key, value: null }], { source: "reset", key: target.key });
1236
+ options.onReset?.(target);
1237
+ }, resetKeys = (keys) => {
1238
+ if (!options.onSetBatch || !nullDefaults)
1239
+ return keys.forEach((key) => onReset({ key }));
1240
+ for (let key of keys)
1241
+ options.onReset?.({ key });
1242
+ send(keys.map((key) => ({ key, value: null })), { source: "reset" });
1243
+ }, controls = defineControls(id, fromDescriptors(frozenDescriptors), {
1244
+ enabled: options.enabled ?? !0,
1245
+ ship: options.ship,
1246
+ echo: options.echo ?? ECHO_MS,
1247
+ storage: options.storage ?? null,
1248
+ persist: options.persist,
1249
+ random: options.random,
1250
+ tunable: options.tunable,
1251
+ history: options.history,
1252
+ presets: options.presets,
1253
+ groupPresets: options.groupPresets,
1254
+ onPreset: options.onPreset,
1255
+ actions: options.actions,
1256
+ theme: options.theme,
1257
+ density: options.density,
1258
+ renderer: options.renderer,
1259
+ keys: options.keys,
1260
+ marks: options.marks,
1261
+ groupLabels: options.groupLabels,
1262
+ sectionLabels: options.sectionLabels,
1263
+ presetLabels: options.presetLabels,
1264
+ defaultLabel: options.defaultLabel,
1265
+ groupPresetDisplay: options.groupPresetDisplay,
1266
+ groupDescriptions: options.groupDescriptions,
1267
+ sectionDescriptions: options.sectionDescriptions,
1268
+ groupFolded: options.groupFolded,
1269
+ sectionFolded: options.sectionFolded,
1270
+ onChange(patch, _values, meta) {
1271
+ if (meta.source === "remote" || meta.source === "reset")
1272
+ return;
1273
+ if (meta.source === "preset" && meta.group !== void 0 && options.onPreset)
1274
+ return;
1275
+ let changes = [];
1276
+ for (let [key, val] of Object.entries(patch)) {
1277
+ if (val === void 0)
1278
+ continue;
1279
+ changes.push({ key, value: nullDefaults && same(val, controls.locked[key]) ? null : val });
1280
+ }
1281
+ send(changes, meta);
1282
+ },
1283
+ onReset,
1284
+ onGesture: options.onGesture,
1285
+ ...{ [RESET_KEYS]: resetKeys },
1286
+ onAction: (key) => options.onAction?.(key)
1287
+ });
1288
+ if (options.values)
1289
+ controls.sync(options.values, { replace: !0 });
1290
+ let reshape = controls[RESHAPE];
1291
+ return extend(controls, {
1292
+ get descriptors() {
1293
+ return frozenDescriptors;
1294
+ },
1295
+ update(next, values = {}, opts) {
1296
+ if (next === given || next === frozenDescriptors)
1297
+ return controls.sync(values, { replace: !0, land: opts?.land, mixed: opts?.mixed });
1298
+ given = next, frozenDescriptors = Object.freeze([...next]), reshape(fromDescriptors(frozenDescriptors), values, opts);
1299
+ },
1300
+ sync: (values, syncOptions) => controls.sync(values, syncOptions),
1301
+ swift: (group) => formatSwift(frozenDescriptors, controls.modified(), group)
1302
+ });
1303
+ }
1304
+ function fromSettings(groups, home = {}) {
1305
+ let descriptors = [], values = {};
1306
+ for (let g of groups)
1307
+ for (let item of g.items) {
1308
+ let meta = { key: item.id, label: item.label, ...g.title ? { group: g.title } : {} };
1309
+ if (item.kind === "action")
1310
+ descriptors.push({ ...meta, kind: "action" });
1311
+ else if (item.kind === "toggle") {
1312
+ values[item.id] = Boolean(item.value);
1313
+ let def = home[item.id];
1314
+ descriptors.push({
1315
+ ...meta,
1316
+ kind: "toggle",
1317
+ default: typeof def === "boolean" ? def : values[item.id]
1318
+ });
1319
+ } else if (item.choices.length) {
1320
+ let ids = item.choices.map((c) => c.id);
1321
+ values[item.id] = item.value != null && ids.includes(item.value) ? item.value : ids[0];
1322
+ let def = home[item.id];
1323
+ descriptors.push({
1324
+ ...meta,
1325
+ kind: "choice",
1326
+ default: typeof def === "string" && ids.includes(def) ? def : values[item.id],
1327
+ choices: item.choices
1328
+ });
1329
+ }
1330
+ }
1331
+ return { descriptors, values };
1332
+ }
1333
+ export {
1334
+ CURVE_SHAPES2 as CURVE_SHAPES,
1335
+ EASINGS2 as EASINGS,
1336
+ SPRING2 as SPRING,
1337
+ action2 as action,
1338
+ angle2 as angle,
1339
+ bezierCss2 as bezierCss,
1340
+ bezierPoint2 as bezierPoint,
1341
+ choice2 as choice,
1342
+ color2 as color,
1343
+ colorHex2 as colorHex,
1344
+ comboFromEvent2 as comboFromEvent,
1345
+ comboLabel2 as comboLabel,
1346
+ comboParts2 as comboParts,
1347
+ createRemoteControls,
1348
+ curve2 as curve,
1349
+ defineControls,
1350
+ descriptorToField,
1351
+ easing2 as easing,
1352
+ flatSpring2 as flatSpring,
1353
+ formatCode,
1354
+ formatSwift,
1355
+ fromDescriptors,
1356
+ fromSettings,
1357
+ gradient2 as gradient,
1358
+ gradientCss2 as gradientCss,
1359
+ graph2 as graph,
1360
+ hasValue2 as hasValue,
1361
+ isReadout2 as isReadout,
1362
+ keybind2 as keybind,
1363
+ knob2 as knob,
1364
+ letterOf2 as letterOf,
1365
+ log2 as log,
1366
+ matchesCombo2 as matchesCombo,
1367
+ memoryStorage2 as memoryStorage,
1368
+ meter2 as meter,
1369
+ normalizeCombo2 as normalizeCombo,
1370
+ parseColor2 as parseColor,
1371
+ point2 as point,
1372
+ range2 as range,
1373
+ sampleCurve2 as sampleCurve,
1374
+ sampleGradient2 as sampleGradient,
1375
+ seed2 as seed,
1376
+ sparkline2 as sparkline,
1377
+ spring2 as spring,
1378
+ springCss2 as springCss,
1379
+ springMotion2 as springMotion,
1380
+ table2 as table,
1381
+ toggle2 as toggle,
1382
+ toolbar2 as toolbar,
1383
+ toolbarShortcut2 as toolbarShortcut,
1384
+ urlFlag2 as urlFlag,
1385
+ vec22 as vec2,
1386
+ vec32 as vec3,
1387
+ watch2 as watch,
1388
+ wrapAngle2 as wrapAngle
1389
+ };