@weasel-js/prefs 1.10.0 → 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/README.md +151 -0
- package/dist/chunk-OZFER7VN.js +706 -0
- package/dist/chunk-OZFER7VN.js.map +1 -0
- package/dist/{chunk-5KB3WBJZ.js → chunk-WN6QQICK.js} +118 -363
- package/dist/chunk-WN6QQICK.js.map +1 -0
- package/dist/chunk-ZLXZRX73.js +32 -0
- package/dist/chunk-ZLXZRX73.js.map +1 -0
- package/dist/css-v-LpmTll.d.ts +49 -0
- package/dist/{open-BEY-aOGe.d.ts → groups-BDZC-ywb.d.ts} +175 -187
- package/dist/index.d.ts +103 -9
- package/dist/index.js +129 -37
- package/dist/index.js.map +1 -1
- package/dist/open-VJ1zlFJz.d.ts +203 -0
- package/dist/react.d.ts +34 -6
- package/dist/react.js +85 -5
- package/dist/react.js.map +1 -1
- package/dist/vite.d.ts +23 -0
- package/dist/vite.js +61 -0
- package/dist/vite.js.map +1 -0
- package/package.json +16 -5
- package/dist/chunk-5KB3WBJZ.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,6 +9,22 @@ store.get('view.gridVisible');
|
|
|
9
9
|
store.set('view.gridVisible', false);
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
A schema is plain data, and `pref` writes it shorter:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
const SCHEMA = pref.group('Prefs', {
|
|
16
|
+
view: pref.group('View', {
|
|
17
|
+
gridVisible: pref.boolean('Grid', true),
|
|
18
|
+
gridGap: pref.number('Grid gap', 8, { min: 2, max: 64, unit: { scale: 1, suffix: 'px' } }),
|
|
19
|
+
mode: pref.enum('Mode', 'dark', ['dark', 'light']),
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each builder returns what the literal would hold (`{ name, children }` for a
|
|
25
|
+
group, `{ kind, name, description, default, … }` for a leaf), so paths and
|
|
26
|
+
value types are read from it the same way, and the two can be mixed.
|
|
27
|
+
|
|
12
28
|
One record per leaf. A leaf with no record follows its schema default. Reads
|
|
13
29
|
repair stored values that no longer fit the schema without writing them back.
|
|
14
30
|
`migrations[i]` takes stored records from version `i` to `i + 1`.
|
|
@@ -26,6 +42,27 @@ It takes an adapter that reads synchronously, and components naming the same
|
|
|
26
42
|
`storage` and `prefix` with different schemas each get a store over the same
|
|
27
43
|
records.
|
|
28
44
|
|
|
45
|
+
## Tags
|
|
46
|
+
|
|
47
|
+
A leaf, a group, and a section can each carry `tags`: words a settings search
|
|
48
|
+
also finds it by, and that gather it with others. A leaf carries its own and
|
|
49
|
+
every group's above it, so tagging a group tags all it holds:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
canvas: { name: 'Canvas', tags: ['workspace'], children: {
|
|
53
|
+
grid: { kind: 'boolean', name: 'Show grid', description: '', default: true, tags: ['guides'] },
|
|
54
|
+
} },
|
|
55
|
+
|
|
56
|
+
prefLeavesTagged(SCHEMA, 'guides'); // Map { 'canvas.grid' => … }
|
|
57
|
+
prefLeafTags(SCHEMA, 'canvas.grid'); // ['workspace', 'guides']
|
|
58
|
+
filterPrefSubtree(SCHEMA, 'guide'); // keeps canvas.grid, matched by its tag
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A search matches a tag as it matches a name, and a group a tag matches keeps
|
|
62
|
+
all its leaves, as one its name matches does. An alias carries its target's
|
|
63
|
+
tags and its own. `tags` is unrelated to a `union` leaf's `tag`, the field its
|
|
64
|
+
value's variant is read from.
|
|
65
|
+
|
|
29
66
|
## Ranges
|
|
30
67
|
|
|
31
68
|
A number leaf's range is one scale: the low end is the least of what its label
|
|
@@ -35,3 +72,117 @@ draws it there. Put an unlimited setting at the end of the range it is nearest:
|
|
|
35
72
|
a 0–100% limit is off at 100, and a scale with no such end takes `endless`,
|
|
36
73
|
which adds a stop one step past the range that stores `Infinity` and reads the
|
|
37
74
|
leaf's `infinity` word.
|
|
75
|
+
|
|
76
|
+
A bound that depends on where the value is held takes `minAt` or `maxAt`: a
|
|
77
|
+
function handed a reader of the values beside it, by the paths a condition
|
|
78
|
+
there would name, returning the bound or `undefined`. It is taken with `min`
|
|
79
|
+
or `max`, the tighter winning, and `prefNumberAt(leaf, read)` folds it in for
|
|
80
|
+
one holder. A box's width that may not go under its node's own minimum reads
|
|
81
|
+
`data.minSize` this way: `SelectionPanel` resolves it against each node and
|
|
82
|
+
holds each write to that node's bound, and `PrefsForm` and labkit's
|
|
83
|
+
`ControlPanel` resolve it against their values.
|
|
84
|
+
|
|
85
|
+
## Split values
|
|
86
|
+
|
|
87
|
+
A leaf that lists `splitBy` may hold its value once per option of another
|
|
88
|
+
leaf, where it would hold one. The other leaf, the selector, is an ordinary
|
|
89
|
+
`enum` named by its path:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
'look.mode': { kind: 'enum', default: 'dark', options: [dark, light], … }
|
|
93
|
+
'gap': { kind: 'number', default: 4, splitBy: ['look.mode'], … }
|
|
94
|
+
|
|
95
|
+
store.split('gap', 'look.mode'); // holds { $by: 'look.mode', $of: { dark: 4, light: 4 } }
|
|
96
|
+
store.set('gap', 8); // writes the member the mode is set to
|
|
97
|
+
store.set('look.mode', 'light'); // a change to every leaf split by it
|
|
98
|
+
store.join('gap', 'look.mode'); // back to one value: the member the mode is set to
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The stored value is a locus, `{ $by, $of }`, and a member may itself be split
|
|
102
|
+
by a second selector. `store.get` reads the member the selectors are set to.
|
|
103
|
+
`store.get(path, { weights })` reads the alternatives folded by weight, which
|
|
104
|
+
is what a transition between two options shows on the way:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
store.get('gap', { weights: { 'look.mode': { dark: 0.25, light: 0.75 } } });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A number blends linearly and a color blends in OKLCH. Every other kind takes
|
|
111
|
+
its heaviest alternative, the first option on a tie; `blends` in the open
|
|
112
|
+
options says otherwise for a kind. `store.values({ at: { 'look.mode': 'light' } })`
|
|
113
|
+
is the whole tree as it would read with the selectors set as given.
|
|
114
|
+
|
|
115
|
+
`store.set(path, value, { at })` writes the member a stated choice names,
|
|
116
|
+
whatever the selectors are set to, and `store.loci()` is what every split leaf
|
|
117
|
+
holds, by path: one map until something changes. `usePrefsValues` returns
|
|
118
|
+
both shaped for `PrefsForm`, with `split` and `join` beside them:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const { values, set, loci, split, join, setAt } = usePrefsValues(store);
|
|
122
|
+
<PrefsForm schema={schema} values={values} onChange={set}
|
|
123
|
+
loci={loci} onSplit={split} onJoin={join} onChangeAt={setAt} />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A leaf's default may be split too. `defaultLocus` is what the leaf holds while
|
|
127
|
+
nothing is stored for it, and `default` stays what a member it leaves out
|
|
128
|
+
reads as:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
'gap': { kind: 'number', default: 4, splitBy: ['look.mode'],
|
|
132
|
+
defaultLocus: { $by: 'look.mode', $of: { dark: 4, light: 6 } }, … }
|
|
133
|
+
|
|
134
|
+
store.get('gap'); // 4, or 6 once the mode is light
|
|
135
|
+
store.set('gap', 8, { at: { 'look.mode': 'light' } }); // holds { dark: 4, light: 8 }
|
|
136
|
+
store.reset('gap'); // the split default again
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A selector must be a plain `enum`: not `clearable`, with no `encoding`, and
|
|
140
|
+
not split itself. The store warns of a `splitBy` that names anything else when
|
|
141
|
+
it opens.
|
|
142
|
+
|
|
143
|
+
## As CSS custom properties
|
|
144
|
+
|
|
145
|
+
`prefsCss(store)` writes the store's values as custom properties, and
|
|
146
|
+
`prefsCssAttributes(store)` gives the attributes that pick its blocks:
|
|
147
|
+
|
|
148
|
+
```css
|
|
149
|
+
:where(:root) {
|
|
150
|
+
--look-mode: dark;
|
|
151
|
+
--gap: 4px; /* a split value, at the member the selectors' defaults name */
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
:where(:root[data-look-mode='light']) {
|
|
155
|
+
--look-mode: light;
|
|
156
|
+
--gap: 6px;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Every leaf is set on the root. A block follows for each choice of options a
|
|
161
|
+
split value tells apart, and only those: a value that is one thing under
|
|
162
|
+
`light` at every density gets one block for `light`. Every block is inside
|
|
163
|
+
`:where()`, so a rule of the page's own wins, and blocks naming more selectors
|
|
164
|
+
come later. A number is written in its display unit where the unit's suffix is
|
|
165
|
+
a CSS unit, a boolean as `1` or `0`, an enum's option as an identifier, and a
|
|
166
|
+
string quoted; a leaf of any other kind is left out unless the `value` option
|
|
167
|
+
writes it. `root`, `property`, and `attribute` rename what it writes.
|
|
168
|
+
|
|
169
|
+
`prefsDefaultsSource(schema)` stands in for a store at its defaults, so
|
|
170
|
+
`prefsCss(prefsDefaultsSource(schema))` is a schema's stylesheet with no store.
|
|
171
|
+
The Vite plugin in `@weasel-js/prefs/vite` serves that sheet for every schema
|
|
172
|
+
you name, by module and export, and rewrites it when a schema changes:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
// vite.config.ts
|
|
176
|
+
import { weaselPrefsCss } from '@weasel-js/prefs/vite';
|
|
177
|
+
export default { plugins: [weaselPrefsCss({ schemas: { './src/prefs.ts': 'SCHEMA' } })] };
|
|
178
|
+
|
|
179
|
+
// main.ts
|
|
180
|
+
import 'virtual:weasel-prefs.css';
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
For the kit's own settings, `<KitSettingsFromPrefs store at="kit">` in
|
|
184
|
+
`@weasel-js/prefs/react` hands the store's values under `kit` to
|
|
185
|
+
`KitSettingsProvider`, so `useKitSetting('tree.typeaheadMs')` reads the user's
|
|
186
|
+
value. With `css`, it also writes that subtree as `--wzl-kit-*` properties into
|
|
187
|
+
the document or shadow root it renders in, and keeps them current as the store
|
|
188
|
+
changes; `kitSettingsCssOptions(at)` is the naming it uses.
|