@kitlangton/knobs 0.4.0-next.10 → 0.4.0-next.12

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.
package/dist/index.js CHANGED
@@ -460,6 +460,7 @@ var META_KEYS = [
460
460
  "folded",
461
461
  "sectionFolded",
462
462
  "tab",
463
+ "pinned",
463
464
  "subsection"
464
465
  ];
465
466
  function pickMeta(source, skip = []) {
@@ -471,7 +472,29 @@ function pickMeta(source, skip = []) {
471
472
  }
472
473
  return out;
473
474
  }
474
- var READOUT_KINDS = /* @__PURE__ */ new Set(["watch", "sparkline", "graph", "meter", "table", "log"]), isReadout = (field) => READOUT_KINDS.has(field.kind), hasValue = (field) => field.kind !== "action" && field.kind !== "toolbar" && !READOUT_KINDS.has(field.kind), SPRING = {
475
+ var READOUT_KINDS = /* @__PURE__ */ new Set(["watch", "sparkline", "graph", "meter", "table", "log"]), isReadout = (field) => READOUT_KINDS.has(field.kind), hasValue = (field) => field.kind !== "action" && field.kind !== "toolbar" && !READOUT_KINDS.has(field.kind);
476
+ function variantsOf(schema, isPinned = () => !1) {
477
+ let found;
478
+ for (let [key, field] of Object.entries(schema))
479
+ if (field.kind === "choice" && field.variants && !isPinned(key)) {
480
+ if (found)
481
+ throw Error(`Only one choice can hold the variants (${found.key}, ${key}).`);
482
+ found = { key, field };
483
+ }
484
+ return found;
485
+ }
486
+ function pinnedKeys(schema, groups = []) {
487
+ let byGroup = new Map(groups.map((g) => [g, !0]));
488
+ for (let f of Object.values(schema))
489
+ if (f.group !== void 0 && f.pinned !== void 0 && !byGroup.has(f.group))
490
+ byGroup.set(f.group, f.pinned);
491
+ let out = /* @__PURE__ */ new Set;
492
+ for (let [key, f] of Object.entries(schema))
493
+ if (f.group === void 0 ? f.pinned === !0 : byGroup.get(f.group) === !0)
494
+ out.add(key);
495
+ return out;
496
+ }
497
+ var SPRING = {
475
498
  duration: { min: 0.05, max: 2, step: 0.01 },
476
499
  bounce: { min: -0.5, max: 1, step: 0.01 }
477
500
  };
@@ -502,8 +525,9 @@ function choice(value, options, meta) {
502
525
  value,
503
526
  options: Object.freeze([...options]),
504
527
  ...labels && Object.keys(labels).length ? { labels } : {},
505
- ...meta?.display ? { display: meta.display } : {}
506
- }, meta);
528
+ ...meta?.display ? { display: meta.display } : {},
529
+ ...meta?.variants ? { variants: !0 } : {}
530
+ }, meta?.variants ? { ...meta, random: meta.random ?? !1 } : meta);
507
531
  }
508
532
  function action(label, meta) {
509
533
  let { shortcut, global, rebind, run, ...rest } = meta ?? {}, key = shortcutOf({ ...shortcut ? { shortcut } : {}, ...global ? { global } : {} }), combo = key ? normalizeCombo(key.key) : "";
@@ -648,6 +672,17 @@ function keybind(value = "", meta) {
648
672
  let field = { kind: "keybind", value: normalizeCombo(value) };
649
673
  return withMeta(field, { random: !1, ...meta });
650
674
  }
675
+ function text(value = "", options) {
676
+ let { multiline, placeholder, ...meta } = options ?? {}, field = {
677
+ kind: "text",
678
+ value: "",
679
+ ...multiline ? { multiline: !0 } : {},
680
+ ...placeholder ? { placeholder } : {}
681
+ };
682
+ return withMeta({ ...field, value: normalizeText(field, value) }, { random: !1, ...meta });
683
+ }
684
+ var normalizeText = (field, input) => field.multiline ? input.replace(/\r\n?/g, `
685
+ `) : input.replace(/\r\n?|\n/g, " ");
651
686
  function gradient(stops, options = {}) {
652
687
  let value = normalizeStops(stops);
653
688
  if (!value)
@@ -702,7 +737,8 @@ function toolbar(items, meta) {
702
737
  throw Error("A toolbar needs at least one item.");
703
738
  return withMeta({
704
739
  kind: "toolbar",
705
- items: Object.freeze(items.map((item) => Object.freeze({ ...item })))
740
+ items: Object.freeze(items.map((item) => Object.freeze({ ...item }))),
741
+ ...meta?.labels !== void 0 ? { labels: meta.labels } : {}
706
742
  }, meta);
707
743
  }
708
744
  var readoutMeta = (o) => {
@@ -846,6 +882,8 @@ function normalizeField(field, input) {
846
882
  return typeof input === "number" && Number.isFinite(input) ? Math.round(Math.min(field.max, Math.max(field.min, input))) : field.value;
847
883
  case "keybind":
848
884
  return typeof input === "string" ? normalizeCombo(input) : field.value;
885
+ case "text":
886
+ return typeof input === "string" ? normalizeText(field, input) : field.value;
849
887
  case "gradient":
850
888
  return normalizeStops(input) ?? field.value;
851
889
  case "curve":
@@ -996,6 +1034,7 @@ function pick(field, random) {
996
1034
  case "seed":
997
1035
  return lattice(field.min, field.max, 1, r());
998
1036
  case "keybind":
1037
+ case "text":
999
1038
  return field.value;
1000
1039
  case "gradient":
1001
1040
  return randomStops(field.value.length, r);
@@ -1081,6 +1120,7 @@ function around(field, base, random) {
1081
1120
  ]);
1082
1121
  case "seed":
1083
1122
  case "keybind":
1123
+ case "text":
1084
1124
  return pick(field, random);
1085
1125
  }
1086
1126
  }
@@ -1180,6 +1220,7 @@ function shift(field, value, random) {
1180
1220
  case "seed":
1181
1221
  return nudge(value, field.min, field.max, 1, random);
1182
1222
  case "keybind":
1223
+ case "text":
1183
1224
  return value;
1184
1225
  case "gradient":
1185
1226
  return mutateStops(value, random, MUTATE.hue, MUTATE.lightness);
@@ -1612,14 +1653,42 @@ function defineControls(id, input, options = {}) {
1612
1653
  let schema = Object.freeze({ ...input }), locked = normalize(schema, {}), actions = Object.freeze([...options.actions ?? []]), { theme, appearance } = options, density = options.density ?? "default", renderer = options.renderer ?? "auto", enabled = () => (Boolean(options.ship) || isUnlocked()) && (typeof options.enabled === "function" ? options.enabled() : options.enabled ?? (Boolean(options.ship) || isUnlocked() || 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, unsubscribeUnlock, listeners = /* @__PURE__ */ new Set, refreshes = 0, notify = () => {
1613
1654
  for (let cb of [...listeners])
1614
1655
  cb();
1615
- }, mixed = /* @__PURE__ */ new Set, current = locked, read = !1, error = null, locks = /* @__PURE__ */ new Set, bindings = /* @__PURE__ */ new Map, 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, NO_BASE = Object.freeze({ preset: null, groups: Object.freeze({}) }), base = NO_BASE, past = [], future = [], HISTORY = 100, stateKey = storageKey(id, "state"), buildPresets = () => Object.freeze(Object.fromEntries([
1616
- ["default", locked],
1617
- ...Object.entries(options.presets ?? {}).map(([id, patch]) => {
1618
- if (id === "default" || id === "custom")
1619
- throw Error(`Reserved preset id: ${id}`);
1620
- return [id, normalize(schema, { ...locked, ...patch })];
1621
- })
1622
- ])), presets = buildPresets(), buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1656
+ }, mixed = /* @__PURE__ */ new Set, current = locked, read = !1, error = null, locks = /* @__PURE__ */ new Set, bindings = /* @__PURE__ */ new Map, 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, NO_BASE = Object.freeze({ preset: null, groups: Object.freeze({}) }), base = NO_BASE, past = [], future = [], HISTORY = 100, stateKey = storageKey(id, "state"), pinnedOf, pinned = () => {
1657
+ if (pinnedOf?.schema !== schema)
1658
+ pinnedOf = { schema, keys: pinnedKeys(schema, options.pinned) };
1659
+ return pinnedOf.keys;
1660
+ }, variantsChoice = () => variantsOf(schema, (key) => pinned().has(key)), unpinned = (values) => {
1661
+ let keys = pinned();
1662
+ if (keys.size === 0)
1663
+ return values;
1664
+ let out = { ...values };
1665
+ for (let k of keys)
1666
+ if (Object.hasOwn(locked, k))
1667
+ out[k] = locked[k];
1668
+ return Object.freeze(out);
1669
+ }, presetPatch = (values) => {
1670
+ let keys = pinned();
1671
+ if (keys.size === 0)
1672
+ return values;
1673
+ return Object.fromEntries(Object.entries(values).filter(([k]) => !keys.has(k)));
1674
+ }, buildPresets = () => {
1675
+ let own = options.presets ?? {}, v = variantsChoice();
1676
+ if (v && Object.hasOwn(own, v.field.value))
1677
+ throw Error(`The default variant (${v.field.value}) is the schema's defaults; set its values there.`);
1678
+ let ids = [
1679
+ ...v ? v.field.options.filter((o) => o !== v.field.value) : [],
1680
+ ...Object.keys(own).filter((id) => !v?.field.options.includes(id))
1681
+ ];
1682
+ return Object.freeze(Object.fromEntries([
1683
+ ["default", locked],
1684
+ ...ids.map((id) => {
1685
+ if (id === "default" || id === "custom")
1686
+ throw Error(`Reserved preset id: ${id}`);
1687
+ let variant = v?.field.options.includes(id) ? { [v.key]: id } : {};
1688
+ return [id, unpinned(normalize(schema, { ...locked, ...variant, ...own[id] }))];
1689
+ })
1690
+ ]));
1691
+ }, presets = buildPresets(), buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1623
1692
  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) => hasValue(schema[k])));
1624
1693
  return [
1625
1694
  group,
@@ -1718,7 +1787,7 @@ function defineControls(id, input, options = {}) {
1718
1787
  else if (ref?.kind === "variant") {
1719
1788
  let found = list?.find((v) => v.id === ref.id);
1720
1789
  if (found)
1721
- out = normalize(schema, found.values);
1790
+ out = unpinned(normalize(schema, found.values));
1722
1791
  }
1723
1792
  let groups = Object.entries(b.groups);
1724
1793
  if (groups.length) {
@@ -1730,11 +1799,10 @@ function defineControls(id, input, options = {}) {
1730
1799
  return baseCache = { base: b, schema, presets, groupPresets, variants: list, values }, values;
1731
1800
  }
1732
1801
  let covered = (key) => {
1733
- let b = activeBase();
1734
- if (b.preset)
1802
+ let b = activeBase(), group = schema[key]?.group;
1803
+ if (group !== void 0 && Object.hasOwn(b.groups, group))
1735
1804
  return !0;
1736
- let group = schema[key]?.group;
1737
- return group !== void 0 && Object.hasOwn(b.groups, group);
1805
+ return b.preset !== null && !pinned().has(key);
1738
1806
  };
1739
1807
  function declaredShortcut(id) {
1740
1808
  let slash = id.indexOf("/"), key = slash < 0 ? id : id.slice(0, slash), field = Object.hasOwn(schema, key) ? schema[key] : void 0;
@@ -2004,7 +2072,7 @@ function defineControls(id, input, options = {}) {
2004
2072
  listen(cb) {
2005
2073
  return readoutListeners.add(cb), () => readoutListeners.delete(cb);
2006
2074
  }
2007
- }, variants = createVariants(() => schema, id, storageKey(id, "variants"), variantStorage, get, (v, variant, coalesce) => write(v, { source: "variant", coalesce }, makeBase(Object.freeze({ kind: "variant", id: variant }), {})), notify, enabled), resettable = (keys) => (keys ?? fieldKeys()).filter((k) => valueField(k) && !blocked(k));
2075
+ }, variants = createVariants(() => schema, id, storageKey(id, "variants"), variantStorage, () => unpinned(get()), (v, variant, coalesce) => write(presetPatch(v), { source: "variant", coalesce }, makeBase(Object.freeze({ kind: "variant", id: variant }), {})), notify, enabled), resettable = (keys) => (keys ?? fieldKeys()).filter((k) => valueField(k) && !blocked(k));
2008
2076
  function offBase(keys) {
2009
2077
  if (!hasBase())
2010
2078
  return !1;
@@ -2088,7 +2156,11 @@ function defineControls(id, input, options = {}) {
2088
2156
  sectionDescription: (section) => options.sectionDescriptions?.[section] ?? fieldLabels().sectionText.get(section),
2089
2157
  groupFolded: options.groupFolded,
2090
2158
  sectionFolded: options.sectionFolded,
2091
- presetLabel: (presetId) => options.presetLabels?.[presetId] ?? (presetId === "default" ? options.defaultLabel : void 0) ?? presetId,
2159
+ presetLabel: (presetId) => {
2160
+ let v = variantsChoice(), option = presetId === "default" ? v?.field.value : presetId;
2161
+ return options.presetLabels?.[presetId] ?? (presetId === "default" ? options.defaultLabel : void 0) ?? (v && option !== void 0 && v.field.options.includes(option) ? v.field.labels?.[option] ?? option : presetId);
2162
+ },
2163
+ isPinned: (key) => pinned().has(key),
2092
2164
  get,
2093
2165
  set,
2094
2166
  sync,
@@ -2363,9 +2435,12 @@ function defineControls(id, input, options = {}) {
2363
2435
  preset(id, presetOptions) {
2364
2436
  if (!Object.hasOwn(presets, id))
2365
2437
  throw Error(`Unknown preset: ${id}`);
2366
- write(presets[id], { source: "preset", coalesce: presetOptions?.coalesce }, id === "default" ? NO_BASE : makeBase(Object.freeze({ kind: "preset", id }), {}));
2438
+ write(presetPatch(presets[id]), { source: "preset", coalesce: presetOptions?.coalesce }, id === "default" ? NO_BASE : makeBase(Object.freeze({ kind: "preset", id }), {}));
2439
+ },
2440
+ matchingPreset: () => {
2441
+ let cur = unpinned(get());
2442
+ return Object.keys(presets).find((id) => equal(cur, presets[id])) ?? "custom";
2367
2443
  },
2368
- matchingPreset: () => Object.keys(presets).find((id) => equal(get(), presets[id])) ?? "custom",
2369
2444
  get groupPresets() {
2370
2445
  return groupPresets;
2371
2446
  },
@@ -2437,7 +2512,7 @@ function descriptorToField(d) {
2437
2512
  if (readoutDescriptor(d))
2438
2513
  return readoutField(d);
2439
2514
  if (d.kind === "toolbar")
2440
- return toolbar(d.items.map(({ key, ...item }) => ({ ...item, id: key })), meta);
2515
+ return toolbar(d.items.map(({ key, ...item }) => ({ ...item, id: key })), d.labels !== void 0 ? { ...meta, labels: d.labels } : meta);
2441
2516
  if (d.bind)
2442
2517
  return flatSpring({}, { ...meta, id: d.key }).duration;
2443
2518
  if (d.kind === "knob" || d.kind === "number") {
@@ -2512,6 +2587,12 @@ function descriptorToField(d) {
2512
2587
  });
2513
2588
  if (d.kind === "keybind")
2514
2589
  return keybind(typeof d.default === "string" ? d.default : "", meta);
2590
+ if (d.kind === "text")
2591
+ return text(typeof d.default === "string" ? d.default : "", {
2592
+ ...d.multiline ? { multiline: !0 } : {},
2593
+ ...d.placeholder ? { placeholder: d.placeholder } : {},
2594
+ ...meta
2595
+ });
2515
2596
  if (d.kind === "gradient") {
2516
2597
  let fallback = [
2517
2598
  { at: 0, color: "#000000" },
@@ -2590,7 +2671,7 @@ var decimal = (n) => String(Math.round(n * 1e4) / 1e4), swiftLiteral = (d, v) =>
2590
2671
  let [a, b] = v;
2591
2672
  return `${decimal(a)}...${decimal(b)}`;
2592
2673
  }
2593
- if (d.kind === "keybind")
2674
+ if (d.kind === "keybind" || d.kind === "text")
2594
2675
  return JSON.stringify(v);
2595
2676
  if (d.kind === "gradient")
2596
2677
  return `Gradient(stops: [${(Array.isArray(v) ? v : []).map((s) => {
@@ -2619,6 +2700,7 @@ var decimal = (n) => String(Math.round(n * 1e4) / 1e4), swiftLiteral = (d, v) =>
2619
2700
  range: "ClosedRange<Double>",
2620
2701
  seed: "Int",
2621
2702
  keybind: "String",
2703
+ text: "String",
2622
2704
  gradient: "Gradient",
2623
2705
  curve: "[CGPoint]"
2624
2706
  };
@@ -2692,6 +2774,7 @@ function createRemoteControls(id, descriptors, options = {}) {
2692
2774
  tunable: options.tunable,
2693
2775
  history: options.history,
2694
2776
  presets: options.presets,
2777
+ pinned: options.pinned,
2695
2778
  groupPresets: options.groupPresets,
2696
2779
  onPreset: options.onPreset,
2697
2780
  actions: options.actions,
@@ -2827,6 +2910,7 @@ export {
2827
2910
  springCss,
2828
2911
  springMotion,
2829
2912
  table,
2913
+ text,
2830
2914
  toggle,
2831
2915
  toolbar,
2832
2916
  toolbarShortcut,