@kitlangton/knobs 0.4.0-next.0 → 0.4.0-next.1

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 (43) hide show
  1. package/README.md +288 -43
  2. package/dist/dev/{chunk-stbcgz1y.js → chunk-1qzffbpa.js} +443 -451
  3. package/dist/dev/{chunk-7xgkerd2.js → chunk-3ygqgy1x.js} +23 -1
  4. package/dist/dev/{chunk-pmkvb9ep.js → chunk-8mabjeyk.js} +1920 -507
  5. package/dist/dev/{chunk-t68smqkc.js → chunk-ayb292zj.js} +13 -11
  6. package/dist/dev/index.js +10 -5
  7. package/dist/index.js +25 -1
  8. package/dist/panel.js +2900 -1320
  9. package/dist/react.js +294 -6
  10. package/dist/solid.js +292 -4
  11. package/dist/themes.js +1509 -7
  12. package/dist/types/core/adapter.d.ts +6 -2
  13. package/dist/types/core/appearance.d.ts +44 -0
  14. package/dist/types/core/glide.d.ts +7 -0
  15. package/dist/types/core/motion.d.ts +66 -0
  16. package/dist/types/core/root.d.ts +13 -0
  17. package/dist/types/core/store.d.ts +18 -5
  18. package/dist/types/core/theme.d.ts +10 -3
  19. package/dist/types/index.d.ts +2 -1
  20. package/dist/types/panel/gpu/color.d.ts +6 -0
  21. package/dist/types/panel/motion.d.ts +1 -1
  22. package/dist/types/panel/styles.d.ts +2 -3
  23. package/dist/types/themes/define.d.ts +104 -0
  24. package/dist/types/themes/index.d.ts +11 -0
  25. package/dist/types/themes/knobs.d.ts +5 -0
  26. package/dist/types/themes/void.d.ts +8 -0
  27. package/dist/types/tokens/color.d.ts +42 -0
  28. package/dist/types/tokens/css.d.ts +13 -0
  29. package/dist/types/tokens/evaluate.d.ts +8 -0
  30. package/dist/types/tokens/index.d.ts +4 -0
  31. package/dist/types/tokens/schema.d.ts +1100 -0
  32. package/dist/types/ui/bento-css.d.ts +1 -1
  33. package/dist/types/ui/compare-css.d.ts +1 -1
  34. package/dist/types/ui/index.d.ts +1 -1
  35. package/dist/types/ui/look.d.ts +18 -13
  36. package/dist/types/ui/overlay-css.d.ts +1 -1
  37. package/dist/types/ui/readout-css.d.ts +1 -1
  38. package/dist/types/ui/readout-model.d.ts +5 -1
  39. package/dist/types/ui/rgba.d.ts +11 -0
  40. package/dist/ui-react.js +2320 -676
  41. package/dist/ui-solid.js +2320 -676
  42. package/dist/ui.js +2552 -906
  43. package/package.json +1 -1
package/dist/react.js CHANGED
@@ -22,12 +22,299 @@ import {
22
22
  useSyncExternalStore as useSyncExternalStore2
23
23
  } from "react";
24
24
 
25
+ // src/core/spring.ts
26
+ class Spring {
27
+ x;
28
+ omega;
29
+ zeta;
30
+ eps;
31
+ v = 0;
32
+ target;
33
+ next;
34
+ constructor(x, omega = 24, zeta = 0.86, eps = 0.005) {
35
+ this.x = x;
36
+ this.omega = omega;
37
+ this.zeta = zeta;
38
+ this.eps = eps;
39
+ this.target = x;
40
+ }
41
+ set(target, delay = 0) {
42
+ if (delay > 0) {
43
+ if (target !== (this.next?.target ?? this.target))
44
+ this.next = { target, at: performance.now() + delay };
45
+ return this;
46
+ }
47
+ this.next = undefined;
48
+ this.target = target;
49
+ return this;
50
+ }
51
+ snap(x) {
52
+ this.next = undefined;
53
+ this.x = this.target = x;
54
+ this.v = 0;
55
+ return this;
56
+ }
57
+ step(dt) {
58
+ if (this.next && performance.now() >= this.next.at) {
59
+ this.target = this.next.target;
60
+ this.next = undefined;
61
+ }
62
+ if (this.x === this.target && this.v === 0)
63
+ return this.x;
64
+ const clampedDt = Math.min(dt, 0.1);
65
+ const h = 1 / 480;
66
+ for (let t = 0;t < clampedDt; t += h) {
67
+ const k = Math.min(h, clampedDt - t);
68
+ const a = -this.omega * this.omega * (this.x - this.target) - 2 * this.zeta * this.omega * this.v;
69
+ this.v += a * k;
70
+ this.x += this.v * k;
71
+ }
72
+ if (this.resting) {
73
+ this.x = this.target;
74
+ this.v = 0;
75
+ }
76
+ return this.x;
77
+ }
78
+ get resting() {
79
+ return !this.next && Math.abs(this.x - this.target) < this.eps && Math.abs(this.v) < this.eps * 4;
80
+ }
81
+ }
82
+ function springMotion({ duration, bounce }) {
83
+ return {
84
+ omega: 2 * Math.PI / Math.max(0.01, duration),
85
+ zeta: bounce >= 0 ? 1 - bounce : 1 / (1 + bounce)
86
+ };
87
+ }
88
+ function springEasing(omega, zeta) {
89
+ const s = new Spring(0, omega, zeta).set(1);
90
+ const points = ["0"];
91
+ const dt = 1 / 60;
92
+ let t = 0;
93
+ while (t < 4 && !(Math.abs(s.x - 1) < 0.002 && Math.abs(s.v) < 0.05)) {
94
+ s.step(dt);
95
+ t += dt;
96
+ points.push(String(Math.round(s.x * 1000) / 1000));
97
+ }
98
+ points[points.length - 1] = "1";
99
+ return { easing: `linear(${points.join(",")})`, ms: Math.round(t * 1000) };
100
+ }
101
+ function springCss(value) {
102
+ const { omega, zeta } = springMotion(value);
103
+ const { easing, ms } = springEasing(omega, zeta);
104
+ return { easing, duration: ms };
105
+ }
106
+
107
+ // src/core/theme.ts
108
+ var property = (k) => k.startsWith("--") ? k : `--k-${k}`;
109
+ function presetCss(preset) {
110
+ if (!/^[\w-]+$/.test(preset.name))
111
+ throw new Error(`Invalid preset name: ${preset.name}`);
112
+ const at = `.knobs-root[data-preset="${preset.name}"]`;
113
+ const light = preset.light ?? {};
114
+ const decls = Object.entries(preset.dark).map(([k, dark]) => {
115
+ const l = light[k];
116
+ return l === undefined || String(l) === String(dark) ? `${property(k)}:${dark}` : `${property(k)}:light-dark(${l},${dark})`;
117
+ });
118
+ for (const [k, l] of Object.entries(light))
119
+ if (!(k in preset.dark) && k !== "color-scheme")
120
+ decls.push(`${property(k)}:${l}`);
121
+ return `${at}{${decls.join(";")}}${(preset.css ?? "").replaceAll("&", at)}`;
122
+ }
123
+ var glide = /* @__PURE__ */ springCss({ duration: 0.185, bounce: 0.14 });
124
+ var problemsPreset = {
125
+ name: "problems",
126
+ dark: {
127
+ bg: "#161618",
128
+ surface: "rgba(255,255,255,.055)",
129
+ "surface-hi": "rgba(255,255,255,.11)",
130
+ line: "rgba(255,255,255,.075)",
131
+ "line-hi": "rgba(255,255,255,.12)",
132
+ text: "#f5f5f7",
133
+ label: "rgba(235,235,245,.62)",
134
+ dim: "rgba(235,235,245,.36)",
135
+ accent: "#0091ff",
136
+ modified: "#0091ff",
137
+ "seg-bg": "rgba(120,120,128,.16)",
138
+ "seg-active": "rgba(120,120,128,.24)",
139
+ "toggle-track": "rgba(120,120,128,.32)",
140
+ "toggle-thumb": "#fff",
141
+ rim: "transparent",
142
+ font: 'system-ui,-apple-system,BlinkMacSystemFont,"Helvetica Neue",sans-serif',
143
+ mono: '"Kit SF Mono",ui-monospace,Menlo,monospace',
144
+ "font-size": "13px",
145
+ "label-weight": 500,
146
+ row: "34px",
147
+ radius: "8px",
148
+ "panel-radius": "12px",
149
+ pad: "0px",
150
+ inset: "10px",
151
+ gap: "4px",
152
+ "row-gap": "4px",
153
+ glass: 0,
154
+ glow: 0,
155
+ blur: 0.6,
156
+ "hover-in": 0,
157
+ "hover-out": 100,
158
+ "handle-rest": 0.55,
159
+ handle: "var(--k-text)",
160
+ "handle-inset": "7.5px",
161
+ "fill-base": "transparent",
162
+ "fill-rest-mix": "24%",
163
+ "fill-hover-mix": "36%",
164
+ "fill-active-mix": "36%",
165
+ chrome: 0,
166
+ "group-transform": "none",
167
+ "value-font": "var(--k-mono)",
168
+ "unit-gap": "0px",
169
+ "unit-color": "currentColor",
170
+ "readout-mark": 1,
171
+ "group-size": "12px",
172
+ "group-color": "rgba(235,235,245,.62)",
173
+ "group-inset": "0px",
174
+ "group-tracking": "-.01em",
175
+ "group-divider": "rgba(255,255,255,.075)",
176
+ "group-divider-gap": "8px",
177
+ "curve-inset": "0px",
178
+ "curve-guide": "dashed",
179
+ "curve-dot": 0,
180
+ spring: "0.185 0.14",
181
+ "fill-ease": glide.easing,
182
+ "fill-ms": glide.duration
183
+ },
184
+ light: {
185
+ bg: "#fff",
186
+ surface: "rgba(0,0,0,.045)",
187
+ "surface-hi": "rgba(0,0,0,.09)",
188
+ line: "rgba(0,0,0,.07)",
189
+ "line-hi": "rgba(0,0,0,.11)",
190
+ text: "#000",
191
+ label: "rgba(60,60,67,.66)",
192
+ dim: "rgba(60,60,67,.38)",
193
+ accent: "#0088ff",
194
+ modified: "#0088ff",
195
+ "seg-bg": "rgba(120,120,128,.11)",
196
+ "seg-active": "#fff",
197
+ "toggle-track": "rgba(120,120,128,.2)",
198
+ "toggle-thumb": "#fff",
199
+ rim: "transparent",
200
+ "group-color": "rgba(60,60,67,.66)",
201
+ "group-divider": "rgba(0,0,0,.07)"
202
+ }
203
+ };
204
+
205
+ // src/core/appearance.ts
206
+ var MODES = {
207
+ dark: "dark",
208
+ light: "light",
209
+ auto: "system"
210
+ };
211
+ function resolveLook(options = {}, base) {
212
+ const t = options.theme;
213
+ const mode = typeof t === "string" ? MODES[t] : undefined;
214
+ const theme = typeof t === "object" ? t : base?.theme;
215
+ const preset = options.preset ?? base?.preset;
216
+ return {
217
+ ...theme ? { theme } : {},
218
+ appearance: options.appearance ?? mode ?? base?.appearance ?? "inherit",
219
+ ...preset ? { preset } : {}
220
+ };
221
+ }
222
+ var themes = new Map;
223
+ var themeSelector = (name) => `:where(.knobs-root)[data-knobs-theme="${name}"]`;
224
+ function upsertStyle(doc, key, value, content) {
225
+ const existing = doc.querySelector(`style[${key}="${value}"]`);
226
+ if (existing) {
227
+ if (existing.textContent !== content)
228
+ existing.textContent = content;
229
+ return;
230
+ }
231
+ const style = doc.createElement("style");
232
+ style.setAttribute(key, value);
233
+ style.textContent = content;
234
+ doc.head.append(style);
235
+ }
236
+ function injectTheme(doc, theme) {
237
+ themes.set(theme.name, theme);
238
+ upsertStyle(doc, "data-knobs-theme-css", theme.name, theme.css({ selector: themeSelector(theme.name) }));
239
+ }
240
+ var presets = new Map;
241
+ function injectPreset(doc, preset) {
242
+ presets.set(preset.name, preset);
243
+ upsertStyle(doc, "data-knobs-preset", preset.name, presetCss(preset));
244
+ }
245
+ var setAttr = (el, name, value) => {
246
+ if (value === undefined)
247
+ el.removeAttribute(name);
248
+ else if (el.getAttribute(name) !== value)
249
+ el.setAttribute(name, value);
250
+ };
251
+ function applyLook(el, look) {
252
+ const doc = el.ownerDocument;
253
+ if (look.theme)
254
+ injectTheme(doc, look.theme);
255
+ if (look.preset)
256
+ injectPreset(doc, look.preset);
257
+ setAttr(el, "data-knobs-theme", look.theme?.name);
258
+ setAttr(el, "data-preset", look.preset?.name);
259
+ setAttr(el, "data-appearance", look.appearance === "inherit" ? undefined : look.appearance);
260
+ if (look.appearance === "inherit")
261
+ followPage(el);
262
+ else
263
+ clearInherited(el);
264
+ }
265
+ var clearInherited = (el) => {
266
+ el.style.removeProperty("color-scheme");
267
+ el.style.removeProperty("--_k-light");
268
+ };
269
+ function resolveInherited(el) {
270
+ const parent = el.parentElement;
271
+ const win = el.ownerDocument.defaultView;
272
+ if (!parent || !win || el.hasAttribute("data-appearance"))
273
+ return;
274
+ if (parent.closest(".knobs-root"))
275
+ return clearInherited(el);
276
+ const scheme = win.getComputedStyle(parent).colorScheme.trim();
277
+ const dark = /\bdark\b/.test(scheme);
278
+ const light = /\blight\b/.test(scheme);
279
+ if (!dark && !light)
280
+ return clearInherited(el);
281
+ const isLight = dark && light ? win.matchMedia?.("(prefers-color-scheme: light)").matches ?? false : light;
282
+ el.style.setProperty("color-scheme", "inherit");
283
+ el.style.setProperty("--_k-light", isLight ? "1" : "0");
284
+ }
285
+ var watched = new WeakSet;
286
+ function followPage(el) {
287
+ const doc = el.ownerDocument;
288
+ const win = doc.defaultView;
289
+ if (!win)
290
+ return;
291
+ const run = () => resolveInherited(el);
292
+ if (el.isConnected)
293
+ run();
294
+ queueMicrotask(run);
295
+ win.requestAnimationFrame?.(run);
296
+ if (watched.has(doc))
297
+ return;
298
+ watched.add(doc);
299
+ const all = () => {
300
+ for (const root of doc.querySelectorAll(".knobs-root:not([data-appearance])"))
301
+ resolveInherited(root);
302
+ };
303
+ const observer = new MutationObserver(all);
304
+ const attributeFilter = ["class", "data-theme", "data-appearance"];
305
+ observer.observe(doc.documentElement, { attributes: true, attributeFilter });
306
+ if (doc.body)
307
+ observer.observe(doc.body, { attributes: true, attributeFilter });
308
+ win.matchMedia?.("(prefers-color-scheme: light)").addEventListener?.("change", all);
309
+ }
310
+
25
311
  // src/core/adapter.ts
26
- function syncPanelLook(host, controls, theme, density) {
312
+ var panelLook = (controls, look = {}) => resolveLook(look, resolveLook({ theme: controls.theme, appearance: controls.appearance }));
313
+ function syncPanelLook(host, controls, look = {}, density) {
27
314
  const panel = host?.firstElementChild;
28
315
  if (!panel)
29
316
  return;
30
- panel.dataset.theme = theme ?? controls.theme;
317
+ applyLook(panel, panelLook(controls, look));
31
318
  panel.dataset.density = density ?? controls.density;
32
319
  }
33
320
  function syncPanelValues(controls, descriptors, values, land = false) {
@@ -43,6 +330,7 @@ function mountPanelAdapter(host, controls, getProps) {
43
330
  return controls.mount(host, {
44
331
  title: p.title,
45
332
  theme: p.theme,
333
+ appearance: p.appearance,
46
334
  density: p.density,
47
335
  renderer: p.renderer,
48
336
  variants: p.variants,
@@ -57,7 +345,7 @@ function mountPanelAdapter(host, controls, getProps) {
57
345
  onClose: p.onClose ? () => getProps().onClose?.() : undefined,
58
346
  onReady(panel) {
59
347
  const cur = getProps();
60
- syncPanelLook(host, controls, cur.theme, cur.density);
348
+ syncPanelLook(host, controls, cur, cur.density);
61
349
  cur.onReady?.(panel);
62
350
  }
63
351
  });
@@ -89,7 +377,7 @@ function Knobs({
89
377
  return cloneElement(children, { ref });
90
378
  }
91
379
  function KnobsPanel(props) {
92
- const { controls, descriptors, values, land, theme, density } = props;
380
+ const { controls, descriptors, values, land, theme, appearance, preset, density } = props;
93
381
  const enabled = useSyncExternalStore2(controls.subscribe, () => controls.enabled, () => false);
94
382
  const ref = useRef(null);
95
383
  const latest = useRef(props);
@@ -105,8 +393,8 @@ function KnobsPanel(props) {
105
393
  syncPanelValues(controls, descriptors, values, Boolean(land));
106
394
  }, [enabled, controls, descriptors, values, land]);
107
395
  useEffect(() => {
108
- syncPanelLook(ref.current, controls, theme, density);
109
- }, [controls, theme, density]);
396
+ syncPanelLook(ref.current, controls, { theme, appearance, preset }, density);
397
+ }, [controls, theme, appearance, preset, density]);
110
398
  if (!enabled)
111
399
  return null;
112
400
  return /* @__PURE__ */ jsx("div", {
package/dist/solid.js CHANGED
@@ -179,12 +179,299 @@ import {
179
179
  untrack
180
180
  } from "solid-js";
181
181
 
182
+ // src/core/spring.ts
183
+ class Spring {
184
+ x;
185
+ omega;
186
+ zeta;
187
+ eps;
188
+ v = 0;
189
+ target;
190
+ next;
191
+ constructor(x, omega = 24, zeta = 0.86, eps = 0.005) {
192
+ this.x = x;
193
+ this.omega = omega;
194
+ this.zeta = zeta;
195
+ this.eps = eps;
196
+ this.target = x;
197
+ }
198
+ set(target, delay = 0) {
199
+ if (delay > 0) {
200
+ if (target !== (this.next?.target ?? this.target))
201
+ this.next = { target, at: performance.now() + delay };
202
+ return this;
203
+ }
204
+ this.next = undefined;
205
+ this.target = target;
206
+ return this;
207
+ }
208
+ snap(x) {
209
+ this.next = undefined;
210
+ this.x = this.target = x;
211
+ this.v = 0;
212
+ return this;
213
+ }
214
+ step(dt) {
215
+ if (this.next && performance.now() >= this.next.at) {
216
+ this.target = this.next.target;
217
+ this.next = undefined;
218
+ }
219
+ if (this.x === this.target && this.v === 0)
220
+ return this.x;
221
+ const clampedDt = Math.min(dt, 0.1);
222
+ const h = 1 / 480;
223
+ for (let t = 0;t < clampedDt; t += h) {
224
+ const k = Math.min(h, clampedDt - t);
225
+ const a = -this.omega * this.omega * (this.x - this.target) - 2 * this.zeta * this.omega * this.v;
226
+ this.v += a * k;
227
+ this.x += this.v * k;
228
+ }
229
+ if (this.resting) {
230
+ this.x = this.target;
231
+ this.v = 0;
232
+ }
233
+ return this.x;
234
+ }
235
+ get resting() {
236
+ return !this.next && Math.abs(this.x - this.target) < this.eps && Math.abs(this.v) < this.eps * 4;
237
+ }
238
+ }
239
+ function springMotion({ duration, bounce }) {
240
+ return {
241
+ omega: 2 * Math.PI / Math.max(0.01, duration),
242
+ zeta: bounce >= 0 ? 1 - bounce : 1 / (1 + bounce)
243
+ };
244
+ }
245
+ function springEasing(omega, zeta) {
246
+ const s = new Spring(0, omega, zeta).set(1);
247
+ const points = ["0"];
248
+ const dt = 1 / 60;
249
+ let t = 0;
250
+ while (t < 4 && !(Math.abs(s.x - 1) < 0.002 && Math.abs(s.v) < 0.05)) {
251
+ s.step(dt);
252
+ t += dt;
253
+ points.push(String(Math.round(s.x * 1000) / 1000));
254
+ }
255
+ points[points.length - 1] = "1";
256
+ return { easing: `linear(${points.join(",")})`, ms: Math.round(t * 1000) };
257
+ }
258
+ function springCss(value) {
259
+ const { omega, zeta } = springMotion(value);
260
+ const { easing, ms } = springEasing(omega, zeta);
261
+ return { easing, duration: ms };
262
+ }
263
+
264
+ // src/core/theme.ts
265
+ var property = (k) => k.startsWith("--") ? k : `--k-${k}`;
266
+ function presetCss(preset) {
267
+ if (!/^[\w-]+$/.test(preset.name))
268
+ throw new Error(`Invalid preset name: ${preset.name}`);
269
+ const at = `.knobs-root[data-preset="${preset.name}"]`;
270
+ const light = preset.light ?? {};
271
+ const decls = Object.entries(preset.dark).map(([k, dark]) => {
272
+ const l = light[k];
273
+ return l === undefined || String(l) === String(dark) ? `${property(k)}:${dark}` : `${property(k)}:light-dark(${l},${dark})`;
274
+ });
275
+ for (const [k, l] of Object.entries(light))
276
+ if (!(k in preset.dark) && k !== "color-scheme")
277
+ decls.push(`${property(k)}:${l}`);
278
+ return `${at}{${decls.join(";")}}${(preset.css ?? "").replaceAll("&", at)}`;
279
+ }
280
+ var glide = /* @__PURE__ */ springCss({ duration: 0.185, bounce: 0.14 });
281
+ var problemsPreset = {
282
+ name: "problems",
283
+ dark: {
284
+ bg: "#161618",
285
+ surface: "rgba(255,255,255,.055)",
286
+ "surface-hi": "rgba(255,255,255,.11)",
287
+ line: "rgba(255,255,255,.075)",
288
+ "line-hi": "rgba(255,255,255,.12)",
289
+ text: "#f5f5f7",
290
+ label: "rgba(235,235,245,.62)",
291
+ dim: "rgba(235,235,245,.36)",
292
+ accent: "#0091ff",
293
+ modified: "#0091ff",
294
+ "seg-bg": "rgba(120,120,128,.16)",
295
+ "seg-active": "rgba(120,120,128,.24)",
296
+ "toggle-track": "rgba(120,120,128,.32)",
297
+ "toggle-thumb": "#fff",
298
+ rim: "transparent",
299
+ font: 'system-ui,-apple-system,BlinkMacSystemFont,"Helvetica Neue",sans-serif',
300
+ mono: '"Kit SF Mono",ui-monospace,Menlo,monospace',
301
+ "font-size": "13px",
302
+ "label-weight": 500,
303
+ row: "34px",
304
+ radius: "8px",
305
+ "panel-radius": "12px",
306
+ pad: "0px",
307
+ inset: "10px",
308
+ gap: "4px",
309
+ "row-gap": "4px",
310
+ glass: 0,
311
+ glow: 0,
312
+ blur: 0.6,
313
+ "hover-in": 0,
314
+ "hover-out": 100,
315
+ "handle-rest": 0.55,
316
+ handle: "var(--k-text)",
317
+ "handle-inset": "7.5px",
318
+ "fill-base": "transparent",
319
+ "fill-rest-mix": "24%",
320
+ "fill-hover-mix": "36%",
321
+ "fill-active-mix": "36%",
322
+ chrome: 0,
323
+ "group-transform": "none",
324
+ "value-font": "var(--k-mono)",
325
+ "unit-gap": "0px",
326
+ "unit-color": "currentColor",
327
+ "readout-mark": 1,
328
+ "group-size": "12px",
329
+ "group-color": "rgba(235,235,245,.62)",
330
+ "group-inset": "0px",
331
+ "group-tracking": "-.01em",
332
+ "group-divider": "rgba(255,255,255,.075)",
333
+ "group-divider-gap": "8px",
334
+ "curve-inset": "0px",
335
+ "curve-guide": "dashed",
336
+ "curve-dot": 0,
337
+ spring: "0.185 0.14",
338
+ "fill-ease": glide.easing,
339
+ "fill-ms": glide.duration
340
+ },
341
+ light: {
342
+ bg: "#fff",
343
+ surface: "rgba(0,0,0,.045)",
344
+ "surface-hi": "rgba(0,0,0,.09)",
345
+ line: "rgba(0,0,0,.07)",
346
+ "line-hi": "rgba(0,0,0,.11)",
347
+ text: "#000",
348
+ label: "rgba(60,60,67,.66)",
349
+ dim: "rgba(60,60,67,.38)",
350
+ accent: "#0088ff",
351
+ modified: "#0088ff",
352
+ "seg-bg": "rgba(120,120,128,.11)",
353
+ "seg-active": "#fff",
354
+ "toggle-track": "rgba(120,120,128,.2)",
355
+ "toggle-thumb": "#fff",
356
+ rim: "transparent",
357
+ "group-color": "rgba(60,60,67,.66)",
358
+ "group-divider": "rgba(0,0,0,.07)"
359
+ }
360
+ };
361
+
362
+ // src/core/appearance.ts
363
+ var MODES = {
364
+ dark: "dark",
365
+ light: "light",
366
+ auto: "system"
367
+ };
368
+ function resolveLook(options = {}, base) {
369
+ const t = options.theme;
370
+ const mode = typeof t === "string" ? MODES[t] : undefined;
371
+ const theme = typeof t === "object" ? t : base?.theme;
372
+ const preset = options.preset ?? base?.preset;
373
+ return {
374
+ ...theme ? { theme } : {},
375
+ appearance: options.appearance ?? mode ?? base?.appearance ?? "inherit",
376
+ ...preset ? { preset } : {}
377
+ };
378
+ }
379
+ var themes = new Map;
380
+ var themeSelector = (name) => `:where(.knobs-root)[data-knobs-theme="${name}"]`;
381
+ function upsertStyle(doc, key, value, content) {
382
+ const existing = doc.querySelector(`style[${key}="${value}"]`);
383
+ if (existing) {
384
+ if (existing.textContent !== content)
385
+ existing.textContent = content;
386
+ return;
387
+ }
388
+ const style = doc.createElement("style");
389
+ style.setAttribute(key, value);
390
+ style.textContent = content;
391
+ doc.head.append(style);
392
+ }
393
+ function injectTheme(doc, theme) {
394
+ themes.set(theme.name, theme);
395
+ upsertStyle(doc, "data-knobs-theme-css", theme.name, theme.css({ selector: themeSelector(theme.name) }));
396
+ }
397
+ var presets = new Map;
398
+ function injectPreset(doc, preset) {
399
+ presets.set(preset.name, preset);
400
+ upsertStyle(doc, "data-knobs-preset", preset.name, presetCss(preset));
401
+ }
402
+ var setAttr = (el, name, value) => {
403
+ if (value === undefined)
404
+ el.removeAttribute(name);
405
+ else if (el.getAttribute(name) !== value)
406
+ el.setAttribute(name, value);
407
+ };
408
+ function applyLook(el, look) {
409
+ const doc = el.ownerDocument;
410
+ if (look.theme)
411
+ injectTheme(doc, look.theme);
412
+ if (look.preset)
413
+ injectPreset(doc, look.preset);
414
+ setAttr(el, "data-knobs-theme", look.theme?.name);
415
+ setAttr(el, "data-preset", look.preset?.name);
416
+ setAttr(el, "data-appearance", look.appearance === "inherit" ? undefined : look.appearance);
417
+ if (look.appearance === "inherit")
418
+ followPage(el);
419
+ else
420
+ clearInherited(el);
421
+ }
422
+ var clearInherited = (el) => {
423
+ el.style.removeProperty("color-scheme");
424
+ el.style.removeProperty("--_k-light");
425
+ };
426
+ function resolveInherited(el) {
427
+ const parent = el.parentElement;
428
+ const win = el.ownerDocument.defaultView;
429
+ if (!parent || !win || el.hasAttribute("data-appearance"))
430
+ return;
431
+ if (parent.closest(".knobs-root"))
432
+ return clearInherited(el);
433
+ const scheme = win.getComputedStyle(parent).colorScheme.trim();
434
+ const dark = /\bdark\b/.test(scheme);
435
+ const light = /\blight\b/.test(scheme);
436
+ if (!dark && !light)
437
+ return clearInherited(el);
438
+ const isLight = dark && light ? win.matchMedia?.("(prefers-color-scheme: light)").matches ?? false : light;
439
+ el.style.setProperty("color-scheme", "inherit");
440
+ el.style.setProperty("--_k-light", isLight ? "1" : "0");
441
+ }
442
+ var watched = new WeakSet;
443
+ function followPage(el) {
444
+ const doc = el.ownerDocument;
445
+ const win = doc.defaultView;
446
+ if (!win)
447
+ return;
448
+ const run = () => resolveInherited(el);
449
+ if (el.isConnected)
450
+ run();
451
+ queueMicrotask(run);
452
+ win.requestAnimationFrame?.(run);
453
+ if (watched.has(doc))
454
+ return;
455
+ watched.add(doc);
456
+ const all = () => {
457
+ for (const root of doc.querySelectorAll(".knobs-root:not([data-appearance])"))
458
+ resolveInherited(root);
459
+ };
460
+ const observer = new MutationObserver(all);
461
+ const attributeFilter = ["class", "data-theme", "data-appearance"];
462
+ observer.observe(doc.documentElement, { attributes: true, attributeFilter });
463
+ if (doc.body)
464
+ observer.observe(doc.body, { attributes: true, attributeFilter });
465
+ win.matchMedia?.("(prefers-color-scheme: light)").addEventListener?.("change", all);
466
+ }
467
+
182
468
  // src/core/adapter.ts
183
- function syncPanelLook(host, controls, theme, density) {
469
+ var panelLook = (controls, look = {}) => resolveLook(look, resolveLook({ theme: controls.theme, appearance: controls.appearance }));
470
+ function syncPanelLook(host, controls, look = {}, density) {
184
471
  const panel = host?.firstElementChild;
185
472
  if (!panel)
186
473
  return;
187
- panel.dataset.theme = theme ?? controls.theme;
474
+ applyLook(panel, panelLook(controls, look));
188
475
  panel.dataset.density = density ?? controls.density;
189
476
  }
190
477
  function syncPanelValues(controls, descriptors, values, land = false) {
@@ -200,6 +487,7 @@ function mountPanelAdapter(host, controls, getProps) {
200
487
  return controls.mount(host, {
201
488
  title: p.title,
202
489
  theme: p.theme,
490
+ appearance: p.appearance,
203
491
  density: p.density,
204
492
  renderer: p.renderer,
205
493
  variants: p.variants,
@@ -214,7 +502,7 @@ function mountPanelAdapter(host, controls, getProps) {
214
502
  onClose: p.onClose ? () => getProps().onClose?.() : undefined,
215
503
  onReady(panel) {
216
504
  const cur = getProps();
217
- syncPanelLook(host, controls, cur.theme, cur.density);
505
+ syncPanelLook(host, controls, cur, cur.density);
218
506
  cur.onReady?.(panel);
219
507
  }
220
508
  });
@@ -285,7 +573,7 @@ function KnobsPanel(props) {
285
573
  syncPanelValues(props.controls, props.descriptors, props.values, Boolean(props.land));
286
574
  });
287
575
  createEffect(() => {
288
- syncPanelLook(host, props.controls, props.theme, props.density);
576
+ syncPanelLook(host, props.controls, { theme: props.theme, appearance: props.appearance, preset: props.preset }, props.density);
289
577
  });
290
578
  return host;
291
579
  }