@prestack/thread-ui 0.1.10 → 0.1.11
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 +187 -0
- package/dist/ui/attach.js +6 -7
- package/dist/ui/compositions.d.ts +0 -8
- package/dist/ui/compositions.js +3 -166
- package/dist/ui/generators/routes.js +1 -0
- package/package.json +2 -2
- package/dist/ui/animations/anm_appear.ts +0 -13
- package/dist/ui/animations/anm_blur_in.ts +0 -19
- package/dist/ui/animations/anm_blur_out.ts +0 -18
- package/dist/ui/animations/anm_dismiss.ts +0 -18
- package/dist/ui/animations/anm_drop.ts +0 -19
- package/dist/ui/animations/anm_fall.ts +0 -18
- package/dist/ui/animations/anm_flash.ts +0 -18
- package/dist/ui/animations/anm_glow.ts +0 -16
- package/dist/ui/animations/anm_lift.ts +0 -16
- package/dist/ui/animations/anm_nudge.ts +0 -16
- package/dist/ui/animations/anm_pop_in.ts +0 -23
- package/dist/ui/animations/anm_pop_out.ts +0 -22
- package/dist/ui/animations/anm_press.ts +0 -12
- package/dist/ui/animations/anm_pulse.ts +0 -13
- package/dist/ui/animations/anm_rise.ts +0 -19
- package/dist/ui/animations/anm_shake.ts +0 -13
- package/dist/ui/animations/anm_slide_in_left.ts +0 -19
- package/dist/ui/animations/anm_slide_in_right.ts +0 -19
- package/dist/ui/animations/anm_slide_out_left.ts +0 -18
- package/dist/ui/animations/anm_slide_out_right.ts +0 -18
- package/dist/ui/animations/anm_spin.ts +0 -12
- package/dist/ui/animations/anm_swell.ts +0 -16
- package/dist/ui/animations/anm_wobble.ts +0 -24
- package/dist/ui/animations/anm_zoom_in.ts +0 -19
- package/dist/ui/animations/anm_zoom_out.ts +0 -18
- package/dist/ui/animations.ts +0 -308
- package/dist/ui/attach.ts +0 -553
- package/dist/ui/charts.tsx +0 -69
- package/dist/ui/checked.ts +0 -32
- package/dist/ui/collector.ts +0 -140
- package/dist/ui/compositions.ts +0 -613
- package/dist/ui/consent.ts +0 -55
- package/dist/ui/content.tsx +0 -27
- package/dist/ui/contrast.ts +0 -27
- package/dist/ui/controls.tsx +0 -25
- package/dist/ui/disclosure.tsx +0 -20
- package/dist/ui/dismiss-layer.ts +0 -87
- package/dist/ui/door.ts +0 -140
- package/dist/ui/drag.ts +0 -316
- package/dist/ui/elements/accordion.tsx +0 -47
- package/dist/ui/elements/accordion.works.ts +0 -66
- package/dist/ui/elements/aspect-ratio.tsx +0 -31
- package/dist/ui/elements/aspect-ratio.works.ts +0 -5
- package/dist/ui/elements/avatar.tsx +0 -34
- package/dist/ui/elements/avatar.works.ts +0 -16
- package/dist/ui/elements/badge.tsx +0 -33
- package/dist/ui/elements/badge.works.ts +0 -9
- package/dist/ui/elements/bars.tsx +0 -50
- package/dist/ui/elements/bars.works.ts +0 -29
- package/dist/ui/elements/box.tsx +0 -36
- package/dist/ui/elements/breadcrumb.tsx +0 -38
- package/dist/ui/elements/breadcrumb.works.ts +0 -24
- package/dist/ui/elements/button.tsx +0 -46
- package/dist/ui/elements/button.works.tsx +0 -52
- package/dist/ui/elements/column.tsx +0 -29
- package/dist/ui/elements/consent.tsx +0 -71
- package/dist/ui/elements/consent.works.tsx +0 -132
- package/dist/ui/elements/donut.tsx +0 -45
- package/dist/ui/elements/donut.works.ts +0 -42
- package/dist/ui/elements/each.tsx +0 -34
- package/dist/ui/elements/each.works.tsx +0 -82
- package/dist/ui/elements/empty.tsx +0 -33
- package/dist/ui/elements/field.tsx +0 -45
- package/dist/ui/elements/field.works.ts +0 -65
- package/dist/ui/elements/funnel.tsx +0 -50
- package/dist/ui/elements/funnel.works.ts +0 -37
- package/dist/ui/elements/gauge.tsx +0 -40
- package/dist/ui/elements/gauge.works.ts +0 -42
- package/dist/ui/elements/glyph.tsx +0 -30
- package/dist/ui/elements/glyph.works.tsx +0 -42
- package/dist/ui/elements/grid.tsx +0 -29
- package/dist/ui/elements/heatmap.tsx +0 -48
- package/dist/ui/elements/heatmap.works.ts +0 -24
- package/dist/ui/elements/hit-box.tsx +0 -47
- package/dist/ui/elements/hit-box.works.tsx +0 -576
- package/dist/ui/elements/image.tsx +0 -29
- package/dist/ui/elements/line-chart.tsx +0 -45
- package/dist/ui/elements/line-chart.works.ts +0 -41
- package/dist/ui/elements/link.tsx +0 -38
- package/dist/ui/elements/link.works.ts +0 -25
- package/dist/ui/elements/media.tsx +0 -57
- package/dist/ui/elements/menu.tsx +0 -51
- package/dist/ui/elements/menu.works.tsx +0 -154
- package/dist/ui/elements/money.tsx +0 -36
- package/dist/ui/elements/money.works.ts +0 -9
- package/dist/ui/elements/pagination.tsx +0 -39
- package/dist/ui/elements/pagination.works.ts +0 -20
- package/dist/ui/elements/progress.tsx +0 -34
- package/dist/ui/elements/progress.works.ts +0 -8
- package/dist/ui/elements/radio-group.tsx +0 -50
- package/dist/ui/elements/radio-group.works.ts +0 -33
- package/dist/ui/elements/row.tsx +0 -29
- package/dist/ui/elements/scatter.tsx +0 -42
- package/dist/ui/elements/scatter.works.ts +0 -38
- package/dist/ui/elements/select.tsx +0 -43
- package/dist/ui/elements/select.works.ts +0 -5
- package/dist/ui/elements/separator.tsx +0 -31
- package/dist/ui/elements/skeleton.tsx +0 -31
- package/dist/ui/elements/slider.tsx +0 -34
- package/dist/ui/elements/slider.works.ts +0 -5
- package/dist/ui/elements/sparkline.tsx +0 -37
- package/dist/ui/elements/sparkline.works.ts +0 -32
- package/dist/ui/elements/spinner.tsx +0 -33
- package/dist/ui/elements/stack.tsx +0 -29
- package/dist/ui/elements/stat.tsx +0 -36
- package/dist/ui/elements/stat.works.ts +0 -14
- package/dist/ui/elements/surface.tsx +0 -36
- package/dist/ui/elements/surface.works.ts +0 -9
- package/dist/ui/elements/table.tsx +0 -62
- package/dist/ui/elements/table.works.ts +0 -30
- package/dist/ui/elements/tabs.tsx +0 -47
- package/dist/ui/elements/tabs.works.ts +0 -84
- package/dist/ui/elements/text.tsx +0 -33
- package/dist/ui/elements/textarea.tsx +0 -38
- package/dist/ui/elements/textarea.works.ts +0 -5
- package/dist/ui/elements/time.tsx +0 -40
- package/dist/ui/elements/time.works.ts +0 -29
- package/dist/ui/elements/toggle.tsx +0 -34
- package/dist/ui/elements/toggle.works.ts +0 -5
- package/dist/ui/elements/tooltip.tsx +0 -40
- package/dist/ui/elements/tooltip.works.ts +0 -77
- package/dist/ui/elements/value.tsx +0 -38
- package/dist/ui/elements/value.works.ts +0 -9
- package/dist/ui/elements.ts +0 -127
- package/dist/ui/focus-scope.ts +0 -121
- package/dist/ui/fonts.ts +0 -355
- package/dist/ui/generators/dev.d.ts +0 -1
- package/dist/ui/generators/dev.js +0 -62
- package/dist/ui/generators/dev.ts +0 -75
- package/dist/ui/generators/elements.ts +0 -796
- package/dist/ui/generators/i18n.ts +0 -283
- package/dist/ui/generators/icons.ts +0 -207
- package/dist/ui/generators/react.ts +0 -267
- package/dist/ui/generators/routes.ts +0 -847
- package/dist/ui/generators/show.ts +0 -261
- package/dist/ui/generators/styles.ts +0 -677
- package/dist/ui/generators/variants.ts +0 -196
- package/dist/ui/i18n/catalogs/en.ts +0 -191
- package/dist/ui/i18n/format.ts +0 -221
- package/dist/ui/i18n/locales.ts +0 -33
- package/dist/ui/i18n/parse.ts +0 -315
- package/dist/ui/i18n/translator.ts +0 -31
- package/dist/ui/i18n/types.ts +0 -96
- package/dist/ui/icons.ts +0 -331
- package/dist/ui/islands/map.ts +0 -58
- package/dist/ui/localizations.ts +0 -75
- package/dist/ui/material.ts +0 -236
- package/dist/ui/materials/mat_bordered.ts +0 -13
- package/dist/ui/materials/mat_ceramic.ts +0 -13
- package/dist/ui/materials/mat_clay.ts +0 -13
- package/dist/ui/materials/mat_elevated.ts +0 -24
- package/dist/ui/materials/mat_flat.ts +0 -34
- package/dist/ui/materials/mat_glass.ts +0 -20
- package/dist/ui/materials/mat_lit.ts +0 -13
- package/dist/ui/materials/mat_moulded.ts +0 -11
- package/dist/ui/materials.ts +0 -197
- package/dist/ui/modes.ts +0 -44
- package/dist/ui/navigation.tsx +0 -29
- package/dist/ui/positioning.ts +0 -90
- package/dist/ui/presented.tsx +0 -119
- package/dist/ui/provider.tsx +0 -184
- package/dist/ui/render-loop.ts +0 -133
- package/dist/ui/roving-focus.ts +0 -161
- package/dist/ui/screens.ts +0 -141
- package/dist/ui/scroll-lock.ts +0 -28
- package/dist/ui/series.ts +0 -97
- package/dist/ui/signals.ts +0 -386
- package/dist/ui/styleguide.ts +0 -231
- package/dist/ui/styleguides.ts +0 -374
- package/dist/ui/themes.ts +0 -22
- package/dist/ui/token.ts +0 -78
- package/dist/ui/tokens/shadow.ts +0 -25
- package/dist/ui/tokens.ts +0 -234
- package/dist/ui/validators.ts +0 -232
- package/dist/ui/variant.ts +0 -349
- package/dist/ui/variants/var_avatar-round.ts +0 -14
- package/dist/ui/variants/var_bubble-me.ts +0 -14
- package/dist/ui/variants/var_bubble-them.ts +0 -13
- package/dist/ui/variants/var_button-border.ts +0 -76
- package/dist/ui/variants/var_button-cta.ts +0 -76
- package/dist/ui/variants/var_button-destructive-ghost.ts +0 -72
- package/dist/ui/variants/var_button-destructive.ts +0 -76
- package/dist/ui/variants/var_button-fill.ts +0 -76
- package/dist/ui/variants/var_button-ghost.ts +0 -72
- package/dist/ui/variants/var_button-glass.ts +0 -55
- package/dist/ui/variants/var_button-normal.ts +0 -76
- package/dist/ui/variants/var_button-quiet.ts +0 -74
- package/dist/ui/variants/var_card.ts +0 -17
- package/dist/ui/variants/var_chip.ts +0 -13
- package/dist/ui/variants/var_choice.ts +0 -15
- package/dist/ui/variants/var_framed.ts +0 -10
- package/dist/ui/variants/var_glyph-plain.ts +0 -11
- package/dist/ui/variants/var_input.ts +0 -43
- package/dist/ui/variants/var_link-inline.ts +0 -29
- package/dist/ui/variants/var_list-row.ts +0 -34
- package/dist/ui/variants/var_rule.ts +0 -10
- package/dist/ui/variants/var_skeleton-block.ts +0 -12
- package/dist/ui/variants/var_spinner-turning.ts +0 -12
- package/dist/ui/variants/var_stat-tile.ts +0 -13
- package/dist/ui/variants/var_tab-bar.ts +0 -15
- package/dist/ui/variants/var_tap-target.ts +0 -25
- package/dist/ui/variants.ts +0 -64
- package/dist/ui/wrappers.tsx +0 -429
package/dist/ui/animations.ts
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import { existsSync, writeFileSync } from '@prestack/thread/integrations/disk'
|
|
2
|
-
import { basename, join } from 'node:path'
|
|
3
|
-
import { argv, stdout } from 'node:process'
|
|
4
|
-
import { pathToFileURL } from 'node:url'
|
|
5
|
-
|
|
6
|
-
import { exit, invoked } from '@prestack/thread/core/invoked'
|
|
7
|
-
import type { Threaded } from '@prestack/thread/core/thread'
|
|
8
|
-
import { findTree, inTree, strayFiles } from '@prestack/thread/core/tree'
|
|
9
|
-
|
|
10
|
-
import { held, sheeted, type Holds, type Token } from './token.ts'
|
|
11
|
-
|
|
12
|
-
const here = 'thread/ui/animations.ts'
|
|
13
|
-
|
|
14
|
-
export const BOUND = {
|
|
15
|
-
opacity: ['opacity'],
|
|
16
|
-
transform: ['transform'],
|
|
17
|
-
filter: ['filter'],
|
|
18
|
-
backdropFilter: ['blur'],
|
|
19
|
-
background: ['colour', 'gradient'],
|
|
20
|
-
color: ['colour'],
|
|
21
|
-
borderColor: ['colour'],
|
|
22
|
-
boxShadow: ['shadow'],
|
|
23
|
-
} as const
|
|
24
|
-
|
|
25
|
-
type Property = keyof typeof BOUND
|
|
26
|
-
|
|
27
|
-
type SettingFor<P extends Property> = {
|
|
28
|
-
readonly property: P
|
|
29
|
-
readonly is?: string
|
|
30
|
-
readonly token?: (typeof BOUND)[P][number]
|
|
31
|
-
readonly asks?: Readonly<Record<string, string | number>>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type AnimationSetting = { [P in Property]: SettingFor<P> }[Property]
|
|
35
|
-
|
|
36
|
-
export interface Animation {
|
|
37
|
-
readonly id: string
|
|
38
|
-
|
|
39
|
-
readonly runs: string
|
|
40
|
-
|
|
41
|
-
readonly eases: string
|
|
42
|
-
|
|
43
|
-
readonly repeats?: number | 'infinite'
|
|
44
|
-
|
|
45
|
-
readonly fills?: 'none' | 'forwards' | 'backwards' | 'both'
|
|
46
|
-
|
|
47
|
-
readonly stops: Readonly<Record<string, readonly AnimationSetting[]>>
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function keyframeName(id: string): string {
|
|
51
|
-
return `anm-${id}`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function resolve(
|
|
55
|
-
animation: Animation,
|
|
56
|
-
set: AnimationSetting,
|
|
57
|
-
value: string,
|
|
58
|
-
named: ReadonlySet<string>,
|
|
59
|
-
kinds: Readonly<Record<string, string>>,
|
|
60
|
-
): string {
|
|
61
|
-
if (!named.has(value)) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`\`${animation.id}\` sets ${set.property} to "${value}", and the style guide holds no row by ` +
|
|
64
|
-
'that name. An animation composes what the style guide holds, or it composes nothing.',
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
const kind = kinds[value]
|
|
68
|
-
const accepted: readonly string[] = BOUND[set.property]
|
|
69
|
-
if (kind !== undefined && !accepted.includes(kind)) {
|
|
70
|
-
throw new Error(
|
|
71
|
-
`\`${animation.id}\` sets ${set.property} to \`${value}\`, and that row is a \`${kind}\`. ` +
|
|
72
|
-
`${set.property} takes ${accepted.map((one) => `\`${one}\``).join(' or ')}.`,
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
return `var(--${value})`
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function valued(
|
|
79
|
-
animation: Animation,
|
|
80
|
-
set: AnimationSetting,
|
|
81
|
-
named: ReadonlySet<string>,
|
|
82
|
-
tokens: Readonly<Record<string, Token>>,
|
|
83
|
-
kinds: Readonly<Record<string, string>>,
|
|
84
|
-
): Holds {
|
|
85
|
-
if (set.token !== undefined) {
|
|
86
|
-
const token = tokens[set.token]
|
|
87
|
-
if (token?.makes === undefined) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
`\`${animation.id}\` asks \`${set.token}\` for ${set.property}, and that token carries no rule ` +
|
|
90
|
-
'to make a value from. Name a style guide row instead, or give the token a rule.',
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
return sheeted(set.token, token.makes(set.asks ?? {}))
|
|
94
|
-
}
|
|
95
|
-
if (set.is === undefined) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`\`${animation.id}\` states ${set.property} with neither a value nor a token to make one from.`,
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
return held(named, resolve(animation, set, set.is, named, kinds), animation.id)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function stopsOf(
|
|
104
|
-
animation: Animation,
|
|
105
|
-
named: ReadonlySet<string>,
|
|
106
|
-
tokens: Readonly<Record<string, Token>>,
|
|
107
|
-
kinds: Readonly<Record<string, string>>,
|
|
108
|
-
): readonly { readonly stop: string; readonly made: Readonly<Record<string, Holds>> }[] {
|
|
109
|
-
return Object.keys(animation.stops).map((stop) => {
|
|
110
|
-
const made: Record<string, Holds> = {}
|
|
111
|
-
for (const set of animation.stops[stop] ?? []) made[set.property] = valued(animation, set, named, tokens, kinds)
|
|
112
|
-
return { stop, made }
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function shorthandOf(animation: Animation, named: ReadonlySet<string>): string {
|
|
117
|
-
for (const [what, row] of [
|
|
118
|
-
['runs', animation.runs],
|
|
119
|
-
['eases', animation.eases],
|
|
120
|
-
] as const) {
|
|
121
|
-
if (named.has(row)) continue
|
|
122
|
-
throw new Error(
|
|
123
|
-
`\`${animation.id}\` ${what} \`${row}\`, and the style guide holds no row by that name. ` +
|
|
124
|
-
'How long an animation takes and how it is paced are style guide values, named here rather than written.',
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
return [
|
|
128
|
-
keyframeName(animation.id),
|
|
129
|
-
`var(--${animation.runs})`,
|
|
130
|
-
`var(--${animation.eases})`,
|
|
131
|
-
...(animation.repeats === undefined ? [] : [String(animation.repeats)]),
|
|
132
|
-
...(animation.fills === undefined ? [] : [animation.fills]),
|
|
133
|
-
].join(' ')
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const one = (id: string, describes: string): Threaded => ({
|
|
137
|
-
id,
|
|
138
|
-
at: `thread/ui/animations/anm_${id.replace(/-/g, '_')}.ts`,
|
|
139
|
-
describes,
|
|
140
|
-
version: 1,
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
export const declares: readonly Threaded[] = [
|
|
144
|
-
one('press', 'A thing shrinking very slightly and coming back, which is what makes a press feel like it landed rather than like a value changed.'),
|
|
145
|
-
one('appear', 'Something arriving in place — faded up from nothing, without moving, for a thing that was always going to be there.'),
|
|
146
|
-
one('dismiss', 'Something leaving — faded away and shrunk a little, so the eye is not asked to follow it out.'),
|
|
147
|
-
one('rise', 'Something arriving from below, faded up as it comes. What a sheet, a toast or a menu does on its way in.'),
|
|
148
|
-
one('fall', 'Something leaving downward, the exit that answers a rise.'),
|
|
149
|
-
one('pulse', 'A thing breathing in place, repeated without end, for something waiting rather than working.'),
|
|
150
|
-
one('spin', 'A full turn, repeated without end. What says a thing is working and cannot say how far along it is.'),
|
|
151
|
-
one('drop', 'Something arriving from above, faded in as it comes. The entrance that answers a rise.'),
|
|
152
|
-
one('slide-in-left', 'Something coming in from the left, for a panel or a step arriving from off-stage rather than growing in place.'),
|
|
153
|
-
one('slide-in-right', 'Something coming in from the right.'),
|
|
154
|
-
one('slide-out-left', 'Something leaving to the left.'),
|
|
155
|
-
one('slide-out-right', 'Something leaving to the right.'),
|
|
156
|
-
one('zoom-in', 'Something arriving from nearer the reader and settling back to its true size.'),
|
|
157
|
-
one('zoom-out', 'Something leaving toward the reader as it fades.'),
|
|
158
|
-
one('pop-in', 'Something arriving past its own size and coming back — the overshoot is what reads as physical rather than as a value changing.'),
|
|
159
|
-
one('pop-out', 'Something swelling once before it goes, the exit that answers a pop.'),
|
|
160
|
-
one('blur-in', 'Something sharpening into place out of softness, without moving at all.'),
|
|
161
|
-
one('blur-out', 'Something dissolving rather than leaving.'),
|
|
162
|
-
one('lift', 'A thing raised a little off the page while it is pointed at. The plainest way a surface says it is reachable.'),
|
|
163
|
-
one('swell', 'A thing grown very slightly while pointed at, for where lifting it would move its neighbours.'),
|
|
164
|
-
one('nudge', 'A marker leaning the way it would take you, played while the wording beside it is pointed at.'),
|
|
165
|
-
one('wobble', 'A thing turned one way and back to be noticed. Says look at me without saying something is wrong.'),
|
|
166
|
-
one('flash', 'A thing dipping and returning, for a value that changed underneath the reader.'),
|
|
167
|
-
one('glow', 'The light around a thing swelling and settling, for something lit rather than framed.'),
|
|
168
|
-
one('shake', 'A short refusal — a thing pushed off centre and back twice, for an answer that was not accepted.'),
|
|
169
|
-
]
|
|
170
|
-
|
|
171
|
-
export const ANIMATIONS = {
|
|
172
|
-
id: 'animation',
|
|
173
|
-
at: here,
|
|
174
|
-
files: 'ui/anm_*.ts',
|
|
175
|
-
describes:
|
|
176
|
-
'Every animation an app may play, and the only place one may be brought into existence. A row names a file prefixed `anm_`, and that file is the animation: the stops it moves through, how long it takes and how it is paced — all of it naming style guide rows rather than holding values, so an animation moves when the rows move. Naming one is the whole of using one: a variant that plays `press` says `press`, and states no duration, no easing and no keyframes. The style guide picks which animation is the default for a thing, the way it picks every other value. A file under animations that no row names is not an animation but a file somebody wrote.',
|
|
177
|
-
version: 1,
|
|
178
|
-
cites: [
|
|
179
|
-
{
|
|
180
|
-
on: '2026-08-28',
|
|
181
|
-
said: 'Animations.ts, declares rows (through threaded) that names animations files at a path, with a prefix anm_ or ani_ or we do motions.ts with mot_, don\'t know. These define a bunch of animations that style guide will pick for a bunch of things as defaults. Like these template animations we see in video editors, we just name them and it\'s done.',
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
declares,
|
|
185
|
-
} satisfies Threaded & { readonly files: string; readonly declares: readonly Threaded[] }
|
|
186
|
-
|
|
187
|
-
export function nameOf(id: string): string {
|
|
188
|
-
return id.replace(/-/g, '_').toUpperCase()
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function starter(row: Threaded): string {
|
|
192
|
-
return `import type { Animation } from './animations.ts'
|
|
193
|
-
|
|
194
|
-
export const ${nameOf(row.id)} = {
|
|
195
|
-
id: '${row.id}',
|
|
196
|
-
runs: 'motion-normal',
|
|
197
|
-
eases: 'ease-out',
|
|
198
|
-
stops: {},
|
|
199
|
-
} as const satisfies Animation
|
|
200
|
-
`
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function seeds(
|
|
204
|
-
rows: readonly Threaded[],
|
|
205
|
-
has: (at: string) => boolean,
|
|
206
|
-
): readonly { readonly path: string; readonly content: string }[] {
|
|
207
|
-
return rows.filter((row) => !has(row.at)).map((row) => ({ path: row.at, content: starter(row) }))
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export async function mismatched(
|
|
211
|
-
rows: readonly Threaded[],
|
|
212
|
-
loader: (row: Threaded) => Promise<{ readonly id?: string } | undefined>,
|
|
213
|
-
): Promise<readonly string[]> {
|
|
214
|
-
const found: string[] = []
|
|
215
|
-
for (const row of rows) {
|
|
216
|
-
const animation = await loader(row)
|
|
217
|
-
if (animation === undefined) {
|
|
218
|
-
found.push(
|
|
219
|
-
`\`${row.id}\` is declared at \`${row.at}\`, and that file exports no \`${nameOf(row.id)}\`. ` +
|
|
220
|
-
'A row names a file, and the file is the thing.',
|
|
221
|
-
)
|
|
222
|
-
continue
|
|
223
|
-
}
|
|
224
|
-
if (animation.id !== row.id) {
|
|
225
|
-
found.push(
|
|
226
|
-
`\`${row.at}\` declares itself \`${String(animation.id)}\`, and the row that names it calls it \`${row.id}\`. ` +
|
|
227
|
-
"An animation file and the row that names it have to be the same animation — make the file's `id` match the row, or fix the row.",
|
|
228
|
-
)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return found
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export function orphaned(rows: readonly Threaded[], strays: readonly string[]): readonly string[] {
|
|
235
|
-
const named = new Set(rows.map((row) => row.at))
|
|
236
|
-
return strays
|
|
237
|
-
.filter((one) => !named.has(one))
|
|
238
|
-
.map(
|
|
239
|
-
(one) =>
|
|
240
|
-
`\`${one}\` is under animations and no row names it — not a animation, a file somebody wrote. ` +
|
|
241
|
-
'Add a row for it, or delete the file.',
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
async function run(): Promise<number> {
|
|
246
|
-
const tree = findTree()
|
|
247
|
-
const at = inTree(tree, 'animations.ts')
|
|
248
|
-
if (!existsSync(at)) {
|
|
249
|
-
stdout.write(`thread: this tree has no ${tree.name}/${basename(at)}, so it declares no animation and there is nothing to seed or check.\n`)
|
|
250
|
-
return 0
|
|
251
|
-
}
|
|
252
|
-
const sheet = (await import(pathToFileURL(at).href)) as {
|
|
253
|
-
ANIMATION?: { readonly declares?: readonly Threaded[] }
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (sheet.ANIMATION === undefined) {
|
|
257
|
-
stdout.write(`thread: ${tree.name}/animations.ts exports no \`ANIMATION\`, so nothing declares an animation here.\n`)
|
|
258
|
-
return 1
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const rows = sheet.ANIMATION.declares ?? []
|
|
262
|
-
const checking = argv.includes('--check')
|
|
263
|
-
const exists = (where: string): boolean => existsSync(join(tree.at, where))
|
|
264
|
-
const made = seeds(rows, exists)
|
|
265
|
-
|
|
266
|
-
if (checking) {
|
|
267
|
-
const unseeded = rows.find((row) => !exists(row.at))
|
|
268
|
-
if (unseeded !== undefined) {
|
|
269
|
-
stdout.write(
|
|
270
|
-
`thread: \`${unseeded.id}\` is declared at \`${unseeded.at}\`, and the file is not there yet. ` +
|
|
271
|
-
'A row names a file, and `--check` never writes one — run `thread animations` and commit what it seeds.\n',
|
|
272
|
-
)
|
|
273
|
-
return 1
|
|
274
|
-
}
|
|
275
|
-
} else {
|
|
276
|
-
for (const seed of made) {
|
|
277
|
-
writeFileSync(join(tree.at, seed.path), seed.content, 'utf8')
|
|
278
|
-
stdout.write(`thread: seeded ${seed.path}\n`)
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const wrong = (
|
|
283
|
-
await mismatched(rows, async (row) => {
|
|
284
|
-
const module = (await import(pathToFileURL(join(tree.at, row.at)).href)) as Record<string, unknown>
|
|
285
|
-
return module[nameOf(row.id)] as { readonly id?: string } | undefined
|
|
286
|
-
})
|
|
287
|
-
)[0]
|
|
288
|
-
if (wrong !== undefined) {
|
|
289
|
-
stdout.write(`thread: ${wrong}\n`)
|
|
290
|
-
return 1
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const stray = orphaned(rows, strayFiles(tree.at, 'anm_', '.' + 'ts'))[0]
|
|
294
|
-
if (stray !== undefined) {
|
|
295
|
-
stdout.write(`thread: ${stray}\n`)
|
|
296
|
-
return 1
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
stdout.write(
|
|
300
|
-
checking
|
|
301
|
-
? `thread: ${String(rows.length)} animation(s) declared, all seeded\n`
|
|
302
|
-
: `thread: ${String(rows.length)} animation(s) declared, ${String(made.length)} seeded, ` +
|
|
303
|
-
`${String(rows.length - made.length)} already written\n`,
|
|
304
|
-
)
|
|
305
|
-
return 0
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (invoked(import.meta.url)) exit(await run())
|