@prestack/thread-ui 0.1.10 → 0.1.12
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 +375 -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/attach.ts
DELETED
|
@@ -1,553 +0,0 @@
|
|
|
1
|
-
import type { Attaching } from '@prestack/thread/core/attach'
|
|
2
|
-
import { SHAPED } from '@prestack/thread/core/init'
|
|
3
|
-
import { NAMED, named } from '@prestack/thread/core/scope'
|
|
4
|
-
import type { Threaded } from '@prestack/thread/core/thread'
|
|
5
|
-
|
|
6
|
-
import { ANIMATIONS } from './animations.ts'
|
|
7
|
-
import { COMPOSITIONS } from './compositions.ts'
|
|
8
|
-
import { FONTS } from './fonts.ts'
|
|
9
|
-
import { ICONS, SET_ROW, setNamed } from './icons.ts'
|
|
10
|
-
import { LOCALIZATIONS } from './localizations.ts'
|
|
11
|
-
import { ELEMENTS } from './elements.ts'
|
|
12
|
-
import { MATERIALS } from './materials.ts'
|
|
13
|
-
import { MODES } from './modes.ts'
|
|
14
|
-
import { SCREENS } from './screens.ts'
|
|
15
|
-
import { STYLEGUIDES } from './styleguides.ts'
|
|
16
|
-
import { SIGNALS } from './signals.ts'
|
|
17
|
-
import { THEMES } from './themes.ts'
|
|
18
|
-
import { TOKENS } from './tokens.ts'
|
|
19
|
-
import { VARIANTS } from './variants.ts'
|
|
20
|
-
|
|
21
|
-
const SEEDED = {
|
|
22
|
-
attaches: ['@prestack/thread'] as const,
|
|
23
|
-
id: 'ui',
|
|
24
|
-
declares: [
|
|
25
|
-
' {',
|
|
26
|
-
' id: \'ui\',',
|
|
27
|
-
' at: \'_threads/ui.ts\',',
|
|
28
|
-
' describes: \'Draws things. An app declares its elements, variants and screens, and the components, stylesheet and translations follow.\',',
|
|
29
|
-
' version: 1,',
|
|
30
|
-
' },',
|
|
31
|
-
].join('\n'),
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const SHIPPED: readonly { readonly into: string; readonly list: string; readonly id: string; readonly source: string }[] = [
|
|
35
|
-
{
|
|
36
|
-
into: 'ui.ts',
|
|
37
|
-
list: 'GENERATORS',
|
|
38
|
-
id: 'styles-generator',
|
|
39
|
-
source: " {\n id: 'styles-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/styles.js',\n describes: 'The generator of the stylesheet — it reads the tokens, materials, variants and style guide an app declares and writes one class per variant, so what an app looks like is a consequence of its declarations rather than a file somebody maintains beside them.',\n version: 1,\n by: 'thread styles',\n runs: 'thread styles --check',\n derives: [\n {\n id: 'stylesheet',\n at: 'app/_generated/tokens.css',\n describes: 'One class per variant and one variable per value, written from the declarations rather than kept beside them.',\n version: 1,\n by: 'thread styles',\n runs: 'thread styles --check',\n },\n {\n id: 'declared',\n at: 'app/_generated/declared.ts',\n describes: 'What this app declared for itself, said in types so an element offers it — a variant an app wrote is a member on the element that wears it, the way a shipped one is. A declaration file because it weighs nothing: it is gone at build, so an app gets its own variants without a registry being shipped into the artifact.',\n version: 1,\n by: 'thread styles',\n runs: 'thread styles --check',\n },\n ],\n },",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
into: 'ui.ts',
|
|
43
|
-
list: 'GENERATORS',
|
|
44
|
-
id: 'tokens-generator',
|
|
45
|
-
source: " {\n id: 'tokens-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/tokens.js',\n describes: 'The seeder of token files — it reads the tokens an app declares and writes the file each `declares` row names when that file is not there yet, so a token that carries a rule begins by being declared rather than by somebody remembering to add a file beside the row. A `holds` row names no file, because a token that is only a name has nothing to seed. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a file that disagrees with its row, a file under tokens no row names, or a row with no file at all — so an unseeded token is a gate failure, not something the gate quietly fixes.',\n version: 1,\n by: 'thread tokens',\n runs: 'thread tokens --check',\n },",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
into: 'ui.ts',
|
|
49
|
-
list: 'GENERATORS',
|
|
50
|
-
id: 'materials-generator',
|
|
51
|
-
source: " {\n id: 'materials-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/materials.js',\n describes: 'The seeder of material files — it reads the materials an app declares and writes the `mat_` file each row names when that file is not there yet. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a file that disagrees with its row, a `mat_` file no row names, or a row with no file at all — so an unseeded material is a gate failure, not something the gate quietly fixes.',\n version: 1,\n by: 'thread materials',\n runs: 'thread materials --check',\n },",
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
into: 'ui.ts',
|
|
55
|
-
list: 'GENERATORS',
|
|
56
|
-
id: 'i18n-generator',
|
|
57
|
-
source: " {\n id: 'i18n-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/i18n.js',\n describes: 'The generator of an app\\'s wording — it reads the languages the app declares and every message key its interface names, and writes one file per language holding a line for each. It cannot invent a sentence, so a key it has just found arrives holding nothing; run with `--check`, the mode the gate runs it in, it writes nothing and refuses a language file that is not what the declarations produce, and refuses any key left unanswered. It also writes the module the app imports, which states the keys the interface uses as a type, so a language missing one is a compiler error before it is a gate error.',\n version: 1,\n by: 'thread i18n',\n runs: 'thread i18n --check',\n derives: [\n {\n id: 'wording',\n at: 'app/_generated/wording.ts',\n describes: 'Every language this app is in, as one module the layout hands to the provider, with the keys the interface names stated as a type so a language missing one is a compiler error. That type is written as an assignment rather than a satisfies clause, because satisfies would also refuse the extra keys a filled wording always carries.',\n version: 1,\n by: 'thread i18n',\n runs: 'thread i18n --check',\n },\n ],\n },",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
into: 'ui.ts',
|
|
61
|
-
list: 'GENERATORS',
|
|
62
|
-
id: 'routes-generator',
|
|
63
|
-
source: " {\n id: 'routes-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/routes.js',\n describes: 'The generator of the routes, the map, the pages a browser reaches, and the root layout. Nobody types a route. The first page an app declares answers `/`, every other page answers its own name, and a sheet, popover, overlay or toast has no route, so the page under each route follows from the screens sheet. It writes the row on each screen that names that page too, so a screen that stops being the first page, or stops being a page at all, takes its page with it. It reads every `navigateTo` the screens and their compositions hold and writes the map: from which screen, through which button, to which screen. A button is the only thing that makes a link. A press that names a sheet, popover, overlay or toast is a link like any other, and the client half opens that screen where somebody already is. A name no screen has, a destination not written out as a name, and a route typed into a screen are each refused by name. The layout imports what the other generators produce. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses a hand edit to any of these files, exactly as the stylesheet is refused.',\n version: 1,\n by: 'thread routes',\n runs: 'thread routes --check',\n derives: [\n {\n id: 'layout',\n at: 'app/layout.tsx',\n describes: 'The root layout — it imports what the other generators produce and hands the wording to the provider, so the one file every page passes through is a consequence of the declarations rather than something somebody keeps in step with them.',\n version: 1,\n by: 'thread routes',\n runs: 'thread routes --check',\n },\n {\n id: 'door',\n at: 'app/_generated/door.tsx',\n describes: 'This app\\'s own client half. It is written when the app has operations a page can reach, or screens a press can move between. The provider takes something to run an operation with and something to move between screens with, and the layout cannot hand either over: the layout is a server component and the provider is a client one, and a function does not cross that line — \"Functions cannot be passed directly to Client Components\", measured 2026-09-01 as a page that returned 500 on every request while the gate was green. So both are made on the side that uses them. This file imports what the operations half derived and the map, and hands them over itself. The layout renders this and passes only the actor, which is data and crosses the way data does.',\n version: 1,\n by: 'thread routes',\n runs: 'thread routes --check',\n },\n {\n id: 'bundler',\n at: 'next.config.js',\n describes: 'What Next reads to serve this app. It is written whenever the manifest runs Next, whether or not this app declares a screen, because it states three things a served app needs and one of them is that Next may not write files of its own into a tree where every file is declared. It also refuses to compile anything until the gate has passed, and names where the bundler resolves from when the packages live outside this app — which is when a bundler cannot see them and every import fails at run time while the compiler is content. It opens the disk itself rather than through the disk this framework declares, because Next reads this file before any TypeScript in this tree has been loaded — a file that gates the build cannot import the thing it is gating.',\n version: 1,\n by: 'thread routes',\n runs: 'thread routes --check',\n },\n {\n id: 'map',\n at: 'app/_generated/map.ts',\n describes: 'Every screen this app has, where each one lives, and every way from one to another: from which screen, through which button, to which screen. It is read off every `navigateTo` the screens and their compositions hold, so a button is the only thing that makes a link. The client half moves through it: a press that names a page goes to the address held here, and a press that names a sheet, popover, overlay or toast opens it where somebody already is. A screen no button reaches is printed by `thread routes` rather than found by somebody looking for it.',\n version: 1,\n by: 'thread routes',\n runs: 'thread routes --check',\n },\n ],\n },",
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
into: 'ui.ts',
|
|
67
|
-
list: 'GENERATORS',
|
|
68
|
-
id: 'dev-generator',
|
|
69
|
-
source: " {\n id: 'dev-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/dev.js',\n describes: 'The command that runs the app, and the only one here that puts a pixel on a screen — until it existed the framework could build an interface nothing in it could start, because a gate answers whether declarations agree with files and cannot answer whether a button is where somebody says it is not. It is two halves in one word. First it settles this tree: every generator the declarations name is run until the checks stop complaining, which is what `thread create` and `thread run trial` already did and what starting the app was alone in not doing — an app had `thread gate` in front of `next dev`, and a gate refuses a stale file rather than writing it. Then it runs the gate, and then starts Next itself, because Next is what this package installs to serve an app and the manifest carries no script for it. The generators are read off the rows, and `next dev` is the one thing written down here: this package serves an app with Next and nothing else. `--ship` swaps the entry for the build. Alone among the generators it carries no `runs:`, because a server stays up until it is stopped and a gate step that never returns is a gate that hangs.',\n version: 1,\n by: 'thread dev',\n },",
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
into: 'ui.ts',
|
|
73
|
-
list: 'GENERATORS',
|
|
74
|
-
id: 'show-generator',
|
|
75
|
-
source: " {\n id: 'show-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/show.js',\n describes: 'The reader of what nothing reaches — style guide rows nothing names, variants no element accepts, elements wearing nothing, and signals no element is seen to raise. It writes nothing and refuses nothing, because none of those is wrong on its own: a value declared ahead of the thing that will use it is ordinary, and a report that refused it would teach people to stop reading. It exists because the gate answers whether declarations agree with each other and cannot answer whether anything reaches them, and the difference between those two questions cost six capabilities in one week — each declared, typechecked, generated, and unable to run.',\n version: 1,\n by: 'thread show',\n },",
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
into: 'ui.ts',
|
|
79
|
-
list: 'GENERATORS',
|
|
80
|
-
id: 'variants-generator',
|
|
81
|
-
source: " {\n id: 'variants-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/variants.js',\n describes: 'The seeder of variant files — it reads the variants an app declares and writes the `var_` file each row names when that file is not there yet. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a file that disagrees with its row, a `var_` file no row names, or a row with no file at all. It is the last of the three file-backed sheets to get this, and it was the one that needed it — a variant file nothing declared sat in the framework unnoticed until two readers found it by hand, because no gate could.',\n version: 1,\n by: 'thread variants',\n runs: 'thread variants --check',\n },",
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
into: 'ui.ts',
|
|
85
|
-
list: 'GENERATORS',
|
|
86
|
-
id: 'elements-generator',
|
|
87
|
-
source: " {\n id: 'elements-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/elements.js',\n describes: 'The writer of element files — it reads the tag an element row states, whether it arranges other things and the signals it raises, and writes the component out of those three facts. An element file stops being a place a tag is typed and becomes a derived thing. Founder, 2026-08-31: \"elements does not hold anything that can render anything, its functionality only . only our compiler can translate things into proper css and html and only at build time do we produce a renderable result.\" Only a row that names this generator in its own `derives` is written, so an element carrying real behaviour is left exactly as it is until it is converted. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses a file that differs from what its row produces.',\n version: 1,\n by: 'thread elements',\n runs: 'thread elements --check',\n },",
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
into: 'ui.ts',
|
|
91
|
-
list: 'GENERATORS',
|
|
92
|
-
id: 'icons-generator',
|
|
93
|
-
source: " {\n id: 'icons-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/icons.js',\n describes: 'The generator of the icon module — it reads which library the icon rows name and which meanings they declare, and writes the one module that imports exactly those symbols and installs them. A meaning is what an element asks for, so changing the library row redraws every icon in the app and rewrites nothing else. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses a generated file that does not match the rows.',\n version: 1,\n by: 'thread icons',\n runs: 'thread icons --check',\n derives: [\n {\n id: 'symbols',\n at: 'app/_generated/icons.ts',\n describes: 'The one module importing exactly the symbols the icon rows name, from the one library they name. The layout renders it rather than merely importing it, because a bare import of a client module from a server layout is a reference that never runs — the install never happens and every icon on the page refuses.',\n version: 1,\n by: 'thread icons',\n runs: 'thread icons --check',\n },\n ],\n },",
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
into: 'ui.ts',
|
|
97
|
-
list: 'GENERATORS',
|
|
98
|
-
id: 'animations-generator',
|
|
99
|
-
source: " {\n id: 'animations-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/animations.js',\n describes: 'The seeder of animation files — it reads the animations an app declares and writes the `anm_` file each row names when that file is not there yet. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a file that disagrees with its row, an `anm_` file no row names, or a row with no file at all — so an unseeded animation is a gate failure, not something the gate quietly fixes.',\n version: 1,\n by: 'thread animations',\n runs: 'thread animations --check',\n },",
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
into: 'ui.ts',
|
|
103
|
-
list: 'GENERATORS',
|
|
104
|
-
id: 'compositions-generator',
|
|
105
|
-
source: " {\n id: 'compositions-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/compositions.js',\n describes: 'The seeder of composition files — it reads the compositions an app declares and writes the `cmp_` file each row names when that file is not there yet, so a composition begins by being declared rather than by somebody remembering to add a file beside the row. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a row whose file is absent, a `cmp_` file no row names, and an import that is not a declared element, a declared composition or the door — so a composition that did not come from the CLI, or that reaches something nothing declares, stops the build rather than rendering. It also writes each of them compiled, into `app/_generated/compiled` — a variant worn as a tag becomes the class it resolves to and a named place becomes the class its arrangement declares, so a page imports a file this framework wrote rather than one a bundler plugin rewrites on the way past.',\n version: 1,\n by: 'thread compositions',\n runs: 'thread compositions --check',\n derives: [\n {\n id: 'compiled',\n at: '_threads/compiled.ts',\n describes: 'The sheet declaring every file the interface runs from in this app, one row each: the parts of the framework a page needs, copied in, and every composition and screen compiled from the file a person wrote. A page imports only these, so the app builds with no part of this framework installed. `thread compositions` writes the sheet, because a folder declares nothing beneath it. Each row names the command that writes its file: `thread screens` for a compiled screen, `thread compositions` for everything else.',\n version: 1,\n by: 'thread compositions',\n runs: 'thread compositions --check',\n },\n ],\n },",
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
into: 'ui.ts',
|
|
109
|
-
list: 'GENERATORS',
|
|
110
|
-
id: 'screens-generator',
|
|
111
|
-
source: " {\n id: 'screens-generator',\n at: 'node_modules/@prestack/thread-ui/dist/ui/screens.js',\n describes: 'The seeder of screen files — it reads the screens an app declares and writes the `scr_` file each row names when that file is not there yet, so a screen begins by being declared and wears the arrangement its row states rather than carrying one somebody wrote beside it. Run with `--check`, the mode the gate runs it in, it writes nothing and refuses instead: a row whose file is absent, a `scr_` file no row names, and an import that is not a declared composition, a declared element or the door.',\n version: 1,\n by: 'thread screens',\n runs: 'thread screens --check',\n },",
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
into: 'ui.ts',
|
|
115
|
-
list: 'GENERATORS',
|
|
116
|
-
id: 'react-compiler',
|
|
117
|
-
source: " {\n id: 'react-compiler',\n at: 'node_modules/@prestack/thread-ui/dist/ui/generators/react.js',\n describes: 'The compiler of compositions and screens — it runs inside `thread build`, on every file on its way into the artifact, and turns what a person wrote into what React runs. `Button.primary` becomes a tag wearing the class its variant resolves to, and a name of a place becomes the class the composition or screen around it arranges, so neither is worked out again on every render. It writes nothing to disk: the file a person wrote stays the file a person wrote, and the compiled form exists only in the artifact. Everything it does not own — a condition, a list, a hook somebody wrote — is copied through unchanged.',\n version: 1,\n by: 'thread build',\n },",
|
|
118
|
-
},
|
|
119
|
-
]
|
|
120
|
-
export const ATTACH_HOME = `node_modules/${named('ui')}/dist`
|
|
121
|
-
|
|
122
|
-
interface Row {
|
|
123
|
-
readonly id: string
|
|
124
|
-
readonly at?: string
|
|
125
|
-
readonly describes: string
|
|
126
|
-
readonly section?: string
|
|
127
|
-
readonly token?: string
|
|
128
|
-
readonly is?: string
|
|
129
|
-
readonly asks?: Readonly<Record<string, string | number>>
|
|
130
|
-
readonly sets?: Readonly<Record<string, string>>
|
|
131
|
-
readonly modes?: Readonly<Record<string, string | Readonly<Record<string, string>>>>
|
|
132
|
-
readonly places?: Readonly<Record<string, Readonly<Record<string, string>>>>
|
|
133
|
-
readonly themes?: Readonly<Record<string, { readonly is?: string; readonly modes?: Readonly<Record<string, string>> }>>
|
|
134
|
-
readonly wears?: readonly string[]
|
|
135
|
-
readonly selector?: string
|
|
136
|
-
readonly arranges?: boolean
|
|
137
|
-
readonly tag?: string | Readonly<Record<string, string>>
|
|
138
|
-
readonly raises?: readonly string[]
|
|
139
|
-
readonly carries?: Readonly<Record<string, string>>
|
|
140
|
-
readonly always?: readonly string[]
|
|
141
|
-
readonly works?: string
|
|
142
|
-
readonly measures?: readonly string[]
|
|
143
|
-
readonly reads?: string
|
|
144
|
-
readonly gives?: readonly string[]
|
|
145
|
-
readonly keeps?: boolean
|
|
146
|
-
readonly animates?: boolean
|
|
147
|
-
readonly shows?: string
|
|
148
|
-
readonly called?: string
|
|
149
|
-
readonly wires?: string
|
|
150
|
-
readonly dresses?: string
|
|
151
|
-
readonly plays?: Readonly<Record<string, string>>
|
|
152
|
-
readonly by?: string
|
|
153
|
-
readonly runs?: string
|
|
154
|
-
readonly derives?: readonly Threaded[]
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const SAID = {
|
|
158
|
-
on: '2026-09-09',
|
|
159
|
-
said: 'No reason at all for 15....elements are all ONE THING, screens ONE THING, ompositions ONE THING, tokens ONE THING....and so on.',
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const FIELDS: Readonly<Record<string, { readonly is: string; readonly means?: string }>> = {
|
|
163
|
-
section: { is: 'string', means: 'The heading a row sits under in its sheet, so rows that belong together are read together.' },
|
|
164
|
-
token: { is: 'string' },
|
|
165
|
-
is: {
|
|
166
|
-
is: 'string',
|
|
167
|
-
means: 'What a row is, written out as its value: a colour, a media query, the name of a language, the library every icon is drawn from.',
|
|
168
|
-
},
|
|
169
|
-
asks: {
|
|
170
|
-
is: 'Readonly<Record<string, string | number>>',
|
|
171
|
-
means: 'What a token\'s rule is handed instead of a value, written name=value and separated by commas: offset=2, blur=4.',
|
|
172
|
-
},
|
|
173
|
-
sets: {
|
|
174
|
-
is: 'Readonly<Record<string, string>>',
|
|
175
|
-
means:
|
|
176
|
-
'What a row sets, written name=value and separated by commas. For a font role, a composition or an element it is a property and the style guide row it takes, gap=space-3; for an icon it is a library and what this meaning is called there.',
|
|
177
|
-
},
|
|
178
|
-
modes: {
|
|
179
|
-
is: 'Readonly<Record<string, string | Readonly<Record<string, string>>>>',
|
|
180
|
-
means:
|
|
181
|
-
'How what a row sets changes under a mode, written mode.property=row and separated by commas, dark.background=colour-surface, or mode=row where the row itself is the value.',
|
|
182
|
-
},
|
|
183
|
-
places: {
|
|
184
|
-
is: 'Readonly<Record<string, Readonly<Record<string, string>>>>',
|
|
185
|
-
means: 'The named places inside a thing and what each one sets, written place.property=row and separated by commas: hero.display=layout-flex.',
|
|
186
|
-
},
|
|
187
|
-
works: {
|
|
188
|
-
is: 'string',
|
|
189
|
-
means: 'The file beside an element that holds the code it runs, as a path from the element\'s own file: ./price-tag.works.tsx.',
|
|
190
|
-
},
|
|
191
|
-
measures: {
|
|
192
|
-
is: 'readonly string[]',
|
|
193
|
-
means: 'The values an element works out while it runs and hands to the stylesheet by name, separated by commas.',
|
|
194
|
-
},
|
|
195
|
-
reads: { is: 'string', means: 'What an element reads as to assistive technology: picture, progress, divider, grouping.' },
|
|
196
|
-
gives: { is: 'readonly string[]', means: 'The attributes an element hands its tag from what it carries, separated by commas.' },
|
|
197
|
-
keeps: { is: 'boolean', means: 'Whether an element keeps state of its own between renders.' },
|
|
198
|
-
animates: { is: 'boolean', means: 'Whether an element plays the animation the variant it wears names.' },
|
|
199
|
-
shows: { is: 'string', means: 'Which of the things an element carries is shown as its wording.' },
|
|
200
|
-
called: { is: 'string', means: 'The landmark an element is announced as: nav.breadcrumb.' },
|
|
201
|
-
wires: { is: 'string', means: 'The function in an element\'s works file that wires its events.' },
|
|
202
|
-
dresses: {
|
|
203
|
-
is: 'string',
|
|
204
|
-
means: 'The named place inside an element that wears the variant, when the variant is not worn by the element itself.',
|
|
205
|
-
},
|
|
206
|
-
themes: {
|
|
207
|
-
is: 'Readonly<Record<string, { readonly is?: string; readonly modes?: Readonly<Record<string, string>> }>>',
|
|
208
|
-
means:
|
|
209
|
-
'How a value changes under a theme, written theme.is=value, or theme.modes.mode=value where the theme has a dark and a light of its own, separated by commas.',
|
|
210
|
-
},
|
|
211
|
-
wears: { is: 'readonly string[]', means: 'The elements that accept a variant, by their names and separated by commas: Button, Link.' },
|
|
212
|
-
selector: {
|
|
213
|
-
is: 'string',
|
|
214
|
-
means:
|
|
215
|
-
'The CSS selector that is true while a signal holds. One the browser sets has its own, :hover; one an element raises is a data attribute named after the signal, and that is what is used when this is left blank.',
|
|
216
|
-
},
|
|
217
|
-
arranges: { is: 'boolean', means: 'Whether a thing arranges other things inside it, which is what lets it take children.' },
|
|
218
|
-
tag: {
|
|
219
|
-
is: 'string | Readonly<Record<string, string>>',
|
|
220
|
-
means:
|
|
221
|
-
'The HTML tag an element is written as: button, div, svg. When the tag depends on what the element carries, name that prop as by and give one entry per value, separated by commas: by=as, image=img, video=video.',
|
|
222
|
-
},
|
|
223
|
-
raises: { is: 'readonly string[]', means: 'The signals an element raises, separated by commas, each one a row in the signals sheet.' },
|
|
224
|
-
carries: {
|
|
225
|
-
is: 'Readonly<Record<string, string>>',
|
|
226
|
-
means: 'What an element takes as props, written name=kind and separated by commas: label=wording, disabled=flag.',
|
|
227
|
-
},
|
|
228
|
-
always: { is: 'readonly string[]', means: 'The signals that hold for as long as an element is on screen, separated by commas.' },
|
|
229
|
-
|
|
230
|
-
plays: {
|
|
231
|
-
is: 'Readonly<Record<string, string>>',
|
|
232
|
-
means: 'What a screen or a composition plays arriving and leaving, each naming an animation: in=rise, out=fall.',
|
|
233
|
-
},
|
|
234
|
-
|
|
235
|
-
derives: { is: 'readonly Threaded[]' },
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const SHAPES: Readonly<Record<string, string>> = Object.fromEntries(
|
|
239
|
-
Object.entries(FIELDS).map(([key, one]) => [key, ` readonly ${key}?: ${one.is}`]),
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
const CONCEPTS: readonly { readonly id: string; readonly means: string }[] = Object.entries(FIELDS).flatMap(([id, one]) =>
|
|
243
|
-
one.means === undefined ? [] : [{ id, means: one.means }],
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
function concept(one: { readonly id: string; readonly means: string }): string {
|
|
247
|
-
return [
|
|
248
|
-
' {',
|
|
249
|
-
` id: ${quoted(one.id)},`,
|
|
250
|
-
" at: '_threads/concepts.ts',",
|
|
251
|
-
` describes: ${quoted(one.means)},`,
|
|
252
|
-
' version: 1,',
|
|
253
|
-
' cites: [',
|
|
254
|
-
` { on: ${quoted(SAID.on)}, said: ${quoted(SAID.said)} },`,
|
|
255
|
-
' ],',
|
|
256
|
-
' },',
|
|
257
|
-
].join('\n')
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function stated(rows: readonly Row[], always: readonly string[] = []): readonly string[] {
|
|
261
|
-
const held = new Set<string>(always)
|
|
262
|
-
for (const one of rows) {
|
|
263
|
-
for (const key of Object.keys(SHAPES)) {
|
|
264
|
-
if (one[key as keyof Row] !== undefined) held.add(key)
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return Object.keys(SHAPES).filter((key) => held.has(key))
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
interface Node {
|
|
271
|
-
readonly id: string
|
|
272
|
-
readonly at: string
|
|
273
|
-
readonly describes: string
|
|
274
|
-
readonly files?: string
|
|
275
|
-
readonly declares?: readonly Row[]
|
|
276
|
-
readonly derives?: readonly Row[]
|
|
277
|
-
readonly holds?: readonly Row[]
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function inside(node: Node): readonly Row[] {
|
|
281
|
-
return [...(node.holds ?? []), ...(node.declares ?? []), ...(node.derives ?? [])]
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function quoted(value: string): string {
|
|
285
|
-
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function installed(at: string): string {
|
|
289
|
-
return at.replace(/^thread\/(.*)\.tsx?$/, `${ATTACH_HOME}/$1.js`)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function literal(value: string | number): string {
|
|
293
|
-
return typeof value === 'number' ? String(value) : quoted(value)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
type Pair = string | number | Readonly<Record<string, string | number>>
|
|
297
|
-
|
|
298
|
-
const BARE = /^[A-Za-z_$][A-Za-z0-9_$]*$/
|
|
299
|
-
|
|
300
|
-
function pairs(held: Readonly<Record<string, Pair>>): string {
|
|
301
|
-
const each = Object.entries(held).map(
|
|
302
|
-
([key, value]) =>
|
|
303
|
-
`${BARE.test(key) ? key : quoted(key)}: ${typeof value === 'object' ? pairs(value) : literal(value)}`,
|
|
304
|
-
)
|
|
305
|
-
return `{ ${each.join(', ')} }`
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function listed(held: readonly string[]): string {
|
|
309
|
-
return `[${held.map(quoted).join(', ')}]`
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function themed(
|
|
313
|
-
held: Readonly<Record<string, { readonly is?: string; readonly modes?: Readonly<Record<string, string>> }>>,
|
|
314
|
-
): string {
|
|
315
|
-
const each = Object.entries(held).map(([key, one]) => {
|
|
316
|
-
const parts = [
|
|
317
|
-
...(one.is === undefined ? [] : [`is: ${quoted(one.is)}`]),
|
|
318
|
-
...(one.modes === undefined ? [] : [`modes: ${pairs(one.modes)}`]),
|
|
319
|
-
]
|
|
320
|
-
return `${key}: { ${parts.join(', ')} }`
|
|
321
|
-
})
|
|
322
|
-
return `{ ${each.join(', ')} }`
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const WRITTEN = new Set([
|
|
326
|
-
'id', 'at', 'describes', 'version', 'derives', 'holds', 'runs',
|
|
327
|
-
'section', 'token', 'is', 'asks', 'sets', 'modes', 'places', 'themes', 'wears', 'selector',
|
|
328
|
-
'arranges', 'plays',
|
|
329
|
-
])
|
|
330
|
-
|
|
331
|
-
function valued(held: unknown): string | undefined {
|
|
332
|
-
if (typeof held === 'string') return quoted(held)
|
|
333
|
-
if (typeof held === 'boolean' || typeof held === 'number') return String(held)
|
|
334
|
-
if (Array.isArray(held)) return held.every((one) => typeof one === 'string') ? listed(held as string[]) : undefined
|
|
335
|
-
if (held !== null && typeof held === 'object') {
|
|
336
|
-
return pairs(held as Readonly<Record<string, string | number>>)
|
|
337
|
-
}
|
|
338
|
-
return undefined
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function rest(one: Row): readonly string[] {
|
|
342
|
-
const out: string[] = []
|
|
343
|
-
for (const [key, held] of Object.entries(one)) {
|
|
344
|
-
if (WRITTEN.has(key) || held === undefined) continue
|
|
345
|
-
const said = valued(held)
|
|
346
|
-
if (said !== undefined) out.push(` ${key}: ${said},`)
|
|
347
|
-
}
|
|
348
|
-
return out
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function row(one: Row, file: string, sheet: string): string {
|
|
352
|
-
const held = one.at === undefined || one.at === sheet
|
|
353
|
-
const derives = (one.derives ?? []).filter((each) => installed(each.at) === each.at)
|
|
354
|
-
return [
|
|
355
|
-
' {',
|
|
356
|
-
` id: ${quoted(one.id)},`,
|
|
357
|
-
...(one.section === undefined ? [] : [` section: ${quoted(one.section)},`]),
|
|
358
|
-
...(one.token === undefined ? [] : [` token: ${quoted(one.token)},`]),
|
|
359
|
-
...(one.is === undefined ? [] : [` is: ${quoted(one.is)},`]),
|
|
360
|
-
...(one.asks === undefined ? [] : [` asks: ${pairs(one.asks)},`]),
|
|
361
|
-
...(one.sets === undefined ? [] : [` sets: ${pairs(one.sets)},`]),
|
|
362
|
-
...(one.modes === undefined ? [] : [` modes: ${pairs(one.modes)},`]),
|
|
363
|
-
...(one.places === undefined ? [] : [` places: ${pairs(one.places)},`]),
|
|
364
|
-
...(one.themes === undefined ? [] : [` themes: ${themed(one.themes)},`]),
|
|
365
|
-
...(one.wears === undefined ? [] : [` wears: ${listed(one.wears)},`]),
|
|
366
|
-
...(one.selector === undefined ? [] : [` selector: ${quoted(one.selector)},`]),
|
|
367
|
-
...(one.arranges === undefined ? [] : [` arranges: ${String(one.arranges)},`]),
|
|
368
|
-
...(one.plays === undefined ? [] : [` plays: ${pairs(one.plays)},`]),
|
|
369
|
-
...rest(one),
|
|
370
|
-
...(derives.length === 0
|
|
371
|
-
? []
|
|
372
|
-
: [
|
|
373
|
-
' derives: [',
|
|
374
|
-
...derives.flatMap((each) => [
|
|
375
|
-
' {',
|
|
376
|
-
` id: ${quoted(each.id)},`,
|
|
377
|
-
` at: ${quoted(each.at)},`,
|
|
378
|
-
...(each.by === undefined ? [] : [` by: ${quoted(each.by)},`]),
|
|
379
|
-
...(each.runs === undefined ? [] : [` runs: ${quoted(each.runs)},`]),
|
|
380
|
-
` describes: ${quoted(each.describes)},`,
|
|
381
|
-
' version: 1,',
|
|
382
|
-
' },',
|
|
383
|
-
]),
|
|
384
|
-
' ],',
|
|
385
|
-
]),
|
|
386
|
-
...(held ? [] : [` at: ${quoted(installed(one.at ?? ''))},`]),
|
|
387
|
-
...(one.runs === undefined ? [] : [` runs: ${quoted(one.runs.split(' --own').join(''))},`]),
|
|
388
|
-
` describes: ${quoted(one.describes)},`,
|
|
389
|
-
' version: 1,',
|
|
390
|
-
' },',
|
|
391
|
-
].join('\n')
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const ARRANGES: Readonly<Record<string, readonly string[]>> = {
|
|
395
|
-
composition: ['sets', 'modes', 'places', 'plays'],
|
|
396
|
-
screen: ['sets', 'modes', 'places', 'plays'],
|
|
397
|
-
styleguide: ['themes'],
|
|
398
|
-
|
|
399
|
-
element: ['tag', 'raises', 'carries', 'always', 'places', 'works', 'measures', 'reads', 'gives', 'keeps', 'animates', 'shows', 'called', 'wires', 'dresses'],
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function source(node: Node, file: string, rows: readonly Row[]): string {
|
|
403
|
-
const extra = stated(rows, ARRANGES[node.id] ?? []).map((key) => SHAPES[key] ?? '')
|
|
404
|
-
|
|
405
|
-
const authors = node.declares !== undefined || node.derives !== undefined || rows.some((one) => one.at !== undefined && one.at !== node.at)
|
|
406
|
-
const values = node.holds !== undefined || rows.some((one) => one.at === undefined || one.at === node.at)
|
|
407
|
-
|
|
408
|
-
const own = node.id
|
|
409
|
-
.split('-')
|
|
410
|
-
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
411
|
-
.join('')
|
|
412
|
-
|
|
413
|
-
const widened = (base: string): string =>
|
|
414
|
-
extra.length === 0 ? base : `(${base} & {\n${extra.join('\n')}\n })`
|
|
415
|
-
|
|
416
|
-
const lists = [
|
|
417
|
-
...(authors || !values ? [` readonly declares?: readonly ${widened('Threaded')}[]`] : []),
|
|
418
|
-
...(values ? [` readonly holds?: readonly ${widened("Omit<Threaded, 'at'>")}[]`] : []),
|
|
419
|
-
]
|
|
420
|
-
|
|
421
|
-
const bespoke = extra.length > 0 || values || node.files !== undefined
|
|
422
|
-
|
|
423
|
-
const shape = bespoke
|
|
424
|
-
? `
|
|
425
|
-
export interface ${own} extends Threaded {
|
|
426
|
-
${[...(node.files === undefined ? [] : [' readonly files?: string']), ...lists].join('\n')}
|
|
427
|
-
}
|
|
428
|
-
`
|
|
429
|
-
: ''
|
|
430
|
-
|
|
431
|
-
const held = [
|
|
432
|
-
...(node.files === undefined ? [] : [` files: ${quoted(node.files)},`]),
|
|
433
|
-
...(authors || !values ? [' declares: [],'] : []),
|
|
434
|
-
...(values ? [' holds: [],'] : []),
|
|
435
|
-
]
|
|
436
|
-
|
|
437
|
-
const wants = shape.includes('Condition')
|
|
438
|
-
|
|
439
|
-
return `import type { Threaded } from '${SHAPED}'${wants ? `\nimport type { Condition } from '${NAMED}/core/condition'` : ''}
|
|
440
|
-
${shape}
|
|
441
|
-
export const ${node.id.toUpperCase()}: ${bespoke ? own : 'Threaded'} = {
|
|
442
|
-
id: ${quoted(node.id)},
|
|
443
|
-
at: ${quoted(`_threads/${file}`)},
|
|
444
|
-
describes: ${quoted(node.describes)},
|
|
445
|
-
version: 1,
|
|
446
|
-
${held.join('\n')}
|
|
447
|
-
}
|
|
448
|
-
`
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
const LISTS: readonly { readonly node: Node; readonly file: string; readonly rows?: readonly Row[] }[] = [
|
|
452
|
-
{ node: TOKENS, file: 'tokens.ts' },
|
|
453
|
-
{ node: FONTS, file: 'fonts.ts' },
|
|
454
|
-
{ node: ICONS, file: 'icons.ts' },
|
|
455
|
-
{ node: ANIMATIONS, file: 'animations.ts' },
|
|
456
|
-
{ node: SIGNALS, file: 'signals.ts' },
|
|
457
|
-
{ node: MATERIALS, file: 'materials.ts' },
|
|
458
|
-
{ node: VARIANTS, file: 'variants.ts' },
|
|
459
|
-
{ node: STYLEGUIDES, file: 'styleguides.ts' },
|
|
460
|
-
{ node: LOCALIZATIONS, file: 'localizations.ts' },
|
|
461
|
-
{ node: MODES, file: 'modes.ts' },
|
|
462
|
-
{ node: THEMES, file: 'themes.ts' },
|
|
463
|
-
{ node: ELEMENTS, file: 'elements.ts' },
|
|
464
|
-
{ node: COMPOSITIONS, file: 'compositions.ts' },
|
|
465
|
-
{ node: SCREENS, file: 'screens.ts' },
|
|
466
|
-
]
|
|
467
|
-
|
|
468
|
-
function child(one: { readonly node: Node; readonly file: string }): string {
|
|
469
|
-
return [
|
|
470
|
-
' {',
|
|
471
|
-
` id: ${quoted(one.node.id)},`,
|
|
472
|
-
` at: ${quoted(`_threads/${one.file}`)},`,
|
|
473
|
-
` describes: ${quoted(one.node.describes)},`,
|
|
474
|
-
' version: 1,',
|
|
475
|
-
' },',
|
|
476
|
-
].join('\n')
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function sectioned(one: { readonly node: Node; readonly file: string; readonly rows?: readonly Row[] }): readonly {
|
|
480
|
-
readonly into: string
|
|
481
|
-
readonly list: string
|
|
482
|
-
readonly id: string
|
|
483
|
-
readonly source: string
|
|
484
|
-
}[] {
|
|
485
|
-
const last = new Map<string, string>()
|
|
486
|
-
|
|
487
|
-
return (one.rows ?? inside(one.node)).map((held) => {
|
|
488
|
-
const list = held.at === undefined || held.at === one.node.at ? 'holds' : 'declares'
|
|
489
|
-
const before = last.get(list)
|
|
490
|
-
const section = held.section ?? ''
|
|
491
|
-
last.set(list, section)
|
|
492
|
-
const turned = before !== undefined && before !== section
|
|
493
|
-
return {
|
|
494
|
-
into: one.file,
|
|
495
|
-
list,
|
|
496
|
-
id: held.id,
|
|
497
|
-
source: `${turned ? '\n' : ''}${row(held, one.file, one.node.at)}`,
|
|
498
|
-
}
|
|
499
|
-
})
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
const UI_SOURCE = `import type { Threaded } from '${SHAPED}'
|
|
503
|
-
|
|
504
|
-
export const UI: Threaded = {
|
|
505
|
-
${SEEDED.declares.split('\n').slice(1, -1).map((line) => line.slice(4)).join('\n')}
|
|
506
|
-
declares: [],
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
export const GENERATORS: readonly Threaded[] = []
|
|
510
|
-
`
|
|
511
|
-
|
|
512
|
-
const LIBRARY = setNamed(ICONS.holds.find((one) => one.id === SET_ROW)?.is ?? '').module
|
|
513
|
-
|
|
514
|
-
export const ATTACH: Attaching = {
|
|
515
|
-
attaches: SEEDED.attaches,
|
|
516
|
-
id: SEEDED.id,
|
|
517
|
-
|
|
518
|
-
needs: {
|
|
519
|
-
'@floating-ui/dom': '^1.7.0',
|
|
520
|
-
'@floating-ui/react-dom': '^2.1.0',
|
|
521
|
-
'@types/react': '^19.0.0',
|
|
522
|
-
'@types/react-dom': '^19.0.0',
|
|
523
|
-
next: '^16.0.0',
|
|
524
|
-
react: '^19.0.0',
|
|
525
|
-
'react-dom': '^19.0.0',
|
|
526
|
-
zod: '^4.5.4',
|
|
527
|
-
[LIBRARY]: 'latest',
|
|
528
|
-
},
|
|
529
|
-
rows: [
|
|
530
|
-
...CONCEPTS.map((one) => ({
|
|
531
|
-
into: 'concepts.ts',
|
|
532
|
-
list: 'CONCEPTS',
|
|
533
|
-
id: one.id,
|
|
534
|
-
source: concept(one),
|
|
535
|
-
})),
|
|
536
|
-
...LISTS.map((one) => ({
|
|
537
|
-
into: 'ui.ts',
|
|
538
|
-
list: 'declares',
|
|
539
|
-
id: one.node.id,
|
|
540
|
-
source: child(one),
|
|
541
|
-
})),
|
|
542
|
-
...LISTS.flatMap((one) => sectioned(one)),
|
|
543
|
-
...SHIPPED,
|
|
544
|
-
],
|
|
545
|
-
declares: SEEDED.declares,
|
|
546
|
-
writes: [
|
|
547
|
-
{ file: 'ui.ts', source: UI_SOURCE },
|
|
548
|
-
...LISTS.map((one) => ({
|
|
549
|
-
file: one.file,
|
|
550
|
-
source: source(one.node, one.file, one.rows ?? inside(one.node)),
|
|
551
|
-
})),
|
|
552
|
-
],
|
|
553
|
-
}
|
package/dist/ui/charts.tsx
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { seriesRamp } from './series.ts'
|
|
4
|
-
import { classOfElement } from './variant.ts'
|
|
5
|
-
|
|
6
|
-
import { useUi } from './wrappers.tsx'
|
|
7
|
-
import type { MessageKey } from './content.tsx'
|
|
8
|
-
|
|
9
|
-
export type Row = Readonly<Record<string, unknown>>
|
|
10
|
-
|
|
11
|
-
export type WhenTight = 'scroll' | 'bucket' | 'wrap' | 'shrink'
|
|
12
|
-
|
|
13
|
-
export interface ChartBase {
|
|
14
|
-
readonly rows: readonly Row[]
|
|
15
|
-
readonly titleKey?: MessageKey
|
|
16
|
-
|
|
17
|
-
readonly whenTight?: WhenTight
|
|
18
|
-
|
|
19
|
-
readonly format?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const num = (row: Row, key: string): number => {
|
|
23
|
-
const v = row[key]
|
|
24
|
-
return typeof v === 'number' ? v : Number(v ?? 0)
|
|
25
|
-
}
|
|
26
|
-
export const str = (row: Row, key: string): string => String(row[key] ?? '')
|
|
27
|
-
|
|
28
|
-
export function useRamp(count: number): readonly string[] {
|
|
29
|
-
const { palette } = useUi()
|
|
30
|
-
return seriesRamp(palette.accent, palette.surface, Math.max(1, count))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function placed(element: string, place: string): string {
|
|
34
|
-
return `${classOfElement(element)}-${place}`
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function measured(held: Readonly<Record<string, string | number>>): Record<string, string | number> {
|
|
38
|
-
const out: Record<string, string | number> = {}
|
|
39
|
-
for (const [name, value] of Object.entries(held)) out[`--${name}`] = value
|
|
40
|
-
return out
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface SeriesProps extends ChartBase {
|
|
44
|
-
readonly value: string
|
|
45
|
-
readonly at: string
|
|
46
|
-
|
|
47
|
-
readonly by?: string
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function polyline(values: readonly number[], width: number, height: number): string {
|
|
51
|
-
if (values.length === 0) return ''
|
|
52
|
-
const max = Math.max(...values)
|
|
53
|
-
const min = Math.min(...values, 0)
|
|
54
|
-
const span = max - min || 1
|
|
55
|
-
const step = values.length === 1 ? 0 : width / (values.length - 1)
|
|
56
|
-
return values.map((v, i) => `${(i * step).toFixed(2)},${(height - ((v - min) / span) * height).toFixed(2)}`).join(' ')
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface CategoryProps extends ChartBase {
|
|
60
|
-
readonly value: string
|
|
61
|
-
readonly by: string
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface TwoAxisProps extends ChartBase {
|
|
65
|
-
readonly x: string
|
|
66
|
-
readonly y: string
|
|
67
|
-
readonly value?: string
|
|
68
|
-
}
|
|
69
|
-
|