@prestack/thread-ui 0.0.1
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 +348 -0
- package/dist/attach.d.ts +1 -0
- package/dist/attach.js +1 -0
- package/dist/ui/animations/anm_appear.d.ts +16 -0
- package/dist/ui/animations/anm_appear.js +10 -0
- package/dist/ui/animations/anm_blur_in.d.ts +22 -0
- package/dist/ui/animations/anm_blur_in.js +16 -0
- package/dist/ui/animations/anm_blur_out.d.ts +22 -0
- package/dist/ui/animations/anm_blur_out.js +16 -0
- package/dist/ui/animations/anm_dismiss.d.ts +22 -0
- package/dist/ui/animations/anm_dismiss.js +16 -0
- package/dist/ui/animations/anm_drop.d.ts +22 -0
- package/dist/ui/animations/anm_drop.js +16 -0
- package/dist/ui/animations/anm_fall.d.ts +22 -0
- package/dist/ui/animations/anm_fall.js +16 -0
- package/dist/ui/animations/anm_flash.d.ts +19 -0
- package/dist/ui/animations/anm_flash.js +16 -0
- package/dist/ui/animations/anm_glow.d.ts +16 -0
- package/dist/ui/animations/anm_glow.js +14 -0
- package/dist/ui/animations/anm_lift.d.ts +16 -0
- package/dist/ui/animations/anm_lift.js +14 -0
- package/dist/ui/animations/anm_nudge.d.ts +16 -0
- package/dist/ui/animations/anm_nudge.js +14 -0
- package/dist/ui/animations/anm_pop_in.d.ts +29 -0
- package/dist/ui/animations/anm_pop_in.js +20 -0
- package/dist/ui/animations/anm_pop_out.d.ts +29 -0
- package/dist/ui/animations/anm_pop_out.js +20 -0
- package/dist/ui/animations/anm_press.d.ts +19 -0
- package/dist/ui/animations/anm_press.js +10 -0
- package/dist/ui/animations/anm_pulse.d.ts +20 -0
- package/dist/ui/animations/anm_pulse.js +11 -0
- package/dist/ui/animations/anm_rise.d.ts +22 -0
- package/dist/ui/animations/anm_rise.js +16 -0
- package/dist/ui/animations/anm_shake.d.ts +23 -0
- package/dist/ui/animations/anm_shake.js +11 -0
- package/dist/ui/animations/anm_slide_in_left.d.ts +22 -0
- package/dist/ui/animations/anm_slide_in_left.js +16 -0
- package/dist/ui/animations/anm_slide_in_right.d.ts +22 -0
- package/dist/ui/animations/anm_slide_in_right.js +16 -0
- package/dist/ui/animations/anm_slide_out_left.d.ts +22 -0
- package/dist/ui/animations/anm_slide_out_left.js +16 -0
- package/dist/ui/animations/anm_slide_out_right.d.ts +22 -0
- package/dist/ui/animations/anm_slide_out_right.js +16 -0
- package/dist/ui/animations/anm_spin.d.ts +16 -0
- package/dist/ui/animations/anm_spin.js +10 -0
- package/dist/ui/animations/anm_swell.d.ts +16 -0
- package/dist/ui/animations/anm_swell.js +14 -0
- package/dist/ui/animations/anm_wobble.d.ts +27 -0
- package/dist/ui/animations/anm_wobble.js +22 -0
- package/dist/ui/animations/anm_zoom_in.d.ts +22 -0
- package/dist/ui/animations/anm_zoom_in.js +16 -0
- package/dist/ui/animations/anm_zoom_out.d.ts +22 -0
- package/dist/ui/animations/anm_zoom_out.js +16 -0
- package/dist/ui/animations.d.ts +59 -0
- package/dist/ui/animations.js +227 -0
- package/dist/ui/attach.d.ts +3 -0
- package/dist/ui/attach.js +497 -0
- package/dist/ui/charts.d.ts +32 -0
- package/dist/ui/charts.js +35 -0
- package/dist/ui/checked.d.ts +19 -0
- package/dist/ui/checked.js +3 -0
- package/dist/ui/collector.d.ts +32 -0
- package/dist/ui/collector.js +75 -0
- package/dist/ui/compositions.d.ts +21 -0
- package/dist/ui/compositions.js +305 -0
- package/dist/ui/consent.d.ts +22 -0
- package/dist/ui/consent.js +44 -0
- package/dist/ui/content.d.ts +9 -0
- package/dist/ui/content.js +11 -0
- package/dist/ui/contrast.d.ts +3 -0
- package/dist/ui/contrast.js +23 -0
- package/dist/ui/controls.d.ts +14 -0
- package/dist/ui/controls.js +2 -0
- package/dist/ui/disclosure.d.ts +14 -0
- package/dist/ui/disclosure.js +2 -0
- package/dist/ui/dismiss-layer.d.ts +14 -0
- package/dist/ui/dismiss-layer.js +66 -0
- package/dist/ui/door.d.ts +40 -0
- package/dist/ui/door.js +100 -0
- package/dist/ui/drag.d.ts +82 -0
- package/dist/ui/drag.js +212 -0
- package/dist/ui/elements/accordion.d.ts +12 -0
- package/dist/ui/elements/accordion.js +16 -0
- package/dist/ui/elements/accordion.works.d.ts +22 -0
- package/dist/ui/elements/accordion.works.js +44 -0
- package/dist/ui/elements/aspect-ratio.d.ts +10 -0
- package/dist/ui/elements/aspect-ratio.js +9 -0
- package/dist/ui/elements/aspect-ratio.works.d.ts +2 -0
- package/dist/ui/elements/aspect-ratio.works.js +3 -0
- package/dist/ui/elements/avatar.d.ts +11 -0
- package/dist/ui/elements/avatar.js +10 -0
- package/dist/ui/elements/avatar.works.d.ts +4 -0
- package/dist/ui/elements/avatar.works.js +16 -0
- package/dist/ui/elements/badge.d.ts +11 -0
- package/dist/ui/elements/badge.js +10 -0
- package/dist/ui/elements/badge.works.d.ts +5 -0
- package/dist/ui/elements/badge.works.js +6 -0
- package/dist/ui/elements/bars.d.ts +14 -0
- package/dist/ui/elements/bars.js +17 -0
- package/dist/ui/elements/bars.works.d.ts +12 -0
- package/dist/ui/elements/bars.works.js +20 -0
- package/dist/ui/elements/box.d.ts +12 -0
- package/dist/ui/elements/box.js +11 -0
- package/dist/ui/elements/breadcrumb.d.ts +10 -0
- package/dist/ui/elements/breadcrumb.js +12 -0
- package/dist/ui/elements/breadcrumb.works.d.ts +7 -0
- package/dist/ui/elements/breadcrumb.works.js +21 -0
- package/dist/ui/elements/button.d.ts +17 -0
- package/dist/ui/elements/button.js +16 -0
- package/dist/ui/elements/button.works.d.ts +17 -0
- package/dist/ui/elements/button.works.js +34 -0
- package/dist/ui/elements/column.d.ts +9 -0
- package/dist/ui/elements/column.js +8 -0
- package/dist/ui/elements/consent.d.ts +13 -0
- package/dist/ui/elements/consent.js +21 -0
- package/dist/ui/elements/consent.works.d.ts +41 -0
- package/dist/ui/elements/consent.works.js +79 -0
- package/dist/ui/elements/donut.d.ts +13 -0
- package/dist/ui/elements/donut.js +16 -0
- package/dist/ui/elements/donut.works.d.ts +11 -0
- package/dist/ui/elements/donut.works.js +28 -0
- package/dist/ui/elements/each.d.ts +14 -0
- package/dist/ui/elements/each.js +9 -0
- package/dist/ui/elements/each.works.d.ts +3 -0
- package/dist/ui/elements/each.works.js +68 -0
- package/dist/ui/elements/empty.d.ts +9 -0
- package/dist/ui/elements/empty.js +12 -0
- package/dist/ui/elements/field.d.ts +16 -0
- package/dist/ui/elements/field.js +15 -0
- package/dist/ui/elements/field.works.d.ts +17 -0
- package/dist/ui/elements/field.works.js +45 -0
- package/dist/ui/elements/funnel.d.ts +14 -0
- package/dist/ui/elements/funnel.js +17 -0
- package/dist/ui/elements/funnel.works.d.ts +12 -0
- package/dist/ui/elements/funnel.works.js +23 -0
- package/dist/ui/elements/gauge.d.ts +12 -0
- package/dist/ui/elements/gauge.js +15 -0
- package/dist/ui/elements/gauge.works.d.ts +11 -0
- package/dist/ui/elements/gauge.works.js +31 -0
- package/dist/ui/elements/glyph.d.ts +10 -0
- package/dist/ui/elements/glyph.js +9 -0
- package/dist/ui/elements/glyph.works.d.ts +5 -0
- package/dist/ui/elements/glyph.works.js +16 -0
- package/dist/ui/elements/grid.d.ts +9 -0
- package/dist/ui/elements/grid.js +8 -0
- package/dist/ui/elements/heatmap.d.ts +15 -0
- package/dist/ui/elements/heatmap.js +17 -0
- package/dist/ui/elements/heatmap.works.d.ts +11 -0
- package/dist/ui/elements/heatmap.works.js +11 -0
- package/dist/ui/elements/hit-box.d.ts +19 -0
- package/dist/ui/elements/hit-box.js +15 -0
- package/dist/ui/elements/hit-box.works.d.ts +87 -0
- package/dist/ui/elements/hit-box.works.js +451 -0
- package/dist/ui/elements/image.d.ts +10 -0
- package/dist/ui/elements/image.js +9 -0
- package/dist/ui/elements/line-chart.d.ts +13 -0
- package/dist/ui/elements/line-chart.js +16 -0
- package/dist/ui/elements/line-chart.works.d.ts +12 -0
- package/dist/ui/elements/line-chart.works.js +27 -0
- package/dist/ui/elements/link.d.ts +12 -0
- package/dist/ui/elements/link.js +15 -0
- package/dist/ui/elements/link.works.d.ts +10 -0
- package/dist/ui/elements/link.works.js +15 -0
- package/dist/ui/elements/media.d.ts +11 -0
- package/dist/ui/elements/media.js +22 -0
- package/dist/ui/elements/menu.d.ts +12 -0
- package/dist/ui/elements/menu.js +18 -0
- package/dist/ui/elements/menu.works.d.ts +50 -0
- package/dist/ui/elements/menu.works.js +100 -0
- package/dist/ui/elements/money.d.ts +10 -0
- package/dist/ui/elements/money.js +9 -0
- package/dist/ui/elements/money.works.d.ts +4 -0
- package/dist/ui/elements/money.works.js +4 -0
- package/dist/ui/elements/pagination.d.ts +11 -0
- package/dist/ui/elements/pagination.js +12 -0
- package/dist/ui/elements/pagination.works.d.ts +5 -0
- package/dist/ui/elements/pagination.works.js +15 -0
- package/dist/ui/elements/progress.d.ts +11 -0
- package/dist/ui/elements/progress.js +11 -0
- package/dist/ui/elements/progress.works.d.ts +2 -0
- package/dist/ui/elements/progress.works.js +6 -0
- package/dist/ui/elements/radio-group.d.ts +15 -0
- package/dist/ui/elements/radio-group.js +16 -0
- package/dist/ui/elements/radio-group.works.d.ts +10 -0
- package/dist/ui/elements/radio-group.works.js +22 -0
- package/dist/ui/elements/row.d.ts +9 -0
- package/dist/ui/elements/row.js +8 -0
- package/dist/ui/elements/scatter.d.ts +13 -0
- package/dist/ui/elements/scatter.js +15 -0
- package/dist/ui/elements/scatter.works.d.ts +11 -0
- package/dist/ui/elements/scatter.works.js +24 -0
- package/dist/ui/elements/select.d.ts +13 -0
- package/dist/ui/elements/select.js +11 -0
- package/dist/ui/elements/select.works.d.ts +4 -0
- package/dist/ui/elements/select.works.js +3 -0
- package/dist/ui/elements/separator.d.ts +10 -0
- package/dist/ui/elements/separator.js +9 -0
- package/dist/ui/elements/skeleton.d.ts +8 -0
- package/dist/ui/elements/skeleton.js +9 -0
- package/dist/ui/elements/slider.d.ts +14 -0
- package/dist/ui/elements/slider.js +10 -0
- package/dist/ui/elements/slider.works.d.ts +4 -0
- package/dist/ui/elements/slider.works.js +3 -0
- package/dist/ui/elements/sparkline.d.ts +10 -0
- package/dist/ui/elements/sparkline.js +15 -0
- package/dist/ui/elements/sparkline.works.d.ts +10 -0
- package/dist/ui/elements/sparkline.works.js +19 -0
- package/dist/ui/elements/spinner.d.ts +9 -0
- package/dist/ui/elements/spinner.js +12 -0
- package/dist/ui/elements/stack.d.ts +9 -0
- package/dist/ui/elements/stack.js +8 -0
- package/dist/ui/elements/stat.d.ts +12 -0
- package/dist/ui/elements/stat.js +10 -0
- package/dist/ui/elements/stat.works.d.ts +3 -0
- package/dist/ui/elements/stat.works.js +10 -0
- package/dist/ui/elements/surface.d.ts +9 -0
- package/dist/ui/elements/surface.js +15 -0
- package/dist/ui/elements/surface.works.d.ts +7 -0
- package/dist/ui/elements/surface.works.js +4 -0
- package/dist/ui/elements/table.d.ts +13 -0
- package/dist/ui/elements/table.js +16 -0
- package/dist/ui/elements/table.works.d.ts +11 -0
- package/dist/ui/elements/table.works.js +15 -0
- package/dist/ui/elements/tabs.d.ts +12 -0
- package/dist/ui/elements/tabs.js +16 -0
- package/dist/ui/elements/tabs.works.d.ts +25 -0
- package/dist/ui/elements/tabs.works.js +53 -0
- package/dist/ui/elements/text.d.ts +13 -0
- package/dist/ui/elements/text.js +9 -0
- package/dist/ui/elements/textarea.d.ts +14 -0
- package/dist/ui/elements/textarea.js +11 -0
- package/dist/ui/elements/textarea.works.d.ts +4 -0
- package/dist/ui/elements/textarea.works.js +3 -0
- package/dist/ui/elements/time.d.ts +11 -0
- package/dist/ui/elements/time.js +14 -0
- package/dist/ui/elements/time.works.d.ts +11 -0
- package/dist/ui/elements/time.works.js +16 -0
- package/dist/ui/elements/toggle.d.ts +11 -0
- package/dist/ui/elements/toggle.js +10 -0
- package/dist/ui/elements/toggle.works.d.ts +4 -0
- package/dist/ui/elements/toggle.works.js +3 -0
- package/dist/ui/elements/tooltip.d.ts +12 -0
- package/dist/ui/elements/tooltip.js +15 -0
- package/dist/ui/elements/tooltip.works.d.ts +28 -0
- package/dist/ui/elements/tooltip.works.js +54 -0
- package/dist/ui/elements/value.d.ts +12 -0
- package/dist/ui/elements/value.js +9 -0
- package/dist/ui/elements/value.works.d.ts +4 -0
- package/dist/ui/elements/value.works.js +4 -0
- package/dist/ui/elements.d.ts +1143 -0
- package/dist/ui/elements.js +68 -0
- package/dist/ui/focus-scope.d.ts +7 -0
- package/dist/ui/focus-scope.js +109 -0
- package/dist/ui/fonts.d.ts +103 -0
- package/dist/ui/fonts.js +243 -0
- package/dist/ui/generators/dev.d.ts +2 -0
- package/dist/ui/generators/dev.js +61 -0
- package/dist/ui/generators/elements.d.ts +31 -0
- package/dist/ui/generators/elements.js +520 -0
- package/dist/ui/generators/i18n.d.ts +5 -0
- package/dist/ui/generators/i18n.js +264 -0
- package/dist/ui/generators/icons.d.ts +1 -0
- package/dist/ui/generators/icons.js +187 -0
- package/dist/ui/generators/react.d.ts +26 -0
- package/dist/ui/generators/react.js +218 -0
- package/dist/ui/generators/routes.d.ts +11 -0
- package/dist/ui/generators/routes.js +597 -0
- package/dist/ui/generators/show.d.ts +1 -0
- package/dist/ui/generators/show.js +231 -0
- package/dist/ui/generators/styles.d.ts +1 -0
- package/dist/ui/generators/styles.js +502 -0
- package/dist/ui/generators/variants.d.ts +12 -0
- package/dist/ui/generators/variants.js +162 -0
- package/dist/ui/i18n/catalogs/en.d.ts +172 -0
- package/dist/ui/i18n/catalogs/en.js +148 -0
- package/dist/ui/i18n/format.d.ts +13 -0
- package/dist/ui/i18n/format.js +161 -0
- package/dist/ui/i18n/locales.d.ts +9 -0
- package/dist/ui/i18n/locales.js +20 -0
- package/dist/ui/i18n/parse.d.ts +45 -0
- package/dist/ui/i18n/parse.js +249 -0
- package/dist/ui/i18n/translator.d.ts +10 -0
- package/dist/ui/i18n/translator.js +22 -0
- package/dist/ui/i18n/types.d.ts +33 -0
- package/dist/ui/i18n/types.js +9 -0
- package/dist/ui/icons.d.ts +67 -0
- package/dist/ui/icons.js +249 -0
- package/dist/ui/islands/map.d.ts +33 -0
- package/dist/ui/islands/map.js +44 -0
- package/dist/ui/localizations.d.ts +33 -0
- package/dist/ui/localizations.js +51 -0
- package/dist/ui/makers/message.d.ts +1 -0
- package/dist/ui/makers/message.js +230 -0
- package/dist/ui/material.d.ts +83 -0
- package/dist/ui/material.js +95 -0
- package/dist/ui/materials/mat_bordered.d.ts +22 -0
- package/dist/ui/materials/mat_bordered.js +12 -0
- package/dist/ui/materials/mat_ceramic.d.ts +22 -0
- package/dist/ui/materials/mat_ceramic.js +12 -0
- package/dist/ui/materials/mat_clay.d.ts +22 -0
- package/dist/ui/materials/mat_clay.js +12 -0
- package/dist/ui/materials/mat_elevated.d.ts +32 -0
- package/dist/ui/materials/mat_elevated.js +23 -0
- package/dist/ui/materials/mat_flat.d.ts +50 -0
- package/dist/ui/materials/mat_flat.js +33 -0
- package/dist/ui/materials/mat_glass.d.ts +32 -0
- package/dist/ui/materials/mat_glass.js +19 -0
- package/dist/ui/materials/mat_lit.d.ts +22 -0
- package/dist/ui/materials/mat_lit.js +12 -0
- package/dist/ui/materials/mat_moulded.d.ts +16 -0
- package/dist/ui/materials/mat_moulded.js +10 -0
- package/dist/ui/materials.d.ts +56 -0
- package/dist/ui/materials.js +175 -0
- package/dist/ui/modes.d.ts +25 -0
- package/dist/ui/modes.js +25 -0
- package/dist/ui/navigation.d.ts +3 -0
- package/dist/ui/navigation.js +24 -0
- package/dist/ui/positioning.d.ts +24 -0
- package/dist/ui/positioning.js +48 -0
- package/dist/ui/presented.d.ts +10 -0
- package/dist/ui/presented.js +81 -0
- package/dist/ui/provider.d.ts +31 -0
- package/dist/ui/provider.js +104 -0
- package/dist/ui/render-loop.d.ts +12 -0
- package/dist/ui/render-loop.js +94 -0
- package/dist/ui/roving-focus.d.ts +15 -0
- package/dist/ui/roving-focus.js +143 -0
- package/dist/ui/screens.d.ts +17 -0
- package/dist/ui/screens.js +112 -0
- package/dist/ui/scroll-lock.d.ts +2 -0
- package/dist/ui/scroll-lock.js +24 -0
- package/dist/ui/series.d.ts +9 -0
- package/dist/ui/series.js +67 -0
- package/dist/ui/signals.d.ts +120 -0
- package/dist/ui/signals.js +286 -0
- package/dist/ui/styleguide.d.ts +27 -0
- package/dist/ui/styleguide.js +138 -0
- package/dist/ui/styleguides.d.ts +11 -0
- package/dist/ui/styleguides.js +299 -0
- package/dist/ui/themes.d.ts +5 -0
- package/dist/ui/themes.js +16 -0
- package/dist/ui/token.d.ts +16 -0
- package/dist/ui/token.js +37 -0
- package/dist/ui/tokens/shadow.d.ts +6 -0
- package/dist/ui/tokens/shadow.js +17 -0
- package/dist/ui/tokens.d.ts +180 -0
- package/dist/ui/tokens.js +200 -0
- package/dist/ui/validators.d.ts +37 -0
- package/dist/ui/validators.js +184 -0
- package/dist/ui/variant.d.ts +122 -0
- package/dist/ui/variant.js +201 -0
- package/dist/ui/variants/var_avatar-round.d.ts +23 -0
- package/dist/ui/variants/var_avatar-round.js +13 -0
- package/dist/ui/variants/var_bubble-me.d.ts +21 -0
- package/dist/ui/variants/var_bubble-me.js +13 -0
- package/dist/ui/variants/var_bubble-them.d.ts +18 -0
- package/dist/ui/variants/var_bubble-them.js +12 -0
- package/dist/ui/variants/var_button-border.d.ts +116 -0
- package/dist/ui/variants/var_button-border.js +75 -0
- package/dist/ui/variants/var_button-cta.d.ts +116 -0
- package/dist/ui/variants/var_button-cta.js +75 -0
- package/dist/ui/variants/var_button-destructive-ghost.d.ts +113 -0
- package/dist/ui/variants/var_button-destructive-ghost.js +71 -0
- package/dist/ui/variants/var_button-destructive.d.ts +116 -0
- package/dist/ui/variants/var_button-destructive.js +75 -0
- package/dist/ui/variants/var_button-fill.d.ts +116 -0
- package/dist/ui/variants/var_button-fill.js +75 -0
- package/dist/ui/variants/var_button-ghost.d.ts +113 -0
- package/dist/ui/variants/var_button-ghost.js +71 -0
- package/dist/ui/variants/var_button-glass.d.ts +84 -0
- package/dist/ui/variants/var_button-glass.js +54 -0
- package/dist/ui/variants/var_button-normal.d.ts +116 -0
- package/dist/ui/variants/var_button-normal.js +75 -0
- package/dist/ui/variants/var_button-quiet.d.ts +119 -0
- package/dist/ui/variants/var_button-quiet.js +73 -0
- package/dist/ui/variants/var_card.d.ts +30 -0
- package/dist/ui/variants/var_card.js +16 -0
- package/dist/ui/variants/var_chip.d.ts +18 -0
- package/dist/ui/variants/var_chip.js +12 -0
- package/dist/ui/variants/var_choice.d.ts +26 -0
- package/dist/ui/variants/var_choice.js +14 -0
- package/dist/ui/variants/var_framed.d.ts +11 -0
- package/dist/ui/variants/var_framed.js +9 -0
- package/dist/ui/variants/var_glyph-plain.d.ts +14 -0
- package/dist/ui/variants/var_glyph-plain.js +10 -0
- package/dist/ui/variants/var_input.d.ts +61 -0
- package/dist/ui/variants/var_input.js +42 -0
- package/dist/ui/variants/var_link-inline.d.ts +39 -0
- package/dist/ui/variants/var_link-inline.js +28 -0
- package/dist/ui/variants/var_list-row.d.ts +47 -0
- package/dist/ui/variants/var_list-row.js +33 -0
- package/dist/ui/variants/var_rule.d.ts +11 -0
- package/dist/ui/variants/var_rule.js +9 -0
- package/dist/ui/variants/var_skeleton-block.d.ts +17 -0
- package/dist/ui/variants/var_skeleton-block.js +11 -0
- package/dist/ui/variants/var_spinner-turning.d.ts +17 -0
- package/dist/ui/variants/var_spinner-turning.js +11 -0
- package/dist/ui/variants/var_stat-tile.d.ts +18 -0
- package/dist/ui/variants/var_stat-tile.js +12 -0
- package/dist/ui/variants/var_tab-bar.d.ts +24 -0
- package/dist/ui/variants/var_tab-bar.js +14 -0
- package/dist/ui/variants/var_tap-target.d.ts +33 -0
- package/dist/ui/variants/var_tap-target.js +24 -0
- package/dist/ui/variants.d.ts +174 -0
- package/dist/ui/variants.js +50 -0
- package/dist/ui/wrappers.d.ts +128 -0
- package/dist/ui/wrappers.js +220 -0
- package/package.json +16 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const INERT_COLLECTOR = {
|
|
2
|
+
record: () => undefined,
|
|
3
|
+
flush: async () => undefined,
|
|
4
|
+
stop: () => undefined,
|
|
5
|
+
dropped: () => 0,
|
|
6
|
+
pending: () => 0,
|
|
7
|
+
};
|
|
8
|
+
export function createCollector(options) {
|
|
9
|
+
const now = options.now ?? (() => Date.now());
|
|
10
|
+
const random = options.random ?? Math.random;
|
|
11
|
+
const maxBatch = options.maxBatch ?? 25;
|
|
12
|
+
const intervalMs = options.intervalMs ?? 10_000;
|
|
13
|
+
const sampled = (options.sample ?? 1) >= 1 || random() < (options.sample ?? 1);
|
|
14
|
+
if (!sampled)
|
|
15
|
+
return INERT_COLLECTOR;
|
|
16
|
+
let buffer = [];
|
|
17
|
+
let dropped = 0;
|
|
18
|
+
let stopped = false;
|
|
19
|
+
let seq = 0;
|
|
20
|
+
const send = async (batch) => {
|
|
21
|
+
if (batch.length === 0)
|
|
22
|
+
return;
|
|
23
|
+
const body = JSON.stringify({ events: batch });
|
|
24
|
+
if (options.beacon !== undefined && options.beacon(options.endpoint, body))
|
|
25
|
+
return;
|
|
26
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
27
|
+
if (doFetch === undefined) {
|
|
28
|
+
dropped += batch.length;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const response = await doFetch(options.endpoint, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: { 'content-type': 'application/json' },
|
|
35
|
+
keepalive: true,
|
|
36
|
+
body,
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
dropped += batch.length;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
dropped += batch.length;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const flush = async () => {
|
|
46
|
+
const batch = buffer;
|
|
47
|
+
buffer = [];
|
|
48
|
+
await send(batch);
|
|
49
|
+
};
|
|
50
|
+
const record = (event) => {
|
|
51
|
+
if (stopped || !options.allowed())
|
|
52
|
+
return;
|
|
53
|
+
buffer.push({ ...event, at: now(), seq: ++seq });
|
|
54
|
+
if (buffer.length >= maxBatch)
|
|
55
|
+
void flush();
|
|
56
|
+
};
|
|
57
|
+
const timer = setInterval(() => void flush(), intervalMs);
|
|
58
|
+
timer.unref?.();
|
|
59
|
+
const onHide = () => {
|
|
60
|
+
if (globalThis.document?.visibilityState === 'hidden')
|
|
61
|
+
void flush();
|
|
62
|
+
};
|
|
63
|
+
globalThis.document?.addEventListener('visibilitychange', onHide);
|
|
64
|
+
return {
|
|
65
|
+
record,
|
|
66
|
+
flush,
|
|
67
|
+
stop: () => {
|
|
68
|
+
stopped = true;
|
|
69
|
+
clearInterval(timer);
|
|
70
|
+
globalThis.document?.removeEventListener('visibilitychange', onHide);
|
|
71
|
+
},
|
|
72
|
+
dropped: () => dropped,
|
|
73
|
+
pending: () => buffer.length,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Threaded } from '@prestack/thread/core/thread';
|
|
2
|
+
import type { Tree } from '@prestack/thread/core/tree';
|
|
3
|
+
export declare const TEACHES: readonly string[];
|
|
4
|
+
export declare const REACHES: RegExp;
|
|
5
|
+
export declare const declares: readonly Threaded[];
|
|
6
|
+
export declare const COMPOSITIONS: Threaded & {
|
|
7
|
+
readonly files: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function nameOf(at: string): string;
|
|
10
|
+
export declare function catalogue(tree: Tree, making: 'composition' | 'screen'): Promise<readonly string[]>;
|
|
11
|
+
export declare function composed(body: string, rows: readonly {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly at?: string;
|
|
14
|
+
}[], from: 'screens' | 'compositions', except?: string): readonly string[];
|
|
15
|
+
export declare const DOORS: ReadonlySet<string>;
|
|
16
|
+
export declare function reaching(at: string, text: string, elements: ReadonlySet<string>, declared: ReadonlySet<string>): readonly string[];
|
|
17
|
+
export declare function undeclared(tree: Tree, rows: readonly Threaded[]): Promise<readonly string[]>;
|
|
18
|
+
export declare function seeds(rows: readonly Threaded[], held: (at: string) => boolean): readonly {
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly content: string;
|
|
21
|
+
}[];
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { basename, dirname, join } from 'node:path';
|
|
11
|
+
import { stdout } from 'node:process';
|
|
12
|
+
import { pathToFileURL } from 'node:url';
|
|
13
|
+
import { wrapped } from "@prestack/thread/core/asking";
|
|
14
|
+
import { exit, invoked } from "@prestack/thread/core/invoked";
|
|
15
|
+
import { named as packageOf } from "@prestack/thread/core/scope";
|
|
16
|
+
import { findTree, inTree } from "@prestack/thread/core/tree";
|
|
17
|
+
export const TEACHES = [
|
|
18
|
+
' what the body may reach, and how a premium state is written:',
|
|
19
|
+
'',
|
|
20
|
+
' `useUi()` is the door. It carries `actor` — who is asking, with the roles read from',
|
|
21
|
+
' the row that declared itself the caller — and `translate`, `clock` and `dispatch`. Name',
|
|
22
|
+
' it in the body and the import is written for you.',
|
|
23
|
+
'',
|
|
24
|
+
' A premium state is DATA, not a permission. The row says what somebody IS; a grant says',
|
|
25
|
+
' what they may RUN; a variant says how a thing LOOKS. So a locked look is a signal set',
|
|
26
|
+
' from a value you already have, so the hook is read where it is used:',
|
|
27
|
+
'',
|
|
28
|
+
' <FeatureBox.paywalled locked={useUi().actor?.roles.includes(\'role_paid\') !== true}>',
|
|
29
|
+
' <Text k=\'feature.title\' />',
|
|
30
|
+
' </FeatureBox.paywalled>',
|
|
31
|
+
'',
|
|
32
|
+
' Read it in three parts, and each is its own command:',
|
|
33
|
+
'',
|
|
34
|
+
' `locked` is a boolean prop because the ELEMENT declares it raises that signal —',
|
|
35
|
+
' `thread create element` with `raises: locked`. A signal this app declares cannot be',
|
|
36
|
+
' raised on an element that never said it raises one, so `Box` will not take it.',
|
|
37
|
+
' `.paywalled` is a variant worn as the TAG, never passed as a prop, and it is what',
|
|
38
|
+
' carries the look — `thread create variant` with a `state: locked` and what it sets.',
|
|
39
|
+
' `useUi().actor` is who is asking, with the roles read off the row that declared',
|
|
40
|
+
' itself the caller in `thread create entity`.',
|
|
41
|
+
'',
|
|
42
|
+
' THE MEMBER IS THE VARIANT\'S WHOLE ID, CAMELCASED — never the part after the element',
|
|
43
|
+
' name. A variant `button-fill` is worn `<Button.buttonFill>`, and `<Button.fill>` is not',
|
|
44
|
+
' a thing. `.paywalled` above reads short only because that variant is itself named',
|
|
45
|
+
' `paywalled`; most carry the element in their id and wear all of it.',
|
|
46
|
+
'',
|
|
47
|
+
' how a control reaches an operation:',
|
|
48
|
+
'',
|
|
49
|
+
' Wiring is imperative. There is no `run=`, `operation=` or `dispatch=` prop on any',
|
|
50
|
+
' element, and the compiler is what will tell you so. A control calls dispatch in its own',
|
|
51
|
+
' handler:',
|
|
52
|
+
'',
|
|
53
|
+
' <Button.buttonFill label=\'common.save\'',
|
|
54
|
+
' onPress={() => useUi().dispatch?.(\'wf_save\')} />',
|
|
55
|
+
'',
|
|
56
|
+
' `dispatch` is optional on the hook, so `?.` is required — without it the compiler says',
|
|
57
|
+
' "Cannot invoke an object which is possibly \'undefined\'". The name is the operation\'s own',
|
|
58
|
+
' id from `thread create operation`, and one this app never declared is refused before it',
|
|
59
|
+
' runs. An operation whose `to:` named nobody is refused however the button looks — and',
|
|
60
|
+
' `to:` takes roles off an entity, which is a noun that arrives with `thread attach',
|
|
61
|
+
` ${packageOf('data')}\`.`,
|
|
62
|
+
'',
|
|
63
|
+
' Nothing here decides access. The gate still refuses the operation behind the lock',
|
|
64
|
+
' whatever the screen shows, so a screen that got this wrong shows the wrong thing and',
|
|
65
|
+
' still cannot do the wrong thing.',
|
|
66
|
+
'',
|
|
67
|
+
' how a press moves to another screen:',
|
|
68
|
+
'',
|
|
69
|
+
' Name the screen. `navigateTo` takes the screen\'s export name — its id in PascalCase, so',
|
|
70
|
+
' `order-detail` is reached as `navigateTo="OrderDetail"`:',
|
|
71
|
+
'',
|
|
72
|
+
' <Button.buttonNormal label=\'home.orders\' navigateTo="Orders" />',
|
|
73
|
+
'',
|
|
74
|
+
' That is the whole of it. `thread routes` reads every `navigateTo` the screens and their',
|
|
75
|
+
' compositions hold and writes the map — from which screen, through which button, to which',
|
|
76
|
+
' screen — and the pages. A page is reached by its route, and a sheet, popover, overlay or',
|
|
77
|
+
' toast opens where somebody already is, so the press is written the same way for both.',
|
|
78
|
+
' A name no screen has and a destination not written out as a name are each refused there.',
|
|
79
|
+
' Never an `href` and never',
|
|
80
|
+
' a router: a move the map cannot see is a screen the map reads as unreachable.',
|
|
81
|
+
];
|
|
82
|
+
export const REACHES = /\buseUi\s*\(/;
|
|
83
|
+
const here = 'thread/ui/compositions.ts';
|
|
84
|
+
const said = [
|
|
85
|
+
{
|
|
86
|
+
on: '2026-08-25',
|
|
87
|
+
said: 'Compositions is basically a mix of elements+variants, arranged with arrangement elements, with ways to invoke functions (navigateTo, dispatch).',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
on: '2026-08-25',
|
|
91
|
+
said: 'The compositions.ts just says what the thing is, and describes it. Then the file itself, seeded, is a cmp_ file, where we build the actual UI from. And the UI file is plain react, just with our system.',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
on: '2026-08-25',
|
|
95
|
+
said: 'Variants themselves declare what elements they relate to, in their declarations. Then the composition says button.primary and if that matches the combination of variant and element it is acceptable. And make sure the composition can only dispatch existing operations.',
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
export const declares = [];
|
|
99
|
+
export const COMPOSITIONS = {
|
|
100
|
+
id: 'composition',
|
|
101
|
+
at: here,
|
|
102
|
+
files: 'compositions/cmp_*.tsx',
|
|
103
|
+
describes: 'A React component made through this system: elements wearing variants, arranged, and able to reach a declared operation. Each row names a file prefixed `cmp_`, and that file is plain React a person writes, because the arrangement, the conditions and the content are theirs. A call site states only what is left over: what a thing does comes from its element, and how it looks and which states it answers to come from its variant, so `Button.primary` is legal only where a variant `primary` says it is worn by `Button`. Text in it is a message key, a look is a variant, and a value names a style guide row, never a raw one. The framework ships none, because what an app is made of is the app’s, and this row says what a composition is, never what is inside it.',
|
|
104
|
+
version: 1,
|
|
105
|
+
cites: said,
|
|
106
|
+
declares,
|
|
107
|
+
};
|
|
108
|
+
const PASCAL = (id) => id
|
|
109
|
+
.split('-')
|
|
110
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
111
|
+
.join('');
|
|
112
|
+
export function nameOf(at) {
|
|
113
|
+
const file = at.split('\\').join('/').split('/').at(-1) ?? at;
|
|
114
|
+
return PASCAL(file.replace(/^cmp_/, '').replace(/\.[^.]+$/, ''));
|
|
115
|
+
}
|
|
116
|
+
async function sheetOf(tree, file, ...named) {
|
|
117
|
+
try {
|
|
118
|
+
const held = (await import(__rewriteRelativeImportExtension(pathToFileURL(inTree(tree, file)).href)));
|
|
119
|
+
for (const one of named) {
|
|
120
|
+
const found = held[one]?.declares;
|
|
121
|
+
if (found !== undefined)
|
|
122
|
+
return found;
|
|
123
|
+
}
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const camelOf = (id) => id.replace(/-([a-z0-9])/g, (_, one) => one.toUpperCase());
|
|
131
|
+
const sentence = (one, pad) => String(one.describes ?? '').trim() === '' ? [] : wrapped(String(one.describes), pad);
|
|
132
|
+
export async function catalogue(tree, making) {
|
|
133
|
+
const [elements, variants, compositions, screens] = await Promise.all([
|
|
134
|
+
sheetOf(tree, `elements.${'ts'}`, 'ELEMENT', 'ELEMENTS'),
|
|
135
|
+
sheetOf(tree, `variants.${'ts'}`, 'VARIANT', 'VARIANTS'),
|
|
136
|
+
sheetOf(tree, `compositions.${'ts'}`, 'COMPOSITION', 'COMPOSITIONS'),
|
|
137
|
+
making === 'screen' ? sheetOf(tree, `screens.${'ts'}`, 'SCREEN', 'SCREENS') : Promise.resolve([]),
|
|
138
|
+
]);
|
|
139
|
+
const worn = new Map();
|
|
140
|
+
for (const one of variants) {
|
|
141
|
+
for (const each of one.wears ?? []) {
|
|
142
|
+
const key = PASCAL(each);
|
|
143
|
+
const already = worn.get(key) ?? [];
|
|
144
|
+
if (!already.includes(one.id))
|
|
145
|
+
worn.set(key, [...already, one.id]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const writes = (one) => {
|
|
149
|
+
const name = PASCAL(one.id);
|
|
150
|
+
const members = (worn.get(name) ?? []).sort().map((each) => `<${name}.${camelOf(each)}>`);
|
|
151
|
+
if (members.length === 0)
|
|
152
|
+
return `<${name}>`;
|
|
153
|
+
return one.arranges === true ? `<${name}>, or ${members.join(' ')}` : members.join(' ');
|
|
154
|
+
};
|
|
155
|
+
const section = (title, rows, write) => rows.length === 0
|
|
156
|
+
? [` ${title}: none yet.`, '']
|
|
157
|
+
: [
|
|
158
|
+
` ${title} (${String(rows.length)}):`,
|
|
159
|
+
...rows.flatMap((one) => [` ${write(one)}`, ...sentence(one, ' ')]),
|
|
160
|
+
'',
|
|
161
|
+
];
|
|
162
|
+
return [
|
|
163
|
+
'',
|
|
164
|
+
...(making === 'screen'
|
|
165
|
+
? section('SCREENS that exist, and the name a press reaches each one by', screens, (one) => `${one.id} — navigateTo="${PASCAL(one.id)}"`)
|
|
166
|
+
: []),
|
|
167
|
+
...section('COMPOSITIONS you can place', compositions, (one) => `<${typeof one.at === 'string' && one.at !== '' ? nameOf(one.at) : PASCAL(one.id)}>`),
|
|
168
|
+
...section('ELEMENTS, written as the tags they can actually be typed as', elements, writes),
|
|
169
|
+
...(variants.length === 0
|
|
170
|
+
? [' VARIANTS: none yet.', '']
|
|
171
|
+
: [
|
|
172
|
+
` VARIANTS (${String(variants.length)}), under the elements that accept them:`,
|
|
173
|
+
...[...worn.keys()].sort().map((name) => ` ${name} — ${(worn.get(name) ?? []).sort().map(camelOf).join(', ')}`),
|
|
174
|
+
...(() => {
|
|
175
|
+
const nobody = variants.filter((one) => (one.wears ?? []).length === 0).map((one) => one.id);
|
|
176
|
+
return nobody.length === 0
|
|
177
|
+
? []
|
|
178
|
+
: [` worn by nothing, so writable nowhere: ${nobody.sort().join(', ')}`];
|
|
179
|
+
})(),
|
|
180
|
+
'',
|
|
181
|
+
]),
|
|
182
|
+
' Materials, style guide values, fonts and animations are chosen inside a VARIANT, never inside',
|
|
183
|
+
' a body — `npx thread create variant` prints every one of them at the moment one is needed.',
|
|
184
|
+
'',
|
|
185
|
+
' Every element and the tags it is written as: `npx thread create element`. Every variant and',
|
|
186
|
+
' the tag it is worn as: `npx thread create variant`. Then open the one nearest to what you are',
|
|
187
|
+
' about to build with `npx thread read <id>` — it already answers how a body is arranged, how a',
|
|
188
|
+
' variant is worn and how a control reaches an operation, and a file cannot be wrong in the way',
|
|
189
|
+
' a remembered example can.',
|
|
190
|
+
'',
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
const TAG = /<([A-Z][A-Za-z0-9]*)/g;
|
|
194
|
+
export function composed(body, rows, from, except) {
|
|
195
|
+
const named = new Map();
|
|
196
|
+
for (const row of rows) {
|
|
197
|
+
const at = row.at;
|
|
198
|
+
if (typeof at !== 'string' || at === '' || at === except)
|
|
199
|
+
continue;
|
|
200
|
+
named.set(PASCAL(row.id), at);
|
|
201
|
+
}
|
|
202
|
+
const found = new Set();
|
|
203
|
+
for (const [, tag] of body.matchAll(TAG))
|
|
204
|
+
if (tag !== undefined && named.has(tag))
|
|
205
|
+
found.add(tag);
|
|
206
|
+
return [...found].sort().map((one) => {
|
|
207
|
+
const at = named.get(one) ?? '';
|
|
208
|
+
const file = (at.split('\\').join('/').split('/').at(-1) ?? at).replace(/\.[^.]+$/, '');
|
|
209
|
+
return `import { ${one} } from '${from === 'screens' ? '../compositions' : '.'}/${file}.tsx'`;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
const IMPORTS = /^import\s[\s\S]*?from\s*['"]([^'"]+)['"]/gm;
|
|
213
|
+
export const DOORS = new Set(['react', `${packageOf('ui')}/wrappers`, `${packageOf('ui')}/drag`]);
|
|
214
|
+
const SHIPPED = new RegExp(`^${packageOf('ui')}/elements/([a-z0-9-]+)$`);
|
|
215
|
+
const slashed = (path) => path.split('\\').join('/');
|
|
216
|
+
export function reaching(at, text, elements, declared) {
|
|
217
|
+
const here = slashed(at).split('/').slice(0, -1).join('/');
|
|
218
|
+
const found = new Set();
|
|
219
|
+
for (const one of text.matchAll(IMPORTS)) {
|
|
220
|
+
const from = one[1];
|
|
221
|
+
if (from === undefined || DOORS.has(from))
|
|
222
|
+
continue;
|
|
223
|
+
const shipped = SHIPPED.exec(from)?.[1];
|
|
224
|
+
if (shipped !== undefined && elements.has(shipped))
|
|
225
|
+
continue;
|
|
226
|
+
if (from.startsWith('.') && declared.has(slashed(join(here, from))))
|
|
227
|
+
continue;
|
|
228
|
+
found.add(from);
|
|
229
|
+
}
|
|
230
|
+
return [...found].sort();
|
|
231
|
+
}
|
|
232
|
+
export async function undeclared(tree, rows) {
|
|
233
|
+
const elements = new Set();
|
|
234
|
+
const declared = new Set();
|
|
235
|
+
for (const [file, exported] of [
|
|
236
|
+
['elements.ts', 'ELEMENT'],
|
|
237
|
+
['compositions.ts', 'COMPOSITION'],
|
|
238
|
+
['screens.ts', 'SCREEN'],
|
|
239
|
+
]) {
|
|
240
|
+
const where = inTree(tree, file);
|
|
241
|
+
if (!existsSync(where))
|
|
242
|
+
continue;
|
|
243
|
+
const sheet = (await import(__rewriteRelativeImportExtension(pathToFileURL(where).href)));
|
|
244
|
+
for (const row of sheet[exported]?.declares ?? []) {
|
|
245
|
+
if (exported === 'ELEMENT')
|
|
246
|
+
elements.add(row.id);
|
|
247
|
+
if (row.at !== '')
|
|
248
|
+
declared.add(slashed(row.at));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const found = [];
|
|
252
|
+
for (const row of rows) {
|
|
253
|
+
const file = join(tree.at, row.at);
|
|
254
|
+
if (!existsSync(file))
|
|
255
|
+
continue;
|
|
256
|
+
for (const one of reaching(row.at, readFileSync(file, 'utf8'), elements, declared)) {
|
|
257
|
+
found.push(`${row.at} imports \`${one}\`, which this app declares nothing by. A composition reaches ` +
|
|
258
|
+
'declared elements, other declared compositions, and the door — everything else is a thing ' +
|
|
259
|
+
'nothing wrote down. Declare it, or take it out and write the body through `thread create`.');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return found;
|
|
263
|
+
}
|
|
264
|
+
function starter(row) {
|
|
265
|
+
const name = nameOf(row.at);
|
|
266
|
+
return `'use client'
|
|
267
|
+
|
|
268
|
+
import { Box } from './elements/box.tsx'
|
|
269
|
+
import { composition } from './wrappers.tsx'
|
|
270
|
+
|
|
271
|
+
export const ${name} = composition('${name}', () => <Box.card />)
|
|
272
|
+
`;
|
|
273
|
+
}
|
|
274
|
+
export function seeds(rows, held) {
|
|
275
|
+
return rows.filter((row) => !held(row.at)).map((row) => ({ path: row.at, content: starter(row) }));
|
|
276
|
+
}
|
|
277
|
+
async function run() {
|
|
278
|
+
const tree = findTree();
|
|
279
|
+
const at = inTree(tree, 'compositions.ts');
|
|
280
|
+
if (!existsSync(at)) {
|
|
281
|
+
stdout.write(`thread: this tree has no ${tree.name}/${basename(at)}, so it declares no composition and there is nothing to seed or check.\n`);
|
|
282
|
+
return 0;
|
|
283
|
+
}
|
|
284
|
+
const held = (await import(__rewriteRelativeImportExtension(pathToFileURL(at).href)));
|
|
285
|
+
if (held.COMPOSITION === undefined) {
|
|
286
|
+
stdout.write(`thread: ${tree.name}/compositions.ts exports no \`COMPOSITION\`, so nothing declares a composition here.\n`);
|
|
287
|
+
return 1;
|
|
288
|
+
}
|
|
289
|
+
const rows = held.COMPOSITION.declares ?? [];
|
|
290
|
+
const made = seeds(rows, (where) => existsSync(join(tree.at, where)));
|
|
291
|
+
for (const one of made) {
|
|
292
|
+
mkdirSync(dirname(join(tree.at, one.path)), { recursive: true });
|
|
293
|
+
writeFileSync(join(tree.at, one.path), one.content, 'utf8');
|
|
294
|
+
stdout.write(`thread: seeded ${one.path}\n`);
|
|
295
|
+
}
|
|
296
|
+
const loose = await undeclared(tree, rows);
|
|
297
|
+
for (const one of loose)
|
|
298
|
+
stdout.write(`thread: ${one}\n`);
|
|
299
|
+
stdout.write(`thread: ${String(rows.length)} composition(s) declared, ${String(made.length)} seeded, ` +
|
|
300
|
+
`${String(rows.length - made.length)} already written, ` +
|
|
301
|
+
`${loose.length === 0 ? 'none reaching anything undeclared' : `${String(loose.length)} reaching something undeclared`}\n`);
|
|
302
|
+
return loose.length === 0 ? 0 : 1;
|
|
303
|
+
}
|
|
304
|
+
if (invoked(import.meta.url))
|
|
305
|
+
exit(await run());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const ConsentCategorySchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
labelKey: z.ZodString;
|
|
5
|
+
describeKey: z.ZodString;
|
|
6
|
+
required: z.ZodDefault<z.ZodBoolean>;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type ConsentCategory = z.infer<typeof ConsentCategorySchema>;
|
|
9
|
+
export declare function defineConsentCategory(category: ConsentCategory): void;
|
|
10
|
+
export declare function consentCategories(): readonly ConsentCategory[];
|
|
11
|
+
export declare function consentCategory(id: string): ConsentCategory | undefined;
|
|
12
|
+
export declare const ConsentDecisionSchema: z.ZodObject<{
|
|
13
|
+
decision: z.ZodEnum<{
|
|
14
|
+
accepted: "accepted";
|
|
15
|
+
declined: "declined";
|
|
16
|
+
withdrawn: "withdrawn";
|
|
17
|
+
}>;
|
|
18
|
+
accepted: z.ZodArray<z.ZodString>;
|
|
19
|
+
offered: z.ZodArray<z.ZodString>;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
export type ConsentDecision = z.infer<typeof ConsentDecisionSchema>;
|
|
22
|
+
export declare function consentAllows(decision: ConsentDecision | undefined, categoryId: string): boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const ConsentCategorySchema = z
|
|
3
|
+
.strictObject({
|
|
4
|
+
id: z
|
|
5
|
+
.string()
|
|
6
|
+
.regex(/^[a-z][a-z0-9_]*$/, 'a consent category id is lower_snake_case')
|
|
7
|
+
.describe('The id recorded in `thread.consent.categories`.'),
|
|
8
|
+
labelKey: z.string().min(1).describe('The category’s name, as a message key. Never a sentence.'),
|
|
9
|
+
describeKey: z.string().min(1).describe('What is collected under it, as a message key.'),
|
|
10
|
+
required: z.boolean().default(false).describe('True where the app cannot function without it.'),
|
|
11
|
+
})
|
|
12
|
+
.describe('One thing an app may ask permission to collect.');
|
|
13
|
+
const TELEMETRY = ConsentCategorySchema.parse({
|
|
14
|
+
id: 'telemetry',
|
|
15
|
+
labelKey: 'consent.telemetry.label',
|
|
16
|
+
describeKey: 'consent.telemetry.describe',
|
|
17
|
+
});
|
|
18
|
+
const REGISTRY = new Map([[TELEMETRY.id, TELEMETRY]]);
|
|
19
|
+
export function defineConsentCategory(category) {
|
|
20
|
+
const parsed = ConsentCategorySchema.parse(category);
|
|
21
|
+
if (REGISTRY.has(parsed.id))
|
|
22
|
+
throw new Error(`consent category "${parsed.id}" is already registered`);
|
|
23
|
+
REGISTRY.set(parsed.id, parsed);
|
|
24
|
+
}
|
|
25
|
+
export function consentCategories() {
|
|
26
|
+
return [...REGISTRY.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
27
|
+
}
|
|
28
|
+
export function consentCategory(id) {
|
|
29
|
+
return REGISTRY.get(id);
|
|
30
|
+
}
|
|
31
|
+
export const ConsentDecisionSchema = z
|
|
32
|
+
.strictObject({
|
|
33
|
+
decision: z.enum(['accepted', 'declined', 'withdrawn']).describe('Withdrawal is a decision and is recorded like any other.'),
|
|
34
|
+
accepted: z.array(z.string()).describe('The category ids accepted.'),
|
|
35
|
+
offered: z.array(z.string()).describe('Every category shown at that moment, accepted or not.'),
|
|
36
|
+
})
|
|
37
|
+
.describe('One consent decision, with the choice set as it stood when it was made.');
|
|
38
|
+
export function consentAllows(decision, categoryId) {
|
|
39
|
+
if (consentCategory(categoryId)?.required === true)
|
|
40
|
+
return true;
|
|
41
|
+
if (decision === undefined || decision.decision !== 'accepted')
|
|
42
|
+
return false;
|
|
43
|
+
return decision.accepted.includes(categoryId);
|
|
44
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { useSurface } from './wrappers.tsx';
|
|
3
|
+
export type MessageKey = string;
|
|
4
|
+
export interface ValueProps {
|
|
5
|
+
readonly validator: string;
|
|
6
|
+
readonly value: unknown;
|
|
7
|
+
readonly context?: Readonly<Record<string, unknown>>;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderValue({ validator, value, context }: ValueProps, surface: ReturnType<typeof useSurface>): ReactNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { formatValue, runValidator, validatorFor } from "./validators.js";
|
|
4
|
+
export function renderValue({ validator, value, context }, surface) {
|
|
5
|
+
const entry = validatorFor(validator);
|
|
6
|
+
const result = runValidator(validator, value, context ?? {});
|
|
7
|
+
if (!result.ok) {
|
|
8
|
+
return (_jsx("span", { className: surface.className, ...surface.marks, "data-invalid": "true", children: surface.text(result.errorKey) }));
|
|
9
|
+
}
|
|
10
|
+
return (_jsx("span", { className: surface.className, ...surface.marks, "data-validator": entry.name, children: formatValue(validator, result.value, context ?? {}) }));
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const CONTRAST_LARGE = 3;
|
|
2
|
+
function channel(value) {
|
|
3
|
+
const c = value / 255;
|
|
4
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
5
|
+
}
|
|
6
|
+
export function luminance(hex) {
|
|
7
|
+
const clean = hex.replace('#', '');
|
|
8
|
+
const full = clean.length === 3
|
|
9
|
+
? clean
|
|
10
|
+
.split('')
|
|
11
|
+
.map((c) => c + c)
|
|
12
|
+
.join('')
|
|
13
|
+
: clean.slice(0, 6);
|
|
14
|
+
const num = Number.parseInt(full, 16);
|
|
15
|
+
const r = channel((num >> 16) & 255);
|
|
16
|
+
const g = channel((num >> 8) & 255);
|
|
17
|
+
const b = channel(num & 255);
|
|
18
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
19
|
+
}
|
|
20
|
+
export function contrast(a, b) {
|
|
21
|
+
const [light, dark] = [luminance(a), luminance(b)].sort((x, y) => y - x);
|
|
22
|
+
return (light + 0.05) / (dark + 0.05);
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MessageKey } from './content.tsx';
|
|
2
|
+
import type { Dispatching } from './checked.ts';
|
|
3
|
+
export interface PressProps {
|
|
4
|
+
readonly dispatch?: [keyof Dispatching] extends [never] ? string : keyof Dispatching & string;
|
|
5
|
+
readonly input?: Readonly<Record<string, unknown>>;
|
|
6
|
+
readonly navigateTo?: string;
|
|
7
|
+
readonly onPress?: () => void;
|
|
8
|
+
}
|
|
9
|
+
export interface Option {
|
|
10
|
+
readonly value: string;
|
|
11
|
+
readonly labelKey: MessageKey;
|
|
12
|
+
}
|
|
13
|
+
export { Menu, type MenuProps } from './elements/menu.tsx';
|
|
14
|
+
export { type MenuItem } from './elements/menu.works.tsx';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { MessageKey } from './content.tsx';
|
|
3
|
+
export interface TabItem {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly labelKey: MessageKey;
|
|
6
|
+
readonly disabled?: boolean;
|
|
7
|
+
readonly content: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export interface AccordionItem {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly labelKey: MessageKey;
|
|
12
|
+
readonly disabled?: boolean;
|
|
13
|
+
readonly content: ReactNode;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
export interface Layer {
|
|
3
|
+
readonly ref: RefObject<HTMLElement | null>;
|
|
4
|
+
readonly dismissOnEscape: boolean;
|
|
5
|
+
readonly dismissOnOutside: boolean;
|
|
6
|
+
readonly onDismiss: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function useDismissLayer(ref: RefObject<HTMLElement | null>, options: {
|
|
9
|
+
readonly active: boolean;
|
|
10
|
+
readonly dismissOnEscape: boolean;
|
|
11
|
+
readonly dismissOnOutside: boolean;
|
|
12
|
+
readonly onDismiss: () => void;
|
|
13
|
+
}): void;
|
|
14
|
+
export declare function openLayers(): number;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
const layers = [];
|
|
4
|
+
function ordered() {
|
|
5
|
+
return layers
|
|
6
|
+
.filter((layer) => layer.ref.current !== null)
|
|
7
|
+
.sort((a, b) => {
|
|
8
|
+
const first = a.ref.current;
|
|
9
|
+
const second = b.ref.current;
|
|
10
|
+
if (first === second)
|
|
11
|
+
return 0;
|
|
12
|
+
return (first.compareDocumentPosition(second) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0 ? -1 : 1;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function target(kind) {
|
|
16
|
+
const open = ordered();
|
|
17
|
+
for (let i = open.length - 1; i >= 0; i -= 1) {
|
|
18
|
+
const layer = open[i];
|
|
19
|
+
if (kind === 'escape' ? layer.dismissOnEscape : layer.dismissOnOutside)
|
|
20
|
+
return layer;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
export function useDismissLayer(ref, options) {
|
|
25
|
+
const { active, dismissOnEscape, dismissOnOutside, onDismiss } = options;
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!active)
|
|
28
|
+
return;
|
|
29
|
+
const layer = { ref, dismissOnEscape, dismissOnOutside, onDismiss };
|
|
30
|
+
layers.push(layer);
|
|
31
|
+
const onKeyDown = (event) => {
|
|
32
|
+
if (event.key !== 'Escape')
|
|
33
|
+
return;
|
|
34
|
+
if (target('escape') !== layer)
|
|
35
|
+
return;
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
event.stopPropagation();
|
|
38
|
+
layer.onDismiss();
|
|
39
|
+
};
|
|
40
|
+
const onPointerDown = (event) => {
|
|
41
|
+
if (target('outside') !== layer)
|
|
42
|
+
return;
|
|
43
|
+
const root = ref.current;
|
|
44
|
+
const node = event.target;
|
|
45
|
+
if (root === null || !(node instanceof Node))
|
|
46
|
+
return;
|
|
47
|
+
if (root.contains(node))
|
|
48
|
+
return;
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
event.stopPropagation();
|
|
51
|
+
layer.onDismiss();
|
|
52
|
+
};
|
|
53
|
+
document.addEventListener('keydown', onKeyDown, true);
|
|
54
|
+
document.addEventListener('pointerdown', onPointerDown, true);
|
|
55
|
+
return () => {
|
|
56
|
+
document.removeEventListener('keydown', onKeyDown, true);
|
|
57
|
+
document.removeEventListener('pointerdown', onPointerDown, true);
|
|
58
|
+
const at = layers.indexOf(layer);
|
|
59
|
+
if (at !== -1)
|
|
60
|
+
layers.splice(at, 1);
|
|
61
|
+
};
|
|
62
|
+
}, [active, dismissOnEscape, dismissOnOutside, onDismiss, ref]);
|
|
63
|
+
}
|
|
64
|
+
export function openLayers() {
|
|
65
|
+
return layers.length;
|
|
66
|
+
}
|