@prestack/thread-ui 0.1.1 → 0.1.3
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 +518 -0
- package/dist/ui/animations/anm_appear.d.ts +8 -8
- package/dist/ui/animations/anm_blur_in.d.ts +12 -12
- package/dist/ui/animations/anm_blur_out.d.ts +12 -12
- package/dist/ui/animations/anm_dismiss.d.ts +12 -12
- package/dist/ui/animations/anm_drop.d.ts +12 -12
- package/dist/ui/animations/anm_fall.d.ts +12 -12
- package/dist/ui/animations/anm_flash.d.ts +9 -9
- package/dist/ui/animations/anm_glow.d.ts +8 -8
- package/dist/ui/animations/anm_lift.d.ts +8 -8
- package/dist/ui/animations/anm_nudge.d.ts +8 -8
- package/dist/ui/animations/anm_pop_in.d.ts +16 -16
- package/dist/ui/animations/anm_pop_out.d.ts +16 -16
- package/dist/ui/animations/anm_press.d.ts +9 -9
- package/dist/ui/animations/anm_pulse.d.ts +10 -10
- package/dist/ui/animations/anm_rise.d.ts +12 -12
- package/dist/ui/animations/anm_shake.d.ts +11 -11
- package/dist/ui/animations/anm_slide_in_left.d.ts +12 -12
- package/dist/ui/animations/anm_slide_in_right.d.ts +12 -12
- package/dist/ui/animations/anm_slide_out_left.d.ts +12 -12
- package/dist/ui/animations/anm_slide_out_right.d.ts +12 -12
- package/dist/ui/animations/anm_spin.d.ts +8 -8
- package/dist/ui/animations/anm_swell.d.ts +8 -8
- package/dist/ui/animations/anm_wobble.d.ts +13 -13
- package/dist/ui/animations/anm_zoom_in.d.ts +12 -12
- package/dist/ui/animations/anm_zoom_out.d.ts +12 -12
- package/dist/ui/animations.d.ts +8 -8
- package/dist/ui/animations.js +4 -4
- package/dist/ui/animations.ts +1 -1
- package/dist/ui/attach.js +25 -80
- package/dist/ui/attach.ts +12 -69
- package/dist/ui/charts.d.ts +0 -3
- package/dist/ui/charts.js +3 -7
- package/dist/ui/charts.tsx +0 -4
- package/dist/ui/checked.d.ts +1 -1
- package/dist/ui/checked.ts +1 -1
- package/dist/ui/collector.js +1 -1
- package/dist/ui/collector.ts +1 -1
- package/dist/ui/compositions.d.ts +9 -3
- package/dist/ui/compositions.js +9 -158
- package/dist/ui/compositions.ts +6 -170
- package/dist/ui/content.js +4 -7
- package/dist/ui/content.tsx +4 -15
- package/dist/ui/controls.js +1 -1
- package/dist/ui/door.d.ts +1 -1
- package/dist/ui/elements/accordion.d.ts +2 -1
- package/dist/ui/elements/accordion.js +4 -4
- package/dist/ui/elements/accordion.tsx +2 -1
- package/dist/ui/elements/aspect-ratio.d.ts +2 -1
- package/dist/ui/elements/aspect-ratio.js +1 -1
- package/dist/ui/elements/aspect-ratio.tsx +2 -1
- package/dist/ui/elements/avatar.d.ts +2 -1
- package/dist/ui/elements/avatar.js +3 -3
- package/dist/ui/elements/avatar.tsx +2 -1
- package/dist/ui/elements/badge.d.ts +2 -1
- package/dist/ui/elements/badge.js +3 -3
- package/dist/ui/elements/badge.tsx +2 -1
- package/dist/ui/elements/bars.d.ts +2 -1
- package/dist/ui/elements/bars.js +5 -5
- package/dist/ui/elements/bars.tsx +2 -1
- package/dist/ui/elements/bars.works.js +3 -3
- package/dist/ui/elements/box.d.ts +2 -1
- package/dist/ui/elements/box.js +1 -1
- package/dist/ui/elements/box.tsx +2 -1
- package/dist/ui/elements/breadcrumb.d.ts +2 -1
- package/dist/ui/elements/breadcrumb.js +5 -5
- package/dist/ui/elements/breadcrumb.tsx +2 -1
- package/dist/ui/elements/breadcrumb.works.js +1 -1
- package/dist/ui/elements/button.d.ts +2 -1
- package/dist/ui/elements/button.js +3 -3
- package/dist/ui/elements/button.tsx +2 -1
- package/dist/ui/elements/button.works.js +2 -2
- package/dist/ui/elements/column.d.ts +2 -1
- package/dist/ui/elements/column.js +1 -1
- package/dist/ui/elements/column.tsx +2 -1
- package/dist/ui/elements/consent.d.ts +2 -1
- package/dist/ui/elements/consent.js +10 -10
- package/dist/ui/elements/consent.tsx +2 -1
- package/dist/ui/elements/consent.works.js +1 -1
- package/dist/ui/elements/donut.d.ts +2 -1
- package/dist/ui/elements/donut.js +4 -4
- package/dist/ui/elements/donut.tsx +2 -1
- package/dist/ui/elements/donut.works.js +2 -2
- package/dist/ui/elements/each.d.ts +2 -1
- package/dist/ui/elements/each.js +3 -3
- package/dist/ui/elements/each.tsx +2 -1
- package/dist/ui/elements/each.works.js +2 -2
- package/dist/ui/elements/empty.d.ts +2 -1
- package/dist/ui/elements/empty.js +2 -2
- package/dist/ui/elements/empty.tsx +2 -1
- package/dist/ui/elements/field.d.ts +2 -1
- package/dist/ui/elements/field.js +3 -3
- package/dist/ui/elements/field.tsx +2 -1
- package/dist/ui/elements/field.works.js +1 -1
- package/dist/ui/elements/funnel.d.ts +2 -1
- package/dist/ui/elements/funnel.js +5 -5
- package/dist/ui/elements/funnel.tsx +2 -1
- package/dist/ui/elements/funnel.works.js +3 -3
- package/dist/ui/elements/gauge.d.ts +2 -1
- package/dist/ui/elements/gauge.js +3 -3
- package/dist/ui/elements/gauge.tsx +2 -1
- package/dist/ui/elements/gauge.works.js +1 -1
- package/dist/ui/elements/glyph.d.ts +2 -1
- package/dist/ui/elements/glyph.js +3 -3
- package/dist/ui/elements/glyph.tsx +2 -1
- package/dist/ui/elements/glyph.works.js +1 -1
- package/dist/ui/elements/grid.d.ts +2 -1
- package/dist/ui/elements/grid.js +1 -1
- package/dist/ui/elements/grid.tsx +2 -1
- package/dist/ui/elements/heatmap.d.ts +2 -1
- package/dist/ui/elements/heatmap.js +5 -5
- package/dist/ui/elements/heatmap.tsx +2 -1
- package/dist/ui/elements/heatmap.works.js +1 -1
- package/dist/ui/elements/hit-box.d.ts +2 -1
- package/dist/ui/elements/hit-box.js +2 -2
- package/dist/ui/elements/hit-box.tsx +2 -1
- package/dist/ui/elements/hit-box.works.d.ts +2 -2
- package/dist/ui/elements/hit-box.works.js +5 -5
- package/dist/ui/elements/hit-box.works.tsx +2 -1
- package/dist/ui/elements/image.d.ts +2 -1
- package/dist/ui/elements/image.js +2 -2
- package/dist/ui/elements/image.tsx +2 -1
- package/dist/ui/elements/line-chart.d.ts +2 -1
- package/dist/ui/elements/line-chart.js +4 -4
- package/dist/ui/elements/line-chart.tsx +2 -1
- package/dist/ui/elements/line-chart.works.js +2 -2
- package/dist/ui/elements/link.d.ts +2 -1
- package/dist/ui/elements/link.js +3 -3
- package/dist/ui/elements/link.tsx +2 -1
- package/dist/ui/elements/link.works.js +1 -1
- package/dist/ui/elements/media.d.ts +2 -1
- package/dist/ui/elements/media.js +2 -2
- package/dist/ui/elements/media.tsx +2 -1
- package/dist/ui/elements/menu.d.ts +2 -1
- package/dist/ui/elements/menu.js +5 -5
- package/dist/ui/elements/menu.tsx +2 -1
- package/dist/ui/elements/menu.works.d.ts +2 -1
- package/dist/ui/elements/menu.works.js +5 -5
- package/dist/ui/elements/menu.works.tsx +2 -1
- package/dist/ui/elements/money.d.ts +3 -1
- package/dist/ui/elements/money.js +10 -5
- package/dist/ui/elements/money.tsx +12 -3
- package/dist/ui/elements/money.works.js +1 -1
- package/dist/ui/elements/pagination.d.ts +2 -1
- package/dist/ui/elements/pagination.js +5 -5
- package/dist/ui/elements/pagination.tsx +2 -1
- package/dist/ui/elements/progress.d.ts +2 -1
- package/dist/ui/elements/progress.js +3 -3
- package/dist/ui/elements/progress.tsx +2 -1
- package/dist/ui/elements/radio-group.d.ts +2 -1
- package/dist/ui/elements/radio-group.js +4 -4
- package/dist/ui/elements/radio-group.tsx +2 -1
- package/dist/ui/elements/radio-group.works.js +1 -1
- package/dist/ui/elements/row.d.ts +2 -1
- package/dist/ui/elements/row.js +1 -1
- package/dist/ui/elements/row.tsx +2 -1
- package/dist/ui/elements/scatter.d.ts +2 -1
- package/dist/ui/elements/scatter.js +3 -3
- package/dist/ui/elements/scatter.tsx +2 -1
- package/dist/ui/elements/scatter.works.js +1 -1
- package/dist/ui/elements/select.d.ts +2 -1
- package/dist/ui/elements/select.js +4 -4
- package/dist/ui/elements/select.tsx +2 -1
- package/dist/ui/elements/separator.d.ts +2 -1
- package/dist/ui/elements/separator.js +2 -2
- package/dist/ui/elements/separator.tsx +2 -1
- package/dist/ui/elements/skeleton.d.ts +2 -1
- package/dist/ui/elements/skeleton.js +2 -2
- package/dist/ui/elements/skeleton.tsx +2 -1
- package/dist/ui/elements/slider.d.ts +2 -1
- package/dist/ui/elements/slider.js +3 -3
- package/dist/ui/elements/slider.tsx +2 -1
- package/dist/ui/elements/sparkline.d.ts +2 -1
- package/dist/ui/elements/sparkline.js +3 -3
- package/dist/ui/elements/sparkline.tsx +2 -1
- package/dist/ui/elements/sparkline.works.js +1 -1
- package/dist/ui/elements/spinner.d.ts +2 -1
- package/dist/ui/elements/spinner.js +2 -2
- package/dist/ui/elements/spinner.tsx +2 -1
- package/dist/ui/elements/stack.d.ts +2 -1
- package/dist/ui/elements/stack.js +1 -1
- package/dist/ui/elements/stack.tsx +2 -1
- package/dist/ui/elements/stat.d.ts +2 -1
- package/dist/ui/elements/stat.js +3 -3
- package/dist/ui/elements/stat.tsx +2 -1
- package/dist/ui/elements/stat.works.js +1 -1
- package/dist/ui/elements/surface.d.ts +2 -1
- package/dist/ui/elements/surface.js +2 -2
- package/dist/ui/elements/surface.tsx +2 -1
- package/dist/ui/elements/surface.works.js +1 -1
- package/dist/ui/elements/table.d.ts +2 -1
- package/dist/ui/elements/table.js +4 -4
- package/dist/ui/elements/table.tsx +2 -1
- package/dist/ui/elements/table.works.js +1 -1
- package/dist/ui/elements/tabs.d.ts +2 -1
- package/dist/ui/elements/tabs.js +4 -4
- package/dist/ui/elements/tabs.tsx +2 -1
- package/dist/ui/elements/tabs.works.js +1 -1
- package/dist/ui/elements/text.d.ts +2 -1
- package/dist/ui/elements/text.js +2 -2
- package/dist/ui/elements/text.tsx +2 -1
- package/dist/ui/elements/textarea.d.ts +2 -1
- package/dist/ui/elements/textarea.js +4 -4
- package/dist/ui/elements/textarea.tsx +2 -1
- package/dist/ui/elements/time.d.ts +3 -1
- package/dist/ui/elements/time.js +7 -4
- package/dist/ui/elements/time.tsx +9 -2
- package/dist/ui/elements/time.works.d.ts +1 -0
- package/dist/ui/elements/time.works.js +7 -3
- package/dist/ui/elements/time.works.ts +6 -2
- package/dist/ui/elements/toggle.d.ts +2 -1
- package/dist/ui/elements/toggle.js +3 -3
- package/dist/ui/elements/toggle.tsx +2 -1
- package/dist/ui/elements/tooltip.d.ts +2 -1
- package/dist/ui/elements/tooltip.js +2 -2
- package/dist/ui/elements/tooltip.tsx +2 -1
- package/dist/ui/elements/tooltip.works.js +2 -2
- package/dist/ui/elements/value.d.ts +3 -1
- package/dist/ui/elements/value.js +10 -5
- package/dist/ui/elements/value.tsx +12 -3
- package/dist/ui/elements/value.works.js +1 -1
- package/dist/ui/elements.d.ts +15 -11
- package/dist/ui/elements.js +6 -6
- package/dist/ui/elements.ts +7 -7
- package/dist/ui/fonts.d.ts +1 -1
- package/dist/ui/fonts.js +1 -1
- package/dist/ui/generators/dev.d.ts +1 -2
- package/dist/ui/generators/dev.js +33 -37
- package/dist/ui/generators/dev.ts +30 -37
- package/dist/ui/generators/elements.d.ts +1 -0
- package/dist/ui/generators/elements.js +11 -9
- package/dist/ui/generators/elements.ts +12 -9
- package/dist/ui/generators/i18n.js +6 -23
- package/dist/ui/generators/i18n.ts +1 -18
- package/dist/ui/generators/icons.js +5 -14
- package/dist/ui/generators/icons.ts +1 -10
- package/dist/ui/generators/react.js +4 -5
- package/dist/ui/generators/react.ts +2 -3
- package/dist/ui/generators/routes.js +66 -51
- package/dist/ui/generators/routes.ts +67 -46
- package/dist/ui/generators/show.js +9 -6
- package/dist/ui/generators/show.ts +4 -2
- package/dist/ui/generators/styles.js +12 -16
- package/dist/ui/generators/styles.ts +1 -5
- package/dist/ui/generators/variants.js +3 -3
- package/dist/ui/generators/variants.ts +1 -1
- package/dist/ui/i18n/catalogs/en.js +1 -1
- package/dist/ui/i18n/format.js +1 -1
- package/dist/ui/i18n/translator.js +2 -2
- package/dist/ui/material.d.ts +11 -11
- package/dist/ui/material.js +1 -1
- package/dist/ui/materials/mat_bordered.d.ts +13 -13
- package/dist/ui/materials/mat_bordered.js +1 -1
- package/dist/ui/materials/mat_ceramic.d.ts +13 -13
- package/dist/ui/materials/mat_ceramic.js +1 -1
- package/dist/ui/materials/mat_clay.d.ts +13 -13
- package/dist/ui/materials/mat_clay.js +1 -1
- package/dist/ui/materials/mat_elevated.d.ts +13 -13
- package/dist/ui/materials/mat_elevated.js +1 -1
- package/dist/ui/materials/mat_flat.d.ts +25 -25
- package/dist/ui/materials/mat_flat.js +1 -1
- package/dist/ui/materials/mat_glass.d.ts +17 -17
- package/dist/ui/materials/mat_glass.js +1 -1
- package/dist/ui/materials/mat_lit.d.ts +13 -13
- package/dist/ui/materials/mat_lit.js +1 -1
- package/dist/ui/materials/mat_moulded.d.ts +9 -9
- package/dist/ui/materials/mat_moulded.js +1 -1
- package/dist/ui/materials.d.ts +30 -30
- package/dist/ui/materials.js +3 -3
- package/dist/ui/materials.ts +1 -1
- package/dist/ui/modes.d.ts +2 -2
- package/dist/ui/presented.js +5 -5
- package/dist/ui/provider.d.ts +3 -0
- package/dist/ui/provider.js +9 -10
- package/dist/ui/provider.tsx +7 -5
- package/dist/ui/screens.js +6 -6
- package/dist/ui/screens.ts +1 -1
- package/dist/ui/scroll-lock.js +1 -1
- package/dist/ui/series.js +1 -1
- package/dist/ui/styleguide.js +1 -1
- package/dist/ui/tokens.d.ts +2 -2
- package/dist/ui/tokens.js +3 -3
- package/dist/ui/tokens.ts +1 -1
- package/dist/ui/validators.js +1 -1
- package/dist/ui/variant.d.ts +37 -37
- package/dist/ui/variant.js +2 -2
- package/dist/ui/variants/var_avatar-round.d.ts +13 -13
- package/dist/ui/variants/var_avatar-round.js +1 -1
- package/dist/ui/variants/var_bubble-me.d.ts +12 -12
- package/dist/ui/variants/var_bubble-me.js +1 -1
- package/dist/ui/variants/var_bubble-them.d.ts +10 -10
- package/dist/ui/variants/var_bubble-them.js +1 -1
- package/dist/ui/variants/var_button-border.d.ts +61 -61
- package/dist/ui/variants/var_button-border.js +1 -1
- package/dist/ui/variants/var_button-cta.d.ts +61 -61
- package/dist/ui/variants/var_button-cta.js +1 -1
- package/dist/ui/variants/var_button-destructive-ghost.d.ts +59 -59
- package/dist/ui/variants/var_button-destructive-ghost.js +1 -1
- package/dist/ui/variants/var_button-destructive.d.ts +61 -61
- package/dist/ui/variants/var_button-destructive.js +1 -1
- package/dist/ui/variants/var_button-fill.d.ts +61 -61
- package/dist/ui/variants/var_button-fill.js +1 -1
- package/dist/ui/variants/var_button-ghost.d.ts +59 -59
- package/dist/ui/variants/var_button-ghost.js +1 -1
- package/dist/ui/variants/var_button-glass.d.ts +40 -40
- package/dist/ui/variants/var_button-glass.js +1 -1
- package/dist/ui/variants/var_button-normal.d.ts +61 -61
- package/dist/ui/variants/var_button-normal.js +1 -1
- package/dist/ui/variants/var_button-quiet.d.ts +63 -63
- package/dist/ui/variants/var_button-quiet.js +1 -1
- package/dist/ui/variants/var_card.d.ts +17 -17
- package/dist/ui/variants/var_card.js +1 -1
- package/dist/ui/variants/var_chip.d.ts +10 -10
- package/dist/ui/variants/var_chip.js +1 -1
- package/dist/ui/variants/var_choice.d.ts +15 -15
- package/dist/ui/variants/var_choice.js +1 -1
- package/dist/ui/variants/var_framed.d.ts +5 -5
- package/dist/ui/variants/var_framed.js +1 -1
- package/dist/ui/variants/var_glyph-plain.d.ts +7 -7
- package/dist/ui/variants/var_glyph-plain.js +1 -1
- package/dist/ui/variants/var_input.d.ts +30 -30
- package/dist/ui/variants/var_input.js +1 -1
- package/dist/ui/variants/var_link-inline.d.ts +17 -17
- package/dist/ui/variants/var_link-inline.js +1 -1
- package/dist/ui/variants/var_list-row.d.ts +22 -22
- package/dist/ui/variants/var_list-row.js +1 -1
- package/dist/ui/variants/var_rule.d.ts +5 -5
- package/dist/ui/variants/var_rule.js +1 -1
- package/dist/ui/variants/var_skeleton-block.d.ts +9 -9
- package/dist/ui/variants/var_skeleton-block.js +1 -1
- package/dist/ui/variants/var_spinner-turning.d.ts +9 -9
- package/dist/ui/variants/var_spinner-turning.js +1 -1
- package/dist/ui/variants/var_stat-tile.d.ts +10 -10
- package/dist/ui/variants/var_stat-tile.js +1 -1
- package/dist/ui/variants/var_tab-bar.d.ts +14 -14
- package/dist/ui/variants/var_tab-bar.js +1 -1
- package/dist/ui/variants/var_tap-target.d.ts +11 -11
- package/dist/ui/variants/var_tap-target.js +1 -1
- package/dist/ui/variants.d.ts +88 -88
- package/dist/ui/wrappers.d.ts +7 -6
- package/dist/ui/wrappers.js +16 -14
- package/dist/ui/wrappers.tsx +21 -18
- package/package.json +2 -2
package/dist/ui/attach.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Attaching } from '@prestack/thread/core/attach'
|
|
2
|
-
import {
|
|
2
|
+
import { SHAPED } from '@prestack/thread/core/init'
|
|
3
|
+
import { NAMED, named } from '@prestack/thread/core/scope'
|
|
3
4
|
import type { Threaded } from '@prestack/thread/core/thread'
|
|
4
5
|
|
|
5
6
|
import { ANIMATIONS } from './animations.ts'
|
|
@@ -53,19 +54,19 @@ const SHIPPED: readonly { readonly into: string; readonly list: string; readonly
|
|
|
53
54
|
into: 'ui.ts',
|
|
54
55
|
list: 'GENERATORS',
|
|
55
56
|
id: 'i18n-generator',
|
|
56
|
-
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.',\n version: 1,\n by: 'thread i18n',\n runs: 'thread i18n --check',\n },\n ],\n },",
|
|
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 },",
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
60
|
into: 'ui.ts',
|
|
60
61
|
list: 'GENERATORS',
|
|
61
62
|
id: 'routes-generator',
|
|
62
|
-
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 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: '
|
|
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 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 },",
|
|
63
64
|
},
|
|
64
65
|
{
|
|
65
66
|
into: 'ui.ts',
|
|
66
67
|
list: 'GENERATORS',
|
|
67
68
|
id: 'dev-generator',
|
|
68
|
-
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
|
|
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 },",
|
|
69
70
|
},
|
|
70
71
|
{
|
|
71
72
|
into: 'ui.ts',
|
|
@@ -89,7 +90,7 @@ const SHIPPED: readonly { readonly into: string; readonly list: string; readonly
|
|
|
89
90
|
into: 'ui.ts',
|
|
90
91
|
list: 'GENERATORS',
|
|
91
92
|
id: 'icons-generator',
|
|
92
|
-
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.',\n version: 1,\n by: 'thread icons',\n runs: 'thread icons --check',\n },\n ],\n },",
|
|
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 },",
|
|
93
94
|
},
|
|
94
95
|
{
|
|
95
96
|
into: 'ui.ts',
|
|
@@ -272,11 +273,12 @@ interface Node {
|
|
|
272
273
|
readonly describes: string
|
|
273
274
|
readonly files?: string
|
|
274
275
|
readonly declares?: readonly Row[]
|
|
276
|
+
readonly derives?: readonly Row[]
|
|
275
277
|
readonly holds?: readonly Row[]
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
function inside(node: Node): readonly Row[] {
|
|
279
|
-
return [...(node.holds ?? []), ...(node.declares ?? [])]
|
|
281
|
+
return [...(node.holds ?? []), ...(node.declares ?? []), ...(node.derives ?? [])]
|
|
280
282
|
}
|
|
281
283
|
|
|
282
284
|
function quoted(value: string): string {
|
|
@@ -397,16 +399,10 @@ const ARRANGES: Readonly<Record<string, readonly string[]>> = {
|
|
|
397
399
|
element: ['tag', 'raises', 'carries', 'always', 'places', 'works', 'measures', 'reads', 'gives', 'keeps', 'animates', 'shows', 'called', 'wires', 'dresses'],
|
|
398
400
|
}
|
|
399
401
|
|
|
400
|
-
const TEACHING: Readonly<Record<string, string>> = {
|
|
401
|
-
composition: `export { TEACHES, catalogue } from '${named('ui')}/compositions'`,
|
|
402
|
-
screen: `export { TEACHES, screening as catalogue } from '${named('ui')}/compositions'`,
|
|
403
|
-
}
|
|
404
|
-
|
|
405
402
|
function source(node: Node, file: string, rows: readonly Row[]): string {
|
|
406
403
|
const extra = stated(rows, ARRANGES[node.id] ?? []).map((key) => SHAPES[key] ?? '')
|
|
407
|
-
const taught = TEACHING[node.id]
|
|
408
404
|
|
|
409
|
-
const authors = node.declares !== undefined || rows.some((one) => one.at !== undefined && one.at !== node.at)
|
|
405
|
+
const authors = node.declares !== undefined || node.derives !== undefined || rows.some((one) => one.at !== undefined && one.at !== node.at)
|
|
410
406
|
const values = node.holds !== undefined || rows.some((one) => one.at === undefined || one.at === node.at)
|
|
411
407
|
|
|
412
408
|
const own = node.id
|
|
@@ -440,7 +436,7 @@ ${[...(node.files === undefined ? [] : [' readonly files?: string']), ...lists]
|
|
|
440
436
|
|
|
441
437
|
const wants = shape.includes('Condition')
|
|
442
438
|
|
|
443
|
-
return `import type { Threaded } from '
|
|
439
|
+
return `import type { Threaded } from '${SHAPED}'${wants ? `\nimport type { Condition } from '${NAMED}/core/condition'` : ''}
|
|
444
440
|
${shape}
|
|
445
441
|
export const ${node.id.toUpperCase()}: ${bespoke ? own : 'Threaded'} = {
|
|
446
442
|
id: ${quoted(node.id)},
|
|
@@ -449,7 +445,7 @@ export const ${node.id.toUpperCase()}: ${bespoke ? own : 'Threaded'} = {
|
|
|
449
445
|
version: 1,
|
|
450
446
|
${held.join('\n')}
|
|
451
447
|
}
|
|
452
|
-
|
|
448
|
+
`
|
|
453
449
|
}
|
|
454
450
|
|
|
455
451
|
const LISTS: readonly { readonly node: Node; readonly file: string; readonly rows?: readonly Row[] }[] = [
|
|
@@ -503,7 +499,7 @@ function sectioned(one: { readonly node: Node; readonly file: string; readonly r
|
|
|
503
499
|
})
|
|
504
500
|
}
|
|
505
501
|
|
|
506
|
-
const UI_SOURCE = `import type { Threaded } from '
|
|
502
|
+
const UI_SOURCE = `import type { Threaded } from '${SHAPED}'
|
|
507
503
|
|
|
508
504
|
export const UI: Threaded = {
|
|
509
505
|
${SEEDED.declares.split('\n').slice(1, -1).map((line) => line.slice(4)).join('\n')}
|
|
@@ -513,58 +509,6 @@ ${SEEDED.declares.split('\n').slice(1, -1).map((line) => line.slice(4)).join('\n
|
|
|
513
509
|
export const GENERATORS: readonly Threaded[] = []
|
|
514
510
|
`
|
|
515
511
|
|
|
516
|
-
const RETIRED = [
|
|
517
|
-
{
|
|
518
|
-
into: 'tokens.ts',
|
|
519
|
-
list: 'holds',
|
|
520
|
-
id: 'font',
|
|
521
|
-
why: 'a font is not a token — the fonts sheet holds faces, sizes and appearance directly, so there is no variable of this kind for a style guide to give a value to',
|
|
522
|
-
},
|
|
523
|
-
...(['sm', 'md', 'lg'] as const).map((one) => ({
|
|
524
|
-
into: 'styleguides.ts',
|
|
525
|
-
list: 'holds',
|
|
526
|
-
id: `icon-${one}`,
|
|
527
|
-
why: 'the style guide holds no icon size — `icons.ts` does, and it is the one place a symbol is measured. These rows and a constant inside the package were both claiming to decide it, and the constant was what anything actually drew at, so changing the row moved the CSS variable and left every icon the size it already was',
|
|
528
|
-
})),
|
|
529
|
-
...(['link', 'glyph', 'avatar', 'skeleton', 'spinner'] as const).map((one) => ({
|
|
530
|
-
into: 'variants.ts',
|
|
531
|
-
list: 'declares',
|
|
532
|
-
id: one,
|
|
533
|
-
why: `a variant sharing a word with the element that wears it — \`${one}\` was coined twice, once as the element and once as the look, with two different meanings. The framework's own rule refuses that, and an app made entirely by these commands failed its own descent on five words this package had shipped. Renamed to \`${one}-\` plus what distinguishes it`,
|
|
534
|
-
})),
|
|
535
|
-
|
|
536
|
-
...(['icon', 'icon-ghost', 'icon-border', 'label-icon', 'elevated'] as const).map((one) => ({
|
|
537
|
-
into: 'variants.ts',
|
|
538
|
-
list: 'declares',
|
|
539
|
-
id: `button-${one}`,
|
|
540
|
-
why: 'a variant may not decide what a button CONTAINS — a symbol, a word or both is the composition\'s to arrange, and four variants existed only to answer it. `button-ghost`, `button-fill` and the rest each serve every shape of content. `button-elevated` is withdrawn as simply poor',
|
|
541
|
-
})),
|
|
542
|
-
...(['filled', 'outlined', 'plain'] as const).map((one) => ({
|
|
543
|
-
into: 'materials.ts',
|
|
544
|
-
list: 'declares',
|
|
545
|
-
id: one,
|
|
546
|
-
why: 'not a material — a background, an ink and a border width are three style guide rows, and wrapping them in a material only added a second place to look. A material is for what composes into one appearance worth naming: glass, a real relief, a glaze. The variants that wore these now name the rows directly',
|
|
547
|
-
})),
|
|
548
|
-
...(['primary', 'secondary'] as const).map((one) => ({
|
|
549
|
-
into: 'variants.ts',
|
|
550
|
-
list: 'declares',
|
|
551
|
-
id: `button-${one}`,
|
|
552
|
-
why: 'a second name for something the button family already carries — `button-primary` is `button-fill` and `button-secondary` is `button-border`. Two names for one look is the defect this framework refuses everywhere else, and it was shipping it in the one place an app looks first',
|
|
553
|
-
})),
|
|
554
|
-
...(['sans', 'serif', 'mono', 'display'] as const).map((one) => ({
|
|
555
|
-
into: 'styleguides.ts',
|
|
556
|
-
list: 'holds',
|
|
557
|
-
id: `font-${one}`,
|
|
558
|
-
why: 'the style guide holds no font — a font is not a token value, and the fonts sheet is the source for faces',
|
|
559
|
-
})),
|
|
560
|
-
...(['display', 'heading', 'body', 'label'] as const).map((one) => ({
|
|
561
|
-
into: 'variants.ts',
|
|
562
|
-
list: 'declares',
|
|
563
|
-
id: one,
|
|
564
|
-
why: 'a type role, not a variant — it set a face, a size and a weight, all of which the fonts sheet now decides',
|
|
565
|
-
})),
|
|
566
|
-
]
|
|
567
|
-
|
|
568
512
|
export const ATTACH: Attaching = {
|
|
569
513
|
attaches: SEEDED.attaches,
|
|
570
514
|
id: SEEDED.id,
|
|
@@ -595,7 +539,6 @@ export const ATTACH: Attaching = {
|
|
|
595
539
|
...LISTS.flatMap((one) => sectioned(one)),
|
|
596
540
|
...SHIPPED,
|
|
597
541
|
],
|
|
598
|
-
retires: RETIRED,
|
|
599
542
|
declares: SEEDED.declares,
|
|
600
543
|
writes: [
|
|
601
544
|
{ file: 'ui.ts', source: UI_SOURCE },
|
package/dist/ui/charts.d.ts
CHANGED
|
@@ -12,9 +12,6 @@ export declare const str: (row: Row, key: string) => string;
|
|
|
12
12
|
export declare function useRamp(count: number): readonly string[];
|
|
13
13
|
export declare function placed(element: string, place: string): string;
|
|
14
14
|
export declare function measured(held: Readonly<Record<string, string | number>>): Record<string, string | number>;
|
|
15
|
-
export declare function EmptyFrame({ className }: {
|
|
16
|
-
className?: string;
|
|
17
|
-
}): React.ReactElement;
|
|
18
15
|
export interface SeriesProps extends ChartBase {
|
|
19
16
|
readonly value: string;
|
|
20
17
|
readonly at: string;
|
package/dist/ui/charts.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useUi } from "./wrappers.js";
|
|
2
|
+
import { seriesRamp } from './series.js';
|
|
3
|
+
import { classOfElement } from './variant.js';
|
|
4
|
+
import { useUi } from './wrappers.js';
|
|
6
5
|
export const num = (row, key) => {
|
|
7
6
|
const v = row[key];
|
|
8
7
|
return typeof v === 'number' ? v : Number(v ?? 0);
|
|
@@ -21,9 +20,6 @@ export function measured(held) {
|
|
|
21
20
|
out[`--${name}`] = value;
|
|
22
21
|
return out;
|
|
23
22
|
}
|
|
24
|
-
export function EmptyFrame({ className }) {
|
|
25
|
-
return _jsx("div", { className: className, "data-empty": "true" });
|
|
26
|
-
}
|
|
27
23
|
export function polyline(values, width, height) {
|
|
28
24
|
if (values.length === 0)
|
|
29
25
|
return '';
|
package/dist/ui/charts.tsx
CHANGED
|
@@ -41,10 +41,6 @@ export function measured(held: Readonly<Record<string, string | number>>): Recor
|
|
|
41
41
|
return out
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export function EmptyFrame({ className }: { className?: string }): React.ReactElement {
|
|
45
|
-
return <div className={className} data-empty="true" />
|
|
46
|
-
}
|
|
47
|
-
|
|
48
44
|
export interface SeriesProps extends ChartBase {
|
|
49
45
|
readonly value: string
|
|
50
46
|
readonly at: string
|
package/dist/ui/checked.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type VariantsFor<E extends string> = Shipped extends infer One ? One exte
|
|
|
11
11
|
} ? E extends One['wears'][number] ? Camel<One['id']> : never : never : never;
|
|
12
12
|
type Pascal<S extends string> = S extends `${infer Head}-${infer Rest}` ? `${Capitalize<Head>}${Pascal<Rest>}` : Capitalize<S>;
|
|
13
13
|
type Camel<S extends string> = S extends `${infer Head}-${infer Rest}` ? `${Head}${Pascal<Rest>}` : S;
|
|
14
|
-
export type ArrangementElement = (typeof ELEMENTS)['
|
|
14
|
+
export type ArrangementElement = (typeof ELEMENTS)['derives'][number] extends infer One ? One extends {
|
|
15
15
|
readonly arranges: true;
|
|
16
16
|
readonly id: infer Id extends string;
|
|
17
17
|
} ? Pascal<Id> : never : never;
|
package/dist/ui/checked.ts
CHANGED
|
@@ -21,7 +21,7 @@ type Pascal<S extends string> = S extends `${infer Head}-${infer Rest}`
|
|
|
21
21
|
|
|
22
22
|
type Camel<S extends string> = S extends `${infer Head}-${infer Rest}` ? `${Head}${Pascal<Rest>}` : S
|
|
23
23
|
|
|
24
|
-
export type ArrangementElement = (typeof ELEMENTS)['
|
|
24
|
+
export type ArrangementElement = (typeof ELEMENTS)['derives'][number] extends infer One
|
|
25
25
|
? One extends { readonly arranges: true; readonly id: infer Id extends string }
|
|
26
26
|
? Pascal<Id>
|
|
27
27
|
: never
|
package/dist/ui/collector.js
CHANGED
|
@@ -23,7 +23,7 @@ export function createCollector(options) {
|
|
|
23
23
|
const body = JSON.stringify({ events: batch });
|
|
24
24
|
if (options.beacon !== undefined && options.beacon(options.endpoint, body))
|
|
25
25
|
return;
|
|
26
|
-
const doFetch = options.fetch
|
|
26
|
+
const doFetch = options.fetch;
|
|
27
27
|
if (doFetch === undefined) {
|
|
28
28
|
dropped += batch.length;
|
|
29
29
|
return;
|
package/dist/ui/collector.ts
CHANGED
|
@@ -82,7 +82,7 @@ export function createCollector(options: CollectorOptions): Collector {
|
|
|
82
82
|
|
|
83
83
|
if (options.beacon !== undefined && options.beacon(options.endpoint, body)) return
|
|
84
84
|
|
|
85
|
-
const doFetch = options.fetch
|
|
85
|
+
const doFetch = options.fetch
|
|
86
86
|
if (doFetch === undefined) {
|
|
87
87
|
dropped += batch.length
|
|
88
88
|
return
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import type { Threaded } from '@prestack/thread/core/thread';
|
|
2
2
|
import type { Tree } from '@prestack/thread/core/tree';
|
|
3
|
-
export declare const TEACHES: readonly string[];
|
|
4
3
|
export declare const REACHES: RegExp;
|
|
5
4
|
export declare const declares: readonly Threaded[];
|
|
6
5
|
export declare const COMPOSITIONS: Threaded & {
|
|
7
6
|
readonly files: string;
|
|
8
7
|
};
|
|
8
|
+
export declare const PASCAL: (id: string) => string;
|
|
9
9
|
export declare function nameOf(at: string): string;
|
|
10
|
-
export
|
|
11
|
-
|
|
10
|
+
export type Listed = {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly at?: string;
|
|
13
|
+
readonly describes?: string;
|
|
14
|
+
readonly wears?: readonly string[];
|
|
15
|
+
readonly arranges?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function sheetOf(tree: Tree, file: string, ...named: readonly string[]): readonly Listed[];
|
|
12
18
|
export declare function composed(body: string, rows: readonly {
|
|
13
19
|
readonly id: string;
|
|
14
20
|
readonly at?: string;
|
package/dist/ui/compositions.js
CHANGED
|
@@ -1,97 +1,11 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from '@prestack/thread/integrations/disk';
|
|
2
2
|
import { basename, dirname, join, relative } from 'node:path';
|
|
3
3
|
import { argv, stdout } from 'node:process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { compiled } from "./generators/react.js";
|
|
10
|
-
export const TEACHES = [
|
|
11
|
-
' what the body may reach, and how a premium state is written:',
|
|
12
|
-
'',
|
|
13
|
-
' `useUi()` is the door. It carries `actor` — who is asking, with the roles read from',
|
|
14
|
-
' the row that declared itself the caller — and `translate`, `clock` and `dispatch`. Name',
|
|
15
|
-
' it in the body and the import is written for you.',
|
|
16
|
-
'',
|
|
17
|
-
' A premium look is not decided at the call site. A grant already says who may run an',
|
|
18
|
-
' operation, in words your own entity declares, and a signal that names that operation',
|
|
19
|
-
' holds for exactly the callers the grant refuses. The rule is written once, on the',
|
|
20
|
-
' grant, and every screen follows it:',
|
|
21
|
-
'',
|
|
22
|
-
' <FeatureBox.paywalled>',
|
|
23
|
-
' <Text k=\'feature.title\' />',
|
|
24
|
-
' </FeatureBox.paywalled>',
|
|
25
|
-
'',
|
|
26
|
-
' Read it in three parts, and each is its own command:',
|
|
27
|
-
'',
|
|
28
|
-
' `locked` is a signal the ELEMENT declares it raises — `thread create element` with',
|
|
29
|
-
' `raises: locked`. A signal this app declares cannot be raised on an element that',
|
|
30
|
-
' never said it raises one, so `Box` will not take it. Nothing passes it here: it is',
|
|
31
|
-
' set for you wherever the gate refuses the operation the signal names.',
|
|
32
|
-
' `.paywalled` is a variant worn as the TAG, never passed as a prop, and it is what',
|
|
33
|
-
' carries the look — `thread create variant` with a `state: locked` and what it sets.',
|
|
34
|
-
' Declare that state on a MATERIAL instead and every variant made of it locks the same',
|
|
35
|
-
' way, which is how one overlay dresses a whole app from one row.',
|
|
36
|
-
' The rule itself is `thread grant`, and the words in it are options on the value your',
|
|
37
|
-
' entity names as saying what a caller may do — `thread create entity`.',
|
|
38
|
-
'',
|
|
39
|
-
' THE MEMBER IS THE VARIANT\'S WHOLE ID, CAMELCASED — never the part after the element',
|
|
40
|
-
' name. A variant `button-fill` is worn `<Button.buttonFill>`, and `<Button.fill>` is not',
|
|
41
|
-
' a thing. `.paywalled` above reads short only because that variant is itself named',
|
|
42
|
-
' `paywalled`; most carry the element in their id and wear all of it.',
|
|
43
|
-
'',
|
|
44
|
-
' how a control reaches an operation:',
|
|
45
|
-
'',
|
|
46
|
-
' Wiring is imperative. There is no `run=`, `operation=` or `dispatch=` prop on any',
|
|
47
|
-
' element, and the compiler is what will tell you so. A control calls dispatch in its own',
|
|
48
|
-
' handler:',
|
|
49
|
-
'',
|
|
50
|
-
' <Button.buttonFill label=\'common.save\'',
|
|
51
|
-
' onPress={() => useUi().dispatch?.(\'wf_save\')} />',
|
|
52
|
-
'',
|
|
53
|
-
' `dispatch` is optional on the hook, so `?.` is required — without it the compiler says',
|
|
54
|
-
' "Cannot invoke an object which is possibly \'undefined\'". The name is the operation\'s own',
|
|
55
|
-
' id from `thread create operation`, and one this app never declared is refused before it',
|
|
56
|
-
' runs. An operation whose `to:` named nobody is refused however the button looks — and',
|
|
57
|
-
' `to:` takes roles off an entity, which is a noun that arrives with `thread attach',
|
|
58
|
-
` ${packageOf('data')}\`.`,
|
|
59
|
-
'',
|
|
60
|
-
' Nothing here decides access. The gate still refuses the operation behind the lock',
|
|
61
|
-
' whatever the screen shows, so a screen that got this wrong shows the wrong thing and',
|
|
62
|
-
' still cannot do the wrong thing.',
|
|
63
|
-
'',
|
|
64
|
-
' how a press moves to another screen:',
|
|
65
|
-
'',
|
|
66
|
-
' Name the screen. `navigateTo` takes the screen\'s export name — its id in PascalCase, so',
|
|
67
|
-
' `order-detail` is reached as `navigateTo="OrderDetail"`:',
|
|
68
|
-
'',
|
|
69
|
-
' <Button.buttonNormal label=\'home.orders\' navigateTo="Orders" />',
|
|
70
|
-
'',
|
|
71
|
-
' That is the whole of it. `thread routes` reads every `navigateTo` the screens and their',
|
|
72
|
-
' compositions hold and writes the map — from which screen, through which button, to which',
|
|
73
|
-
' screen — and the pages. A page is reached by its route, and a sheet, popover, overlay or',
|
|
74
|
-
' toast opens where somebody already is, so the press is written the same way for both.',
|
|
75
|
-
' A name no screen has and a destination not written out as a name are each refused there.',
|
|
76
|
-
' Never an `href` and never',
|
|
77
|
-
' a router: a move the map cannot see is a screen the map reads as unreachable.',
|
|
78
|
-
'',
|
|
79
|
-
' how a screen shows data:',
|
|
80
|
-
'',
|
|
81
|
-
' A screen NAMES the reads it binds, and never fetches. `views` takes the ids of declared',
|
|
82
|
-
' views, the framework runs each one, and `useView` hands back what came out:',
|
|
83
|
-
'',
|
|
84
|
-
' export const Orders = screen(\'orders\', { as: \'page\', views: [\'vw_orders\'] }, () => (',
|
|
85
|
-
' <Each rows={useView<readonly Row[]>(\'vw_orders\') ?? []} by="id">',
|
|
86
|
-
' {(row) => <Text k="orders.line" with={{ name: row.name }} />}',
|
|
87
|
-
' </Each>',
|
|
88
|
-
' ))',
|
|
89
|
-
'',
|
|
90
|
-
' `useView` comes through the same door as `useUi`, and it refuses a name the screen did not',
|
|
91
|
-
' bind. `thread routes` refuses a view this app declares no operation for, and writes what each',
|
|
92
|
-
' screen shows into the map. A fetch of your own, or a hook you wrote, is how a screen ends up',
|
|
93
|
-
' showing something nothing declared, and there is no second way in.',
|
|
94
|
-
];
|
|
4
|
+
import { exit, invoked } from '@prestack/thread/core/invoked';
|
|
5
|
+
import { valuesIn } from '@prestack/thread/core/rows';
|
|
6
|
+
import { named as packageOf } from '@prestack/thread/core/scope';
|
|
7
|
+
import { findTree, inTree } from '@prestack/thread/core/tree';
|
|
8
|
+
import { compiled } from './generators/react.js';
|
|
95
9
|
export const REACHES = /\buseUi\s*\(/;
|
|
96
10
|
const here = 'thread/ui/compositions.ts';
|
|
97
11
|
const said = [
|
|
@@ -118,7 +32,7 @@ export const COMPOSITIONS = {
|
|
|
118
32
|
cites: said,
|
|
119
33
|
declares,
|
|
120
34
|
};
|
|
121
|
-
const PASCAL = (id) => id
|
|
35
|
+
export const PASCAL = (id) => id
|
|
122
36
|
.split('-')
|
|
123
37
|
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
124
38
|
.join('');
|
|
@@ -126,81 +40,18 @@ export function nameOf(at) {
|
|
|
126
40
|
const file = at.split('\\').join('/').split('/').at(-1) ?? at;
|
|
127
41
|
return PASCAL(file.replace(/^cmp_/, '').replace(/\.[^.]+$/, ''));
|
|
128
42
|
}
|
|
129
|
-
function sheetOf(tree, file, ...named) {
|
|
43
|
+
export function sheetOf(tree, file, ...named) {
|
|
130
44
|
const at = inTree(tree, file);
|
|
131
45
|
if (!existsSync(at))
|
|
132
46
|
return [];
|
|
133
47
|
const held = valuesIn(readFileSync(at));
|
|
134
48
|
for (const one of named) {
|
|
135
|
-
const found = held[one]?.declares;
|
|
49
|
+
const found = held[one]?.derives ?? held[one]?.declares;
|
|
136
50
|
if (found !== undefined)
|
|
137
51
|
return found;
|
|
138
52
|
}
|
|
139
53
|
return [];
|
|
140
54
|
}
|
|
141
|
-
const camelOf = (id) => id.replace(/-([a-z0-9])/g, (_, one) => one.toUpperCase());
|
|
142
|
-
const sentence = (one, pad) => String(one.describes ?? '').trim() === '' ? [] : wrapped(String(one.describes), pad);
|
|
143
|
-
function listed(tree, making) {
|
|
144
|
-
const elements = sheetOf(tree, `elements.${'ts'}`, 'ELEMENT', 'ELEMENTS');
|
|
145
|
-
const variants = sheetOf(tree, `variants.${'ts'}`, 'VARIANT', 'VARIANTS');
|
|
146
|
-
const compositions = sheetOf(tree, `compositions.${'ts'}`, 'COMPOSITION', 'COMPOSITIONS');
|
|
147
|
-
const screens = making === 'screen' ? sheetOf(tree, `screens.${'ts'}`, 'SCREEN', 'SCREENS') : [];
|
|
148
|
-
const worn = new Map();
|
|
149
|
-
for (const one of variants) {
|
|
150
|
-
for (const each of one.wears ?? []) {
|
|
151
|
-
const key = PASCAL(each);
|
|
152
|
-
const already = worn.get(key) ?? [];
|
|
153
|
-
if (!already.includes(one.id))
|
|
154
|
-
worn.set(key, [...already, one.id]);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const writes = (one) => {
|
|
158
|
-
const name = PASCAL(one.id);
|
|
159
|
-
const members = (worn.get(name) ?? []).sort().map((each) => `<${name}.${camelOf(each)}>`);
|
|
160
|
-
if (members.length === 0)
|
|
161
|
-
return `<${name}>`;
|
|
162
|
-
return one.arranges === true ? `<${name}>, or ${members.join(' ')}` : members.join(' ');
|
|
163
|
-
};
|
|
164
|
-
const section = (title, rows, write) => rows.length === 0
|
|
165
|
-
? [` ${title}: none yet.`, '']
|
|
166
|
-
: [
|
|
167
|
-
` ${title} (${String(rows.length)}):`,
|
|
168
|
-
...rows.flatMap((one) => [` ${write(one)}`, ...sentence(one, ' ')]),
|
|
169
|
-
'',
|
|
170
|
-
];
|
|
171
|
-
return [
|
|
172
|
-
'',
|
|
173
|
-
...(making === 'screen'
|
|
174
|
-
? section('SCREENS that exist, and the name a press reaches each one by', screens, (one) => `${one.id} — navigateTo="${PASCAL(one.id)}"`)
|
|
175
|
-
: []),
|
|
176
|
-
...section('COMPOSITIONS you can place', compositions, (one) => `<${typeof one.at === 'string' && one.at !== '' ? nameOf(one.at) : PASCAL(one.id)}>`),
|
|
177
|
-
...section('ELEMENTS, written as the tags they can actually be typed as', elements, writes),
|
|
178
|
-
...(variants.length === 0
|
|
179
|
-
? [' VARIANTS: none yet.', '']
|
|
180
|
-
: [
|
|
181
|
-
` VARIANTS (${String(variants.length)}), under the elements that accept them:`,
|
|
182
|
-
...[...worn.keys()].sort().map((name) => ` ${name} — ${(worn.get(name) ?? []).sort().map(camelOf).join(', ')}`),
|
|
183
|
-
...(() => {
|
|
184
|
-
const nobody = variants.filter((one) => (one.wears ?? []).length === 0).map((one) => one.id);
|
|
185
|
-
return nobody.length === 0
|
|
186
|
-
? []
|
|
187
|
-
: [` worn by nothing, so writable nowhere: ${nobody.sort().join(', ')}`];
|
|
188
|
-
})(),
|
|
189
|
-
'',
|
|
190
|
-
]),
|
|
191
|
-
' Materials, style guide values, fonts and animations are chosen inside a VARIANT, never inside',
|
|
192
|
-
` a body — \`${TYPED} create variant\` prints every one of them at the moment one is needed.`,
|
|
193
|
-
'',
|
|
194
|
-
` Every element and the tags it is written as: \`${TYPED} create element\`. Every variant and`,
|
|
195
|
-
` the tag it is worn as: \`${TYPED} create variant\`. Then open the one nearest to what you are`,
|
|
196
|
-
` about to build with \`${TYPED} read <id>\` — it already answers how a body is arranged, how a`,
|
|
197
|
-
' variant is worn and how a control reaches an operation, and a file cannot be wrong in the way',
|
|
198
|
-
' a remembered example can.',
|
|
199
|
-
'',
|
|
200
|
-
];
|
|
201
|
-
}
|
|
202
|
-
export const catalogue = async () => listed(findTree(), 'composition');
|
|
203
|
-
export const screening = async () => listed(findTree(), 'screen');
|
|
204
55
|
const TAG = /<([A-Z][A-Za-z0-9]*)/g;
|
|
205
56
|
export function composed(body, rows, from, except) {
|
|
206
57
|
const named = new Map();
|