@weasel-js/prefs 1.10.1 → 1.11.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.
package/dist/react.js CHANGED
@@ -1,5 +1,8 @@
1
- import { openPrefsCacheSync, createPrefsStore } from './chunk-ASSX3JHY.js';
2
- import { useCallback, useSyncExternalStore } from 'react';
1
+ import { kitSettingsCssOptions, openPrefsCacheSync, createPrefsStore } from './chunk-WN6QQICK.js';
2
+ import { prefValueAtPath, prefsCss, prefsCssAttributes } from './chunk-OZFER7VN.js';
3
+ import { useCallback, useSyncExternalStore, useRef, useLayoutEffect } from 'react';
4
+ import { KitSettingsProvider } from '@weasel-js/react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
6
 
4
7
  function usePref(store, path) {
5
8
  const subscribe = useCallback((onChange) => store.subscribe(onChange), [store]);
@@ -101,6 +104,75 @@ function usePrefsStore(schema, options) {
101
104
  return useSyncExternalStore(hold, current, current);
102
105
  }
103
106
 
104
- export { usePref, usePrefsStore, usePrefsValues };
107
+ // src/adopt.ts
108
+ function prefsStyleRootOf(el) {
109
+ const root = el.getRootNode();
110
+ return root instanceof (el.ownerDocument.defaultView?.ShadowRoot ?? ShadowRoot) ? root : el.ownerDocument;
111
+ }
112
+ function adoptPrefsCss(root, css) {
113
+ const doc = "host" in root ? root.ownerDocument : root;
114
+ const Sheet = doc.defaultView?.CSSStyleSheet;
115
+ if (Sheet && "replaceSync" in Sheet.prototype && Array.isArray(root.adoptedStyleSheets)) {
116
+ const sheet = new Sheet();
117
+ sheet.replaceSync(css);
118
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
119
+ return {
120
+ write: (next) => sheet.replaceSync(next),
121
+ release: () => {
122
+ root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);
123
+ }
124
+ };
125
+ }
126
+ const style = doc.createElement("style");
127
+ style.textContent = css;
128
+ ("host" in root ? root : doc.head).appendChild(style);
129
+ return {
130
+ write: (next) => {
131
+ style.textContent = next;
132
+ },
133
+ release: () => style.remove()
134
+ };
135
+ }
136
+ function KitSettingsFromPrefs({
137
+ store,
138
+ at,
139
+ css = false,
140
+ children
141
+ }) {
142
+ const values = useSyncExternalStore(store.subscribe, store.values, store.values);
143
+ const value = (at ? prefValueAtPath(values, at) : values) ?? {};
144
+ const anchor = useRef(null);
145
+ useLayoutEffect(() => {
146
+ const el = anchor.current;
147
+ if (!css || !el) return;
148
+ const root = prefsStyleRootOf(el);
149
+ const host = "host" in root ? root.host : root.documentElement;
150
+ const options = { ...kitSettingsCssOptions(at), root: "host" in root ? ":host" : ":root" };
151
+ const sheet = adoptPrefsCss(root, prefsCss(store, options));
152
+ let set = [];
153
+ const write = () => {
154
+ for (const name of set) host.removeAttribute(name);
155
+ const attributes = prefsCssAttributes(store, options);
156
+ for (const [name, option] of Object.entries(attributes)) host.setAttribute(name, option);
157
+ set = Object.keys(attributes);
158
+ };
159
+ write();
160
+ const stop = store.subscribe(() => {
161
+ sheet.write(prefsCss(store, options));
162
+ write();
163
+ });
164
+ return () => {
165
+ stop();
166
+ sheet.release();
167
+ for (const name of set) host.removeAttribute(name);
168
+ };
169
+ }, [store, at, css]);
170
+ return /* @__PURE__ */ jsxs(KitSettingsProvider, { value, children: [
171
+ css && /* @__PURE__ */ jsx("span", { hidden: true, ref: anchor }),
172
+ children
173
+ ] });
174
+ }
175
+
176
+ export { KitSettingsFromPrefs, usePref, usePrefsStore, usePrefsValues };
105
177
  //# sourceMappingURL=react.js.map
106
178
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks.ts","../src/usePrefsStore.ts"],"names":["useCallback","useSyncExternalStore"],"mappings":";;;AAOO,SAAS,OAAA,CACd,OACA,IAAA,EAIA;AACA,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,QAAA,KAAyB,KAAA,CAAM,UAAU,QAAQ,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAC1F,EAAA,MAAM,WAAA,GAAc,MAAM,KAAA,CAAM,GAAA,CAAI,IAAI,CAAA;AACxC,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAAqB,SAAA,EAAW,WAAA,EAAa,WAAW,CAAA;AACtE,EAAA,MAAM,GAAA,GAAM,WAAA;AAAA,IACV,CAAC,IAAA,KAA+E;AAC9E,MAAA,KAAA,CAAM,GAAA;AAAA,QACJ,IAAA;AAAA,QACA,OAAO,SAAS,UAAA,GACX,IAAA,CAAwD,MAAM,GAAA,CAAI,IAAI,CAAC,CAAA,GACxE;AAAA,OACN;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAO,IAAI;AAAA,GACd;AACA,EAAA,OAAO,CAAC,OAAO,GAAG,CAAA;AACpB;AAMO,SAAS,eAAoC,KAAA,EAUlD;AACA,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,QAAA,KAAyB,KAAA,CAAM,UAAU,QAAQ,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAC1F,EAAA,MAAM,SAAS,oBAAA,CAAqB,SAAA,EAAW,KAAA,CAAM,MAAA,EAAQ,MAAM,MAAM,CAAA;AACzE,EAAA,MAAM,QAAQ,oBAAA,CAAqB,SAAA,EAAW,KAAA,CAAM,KAAA,EAAO,MAAM,KAAK,CAAA;AACtE,EAAA,MAAM,SAAS,oBAAA,CAAqB,SAAA,EAAW,KAAA,CAAM,MAAA,EAAQ,MAAM,MAAM,CAAA;AACzE,EAAA,MAAM,OAAO,oBAAA,CAAqB,SAAA,EAAW,KAAA,CAAM,IAAA,EAAM,MAAM,IAAI,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,WAAA;AAAA,IACV,CAAC,IAAA,EAAc,KAAA,KAAmB,KAAA,CAAM,GAAA,CAAI,MAAqB,KAAc,CAAA;AAAA,IAC/E,CAAC,KAAK;AAAA,GACR;AACA,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,CAAC,IAAA,KAAkB,KAAA,CAAM,MAAM,IAAI,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACvE,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,CAAC,IAAA,EAAc,EAAA,KAAe,KAAA,CAAM,KAAA,CAAM,IAAA,EAAqB,EAAE,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACrG,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,CAAC,IAAA,EAAc,EAAA,KAAe,KAAA,CAAM,IAAA,CAAK,IAAA,EAAqB,EAAE,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACnG,EAAA,MAAM,KAAA,GAAQ,WAAA;AAAA,IACZ,CAAC,IAAA,EAAc,KAAA,EAAgB,EAAA,KAAsB,KAAA,CAAM,IAAI,IAAA,EAAqB,KAAA,EAAgB,EAAE,EAAA,EAAI,CAAA;AAAA,IAC1G,CAAC,KAAK;AAAA,GACR;AACA,EAAA,OAAO,EAAE,QAAQ,GAAA,EAAK,KAAA,EAAO,QAAQ,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,KAAA,EAAM;AACvE;AC3CA,IAAM,MAAA,uBAAa,OAAA,EAA6C;AAEhE,SAAS,QAAA,CAAS,SAAyB,MAAA,EAAwB;AACjE,EAAA,IAAI,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AACjC,EAAA,IAAI,CAAC,UAAU,MAAA,CAAO,GAAA,CAAI,SAAU,QAAA,mBAAW,IAAI,KAAM,CAAA;AACzD,EAAA,IAAI,KAAA,GAAQ,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,MAAA,EAAS,KAAA,GAAQ,EAAE,IAAA,EAAM,IAAA,EAAM,QAAA,kBAAU,IAAI,GAAA,IAAQ,CAAA;AAC9E,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,MAAA,CAAO,IAAY,MAAA,EAAyB;AACnD,EAAA,IAAI,KAAA,GAAQ,EAAA,CAAG,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AAClC,EAAA,IAAI,CAAC,KAAA,EAAO,EAAA,CAAG,QAAA,CAAS,GAAA,CAAI,MAAA,EAAS,KAAA,GAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,OAAA,EAAS,CAAA,EAAI,CAAA;AACzE,EAAA,OAAO,KAAA;AACT;AAIA,IAAM,IAAA,GAAO,CAAC,KAAA,KACZ,MAAA,CAAO,OAAO,KAAA,EAAO;AAAA,EACnB,KAAA,EAAO;AAAA,IACL,OAAO,YAA2B;AAChC,MAAA,MAAM,MAAM,KAAA,EAAM;AAAA,IACpB;AAAA;AAEJ,CAAC,CAAA;AAKH,SAAS,eAAA,CAAgB,OAAA,EAAyB,MAAA,EAAgB,MAAA,EAAmB,KAAA,EAAmB;AACtG,EAAA,cAAA,CAAe,MAAM;AACnB,IAAA,IAAI,KAAA,CAAM,UAAU,CAAA,EAAG;AACvB,IAAA,KAAK,KAAA,CAAM,OAAO,KAAA,EAAM;AACxB,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AACnC,IAAA,MAAM,EAAA,GAAK,QAAA,EAAU,GAAA,CAAI,MAAM,CAAA;AAC/B,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,QAAA,EAAU;AACtB,IAAA,IAAI,EAAA,CAAG,SAAS,GAAA,CAAI,MAAM,MAAM,KAAA,EAAO,EAAA,CAAG,QAAA,CAAS,MAAA,CAAO,MAAM,CAAA;AAChE,IAAA,IAAI,EAAA,CAAG,QAAA,CAAS,IAAA,GAAO,CAAA,EAAG;AAC1B,IAAA,EAAA,CAAG,MAAM,IAAA,EAAK;AAGd,IAAA,KAAK,EAAA,CAAG,IAAA,EAAM,KAAA,CAAM,KAAA,EAAM;AAC1B,IAAA,QAAA,CAAS,OAAO,MAAM,CAAA;AAAA,EACxB,CAAC,CAAA;AACH;AAEA,SAAS,OAAA,CAA6B,QAAW,OAAA,EAAqC;AACpF,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAO,GAAI,OAAA;AAC5B,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,OAAA,EAAS,MAAM,CAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,EAAA,EAAI,MAAM,CAAA;AAC/B,EAAA,IAAI,CAAC,MAAM,KAAA,EAAO;AAChB,IAAA,EAAA,CAAG,IAAA,KAAS,mBAAmB,OAAO,CAAA;AACtC,IAAA,KAAA,CAAM,KAAA,GAAQ,gBAAA;AAAA,MACZ,MAAA;AAAA,MACA,IAAA,CAAK,EAAA,CAAG,IAAA,CAAK,KAAK,CAAA;AAAA,MAClB,OAAA,CAAQ,UAAA;AAAA,MACR,MAAA;AAAA,MACA,OAAA,CAAQ,YAAY,MAAA,IAAU,CAAA;AAAA,MAC9B,OAAA,CAAQ;AAAA,KACV;AAEA,IAAA,IAAI,MAAM,OAAA,KAAY,CAAA,kBAAmB,OAAA,EAAS,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA,EACzE;AACA,EAAA,OAAO,KAAA,CAAM,KAAA;AACf;AAoBO,SAAS,aAAA,CAAmC,QAAW,OAAA,EAAqC;AACjG,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAO,GAAI,OAAA;AAC5B,EAAA,MAAM,IAAA,GAAOA,YAAY,MAAM;AAC7B,IAAA,MAAM,QAAQ,MAAA,CAAO,QAAA,CAAS,OAAA,EAAS,MAAM,GAAG,MAAM,CAAA;AACtD,IAAA,KAAA,CAAM,OAAA,EAAA;AACN,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,EAAE,MAAM,OAAA,KAAY,CAAA,kBAAmB,OAAA,EAAS,MAAA,EAAQ,QAAQ,KAAK,CAAA;AAAA,IAC3E,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAC,CAAA;AAG5B,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,MAAA,EAAQ,OAAO,CAAA;AAC7C,EAAA,OAAOC,oBAAAA,CAAqB,IAAA,EAAM,OAAA,EAAS,OAAO,CAAA;AACpD","file":"react.js","sourcesContent":["import { useCallback, useSyncExternalStore } from 'react';\nimport type { PrefPath, PrefValueAt } from './paths';\nimport type { PrefGroup } from './groups';\nimport type { PrefLocus, PrefSelection } from './locus';\nimport type { PrefsStore } from './store';\n\n/** One leaf of `store`, as React state. */\nexport function usePref<S extends PrefGroup, P extends PrefPath<S>>(\n store: PrefsStore<S>,\n path: P,\n): [\n PrefValueAt<S, P>,\n (next: PrefValueAt<S, P> | ((prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)) => void,\n] {\n const subscribe = useCallback((onChange: () => void) => store.subscribe(onChange), [store]);\n const getSnapshot = () => store.get(path);\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const set = useCallback(\n (next: PrefValueAt<S, P> | ((prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)) => {\n store.set(\n path,\n typeof next === 'function'\n ? (next as (prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)(store.get(path))\n : next,\n );\n },\n [store, path],\n );\n return [value, set];\n}\n\n/** The whole of `store` as React state, shaped for `PrefsForm`: `values`,\n * `onChange={set}`, `auto={unset}`, and `reset` for `onAutoChange`; for its\n * split values, `loci`, `onSplit={split}`, `onJoin={join}`, and\n * `onChangeAt={setAt}`. `stored` is `store.stored()`. */\nexport function usePrefsValues<S extends PrefGroup>(store: PrefsStore<S>): {\n values: Record<string, unknown>;\n set: (path: string, value: unknown) => void;\n unset: ReadonlySet<string>;\n stored: Record<string, unknown>;\n reset: (path?: string) => void;\n loci: ReadonlyMap<string, PrefLocus>;\n split: (path: string, by: string) => void;\n join: (path: string, by: string) => void;\n setAt: (path: string, value: unknown, at: PrefSelection) => void;\n} {\n const subscribe = useCallback((onChange: () => void) => store.subscribe(onChange), [store]);\n const values = useSyncExternalStore(subscribe, store.values, store.values);\n const unset = useSyncExternalStore(subscribe, store.unset, store.unset);\n const stored = useSyncExternalStore(subscribe, store.stored, store.stored);\n const loci = useSyncExternalStore(subscribe, store.loci, store.loci);\n const set = useCallback(\n (path: string, value: unknown) => store.set(path as PrefPath<S>, value as never),\n [store],\n );\n const reset = useCallback((path?: string) => store.reset(path), [store]);\n const split = useCallback((path: string, by: string) => store.split(path as PrefPath<S>, by), [store]);\n const join = useCallback((path: string, by: string) => store.join(path as PrefPath<S>, by), [store]);\n const setAt = useCallback(\n (path: string, value: unknown, at: PrefSelection) => store.set(path as PrefPath<S>, value as never, { at }),\n [store],\n );\n return { values, set, unset, stored, reset, loci, split, join, setAt };\n}\n","import type { OwnedRecordCache, StorageAdapter, SyncStorageAdapter } from '@weasel-js/storage';\nimport { useCallback, useSyncExternalStore } from 'react';\nimport type { PrefGroup } from './groups';\nimport { openPrefsCacheSync, type PrefsOptions } from './open';\nimport { createPrefsStore, type PrefsStore } from './store';\n\n/** The store open for one schema, and how many mounted components hold it. */\ninterface Held {\n store: PrefsStore<PrefGroup> | null;\n holders: number;\n}\n\n/** The one cache open on a prefix, and a store over it for each schema in use. */\ninterface Shared {\n open: { cache: OwnedRecordCache; stop: () => void } | null;\n bySchema: Map<PrefGroup, Held>;\n}\n\ntype SyncOptions = PrefsOptions & { storage: SyncStorageAdapter };\n\nconst shared = new WeakMap<StorageAdapter, Map<string, Shared>>();\n\nfunction sharedAt(storage: StorageAdapter, prefix: string): Shared {\n let byPrefix = shared.get(storage);\n if (!byPrefix) shared.set(storage, (byPrefix = new Map()));\n let entry = byPrefix.get(prefix);\n if (!entry) byPrefix.set(prefix, (entry = { open: null, bySchema: new Map() }));\n return entry;\n}\n\nfunction heldAt(at: Shared, schema: PrefGroup): Held {\n let entry = at.bySchema.get(schema);\n if (!entry) at.bySchema.set(schema, (entry = { store: null, holders: 0 }));\n return entry;\n}\n\n/** `cache` for one store among several: closing it sends queued writes and\n * leaves the cache open for the others. */\nconst lent = (cache: OwnedRecordCache): OwnedRecordCache =>\n Object.create(cache, {\n close: {\n value: async (): Promise<void> => {\n await cache.flush();\n },\n },\n }) as OwnedRecordCache;\n\n/** Close a store nothing holds, and the cache once no store is over it, a\n * microtask on: after the remount StrictMode and fast refresh make in the\n * same tick, which holds it again. */\nfunction closeUnheldSoon(storage: StorageAdapter, prefix: string, schema: PrefGroup, entry: Held): void {\n queueMicrotask(() => {\n if (entry.holders > 0) return;\n void entry.store?.close();\n entry.store = null;\n const byPrefix = shared.get(storage);\n const at = byPrefix?.get(prefix);\n if (!at || !byPrefix) return;\n if (at.bySchema.get(schema) === entry) at.bySchema.delete(schema);\n if (at.bySchema.size > 0) return;\n at.open?.stop();\n // `close` sends queued writes before its first await, and a sync adapter's\n // write lands in that call, so a cache opened next reads them.\n void at.open?.cache.close();\n byPrefix.delete(prefix);\n });\n}\n\nfunction acquire<S extends PrefGroup>(schema: S, options: SyncOptions): PrefsStore<S> {\n const { storage, prefix } = options;\n const at = sharedAt(storage, prefix);\n const entry = heldAt(at, schema);\n if (!entry.store) {\n at.open ??= openPrefsCacheSync(options);\n entry.store = createPrefsStore(\n schema,\n lent(at.open.cache),\n options.validators,\n undefined,\n options.migrations?.length ?? 0,\n options.blends,\n ) as unknown as PrefsStore<PrefGroup>;\n // Opened by a render that may never mount.\n if (entry.holders === 0) closeUnheldSoon(storage, prefix, schema, entry);\n }\n return entry.store as unknown as PrefsStore<S>;\n}\n\n/**\n * A store for `schema`, open while the component is mounted: opened during\n * the first render, so that render has values, and closed, with its queued\n * writes sent, when the component unmounts.\n *\n * Components naming the same `storage`, `prefix`, and `schema` share one\n * store, which closes when the last of them unmounts. Components naming the\n * same `storage` and `prefix` with different schemas each get a store of\n * their own over the same records, so a write through one is read by the\n * others at once, and each hears it as a `local` change. They must pass the\n * same `migrations`: the records are migrated once, when the first opens.\n *\n * `storage` and `schema` are compared by identity and `prefix` by value, so\n * keep the first two out of the render body. A change to any of the three\n * closes the store and returns the one for the new three. The `options`\n * object itself may be new every render: `migrations` and `validators` are\n * read when a store opens, and a change to either alone opens nothing.\n */\nexport function usePrefsStore<S extends PrefGroup>(schema: S, options: SyncOptions): PrefsStore<S> {\n const { storage, prefix } = options;\n const hold = useCallback(() => {\n const entry = heldAt(sharedAt(storage, prefix), schema);\n entry.holders++;\n return () => {\n if (--entry.holders === 0) closeUnheldSoon(storage, prefix, schema, entry);\n };\n }, [storage, prefix, schema]);\n // Read again once held, so a store closed between render and mount is\n // replaced before anything uses it.\n const current = () => acquire(schema, options);\n return useSyncExternalStore(hold, current, current);\n}\n"]}
1
+ {"version":3,"sources":["../src/hooks.ts","../src/usePrefsStore.ts","../src/adopt.ts","../src/KitSettingsFromPrefs.tsx"],"names":["useCallback","useSyncExternalStore"],"mappings":"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","file":"react.js","sourcesContent":["import { useCallback, useSyncExternalStore } from 'react';\nimport type { PrefPath, PrefValueAt } from './paths';\nimport type { PrefGroup } from './groups';\nimport type { PrefLocus, PrefSelection } from './locus';\nimport type { PrefsStore } from './store';\n\n/** One leaf of `store`, as React state. */\nexport function usePref<S extends PrefGroup, P extends PrefPath<S>>(\n store: PrefsStore<S>,\n path: P,\n): [\n PrefValueAt<S, P>,\n (next: PrefValueAt<S, P> | ((prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)) => void,\n] {\n const subscribe = useCallback((onChange: () => void) => store.subscribe(onChange), [store]);\n const getSnapshot = () => store.get(path);\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const set = useCallback(\n (next: PrefValueAt<S, P> | ((prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)) => {\n store.set(\n path,\n typeof next === 'function'\n ? (next as (prev: PrefValueAt<S, P>) => PrefValueAt<S, P>)(store.get(path))\n : next,\n );\n },\n [store, path],\n );\n return [value, set];\n}\n\n/** The whole of `store` as React state, shaped for `PrefsForm`: `values`,\n * `onChange={set}`, `auto={unset}`, and `reset` for `onAutoChange`; for its\n * split values, `loci`, `onSplit={split}`, `onJoin={join}`, and\n * `onChangeAt={setAt}`. `stored` is `store.stored()`. */\nexport function usePrefsValues<S extends PrefGroup>(store: PrefsStore<S>): {\n values: Record<string, unknown>;\n set: (path: string, value: unknown) => void;\n unset: ReadonlySet<string>;\n stored: Record<string, unknown>;\n reset: (path?: string) => void;\n loci: ReadonlyMap<string, PrefLocus>;\n split: (path: string, by: string) => void;\n join: (path: string, by: string) => void;\n setAt: (path: string, value: unknown, at: PrefSelection) => void;\n} {\n const subscribe = useCallback((onChange: () => void) => store.subscribe(onChange), [store]);\n const values = useSyncExternalStore(subscribe, store.values, store.values);\n const unset = useSyncExternalStore(subscribe, store.unset, store.unset);\n const stored = useSyncExternalStore(subscribe, store.stored, store.stored);\n const loci = useSyncExternalStore(subscribe, store.loci, store.loci);\n const set = useCallback(\n (path: string, value: unknown) => store.set(path as PrefPath<S>, value as never),\n [store],\n );\n const reset = useCallback((path?: string) => store.reset(path), [store]);\n const split = useCallback((path: string, by: string) => store.split(path as PrefPath<S>, by), [store]);\n const join = useCallback((path: string, by: string) => store.join(path as PrefPath<S>, by), [store]);\n const setAt = useCallback(\n (path: string, value: unknown, at: PrefSelection) => store.set(path as PrefPath<S>, value as never, { at }),\n [store],\n );\n return { values, set, unset, stored, reset, loci, split, join, setAt };\n}\n","import type { OwnedRecordCache, StorageAdapter, SyncStorageAdapter } from '@weasel-js/storage';\nimport { useCallback, useSyncExternalStore } from 'react';\nimport type { PrefGroup } from './groups';\nimport { openPrefsCacheSync, type PrefsOptions } from './open';\nimport { createPrefsStore, type PrefsStore } from './store';\n\n/** The store open for one schema, and how many mounted components hold it. */\ninterface Held {\n store: PrefsStore<PrefGroup> | null;\n holders: number;\n}\n\n/** The one cache open on a prefix, and a store over it for each schema in use. */\ninterface Shared {\n open: { cache: OwnedRecordCache; stop: () => void } | null;\n bySchema: Map<PrefGroup, Held>;\n}\n\n/** The store options `usePrefsStore` takes: a store's, with the synchronous storage it reads at once. */\nexport type UsePrefsStoreOptions = PrefsOptions & { storage: SyncStorageAdapter };\n\nconst shared = new WeakMap<StorageAdapter, Map<string, Shared>>();\n\nfunction sharedAt(storage: StorageAdapter, prefix: string): Shared {\n let byPrefix = shared.get(storage);\n if (!byPrefix) shared.set(storage, (byPrefix = new Map()));\n let entry = byPrefix.get(prefix);\n if (!entry) byPrefix.set(prefix, (entry = { open: null, bySchema: new Map() }));\n return entry;\n}\n\nfunction heldAt(at: Shared, schema: PrefGroup): Held {\n let entry = at.bySchema.get(schema);\n if (!entry) at.bySchema.set(schema, (entry = { store: null, holders: 0 }));\n return entry;\n}\n\n/** `cache` for one store among several: closing it sends queued writes and\n * leaves the cache open for the others. */\nconst lent = (cache: OwnedRecordCache): OwnedRecordCache =>\n Object.create(cache, {\n close: {\n value: async (): Promise<void> => {\n await cache.flush();\n },\n },\n }) as OwnedRecordCache;\n\n/** Close a store nothing holds, and the cache once no store is over it, a\n * microtask on: after the remount StrictMode and fast refresh make in the\n * same tick, which holds it again. */\nfunction closeUnheldSoon(storage: StorageAdapter, prefix: string, schema: PrefGroup, entry: Held): void {\n queueMicrotask(() => {\n if (entry.holders > 0) return;\n void entry.store?.close();\n entry.store = null;\n const byPrefix = shared.get(storage);\n const at = byPrefix?.get(prefix);\n if (!at || !byPrefix) return;\n if (at.bySchema.get(schema) === entry) at.bySchema.delete(schema);\n if (at.bySchema.size > 0) return;\n at.open?.stop();\n // `close` sends queued writes before its first await, and a sync adapter's\n // write lands in that call, so a cache opened next reads them.\n void at.open?.cache.close();\n byPrefix.delete(prefix);\n });\n}\n\nfunction acquire<S extends PrefGroup>(schema: S, options: UsePrefsStoreOptions): PrefsStore<S> {\n const { storage, prefix } = options;\n const at = sharedAt(storage, prefix);\n const entry = heldAt(at, schema);\n if (!entry.store) {\n at.open ??= openPrefsCacheSync(options);\n entry.store = createPrefsStore(\n schema,\n lent(at.open.cache),\n options.validators,\n undefined,\n options.migrations?.length ?? 0,\n options.blends,\n ) as unknown as PrefsStore<PrefGroup>;\n // Opened by a render that may never mount.\n if (entry.holders === 0) closeUnheldSoon(storage, prefix, schema, entry);\n }\n return entry.store as unknown as PrefsStore<S>;\n}\n\n/**\n * A store for `schema`, open while the component is mounted: opened during\n * the first render, so that render has values, and closed, with its queued\n * writes sent, when the component unmounts.\n *\n * Components naming the same `storage`, `prefix`, and `schema` share one\n * store, which closes when the last of them unmounts. Components naming the\n * same `storage` and `prefix` with different schemas each get a store of\n * their own over the same records, so a write through one is read by the\n * others at once, and each hears it as a `local` change. They must pass the\n * same `migrations`: the records are migrated once, when the first opens.\n *\n * `storage` and `schema` are compared by identity and `prefix` by value, so\n * keep the first two out of the render body. A change to any of the three\n * closes the store and returns the one for the new three. The `options`\n * object itself may be new every render: `migrations` and `validators` are\n * read when a store opens, and a change to either alone opens nothing.\n */\nexport function usePrefsStore<S extends PrefGroup>(schema: S, options: UsePrefsStoreOptions): PrefsStore<S> {\n const { storage, prefix } = options;\n const hold = useCallback(() => {\n const entry = heldAt(sharedAt(storage, prefix), schema);\n entry.holders++;\n return () => {\n if (--entry.holders === 0) closeUnheldSoon(storage, prefix, schema, entry);\n };\n }, [storage, prefix, schema]);\n // Read again once held, so a store closed between render and mount is\n // replaced before anything uses it.\n const current = () => acquire(schema, options);\n return useSyncExternalStore(hold, current, current);\n}\n","/** Where an element's styles come from. */\nexport type PrefsStyleRoot = Document | ShadowRoot;\n\n/** The root `el`'s styles come from: its shadow root, else its document. */\nexport function prefsStyleRootOf(el: Element): PrefsStyleRoot {\n const root = el.getRootNode();\n return root instanceof (el.ownerDocument.defaultView?.ShadowRoot ?? ShadowRoot) ? (root as ShadowRoot) : el.ownerDocument;\n}\n\n/**\n * A sheet of its own in `root`, holding `css`: an adopted constructed sheet\n * where the root takes one, else a `<style>`. `write` replaces the text and\n * `release` takes the sheet out.\n */\nexport function adoptPrefsCss(root: PrefsStyleRoot, css: string): { write: (css: string) => void; release: () => void } {\n const doc = 'host' in root ? root.ownerDocument : root;\n const Sheet = doc.defaultView?.CSSStyleSheet;\n if (Sheet && 'replaceSync' in Sheet.prototype && Array.isArray(root.adoptedStyleSheets)) {\n // From the root's own window: a constructed sheet cannot be adopted across documents.\n const sheet = new Sheet();\n sheet.replaceSync(css);\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];\n return {\n write: (next) => sheet.replaceSync(next),\n release: () => {\n root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n },\n };\n }\n const style = doc.createElement('style');\n style.textContent = css;\n ('host' in root ? root : doc.head).appendChild(style);\n return {\n write: (next) => {\n style.textContent = next;\n },\n release: () => style.remove(),\n };\n}\n","import { KitSettingsProvider, type KitSettingsOverrides } from '@weasel-js/react';\nimport { useLayoutEffect, useRef, useSyncExternalStore, type ReactNode } from 'react';\nimport { adoptPrefsCss, prefsStyleRootOf } from './adopt';\nimport { prefsCss, prefsCssAttributes } from './css';\nimport type { PrefGroup } from './groups';\nimport { prefValueAtPath } from './helpers';\nimport { kitSettingsCssOptions } from './kitCss';\nimport type { PrefsStore } from './store';\n\n/**\n * Kit settings from a prefs store: everything inside reads the store's values\n * at `at` (the whole store without it) through `useKitSetting`, kept current\n * as the store changes.\n *\n * With `css`, the same subtree is written as `--wzl-kit-*` custom properties\n * (`kitSettingsCssOptions(at)`) into a sheet of the document or shadow root\n * the component renders in, and the selectors' attributes are set on that\n * root's element — `<html>`, or the shadow host, matched as `:root` or\n * `:host`. That root is found from a hidden `<span>` rendered ahead of the\n * children. Both are rewritten on every store change and removed on unmount.\n */\nexport function KitSettingsFromPrefs<S extends PrefGroup>({\n store,\n at,\n css = false,\n children,\n}: {\n store: PrefsStore<S>;\n at?: string;\n css?: boolean;\n children?: ReactNode;\n}): ReactNode {\n const values = useSyncExternalStore(store.subscribe, store.values, store.values);\n const value = (at ? prefValueAtPath(values, at) : values) ?? {};\n const anchor = useRef<HTMLSpanElement>(null);\n\n useLayoutEffect(() => {\n const el = anchor.current;\n if (!css || !el) return;\n const root = prefsStyleRootOf(el);\n const host = 'host' in root ? root.host : root.documentElement;\n const options = { ...kitSettingsCssOptions(at), root: 'host' in root ? ':host' : ':root' };\n const sheet = adoptPrefsCss(root, prefsCss(store, options));\n let set: string[] = [];\n const write = (): void => {\n for (const name of set) host.removeAttribute(name);\n const attributes = prefsCssAttributes(store, options);\n for (const [name, option] of Object.entries(attributes)) host.setAttribute(name, option);\n set = Object.keys(attributes);\n };\n write();\n const stop = store.subscribe(() => {\n sheet.write(prefsCss(store, options));\n write();\n });\n return () => {\n stop();\n sheet.release();\n for (const name of set) host.removeAttribute(name);\n };\n }, [store, at, css]);\n\n return (\n <KitSettingsProvider value={value as KitSettingsOverrides}>\n {css && <span hidden ref={anchor} />}\n {children}\n </KitSettingsProvider>\n );\n}\n"]}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import { Plugin } from 'vite';
2
+ import { a as PrefsCssOptions } from './css-v-LpmTll.js';
3
+ import './groups-BDZC-ywb.js';
4
+ import '@weasel-js/icons';
5
+ import '@weasel-js/quantity';
6
+
7
+ /** Options for {@link weaselPrefsCss}. */
8
+ interface WeaselPrefsCssOptions {
9
+ /** Each schema to write: the module, as a path from Vite's root, and the name it exports its `PrefGroup` under. */
10
+ schemas: Record<string, string>;
11
+ /** How each schema is written, as `prefsCss` takes it. */
12
+ css?: PrefsCssOptions;
13
+ }
14
+ /**
15
+ * Serves `virtual:weasel-prefs.css`: every schema's `prefsCss` at its
16
+ * defaults, in the order `schemas` lists them, through Vite's own CSS
17
+ * pipeline. Import it once (`import 'virtual:weasel-prefs.css'`). Schemas are
18
+ * loaded with Vite's `runnerImport`, so they may be TypeScript; in dev, saving
19
+ * a schema module or anything it imports rewrites the sheet.
20
+ */
21
+ declare function weaselPrefsCss(options: WeaselPrefsCssOptions): Plugin;
22
+
23
+ export { type WeaselPrefsCssOptions, weaselPrefsCss };
package/dist/vite.js ADDED
@@ -0,0 +1,61 @@
1
+ import { prefsDefaultsSource } from './chunk-ZLXZRX73.js';
2
+ import { prefsCss } from './chunk-OZFER7VN.js';
3
+ import { resolve } from 'path';
4
+ import { runnerImport } from 'vite';
5
+
6
+ var ID = "virtual:weasel-prefs.css";
7
+ var RESOLVED = `\0${ID}`;
8
+ function weaselPrefsCss(options) {
9
+ let config;
10
+ let sheet = null;
11
+ let files = /* @__PURE__ */ new Set();
12
+ const build = async () => {
13
+ const parts = [];
14
+ const read = /* @__PURE__ */ new Set();
15
+ for (const [id, name] of Object.entries(options.schemas)) {
16
+ const file = resolve(config.root, id);
17
+ const { module, dependencies } = await runnerImport(file, {
18
+ root: config.root,
19
+ logLevel: "error",
20
+ resolve: { alias: config.resolve.alias }
21
+ });
22
+ read.add(file);
23
+ for (const dependency of dependencies) read.add(dependency);
24
+ const schema = module[name];
25
+ if (!schema || typeof schema !== "object" || !("children" in schema)) {
26
+ throw new Error(`[weasel-prefs] ${id} exports no PrefGroup named "${name}"`);
27
+ }
28
+ parts.push(prefsCss(prefsDefaultsSource(schema), options.css));
29
+ }
30
+ return { css: parts.join("\n\n"), files: read };
31
+ };
32
+ return {
33
+ name: "weasel-prefs-css",
34
+ configResolved(resolved) {
35
+ config = resolved;
36
+ },
37
+ resolveId(id) {
38
+ return id === ID ? RESOLVED : void 0;
39
+ },
40
+ async load(id) {
41
+ if (id !== RESOLVED) return void 0;
42
+ const pending = sheet ??= build();
43
+ try {
44
+ const built = await pending;
45
+ files = built.files;
46
+ for (const file of files) this.addWatchFile(file);
47
+ return built.css;
48
+ } catch (error) {
49
+ if (sheet === pending) sheet = null;
50
+ throw error;
51
+ }
52
+ },
53
+ watchChange(id) {
54
+ if (files.has(id)) sheet = null;
55
+ }
56
+ };
57
+ }
58
+
59
+ export { weaselPrefsCss };
60
+ //# sourceMappingURL=vite.js.map
61
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vite.ts"],"names":[],"mappings":";;;;;AAYA,IAAM,EAAA,GAAK,0BAAA;AACX,IAAM,QAAA,GAAW,KAAK,EAAE,CAAA,CAAA;AAiBjB,SAAS,eAAe,OAAA,EAAwC;AACrE,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,KAAA,GAA6D,IAAA;AACjE,EAAA,IAAI,KAAA,uBAAY,GAAA,EAAY;AAE5B,EAAA,MAAM,QAAQ,YAA0D;AACtE,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,IAAA,KAAA,MAAW,CAAC,IAAI,IAAI,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,CAAA,EAAG;AACxD,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,EAAE,CAAA;AACpC,MAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAa,GAAI,MAAM,aAAsC,IAAA,EAAM;AAAA,QACjF,MAAM,MAAA,CAAO,IAAA;AAAA,QACb,QAAA,EAAU,OAAA;AAAA,QACV,OAAA,EAAS,EAAE,KAAA,EAAO,MAAA,CAAO,QAAQ,KAAA;AAAM,OACxC,CAAA;AACD,MAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AACb,MAAA,KAAA,MAAW,UAAA,IAAc,YAAA,EAAc,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA;AAC1D,MAAA,MAAM,MAAA,GAAS,OAAO,IAAI,CAAA;AAC1B,MAAA,IAAI,CAAC,MAAA,IAAU,OAAO,WAAW,QAAA,IAAY,EAAE,cAAc,MAAA,CAAA,EAAS;AACpE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,EAAE,CAAA,6BAAA,EAAgC,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,MAC7E;AACA,MAAA,KAAA,CAAM,KAAK,QAAA,CAAS,mBAAA,CAAoB,MAAM,CAAA,EAAG,OAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,IAC/D;AACA,IAAA,OAAO,EAAE,GAAA,EAAK,KAAA,CAAM,KAAK,MAAM,CAAA,EAAG,OAAO,IAAA,EAAK;AAAA,EAChD,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,kBAAA;AAAA,IACN,eAAe,QAAA,EAAU;AACvB,MAAA,MAAA,GAAS,QAAA;AAAA,IACX,CAAA;AAAA,IACA,UAAU,EAAA,EAAI;AACZ,MAAA,OAAO,EAAA,KAAO,KAAK,QAAA,GAAW,MAAA;AAAA,IAChC,CAAA;AAAA,IACA,MAAM,KAAK,EAAA,EAAI;AACb,MAAA,IAAI,EAAA,KAAO,UAAU,OAAO,MAAA;AAC5B,MAAA,MAAM,OAAA,GAAW,UAAU,KAAA,EAAM;AACjC,MAAA,IAAI;AACF,QAAA,MAAM,QAAQ,MAAM,OAAA;AACpB,QAAA,KAAA,GAAQ,KAAA,CAAM,KAAA;AACd,QAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA;AAChD,QAAA,OAAO,KAAA,CAAM,GAAA;AAAA,MACf,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,KAAA,KAAU,SAAS,KAAA,GAAQ,IAAA;AAC/B,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAA;AAAA,IACA,YAAY,EAAA,EAAI;AACd,MAAA,IAAI,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG,KAAA,GAAQ,IAAA;AAAA,IAC7B;AAAA,GACF;AACF","file":"vite.js","sourcesContent":["/**\n * @weasel-js/prefs/vite — a Vite plugin serving prefs schemas' defaults as a\n * stylesheet. Vite is an optional peer of this package; nothing else loads it.\n *\n * @packageDocumentation\n */\nimport { resolve } from 'node:path';\nimport { runnerImport, type Plugin, type ResolvedConfig } from 'vite';\nimport { prefsCss, type PrefsCssOptions } from './css';\nimport { prefsDefaultsSource } from './defaultsSource';\nimport type { PrefGroup } from './groups';\n\nconst ID = 'virtual:weasel-prefs.css';\nconst RESOLVED = `\\0${ID}`;\n\n/** Options for {@link weaselPrefsCss}. */\nexport interface WeaselPrefsCssOptions {\n /** Each schema to write: the module, as a path from Vite's root, and the name it exports its `PrefGroup` under. */\n schemas: Record<string, string>;\n /** How each schema is written, as `prefsCss` takes it. */\n css?: PrefsCssOptions;\n}\n\n/**\n * Serves `virtual:weasel-prefs.css`: every schema's `prefsCss` at its\n * defaults, in the order `schemas` lists them, through Vite's own CSS\n * pipeline. Import it once (`import 'virtual:weasel-prefs.css'`). Schemas are\n * loaded with Vite's `runnerImport`, so they may be TypeScript; in dev, saving\n * a schema module or anything it imports rewrites the sheet.\n */\nexport function weaselPrefsCss(options: WeaselPrefsCssOptions): Plugin {\n let config: ResolvedConfig;\n let sheet: Promise<{ css: string; files: Set<string> }> | null = null;\n let files = new Set<string>();\n\n const build = async (): Promise<{ css: string; files: Set<string> }> => {\n const parts: string[] = [];\n const read = new Set<string>();\n for (const [id, name] of Object.entries(options.schemas)) {\n const file = resolve(config.root, id);\n const { module, dependencies } = await runnerImport<Record<string, unknown>>(file, {\n root: config.root,\n logLevel: 'error',\n resolve: { alias: config.resolve.alias },\n });\n read.add(file);\n for (const dependency of dependencies) read.add(dependency);\n const schema = module[name] as PrefGroup | undefined;\n if (!schema || typeof schema !== 'object' || !('children' in schema)) {\n throw new Error(`[weasel-prefs] ${id} exports no PrefGroup named \"${name}\"`);\n }\n parts.push(prefsCss(prefsDefaultsSource(schema), options.css));\n }\n return { css: parts.join('\\n\\n'), files: read };\n };\n\n return {\n name: 'weasel-prefs-css',\n configResolved(resolved) {\n config = resolved;\n },\n resolveId(id) {\n return id === ID ? RESOLVED : undefined;\n },\n async load(id) {\n if (id !== RESOLVED) return undefined;\n const pending = (sheet ??= build());\n try {\n const built = await pending;\n files = built.files;\n for (const file of files) this.addWatchFile(file);\n return built.css;\n } catch (error) {\n if (sheet === pending) sheet = null;\n throw error;\n }\n },\n watchChange(id) {\n if (files.has(id)) sheet = null;\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/prefs",
3
- "version": "1.10.1",
3
+ "version": "1.11.0",
4
4
  "description": "A preferences schema, a store that loads, validates, migrates and persists values against it, and React hooks over the store.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,6 +17,10 @@
17
17
  "import": "./dist/react.js",
18
18
  "types": "./dist/react.d.ts"
19
19
  },
20
+ "./vite": {
21
+ "import": "./dist/vite.js",
22
+ "types": "./dist/vite.d.ts"
23
+ },
20
24
  "./package.json": "./package.json"
21
25
  },
22
26
  "author": "orochi235",
@@ -41,17 +45,23 @@
41
45
  "build": "tsup"
42
46
  },
43
47
  "dependencies": {
44
- "@weasel-js/paint": "1.10.1",
45
- "@weasel-js/quantity": "1.10.1",
46
- "@weasel-js/registry": "1.10.1",
47
- "@weasel-js/storage": "1.10.1"
48
+ "@weasel-js/icons": "1.11.0",
49
+ "@weasel-js/paint": "1.11.0",
50
+ "@weasel-js/quantity": "1.11.0",
51
+ "@weasel-js/react": "1.11.0",
52
+ "@weasel-js/registry": "1.11.0",
53
+ "@weasel-js/storage": "1.11.0"
48
54
  },
49
55
  "peerDependencies": {
50
- "react": ">=18"
56
+ "react": ">=18",
57
+ "vite": ">=6.1"
51
58
  },
52
59
  "peerDependenciesMeta": {
53
60
  "react": {
54
61
  "optional": true
62
+ },
63
+ "vite": {
64
+ "optional": true
55
65
  }
56
66
  },
57
67
  "publishConfig": {