@motion-proto/live-tokens 0.64.0 → 0.64.2
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/CHANGELOG.md +32 -0
- package/package.json +1 -1
- package/src/editor/core/sketch/index.ts +10 -0
- package/src/editor/ui/FontStackEditor.svelte +76 -27
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.64.2 — A stack can gain a second font
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **A stack could not gain a second font.** "+ add fallback" only ever walked
|
|
8
|
+
the system-and-generic ladder, and the row `<select>` could only retarget a
|
|
9
|
+
row that already existed — so the one path to a font was to add a fallback
|
|
10
|
+
and then change it, and once every fallback was in use the button disabled
|
|
11
|
+
itself and the path closed. The add button now leads with any project font
|
|
12
|
+
the stack doesn't carry, names it (`+ add Domine`), and drops it in with the
|
|
13
|
+
other fonts above the fallbacks.
|
|
14
|
+
|
|
15
|
+
- **Duplicate slots survived 0.64 and made a stack look frozen.** 0.64 kept a
|
|
16
|
+
stack persisted by the old add bug renderable, but left the repeats in place:
|
|
17
|
+
two identical rows are indistinguishable, so dragging one past the other
|
|
18
|
+
changed nothing on screen, and each repeat ate a rung of the add ladder.
|
|
19
|
+
Repeats are now dropped as the stack is read, and no row offers a value
|
|
20
|
+
another row in the same stack holds, so the state can't be re-entered.
|
|
21
|
+
|
|
22
|
+
## 0.64.1 — The sketch entry point carries its last symbol
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **`hasPersistedSketchState` joins `@motion-proto/live-tokens/sketch`.** A site
|
|
27
|
+
moving its visitors off its own storage key has to guard that one-time carry
|
|
28
|
+
on whether the store has already recorded a decision, or it overwrites a pick
|
|
29
|
+
the visitor has since made in the Sketchstyle view with the stale one. It was
|
|
30
|
+
the only symbol that errand still needed and the only one 0.64.0 left inside,
|
|
31
|
+
so the bundler alias the entry point set out to retire survived for it alone.
|
|
32
|
+
Reading `lt.sketchTouched` directly was never the answer: the key is ours to
|
|
33
|
+
rename.
|
|
34
|
+
|
|
3
35
|
## 0.64.0 — A site picks the sketch through the front door
|
|
4
36
|
|
|
5
37
|
### Added
|
package/package.json
CHANGED
|
@@ -58,3 +58,13 @@ export function setSketch(id: string | null): void {
|
|
|
58
58
|
selectSketchStyle(id);
|
|
59
59
|
setSketchEnabled(true);
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Whether the store has recorded a decision of its own in this browser.
|
|
64
|
+
*
|
|
65
|
+
* For a consumer carrying visitors over from its own storage key: a one-time
|
|
66
|
+
* carry has to be guarded on this, or it overwrites a pick the visitor has
|
|
67
|
+
* since made in the editor's Sketchstyle view with the stale one. Reading the
|
|
68
|
+
* key directly is not an option worth offering — it is ours to rename.
|
|
69
|
+
*/
|
|
70
|
+
export { hasPersistedSketchState } from './sketchStore';
|
|
@@ -64,11 +64,25 @@
|
|
|
64
64
|
return slots;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/** A repeated slot contributes nothing to the CSS list, and two identical
|
|
68
|
+
* rows are indistinguishable — dragging one past the other looks like a
|
|
69
|
+
* dead control. Stacks written by the pre-0.64 "+ add fallback" bug are
|
|
70
|
+
* still in localStorage, so drop repeats on the way in. */
|
|
71
|
+
function dedupeSlots(slots: FontStackSlot[]): FontStackSlot[] {
|
|
72
|
+
const seen = new Set<string>();
|
|
73
|
+
return slots.filter((slot) => {
|
|
74
|
+
const key = slotKey(slot);
|
|
75
|
+
if (seen.has(key)) return false;
|
|
76
|
+
seen.add(key);
|
|
77
|
+
return true;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
67
81
|
function ensureAllStacksPresent(current: FontStack[]): FontStack[] {
|
|
68
82
|
const byVar = new Map(current.map((s) => [s.variable, s]));
|
|
69
83
|
return STACK_VARIABLES.map((v) => {
|
|
70
84
|
const stack = byVar.get(v);
|
|
71
|
-
const slots = withTerminalFallback(v, stack?.slots ?? []);
|
|
85
|
+
const slots = withTerminalFallback(v, dedupeSlots(stack?.slots ?? []));
|
|
72
86
|
return stack ? { ...stack, slots } : { variable: v, slots };
|
|
73
87
|
});
|
|
74
88
|
}
|
|
@@ -136,16 +150,19 @@
|
|
|
136
150
|
});
|
|
137
151
|
}
|
|
138
152
|
|
|
139
|
-
/**
|
|
140
|
-
*
|
|
141
|
-
* preset,
|
|
142
|
-
*
|
|
153
|
+
/** What the add button reaches for, in order of preference: a project font
|
|
154
|
+
* the stack doesn't carry yet, then the variable's preferred generic and
|
|
155
|
+
* preset, then the rest of the system-and-generic ladder. Project fonts lead
|
|
156
|
+
* because a stack that already holds every fallback otherwise had no way to
|
|
157
|
+
* gain a second font — the row's own <select> could only retarget a row that
|
|
158
|
+
* the button had to create first. */
|
|
143
159
|
function addCandidates(variable: FontStackVariable): FontStackSlot[] {
|
|
144
160
|
const generic: GenericFamily =
|
|
145
161
|
variable === '--font-mono' ? 'monospace' : variable === '--font-serif' ? 'serif' : 'sans-serif';
|
|
146
162
|
const preset: SystemCascadePreset =
|
|
147
163
|
variable === '--font-mono' ? 'system-ui-mono' : variable === '--font-serif' ? 'system-ui-serif' : 'system-ui-sans';
|
|
148
164
|
return [
|
|
165
|
+
...allFamilies.map((f) => ({ kind: 'project' as const, familyId: f.id })),
|
|
149
166
|
{ kind: 'generic', value: generic },
|
|
150
167
|
{ kind: 'system', preset },
|
|
151
168
|
...SYSTEM_PRESETS.map((p) => ({ kind: 'system' as const, preset: p })),
|
|
@@ -153,6 +170,20 @@
|
|
|
153
170
|
];
|
|
154
171
|
}
|
|
155
172
|
|
|
173
|
+
/** The terminal row offers its stack's matching preset and generic, minus
|
|
174
|
+
* whatever a row above holds — plus its own current value whatever that is.
|
|
175
|
+
* A <select> with no option matching its value renders the first option
|
|
176
|
+
* instead, so the row would read as a slot the stack doesn't have. */
|
|
177
|
+
function terminalOptions(variable: FontStackVariable, slot: FontStackSlot, taken: Set<string>): FontStackSlot[] {
|
|
178
|
+
const current = slotKey(slot);
|
|
179
|
+
const pair: FontStackSlot[] = [
|
|
180
|
+
{ kind: 'system', preset: TERMINAL_SYSTEM_BY_VAR[variable] },
|
|
181
|
+
{ kind: 'generic', value: TERMINAL_FALLBACK_BY_VAR[variable] },
|
|
182
|
+
];
|
|
183
|
+
const offered = pair.filter((c) => slotKey(c) === current || !taken.has(slotKey(c)));
|
|
184
|
+
return offered.some((c) => slotKey(c) === current) ? offered : [slot, ...offered];
|
|
185
|
+
}
|
|
186
|
+
|
|
156
187
|
/** A slot duplicated within a stack collides with itself in the keyed each,
|
|
157
188
|
* so only one the stack doesn't already hold may be added. */
|
|
158
189
|
function nextAddableSlot(variable: FontStackVariable): FontStackSlot | null {
|
|
@@ -161,14 +192,23 @@
|
|
|
161
192
|
return addCandidates(variable).find((c) => !existing.has(slotKey(c))) ?? null;
|
|
162
193
|
}
|
|
163
194
|
|
|
195
|
+
function addLabel(variable: FontStackVariable): string {
|
|
196
|
+
const next = nextAddableSlot(variable);
|
|
197
|
+
return next?.kind === 'project' ? `+ add ${slotDisplayName(next)}` : '+ add fallback';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** A font joins the other fonts, above the fallbacks; a fallback lands just
|
|
201
|
+
* above the terminal, which stays at the bottom. */
|
|
202
|
+
function insertIndexFor(slots: FontStackSlot[], slot: FontStackSlot): number {
|
|
203
|
+
if (slot.kind !== 'project') return Math.max(0, slots.length - 1);
|
|
204
|
+
return slots.reduce((acc, s, i) => (s.kind === 'project' ? i : acc), -1) + 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
164
207
|
function addSlot(variable: FontStackVariable) {
|
|
165
208
|
const newSlot = nextAddableSlot(variable);
|
|
166
209
|
if (!newSlot) return;
|
|
167
210
|
updateStack(variable, (slots) => {
|
|
168
|
-
|
|
169
|
-
// terminal stays at the bottom.
|
|
170
|
-
const insertAt = Math.max(0, slots.length - 1);
|
|
171
|
-
slots.splice(insertAt, 0, newSlot);
|
|
211
|
+
slots.splice(insertIndexFor(slots, newSlot), 0, newSlot);
|
|
172
212
|
return slots;
|
|
173
213
|
});
|
|
174
214
|
}
|
|
@@ -265,6 +305,9 @@
|
|
|
265
305
|
<div class="font-stack-list">
|
|
266
306
|
{#each keyedSlots(stack.slots) as { slot, key }, i (key)}
|
|
267
307
|
{@const isTerminal = i === stack.slots.length - 1}
|
|
308
|
+
<!-- A value another row already holds is off this row's menu, so the
|
|
309
|
+
stack can't be edited back into the duplicate state. -->
|
|
310
|
+
{@const taken = new Set(stack.slots.filter((_, j) => j !== i).map(slotKey))}
|
|
268
311
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
269
312
|
<div
|
|
270
313
|
class="slot-row"
|
|
@@ -296,28 +339,34 @@
|
|
|
296
339
|
onchange={(e) => onSelectChange(e, stack.variable, i)}
|
|
297
340
|
>
|
|
298
341
|
{#if isTerminal}
|
|
299
|
-
{
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
<option value={`generic:${gen}`}>{gen}</option>
|
|
342
|
+
{#each terminalOptions(stack.variable, slot, taken) as opt}
|
|
343
|
+
<option value={slotKey(opt)}>{slotDisplayName(opt)}</option>
|
|
344
|
+
{/each}
|
|
303
345
|
{:else}
|
|
304
|
-
{
|
|
346
|
+
{@const families = allFamilies.filter((f) => !taken.has(`project:${f.id}`))}
|
|
347
|
+
{@const presets = SYSTEM_PRESETS.filter((p) => !taken.has(`system:${p}`))}
|
|
348
|
+
{@const generics = GENERIC_VALUES.filter((g) => !taken.has(`generic:${g}`))}
|
|
349
|
+
{#if families.length > 0}
|
|
305
350
|
<optgroup label="Project fonts">
|
|
306
|
-
{#each
|
|
351
|
+
{#each families as fam}
|
|
307
352
|
<option value={`project:${fam.id}`}>{fam.name}</option>
|
|
308
353
|
{/each}
|
|
309
354
|
</optgroup>
|
|
310
355
|
{/if}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
356
|
+
{#if presets.length > 0}
|
|
357
|
+
<optgroup label="System cascade">
|
|
358
|
+
{#each presets as p}
|
|
359
|
+
<option value={`system:${p}`}>{p === 'system-ui-sans' ? 'System UI (sans)' : p === 'system-ui-serif' ? 'System UI (serif)' : 'System UI (mono)'}</option>
|
|
360
|
+
{/each}
|
|
361
|
+
</optgroup>
|
|
362
|
+
{/if}
|
|
363
|
+
{#if generics.length > 0}
|
|
364
|
+
<optgroup label="Generic">
|
|
365
|
+
{#each generics as g}
|
|
366
|
+
<option value={`generic:${g}`}>{g}</option>
|
|
367
|
+
{/each}
|
|
368
|
+
</optgroup>
|
|
369
|
+
{/if}
|
|
321
370
|
{/if}
|
|
322
371
|
</select>
|
|
323
372
|
{#if isTerminal}
|
|
@@ -343,10 +392,10 @@
|
|
|
343
392
|
type="button"
|
|
344
393
|
class="add-fallback"
|
|
345
394
|
disabled={nextAddableSlot(stack.variable) === null}
|
|
346
|
-
title={nextAddableSlot(stack.variable) === null ? 'Every
|
|
395
|
+
title={nextAddableSlot(stack.variable) === null ? 'Every project font and fallback is already in this stack' : undefined}
|
|
347
396
|
onclick={() => addSlot(stack.variable)}
|
|
348
397
|
>
|
|
349
|
-
|
|
398
|
+
{addLabel(stack.variable)}
|
|
350
399
|
</button>
|
|
351
400
|
</div>
|
|
352
401
|
{/each}
|