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

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
@@ -461,6 +461,7 @@ var META_KEYS = [
461
461
  "sectionFolded",
462
462
  "tab",
463
463
  "pinned",
464
+ "inPresets",
464
465
  "subsection"
465
466
  ];
466
467
  function pickMeta(source, skip = []) {
@@ -494,6 +495,13 @@ function pinnedKeys(schema, groups = []) {
494
495
  out.add(key);
495
496
  return out;
496
497
  }
498
+ function presetFreeKeys(schema, pinned, groups = {}) {
499
+ let out = new Set(pinned);
500
+ for (let [key, f] of Object.entries(schema))
501
+ if (f.inPresets === !1 || f.group !== void 0 && groups[f.group] === !1)
502
+ out.add(key);
503
+ return out;
504
+ }
497
505
  var SPRING = {
498
506
  duration: { min: 0.05, max: 2, step: 0.01 },
499
507
  bounce: { min: -0.5, max: 1, step: 0.01 }
@@ -1537,7 +1545,7 @@ function unlock(options) {
1537
1545
  }
1538
1546
 
1539
1547
  // src/core/variants.ts
1540
- function createVariants(schema, id, key, storage, get, set, notify, enabled) {
1548
+ function createVariants(schema, id, key, storage, get, set, notify, enabled, seed) {
1541
1549
  let ready = !1, list = Object.freeze([]);
1542
1550
  function parse(json) {
1543
1551
  let data = JSON.parse(json);
@@ -1566,7 +1574,7 @@ function createVariants(schema, id, key, storage, get, set, notify, enabled) {
1566
1574
  if (ready || !enabled())
1567
1575
  return;
1568
1576
  let json = storage()?.getItem(key);
1569
- list = json ? parse(json) : Object.freeze([]), ready = !0;
1577
+ list = json ? parse(json) : Object.freeze([...seed?.() ?? []]), ready = !0;
1570
1578
  }
1571
1579
  function persist(next) {
1572
1580
  if (!enabled())
@@ -1631,7 +1639,7 @@ function createVariants(schema, id, key, storage, get, set, notify, enabled) {
1631
1639
  }
1632
1640
 
1633
1641
  // src/core/store.ts
1634
- var devBuild = () => !1;
1642
+ var devBuild = () => !1, defaultLabelOf = (label, scope) => typeof label === "object" ? label[scope] : label;
1635
1643
  function sameField(a, b) {
1636
1644
  if (a === b)
1637
1645
  return !0;
@@ -1653,26 +1661,50 @@ function defineControls(id, input, options = {}) {
1653
1661
  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 = () => {
1654
1662
  for (let cb of [...listeners])
1655
1663
  cb();
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 = () => {
1664
+ }, 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({
1665
+ preset: null,
1666
+ groups: Object.freeze({}),
1667
+ scopes: Object.freeze({})
1668
+ }), base = NO_BASE, past = [], future = [], HISTORY = 100, stateKey = storageKey(id, "state"), pinnedOf, pinned = () => {
1657
1669
  if (pinnedOf?.schema !== schema)
1658
1670
  pinnedOf = { schema, keys: pinnedKeys(schema, options.pinned) };
1659
1671
  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();
1672
+ }, freeOf, presetFree = () => {
1673
+ if (freeOf?.schema !== schema)
1674
+ freeOf = { schema, keys: presetFreeKeys(schema, pinned(), options.inPresets) };
1675
+ return freeOf.keys;
1676
+ }, variantsChoice = () => variantsOf(schema, (key) => presetFree().has(key)), scopingOf, scoping = () => {
1677
+ if (scopingOf?.schema === schema)
1678
+ return scopingOf;
1679
+ let fields = schema, groupTab = /* @__PURE__ */ new Map;
1680
+ for (let f of Object.values(fields))
1681
+ if (f.group !== void 0 && f.tab !== void 0 && !groupTab.has(f.group))
1682
+ groupTab.set(f.group, f.tab);
1683
+ let tabOf = (f) => f.tab ?? (f.group !== void 0 ? groupTab.get(f.group) : void 0), named = new Set(Object.keys(options.scopedPresets ?? {}));
1684
+ if (named.has(""))
1685
+ throw Error("A scope needs a nonempty tab or group id.");
1686
+ let v = variantsChoice(), group = v?.field.group, variants = v ? tabOf(v.field) ?? (group !== void 0 && named.has(group) ? group : "") : void 0;
1687
+ if (variants)
1688
+ named.add(variants);
1689
+ let of = /* @__PURE__ */ new Map;
1690
+ for (let k of valueKeys(schema)) {
1691
+ if (presetFree().has(k))
1692
+ continue;
1693
+ let f = fields[k], tab = tabOf(f);
1694
+ of.set(k, tab !== void 0 && named.has(tab) ? tab : f.group !== void 0 && named.has(f.group) ? f.group : "");
1695
+ }
1696
+ return scopingOf = { schema, of, named: [...named], variants }, scopingOf;
1697
+ }, within = (values, scope) => {
1698
+ let of = scoping().of, out;
1699
+ for (let k of Object.keys(locked))
1700
+ if (of.get(k) !== scope && !same(values[k], locked[k]))
1701
+ out ??= { ...values }, out[k] = locked[k];
1702
+ return out ? Object.freeze(out) : values;
1703
+ }, unpinned = (values) => within(values, ""), patchIn = (values, scope) => {
1704
+ let of = scoping().of;
1705
+ return Object.fromEntries(Object.entries(values).filter(([k]) => of.get(k) === scope));
1706
+ }, buildPresets = (scope) => {
1707
+ let own = (scope === "" ? options.presets : options.scopedPresets?.[scope]) ?? {}, v = scoping().variants === scope ? variantsChoice() : void 0;
1676
1708
  if (v && Object.hasOwn(own, v.field.value))
1677
1709
  throw Error(`The default variant (${v.field.value}) is the schema's defaults; set its values there.`);
1678
1710
  let ids = [
@@ -1685,10 +1717,17 @@ function defineControls(id, input, options = {}) {
1685
1717
  if (id === "default" || id === "custom")
1686
1718
  throw Error(`Reserved preset id: ${id}`);
1687
1719
  let variant = v?.field.options.includes(id) ? { [v.key]: id } : {};
1688
- return [id, unpinned(normalize(schema, { ...locked, ...variant, ...own[id] }))];
1720
+ return [id, within(normalize(schema, { ...locked, ...variant, ...own[id] }), scope)];
1689
1721
  })
1690
1722
  ]));
1691
- }, presets = buildPresets(), buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1723
+ }, buildScopePresets = () => new Map(scoping().named.map((scope) => [scope, buildPresets(scope)])), presets = buildPresets(""), scopePresets = buildScopePresets(), presetsIn = (scope) => {
1724
+ if (scope === "")
1725
+ return presets;
1726
+ let found = scopePresets.get(scope);
1727
+ if (!found)
1728
+ throw Error(`Unknown preset scope: ${scope}`);
1729
+ return found;
1730
+ }, buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1692
1731
  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])));
1693
1732
  return [
1694
1733
  group,
@@ -1753,22 +1792,54 @@ function defineControls(id, input, options = {}) {
1753
1792
  function commit(next) {
1754
1793
  current = next, persist(), notify();
1755
1794
  }
1756
- let makeBase = (preset, groups) => preset === null && Object.keys(groups).length === 0 ? NO_BASE : Object.freeze({ preset, groups: Object.freeze({ ...groups }) }), sameBase = (a, b) => a === b || a.preset?.kind === b.preset?.kind && a.preset?.id === b.preset?.id && Object.keys(a.groups).length === Object.keys(b.groups).length && Object.entries(a.groups).every(([g, i]) => b.groups[g] === i);
1795
+ let makeBase = (preset, groups, scopes = {}) => preset === null && Object.keys(groups).length === 0 && Object.keys(scopes).length === 0 ? NO_BASE : Object.freeze({
1796
+ preset,
1797
+ groups: Object.freeze({ ...groups }),
1798
+ scopes: Object.freeze({ ...scopes })
1799
+ }), withScope = (scopes, scope, ref) => {
1800
+ let { [scope]: _, ...others } = scopes;
1801
+ return ref ? { ...others, [scope]: ref } : others;
1802
+ }, sameRef = (a, b) => a?.kind === b?.kind && a?.id === b?.id, sameBase = (a, b) => a === b || sameRef(a.preset, b.preset) && Object.keys(a.groups).length === Object.keys(b.groups).length && Object.entries(a.groups).every(([g, i]) => b.groups[g] === i) && Object.keys(a.scopes).length === Object.keys(b.scopes).length && Object.entries(a.scopes).every(([s, ref]) => sameRef(ref, b.scopes[s])), seedsScopes = () => scopePresets.size > 0 && Object.keys(options.presets ?? {}).length === 0, groupsOutside = (groups, scope) => {
1803
+ let of = scoping().of;
1804
+ return Object.fromEntries(Object.entries(groups).filter(([g]) => !(groupPresets[g] ?? []).some((p) => Object.keys(p.values).some((k) => of.get(k) === scope))));
1805
+ }, known = (ref, scope) => ref.kind === "variant" || ref.id !== "default" && Object.hasOwn(scopePresets.get(scope) ?? {}, ref.id);
1757
1806
  function validBase(b) {
1758
- let preset = b.preset?.kind === "preset" && !(b.preset.id !== "default" && Object.hasOwn(presets, b.preset.id)) ? null : b.preset, groups = Object.fromEntries(Object.entries(b.groups).filter(([g, i]) => groupPresets[g]?.[i] !== void 0)), next = makeBase(preset, groups);
1807
+ let preset = b.preset?.kind === "preset" && !(b.preset.id !== "default" && Object.hasOwn(presets, b.preset.id)) ? null : b.preset, groups = Object.fromEntries(Object.entries(b.groups).filter(([g, i]) => groupPresets[g]?.[i] !== void 0)), scopes = Object.fromEntries(Object.entries(b.scopes).filter(([s, ref]) => scopePresets.has(s) && known(ref, s))), next = makeBase(preset, groups, scopes);
1759
1808
  return sameBase(next, b) ? b : next;
1760
1809
  }
1810
+ let readRef = (raw) => raw && typeof raw === "object" && (raw.kind === "preset" || raw.kind === "variant") && typeof raw.id === "string" ? Object.freeze({ kind: raw.kind, id: raw.id }) : null;
1761
1811
  function readBase(raw) {
1762
1812
  if (!raw || typeof raw !== "object")
1763
1813
  return NO_BASE;
1764
- let { preset, groups } = raw, ref = preset && typeof preset === "object" && (preset.kind === "preset" || preset.kind === "variant") && typeof preset.id === "string" ? Object.freeze({ kind: preset.kind, id: preset.id }) : null, byGroup = groups && typeof groups === "object" ? Object.fromEntries(Object.entries(groups).filter((e) => Number.isInteger(e[1]))) : {};
1765
- return validBase(makeBase(ref, byGroup));
1814
+ let { preset, groups, scopes } = raw, ref = readRef(preset), byGroup = groups && typeof groups === "object" ? Object.fromEntries(Object.entries(groups).filter((e) => Number.isInteger(e[1]))) : {}, byScope = {};
1815
+ if (scopes && typeof scopes === "object")
1816
+ for (let [s, r] of Object.entries(scopes)) {
1817
+ let found = readRef(r);
1818
+ if (found)
1819
+ byScope[s] = found;
1820
+ }
1821
+ if (ref?.kind === "preset" && !Object.hasOwn(presets, ref.id)) {
1822
+ for (let [s, list] of scopePresets)
1823
+ if (!byScope[s] && ref.id !== "default" && Object.hasOwn(list, ref.id))
1824
+ byScope[s] = ref;
1825
+ ref = null;
1826
+ } else if (ref?.kind === "variant" && seedsScopes()) {
1827
+ let id = ref.id;
1828
+ for (let s of scopePresets.keys())
1829
+ if (!byScope[s] && scopeVariants(s).list().some((v) => v.id === id))
1830
+ byScope[s] = ref;
1831
+ ref = null;
1832
+ }
1833
+ return validBase(makeBase(ref, byGroup, byScope));
1766
1834
  }
1767
1835
  function activeBase() {
1768
1836
  load();
1769
- let ref = base.preset;
1770
- if (ref?.kind === "variant" && !variants.list().some((v) => v.id === ref.id))
1771
- base = makeBase(null, base.groups);
1837
+ let gone = (ref, list) => ref?.kind === "variant" && !list().some((v) => v.id === ref.id), preset = gone(base.preset, () => variants.list()) ? null : base.preset, scopes = base.scopes;
1838
+ for (let [s, ref] of Object.entries(base.scopes))
1839
+ if (gone(ref, () => scopeVariants(s).list()))
1840
+ scopes = withScope(scopes, s, void 0);
1841
+ if (preset !== base.preset || scopes !== base.scopes)
1842
+ base = makeBase(preset, base.groups, scopes);
1772
1843
  return base;
1773
1844
  }
1774
1845
  let hasBase = () => activeBase() !== NO_BASE, baseCache;
@@ -1778,17 +1849,23 @@ function defineControls(id, input, options = {}) {
1778
1849
  let b = activeBase();
1779
1850
  if (b === NO_BASE)
1780
1851
  return locked;
1781
- let list = b.preset?.kind === "variant" ? variants.list() : null, c = baseCache;
1782
- if (c && c.base === b && c.schema === schema && c.presets === presets && c.groupPresets === groupPresets && c.variants === list)
1852
+ let lists = [
1853
+ b.preset?.kind === "variant" ? variants.list() : null,
1854
+ ...Object.entries(b.scopes).map(([s, ref]) => ref.kind === "variant" ? scopeVariants(s).list() : null)
1855
+ ], c = baseCache;
1856
+ if (c && c.base === b && c.schema === schema && c.presets === presets && c.scopePresets === scopePresets && c.groupPresets === groupPresets && c.variants.length === lists.length && c.variants.every((l, i) => l === lists[i]))
1783
1857
  return c.values;
1784
- let out = locked, ref = b.preset;
1785
- if (ref?.kind === "preset" && Object.hasOwn(presets, ref.id))
1786
- out = presets[ref.id];
1787
- else if (ref?.kind === "variant") {
1858
+ let valuesOf = (ref, scope, list) => {
1859
+ if (ref.kind === "preset")
1860
+ return presetsIn(scope)[ref.id];
1788
1861
  let found = list?.find((v) => v.id === ref.id);
1789
- if (found)
1790
- out = unpinned(normalize(schema, found.values));
1791
- }
1862
+ return found ? within(normalize(schema, found.values), scope) : void 0;
1863
+ }, out = locked;
1864
+ if (b.preset)
1865
+ out = valuesOf(b.preset, "", lists[0]) ?? locked;
1866
+ let scoped = Object.entries(b.scopes);
1867
+ if (scoped.length)
1868
+ out = { ...out }, scoped.forEach(([s, ref], i) => Object.assign(out, patchIn(valuesOf(ref, s, lists[i + 1]) ?? locked, s)));
1792
1869
  let groups = Object.entries(b.groups);
1793
1870
  if (groups.length) {
1794
1871
  out = { ...out };
@@ -1796,13 +1873,16 @@ function defineControls(id, input, options = {}) {
1796
1873
  Object.assign(out, groupPresets[g]?.[i]?.values);
1797
1874
  }
1798
1875
  let values = Object.freeze(out);
1799
- return baseCache = { base: b, schema, presets, groupPresets, variants: list, values }, values;
1876
+ return baseCache = { base: b, schema, presets, scopePresets, groupPresets, variants: lists, values }, values;
1800
1877
  }
1801
1878
  let covered = (key) => {
1802
1879
  let b = activeBase(), group = schema[key]?.group;
1803
1880
  if (group !== void 0 && Object.hasOwn(b.groups, group))
1804
1881
  return !0;
1805
- return b.preset !== null && !pinned().has(key);
1882
+ let scope = scoping().of.get(key);
1883
+ if (scope === void 0)
1884
+ return !1;
1885
+ return scope === "" ? b.preset !== null : Object.hasOwn(b.scopes, scope);
1806
1886
  };
1807
1887
  function declaredShortcut(id) {
1808
1888
  let slash = id.indexOf("/"), key = slash < 0 ? id : id.slice(0, slash), field = Object.hasOwn(schema, key) ? schema[key] : void 0;
@@ -2037,7 +2117,7 @@ function defineControls(id, input, options = {}) {
2037
2117
  schema = Object.freeze({ ...next });
2038
2118
  if (changed) {
2039
2119
  let previous = load();
2040
- schema = Object.freeze({ ...next }), locked = normalize(schema, {}), presets = buildPresets(), groupPresets = buildGroupPresets(), base = validBase(base);
2120
+ schema = Object.freeze({ ...next }), locked = normalize(schema, {}), presets = buildPresets(""), scopePresets = buildScopePresets(), groupPresets = buildGroupPresets(), base = validBase(base);
2041
2121
  for (let k of [...locks])
2042
2122
  if (!valueField(k))
2043
2123
  locks.delete(k);
@@ -2072,7 +2152,33 @@ function defineControls(id, input, options = {}) {
2072
2152
  listen(cb) {
2073
2153
  return readoutListeners.add(cb), () => readoutListeners.delete(cb);
2074
2154
  }
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));
2155
+ }, variants = createVariants(() => schema, id, storageKey(id, "variants"), variantStorage, () => unpinned(get()), (v, variant, coalesce) => write(patchIn(v, ""), { source: "variant", coalesce }, makeBase(Object.freeze({ kind: "variant", id: variant }), {}, activeBase().scopes)), notify, enabled), scopeVariantsMade = /* @__PURE__ */ new Map;
2156
+ function scopeVariants(scope) {
2157
+ let made = scopeVariantsMade.get(scope);
2158
+ if (made)
2159
+ return made;
2160
+ return made = createVariants(() => schema, id, storageKey(id, `variants:${scope}`), variantStorage, () => within(get(), scope), (v, variant, coalesce) => {
2161
+ let b = activeBase();
2162
+ write(patchIn(v, scope), { source: "variant", coalesce }, makeBase(b.preset, groupsOutside(b.groups, scope), withScope(b.scopes, scope, Object.freeze({ kind: "variant", id: variant }))));
2163
+ }, notify, enabled, () => !seedsScopes() ? [] : variants.list().flatMap((v) => {
2164
+ let values = within(normalize(schema, v.values), scope);
2165
+ return equal(values, locked) ? [] : [{ ...v, values }];
2166
+ })), scopeVariantsMade.set(scope, made), made;
2167
+ }
2168
+ let scopesOf, scopes = () => {
2169
+ if (scopesOf?.presets === scopePresets)
2170
+ return scopesOf.value;
2171
+ let of = scoping().of, value = Object.freeze(Object.fromEntries([...scopePresets].map(([scope, list]) => [
2172
+ scope,
2173
+ Object.freeze({
2174
+ id: scope,
2175
+ keys: Object.freeze([...of].flatMap(([k, s]) => s === scope ? [k] : [])),
2176
+ presets: list,
2177
+ variants: scopeVariants(scope)
2178
+ })
2179
+ ])));
2180
+ return scopesOf = { presets: scopePresets, value }, value;
2181
+ }, resettable = (keys) => (keys ?? fieldKeys()).filter((k) => valueField(k) && !blocked(k));
2076
2182
  function offBase(keys) {
2077
2183
  if (!hasBase())
2078
2184
  return !1;
@@ -2136,6 +2242,10 @@ function defineControls(id, input, options = {}) {
2136
2242
  get presets() {
2137
2243
  return presets;
2138
2244
  },
2245
+ get scopes() {
2246
+ return scopes();
2247
+ },
2248
+ scopeOf: (key) => scoping().of.get(key),
2139
2249
  actions,
2140
2250
  theme,
2141
2251
  appearance,
@@ -2156,11 +2266,12 @@ function defineControls(id, input, options = {}) {
2156
2266
  sectionDescription: (section) => options.sectionDescriptions?.[section] ?? fieldLabels().sectionText.get(section),
2157
2267
  groupFolded: options.groupFolded,
2158
2268
  sectionFolded: options.sectionFolded,
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);
2269
+ presetLabel: (presetId, scope = "") => {
2270
+ let v = scoping().variants === scope ? variantsChoice() : void 0, option = presetId === "default" ? v?.field.value : presetId;
2271
+ return options.presetLabels?.[presetId] ?? (presetId === "default" ? defaultLabelOf(options.defaultLabel, scope) : void 0) ?? (v && option !== void 0 && v.field.options.includes(option) ? v.field.labels?.[option] ?? option : presetId);
2162
2272
  },
2163
2273
  isPinned: (key) => pinned().has(key),
2274
+ inPresets: (key) => !presetFree().has(key),
2164
2275
  get,
2165
2276
  set,
2166
2277
  sync,
@@ -2288,7 +2399,7 @@ function defineControls(id, input, options = {}) {
2288
2399
  options.onPreset?.({ group, index, name: preset.name });
2289
2400
  return;
2290
2401
  }
2291
- let { [group]: _, ...others } = b.groups, forget = index === void 0 ? void 0 : makeBase(b.preset, others);
2402
+ let { [group]: _, ...others } = b.groups, forget = index === void 0 ? void 0 : makeBase(b.preset, others, b.scopes);
2292
2403
  if (open.length < keys.length)
2293
2404
  return toDefaults(open, forget);
2294
2405
  let patch = {};
@@ -2433,13 +2544,15 @@ function defineControls(id, input, options = {}) {
2433
2544
  comparing = before, options.onChange?.(changes(now, before), before, { source: "compare" }), notify();
2434
2545
  },
2435
2546
  preset(id, presetOptions) {
2436
- if (!Object.hasOwn(presets, id))
2547
+ let scope = presetOptions?.scope ?? "", list = presetsIn(scope);
2548
+ if (!Object.hasOwn(list, id))
2437
2549
  throw Error(`Unknown preset: ${id}`);
2438
- write(presetPatch(presets[id]), { source: "preset", coalesce: presetOptions?.coalesce }, id === "default" ? NO_BASE : makeBase(Object.freeze({ kind: "preset", id }), {}));
2550
+ let b = activeBase(), ref = id === "default" ? void 0 : Object.freeze({ kind: "preset", id });
2551
+ write(patchIn(list[id], scope), { source: "preset", coalesce: presetOptions?.coalesce }, scope === "" ? makeBase(ref ?? null, {}, b.scopes) : makeBase(b.preset, groupsOutside(b.groups, scope), withScope(b.scopes, scope, ref)));
2439
2552
  },
2440
- matchingPreset: () => {
2441
- let cur = unpinned(get());
2442
- return Object.keys(presets).find((id) => equal(cur, presets[id])) ?? "custom";
2553
+ matchingPreset: (scope = "") => {
2554
+ let list = presetsIn(scope), cur = within(get(), scope);
2555
+ return Object.keys(list).find((id) => equal(cur, list[id])) ?? "custom";
2443
2556
  },
2444
2557
  get groupPresets() {
2445
2558
  return groupPresets;
@@ -2451,12 +2564,13 @@ function defineControls(id, input, options = {}) {
2451
2564
  if (!enabled())
2452
2565
  return;
2453
2566
  let b = activeBase();
2454
- write(preset.values, { source: "preset", group, coalesce: presetOptions?.coalesce }, makeBase(b.preset, { ...b.groups, [group]: index })), options.onPreset?.({ group, index, name: preset.name });
2567
+ write(preset.values, { source: "preset", group, coalesce: presetOptions?.coalesce }, makeBase(b.preset, { ...b.groups, [group]: index }, b.scopes)), options.onPreset?.({ group, index, name: preset.name });
2455
2568
  },
2456
- activePreset() {
2569
+ activePreset(scope) {
2457
2570
  if (!enabled())
2458
2571
  return null;
2459
- return activeBase().preset;
2572
+ let b = activeBase();
2573
+ return scope ? b.scopes[scope] ?? null : b.preset;
2460
2574
  },
2461
2575
  activeGroupPreset(group) {
2462
2576
  if (!enabled())
@@ -2774,7 +2888,9 @@ function createRemoteControls(id, descriptors, options = {}) {
2774
2888
  tunable: options.tunable,
2775
2889
  history: options.history,
2776
2890
  presets: options.presets,
2891
+ scopedPresets: options.scopedPresets,
2777
2892
  pinned: options.pinned,
2893
+ inPresets: options.inPresets,
2778
2894
  groupPresets: options.groupPresets,
2779
2895
  onPreset: options.onPreset,
2780
2896
  actions: options.actions,