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

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
@@ -1537,7 +1537,7 @@ function unlock(options) {
1537
1537
  }
1538
1538
 
1539
1539
  // src/core/variants.ts
1540
- function createVariants(schema, id, key, storage, get, set, notify, enabled) {
1540
+ function createVariants(schema, id, key, storage, get, set, notify, enabled, seed) {
1541
1541
  let ready = !1, list = Object.freeze([]);
1542
1542
  function parse(json) {
1543
1543
  let data = JSON.parse(json);
@@ -1566,7 +1566,7 @@ function createVariants(schema, id, key, storage, get, set, notify, enabled) {
1566
1566
  if (ready || !enabled())
1567
1567
  return;
1568
1568
  let json = storage()?.getItem(key);
1569
- list = json ? parse(json) : Object.freeze([]), ready = !0;
1569
+ list = json ? parse(json) : Object.freeze([...seed?.() ?? []]), ready = !0;
1570
1570
  }
1571
1571
  function persist(next) {
1572
1572
  if (!enabled())
@@ -1653,26 +1653,46 @@ function defineControls(id, input, options = {}) {
1653
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 = () => {
1654
1654
  for (let cb of [...listeners])
1655
1655
  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 = () => {
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({
1657
+ preset: null,
1658
+ groups: Object.freeze({}),
1659
+ scopes: Object.freeze({})
1660
+ }), base = NO_BASE, past = [], future = [], HISTORY = 100, stateKey = storageKey(id, "state"), pinnedOf, pinned = () => {
1657
1661
  if (pinnedOf?.schema !== schema)
1658
1662
  pinnedOf = { schema, keys: pinnedKeys(schema, options.pinned) };
1659
1663
  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();
1664
+ }, variantsChoice = () => variantsOf(schema, (key) => pinned().has(key)), scopingOf, scoping = () => {
1665
+ if (scopingOf?.schema === schema)
1666
+ return scopingOf;
1667
+ let fields = schema, groupTab = /* @__PURE__ */ new Map;
1668
+ for (let f of Object.values(fields))
1669
+ if (f.group !== void 0 && f.tab !== void 0 && !groupTab.has(f.group))
1670
+ groupTab.set(f.group, f.tab);
1671
+ let tabOf = (f) => f.tab ?? (f.group !== void 0 ? groupTab.get(f.group) : void 0), named = new Set(Object.keys(options.scopedPresets ?? {}));
1672
+ if (named.has(""))
1673
+ throw Error("A scope needs a nonempty tab or group id.");
1674
+ let v = variantsChoice(), group = v?.field.group, variants = v ? tabOf(v.field) ?? (group !== void 0 && named.has(group) ? group : "") : void 0;
1675
+ if (variants)
1676
+ named.add(variants);
1677
+ let of = /* @__PURE__ */ new Map;
1678
+ for (let k of valueKeys(schema)) {
1679
+ if (pinned().has(k))
1680
+ continue;
1681
+ let f = fields[k], tab = tabOf(f);
1682
+ of.set(k, tab !== void 0 && named.has(tab) ? tab : f.group !== void 0 && named.has(f.group) ? f.group : "");
1683
+ }
1684
+ return scopingOf = { schema, of, named: [...named], variants }, scopingOf;
1685
+ }, within = (values, scope) => {
1686
+ let of = scoping().of, out;
1687
+ for (let k of Object.keys(locked))
1688
+ if (of.get(k) !== scope && !same(values[k], locked[k]))
1689
+ out ??= { ...values }, out[k] = locked[k];
1690
+ return out ? Object.freeze(out) : values;
1691
+ }, unpinned = (values) => within(values, ""), patchIn = (values, scope) => {
1692
+ let of = scoping().of;
1693
+ return Object.fromEntries(Object.entries(values).filter(([k]) => of.get(k) === scope));
1694
+ }, buildPresets = (scope) => {
1695
+ let own = (scope === "" ? options.presets : options.scopedPresets?.[scope]) ?? {}, v = scoping().variants === scope ? variantsChoice() : void 0;
1676
1696
  if (v && Object.hasOwn(own, v.field.value))
1677
1697
  throw Error(`The default variant (${v.field.value}) is the schema's defaults; set its values there.`);
1678
1698
  let ids = [
@@ -1685,10 +1705,17 @@ function defineControls(id, input, options = {}) {
1685
1705
  if (id === "default" || id === "custom")
1686
1706
  throw Error(`Reserved preset id: ${id}`);
1687
1707
  let variant = v?.field.options.includes(id) ? { [v.key]: id } : {};
1688
- return [id, unpinned(normalize(schema, { ...locked, ...variant, ...own[id] }))];
1708
+ return [id, within(normalize(schema, { ...locked, ...variant, ...own[id] }), scope)];
1689
1709
  })
1690
1710
  ]));
1691
- }, presets = buildPresets(), buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1711
+ }, buildScopePresets = () => new Map(scoping().named.map((scope) => [scope, buildPresets(scope)])), presets = buildPresets(""), scopePresets = buildScopePresets(), presetsIn = (scope) => {
1712
+ if (scope === "")
1713
+ return presets;
1714
+ let found = scopePresets.get(scope);
1715
+ if (!found)
1716
+ throw Error(`Unknown preset scope: ${scope}`);
1717
+ return found;
1718
+ }, buildGroupPresets = () => Object.freeze(Object.fromEntries(Object.entries(options.groupPresets ?? {}).map(([group, list]) => {
1692
1719
  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
1720
  return [
1694
1721
  group,
@@ -1753,22 +1780,54 @@ function defineControls(id, input, options = {}) {
1753
1780
  function commit(next) {
1754
1781
  current = next, persist(), notify();
1755
1782
  }
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);
1783
+ let makeBase = (preset, groups, scopes = {}) => preset === null && Object.keys(groups).length === 0 && Object.keys(scopes).length === 0 ? NO_BASE : Object.freeze({
1784
+ preset,
1785
+ groups: Object.freeze({ ...groups }),
1786
+ scopes: Object.freeze({ ...scopes })
1787
+ }), withScope = (scopes, scope, ref) => {
1788
+ let { [scope]: _, ...others } = scopes;
1789
+ return ref ? { ...others, [scope]: ref } : others;
1790
+ }, 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) => {
1791
+ let of = scoping().of;
1792
+ return Object.fromEntries(Object.entries(groups).filter(([g]) => !(groupPresets[g] ?? []).some((p) => Object.keys(p.values).some((k) => of.get(k) === scope))));
1793
+ }, known = (ref, scope) => ref.kind === "variant" || ref.id !== "default" && Object.hasOwn(scopePresets.get(scope) ?? {}, ref.id);
1757
1794
  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);
1795
+ 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
1796
  return sameBase(next, b) ? b : next;
1760
1797
  }
1798
+ 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
1799
  function readBase(raw) {
1762
1800
  if (!raw || typeof raw !== "object")
1763
1801
  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));
1802
+ 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 = {};
1803
+ if (scopes && typeof scopes === "object")
1804
+ for (let [s, r] of Object.entries(scopes)) {
1805
+ let found = readRef(r);
1806
+ if (found)
1807
+ byScope[s] = found;
1808
+ }
1809
+ if (ref?.kind === "preset" && !Object.hasOwn(presets, ref.id)) {
1810
+ for (let [s, list] of scopePresets)
1811
+ if (!byScope[s] && ref.id !== "default" && Object.hasOwn(list, ref.id))
1812
+ byScope[s] = ref;
1813
+ ref = null;
1814
+ } else if (ref?.kind === "variant" && seedsScopes()) {
1815
+ let id = ref.id;
1816
+ for (let s of scopePresets.keys())
1817
+ if (!byScope[s] && scopeVariants(s).list().some((v) => v.id === id))
1818
+ byScope[s] = ref;
1819
+ ref = null;
1820
+ }
1821
+ return validBase(makeBase(ref, byGroup, byScope));
1766
1822
  }
1767
1823
  function activeBase() {
1768
1824
  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);
1825
+ 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;
1826
+ for (let [s, ref] of Object.entries(base.scopes))
1827
+ if (gone(ref, () => scopeVariants(s).list()))
1828
+ scopes = withScope(scopes, s, void 0);
1829
+ if (preset !== base.preset || scopes !== base.scopes)
1830
+ base = makeBase(preset, base.groups, scopes);
1772
1831
  return base;
1773
1832
  }
1774
1833
  let hasBase = () => activeBase() !== NO_BASE, baseCache;
@@ -1778,17 +1837,23 @@ function defineControls(id, input, options = {}) {
1778
1837
  let b = activeBase();
1779
1838
  if (b === NO_BASE)
1780
1839
  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)
1840
+ let lists = [
1841
+ b.preset?.kind === "variant" ? variants.list() : null,
1842
+ ...Object.entries(b.scopes).map(([s, ref]) => ref.kind === "variant" ? scopeVariants(s).list() : null)
1843
+ ], c = baseCache;
1844
+ 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
1845
  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") {
1846
+ let valuesOf = (ref, scope, list) => {
1847
+ if (ref.kind === "preset")
1848
+ return presetsIn(scope)[ref.id];
1788
1849
  let found = list?.find((v) => v.id === ref.id);
1789
- if (found)
1790
- out = unpinned(normalize(schema, found.values));
1791
- }
1850
+ return found ? within(normalize(schema, found.values), scope) : void 0;
1851
+ }, out = locked;
1852
+ if (b.preset)
1853
+ out = valuesOf(b.preset, "", lists[0]) ?? locked;
1854
+ let scoped = Object.entries(b.scopes);
1855
+ if (scoped.length)
1856
+ out = { ...out }, scoped.forEach(([s, ref], i) => Object.assign(out, patchIn(valuesOf(ref, s, lists[i + 1]) ?? locked, s)));
1792
1857
  let groups = Object.entries(b.groups);
1793
1858
  if (groups.length) {
1794
1859
  out = { ...out };
@@ -1796,13 +1861,16 @@ function defineControls(id, input, options = {}) {
1796
1861
  Object.assign(out, groupPresets[g]?.[i]?.values);
1797
1862
  }
1798
1863
  let values = Object.freeze(out);
1799
- return baseCache = { base: b, schema, presets, groupPresets, variants: list, values }, values;
1864
+ return baseCache = { base: b, schema, presets, scopePresets, groupPresets, variants: lists, values }, values;
1800
1865
  }
1801
1866
  let covered = (key) => {
1802
1867
  let b = activeBase(), group = schema[key]?.group;
1803
1868
  if (group !== void 0 && Object.hasOwn(b.groups, group))
1804
1869
  return !0;
1805
- return b.preset !== null && !pinned().has(key);
1870
+ let scope = scoping().of.get(key);
1871
+ if (scope === void 0)
1872
+ return !1;
1873
+ return scope === "" ? b.preset !== null : Object.hasOwn(b.scopes, scope);
1806
1874
  };
1807
1875
  function declaredShortcut(id) {
1808
1876
  let slash = id.indexOf("/"), key = slash < 0 ? id : id.slice(0, slash), field = Object.hasOwn(schema, key) ? schema[key] : void 0;
@@ -2037,7 +2105,7 @@ function defineControls(id, input, options = {}) {
2037
2105
  schema = Object.freeze({ ...next });
2038
2106
  if (changed) {
2039
2107
  let previous = load();
2040
- schema = Object.freeze({ ...next }), locked = normalize(schema, {}), presets = buildPresets(), groupPresets = buildGroupPresets(), base = validBase(base);
2108
+ schema = Object.freeze({ ...next }), locked = normalize(schema, {}), presets = buildPresets(""), scopePresets = buildScopePresets(), groupPresets = buildGroupPresets(), base = validBase(base);
2041
2109
  for (let k of [...locks])
2042
2110
  if (!valueField(k))
2043
2111
  locks.delete(k);
@@ -2072,7 +2140,33 @@ function defineControls(id, input, options = {}) {
2072
2140
  listen(cb) {
2073
2141
  return readoutListeners.add(cb), () => readoutListeners.delete(cb);
2074
2142
  }
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));
2143
+ }, 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;
2144
+ function scopeVariants(scope) {
2145
+ let made = scopeVariantsMade.get(scope);
2146
+ if (made)
2147
+ return made;
2148
+ return made = createVariants(() => schema, id, storageKey(id, `variants:${scope}`), variantStorage, () => within(get(), scope), (v, variant, coalesce) => {
2149
+ let b = activeBase();
2150
+ write(patchIn(v, scope), { source: "variant", coalesce }, makeBase(b.preset, groupsOutside(b.groups, scope), withScope(b.scopes, scope, Object.freeze({ kind: "variant", id: variant }))));
2151
+ }, notify, enabled, () => !seedsScopes() ? [] : variants.list().flatMap((v) => {
2152
+ let values = within(normalize(schema, v.values), scope);
2153
+ return equal(values, locked) ? [] : [{ ...v, values }];
2154
+ })), scopeVariantsMade.set(scope, made), made;
2155
+ }
2156
+ let scopesOf, scopes = () => {
2157
+ if (scopesOf?.presets === scopePresets)
2158
+ return scopesOf.value;
2159
+ let of = scoping().of, value = Object.freeze(Object.fromEntries([...scopePresets].map(([scope, list]) => [
2160
+ scope,
2161
+ Object.freeze({
2162
+ id: scope,
2163
+ keys: Object.freeze([...of].flatMap(([k, s]) => s === scope ? [k] : [])),
2164
+ presets: list,
2165
+ variants: scopeVariants(scope)
2166
+ })
2167
+ ])));
2168
+ return scopesOf = { presets: scopePresets, value }, value;
2169
+ }, resettable = (keys) => (keys ?? fieldKeys()).filter((k) => valueField(k) && !blocked(k));
2076
2170
  function offBase(keys) {
2077
2171
  if (!hasBase())
2078
2172
  return !1;
@@ -2136,6 +2230,10 @@ function defineControls(id, input, options = {}) {
2136
2230
  get presets() {
2137
2231
  return presets;
2138
2232
  },
2233
+ get scopes() {
2234
+ return scopes();
2235
+ },
2236
+ scopeOf: (key) => scoping().of.get(key),
2139
2237
  actions,
2140
2238
  theme,
2141
2239
  appearance,
@@ -2156,8 +2254,8 @@ function defineControls(id, input, options = {}) {
2156
2254
  sectionDescription: (section) => options.sectionDescriptions?.[section] ?? fieldLabels().sectionText.get(section),
2157
2255
  groupFolded: options.groupFolded,
2158
2256
  sectionFolded: options.sectionFolded,
2159
- presetLabel: (presetId) => {
2160
- let v = variantsChoice(), option = presetId === "default" ? v?.field.value : presetId;
2257
+ presetLabel: (presetId, scope = "") => {
2258
+ let v = scoping().variants === scope ? variantsChoice() : void 0, option = presetId === "default" ? v?.field.value : presetId;
2161
2259
  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
2260
  },
2163
2261
  isPinned: (key) => pinned().has(key),
@@ -2288,7 +2386,7 @@ function defineControls(id, input, options = {}) {
2288
2386
  options.onPreset?.({ group, index, name: preset.name });
2289
2387
  return;
2290
2388
  }
2291
- let { [group]: _, ...others } = b.groups, forget = index === void 0 ? void 0 : makeBase(b.preset, others);
2389
+ let { [group]: _, ...others } = b.groups, forget = index === void 0 ? void 0 : makeBase(b.preset, others, b.scopes);
2292
2390
  if (open.length < keys.length)
2293
2391
  return toDefaults(open, forget);
2294
2392
  let patch = {};
@@ -2433,13 +2531,15 @@ function defineControls(id, input, options = {}) {
2433
2531
  comparing = before, options.onChange?.(changes(now, before), before, { source: "compare" }), notify();
2434
2532
  },
2435
2533
  preset(id, presetOptions) {
2436
- if (!Object.hasOwn(presets, id))
2534
+ let scope = presetOptions?.scope ?? "", list = presetsIn(scope);
2535
+ if (!Object.hasOwn(list, id))
2437
2536
  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 }), {}));
2537
+ let b = activeBase(), ref = id === "default" ? void 0 : Object.freeze({ kind: "preset", id });
2538
+ 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
2539
  },
2440
- matchingPreset: () => {
2441
- let cur = unpinned(get());
2442
- return Object.keys(presets).find((id) => equal(cur, presets[id])) ?? "custom";
2540
+ matchingPreset: (scope = "") => {
2541
+ let list = presetsIn(scope), cur = within(get(), scope);
2542
+ return Object.keys(list).find((id) => equal(cur, list[id])) ?? "custom";
2443
2543
  },
2444
2544
  get groupPresets() {
2445
2545
  return groupPresets;
@@ -2451,12 +2551,13 @@ function defineControls(id, input, options = {}) {
2451
2551
  if (!enabled())
2452
2552
  return;
2453
2553
  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 });
2554
+ 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
2555
  },
2456
- activePreset() {
2556
+ activePreset(scope) {
2457
2557
  if (!enabled())
2458
2558
  return null;
2459
- return activeBase().preset;
2559
+ let b = activeBase();
2560
+ return scope ? b.scopes[scope] ?? null : b.preset;
2460
2561
  },
2461
2562
  activeGroupPreset(group) {
2462
2563
  if (!enabled())
@@ -2774,6 +2875,7 @@ function createRemoteControls(id, descriptors, options = {}) {
2774
2875
  tunable: options.tunable,
2775
2876
  history: options.history,
2776
2877
  presets: options.presets,
2878
+ scopedPresets: options.scopedPresets,
2777
2879
  pinned: options.pinned,
2778
2880
  groupPresets: options.groupPresets,
2779
2881
  onPreset: options.onPreset,