@prestack/thread-ui 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/ui/animations/anm_appear.ts +13 -0
  2. package/dist/ui/animations/anm_blur_in.ts +19 -0
  3. package/dist/ui/animations/anm_blur_out.ts +18 -0
  4. package/dist/ui/animations/anm_dismiss.ts +18 -0
  5. package/dist/ui/animations/anm_drop.ts +19 -0
  6. package/dist/ui/animations/anm_fall.ts +18 -0
  7. package/dist/ui/animations/anm_flash.ts +18 -0
  8. package/dist/ui/animations/anm_glow.ts +16 -0
  9. package/dist/ui/animations/anm_lift.ts +16 -0
  10. package/dist/ui/animations/anm_nudge.ts +16 -0
  11. package/dist/ui/animations/anm_pop_in.ts +23 -0
  12. package/dist/ui/animations/anm_pop_out.ts +22 -0
  13. package/dist/ui/animations/anm_press.ts +12 -0
  14. package/dist/ui/animations/anm_pulse.ts +13 -0
  15. package/dist/ui/animations/anm_rise.ts +19 -0
  16. package/dist/ui/animations/anm_shake.ts +13 -0
  17. package/dist/ui/animations/anm_slide_in_left.ts +19 -0
  18. package/dist/ui/animations/anm_slide_in_right.ts +19 -0
  19. package/dist/ui/animations/anm_slide_out_left.ts +18 -0
  20. package/dist/ui/animations/anm_slide_out_right.ts +18 -0
  21. package/dist/ui/animations/anm_spin.ts +12 -0
  22. package/dist/ui/animations/anm_swell.ts +16 -0
  23. package/dist/ui/animations/anm_wobble.ts +24 -0
  24. package/dist/ui/animations/anm_zoom_in.ts +19 -0
  25. package/dist/ui/animations/anm_zoom_out.ts +18 -0
  26. package/dist/ui/animations.ts +317 -0
  27. package/dist/ui/attach.js +13 -4
  28. package/dist/ui/attach.ts +613 -0
  29. package/dist/ui/charts.tsx +74 -0
  30. package/dist/ui/checked.d.ts +2 -2
  31. package/dist/ui/checked.ts +32 -0
  32. package/dist/ui/collector.ts +140 -0
  33. package/dist/ui/compositions.d.ts +10 -1
  34. package/dist/ui/compositions.js +262 -23
  35. package/dist/ui/compositions.ts +640 -0
  36. package/dist/ui/consent.ts +55 -0
  37. package/dist/ui/content.tsx +39 -0
  38. package/dist/ui/contrast.ts +27 -0
  39. package/dist/ui/controls.tsx +30 -0
  40. package/dist/ui/disclosure.tsx +22 -0
  41. package/dist/ui/dismiss-layer.ts +87 -0
  42. package/dist/ui/door.ts +140 -0
  43. package/dist/ui/drag.ts +316 -0
  44. package/dist/ui/elements/accordion.js +2 -2
  45. package/dist/ui/elements/accordion.tsx +47 -0
  46. package/dist/ui/elements/accordion.works.ts +66 -0
  47. package/dist/ui/elements/aspect-ratio.js +1 -1
  48. package/dist/ui/elements/aspect-ratio.tsx +30 -0
  49. package/dist/ui/elements/aspect-ratio.works.ts +5 -0
  50. package/dist/ui/elements/avatar.js +1 -1
  51. package/dist/ui/elements/avatar.tsx +33 -0
  52. package/dist/ui/elements/avatar.works.ts +16 -0
  53. package/dist/ui/elements/badge.js +1 -1
  54. package/dist/ui/elements/badge.tsx +32 -0
  55. package/dist/ui/elements/badge.works.ts +9 -0
  56. package/dist/ui/elements/bars.js +2 -2
  57. package/dist/ui/elements/bars.tsx +49 -0
  58. package/dist/ui/elements/bars.works.ts +29 -0
  59. package/dist/ui/elements/box.js +3 -2
  60. package/dist/ui/elements/box.tsx +35 -0
  61. package/dist/ui/elements/breadcrumb.js +2 -2
  62. package/dist/ui/elements/breadcrumb.tsx +37 -0
  63. package/dist/ui/elements/breadcrumb.works.ts +24 -0
  64. package/dist/ui/elements/button.js +1 -1
  65. package/dist/ui/elements/button.tsx +45 -0
  66. package/dist/ui/elements/button.works.tsx +52 -0
  67. package/dist/ui/elements/column.js +1 -1
  68. package/dist/ui/elements/column.tsx +28 -0
  69. package/dist/ui/elements/consent.js +2 -2
  70. package/dist/ui/elements/consent.tsx +70 -0
  71. package/dist/ui/elements/consent.works.tsx +132 -0
  72. package/dist/ui/elements/donut.js +2 -2
  73. package/dist/ui/elements/donut.tsx +44 -0
  74. package/dist/ui/elements/donut.works.ts +42 -0
  75. package/dist/ui/elements/each.js +1 -1
  76. package/dist/ui/elements/each.tsx +33 -0
  77. package/dist/ui/elements/each.works.tsx +82 -0
  78. package/dist/ui/elements/empty.js +1 -1
  79. package/dist/ui/elements/empty.tsx +32 -0
  80. package/dist/ui/elements/field.js +1 -1
  81. package/dist/ui/elements/field.tsx +44 -0
  82. package/dist/ui/elements/field.works.ts +65 -0
  83. package/dist/ui/elements/funnel.js +2 -2
  84. package/dist/ui/elements/funnel.tsx +49 -0
  85. package/dist/ui/elements/funnel.works.ts +37 -0
  86. package/dist/ui/elements/gauge.js +1 -1
  87. package/dist/ui/elements/gauge.tsx +39 -0
  88. package/dist/ui/elements/gauge.works.ts +42 -0
  89. package/dist/ui/elements/glyph.js +1 -1
  90. package/dist/ui/elements/glyph.tsx +29 -0
  91. package/dist/ui/elements/glyph.works.tsx +42 -0
  92. package/dist/ui/elements/grid.js +1 -1
  93. package/dist/ui/elements/grid.tsx +28 -0
  94. package/dist/ui/elements/heatmap.js +2 -2
  95. package/dist/ui/elements/heatmap.tsx +47 -0
  96. package/dist/ui/elements/heatmap.works.ts +24 -0
  97. package/dist/ui/elements/hit-box.js +1 -1
  98. package/dist/ui/elements/hit-box.tsx +46 -0
  99. package/dist/ui/elements/hit-box.works.tsx +576 -0
  100. package/dist/ui/elements/image.js +1 -1
  101. package/dist/ui/elements/image.tsx +28 -0
  102. package/dist/ui/elements/line-chart.js +2 -2
  103. package/dist/ui/elements/line-chart.tsx +44 -0
  104. package/dist/ui/elements/line-chart.works.ts +41 -0
  105. package/dist/ui/elements/link.js +1 -1
  106. package/dist/ui/elements/link.tsx +37 -0
  107. package/dist/ui/elements/link.works.ts +25 -0
  108. package/dist/ui/elements/media.js +1 -1
  109. package/dist/ui/elements/media.tsx +56 -0
  110. package/dist/ui/elements/menu.js +2 -2
  111. package/dist/ui/elements/menu.tsx +50 -0
  112. package/dist/ui/elements/menu.works.tsx +153 -0
  113. package/dist/ui/elements/money.js +1 -1
  114. package/dist/ui/elements/money.tsx +28 -0
  115. package/dist/ui/elements/money.works.ts +9 -0
  116. package/dist/ui/elements/pagination.js +2 -2
  117. package/dist/ui/elements/pagination.tsx +38 -0
  118. package/dist/ui/elements/pagination.works.ts +20 -0
  119. package/dist/ui/elements/progress.js +1 -1
  120. package/dist/ui/elements/progress.tsx +33 -0
  121. package/dist/ui/elements/progress.works.ts +8 -0
  122. package/dist/ui/elements/radio-group.js +2 -2
  123. package/dist/ui/elements/radio-group.tsx +49 -0
  124. package/dist/ui/elements/radio-group.works.ts +33 -0
  125. package/dist/ui/elements/row.js +1 -1
  126. package/dist/ui/elements/row.tsx +28 -0
  127. package/dist/ui/elements/scatter.js +1 -1
  128. package/dist/ui/elements/scatter.tsx +41 -0
  129. package/dist/ui/elements/scatter.works.ts +38 -0
  130. package/dist/ui/elements/select.js +2 -2
  131. package/dist/ui/elements/select.tsx +42 -0
  132. package/dist/ui/elements/select.works.ts +5 -0
  133. package/dist/ui/elements/separator.js +1 -1
  134. package/dist/ui/elements/separator.tsx +30 -0
  135. package/dist/ui/elements/skeleton.js +1 -1
  136. package/dist/ui/elements/skeleton.tsx +30 -0
  137. package/dist/ui/elements/slider.js +1 -1
  138. package/dist/ui/elements/slider.tsx +33 -0
  139. package/dist/ui/elements/slider.works.ts +5 -0
  140. package/dist/ui/elements/sparkline.js +1 -1
  141. package/dist/ui/elements/sparkline.tsx +36 -0
  142. package/dist/ui/elements/sparkline.works.ts +32 -0
  143. package/dist/ui/elements/spinner.js +1 -1
  144. package/dist/ui/elements/spinner.tsx +32 -0
  145. package/dist/ui/elements/stack.js +1 -1
  146. package/dist/ui/elements/stack.tsx +28 -0
  147. package/dist/ui/elements/stat.js +1 -1
  148. package/dist/ui/elements/stat.tsx +35 -0
  149. package/dist/ui/elements/stat.works.ts +14 -0
  150. package/dist/ui/elements/surface.js +1 -1
  151. package/dist/ui/elements/surface.tsx +35 -0
  152. package/dist/ui/elements/surface.works.ts +9 -0
  153. package/dist/ui/elements/table.js +2 -2
  154. package/dist/ui/elements/table.tsx +61 -0
  155. package/dist/ui/elements/table.works.ts +30 -0
  156. package/dist/ui/elements/tabs.js +2 -2
  157. package/dist/ui/elements/tabs.tsx +47 -0
  158. package/dist/ui/elements/tabs.works.ts +84 -0
  159. package/dist/ui/elements/text.js +1 -1
  160. package/dist/ui/elements/text.tsx +32 -0
  161. package/dist/ui/elements/textarea.js +1 -1
  162. package/dist/ui/elements/textarea.tsx +37 -0
  163. package/dist/ui/elements/textarea.works.ts +5 -0
  164. package/dist/ui/elements/time.js +1 -1
  165. package/dist/ui/elements/time.tsx +34 -0
  166. package/dist/ui/elements/time.works.ts +25 -0
  167. package/dist/ui/elements/toggle.js +1 -1
  168. package/dist/ui/elements/toggle.tsx +33 -0
  169. package/dist/ui/elements/toggle.works.ts +5 -0
  170. package/dist/ui/elements/tooltip.js +1 -1
  171. package/dist/ui/elements/tooltip.tsx +39 -0
  172. package/dist/ui/elements/tooltip.works.ts +77 -0
  173. package/dist/ui/elements/value.js +1 -1
  174. package/dist/ui/elements/value.tsx +30 -0
  175. package/dist/ui/elements/value.works.ts +9 -0
  176. package/dist/ui/elements.ts +127 -0
  177. package/dist/ui/focus-scope.ts +121 -0
  178. package/dist/ui/fonts.ts +355 -0
  179. package/dist/ui/generators/dev.ts +79 -0
  180. package/dist/ui/generators/elements.d.ts +1 -11
  181. package/dist/ui/generators/elements.js +43 -13
  182. package/dist/ui/generators/elements.ts +794 -0
  183. package/dist/ui/generators/i18n.ts +301 -0
  184. package/dist/ui/generators/icons.ts +214 -0
  185. package/dist/ui/generators/react.js +10 -3
  186. package/dist/ui/generators/react.ts +268 -0
  187. package/dist/ui/generators/routes.d.ts +1 -0
  188. package/dist/ui/generators/routes.js +89 -69
  189. package/dist/ui/generators/routes.ts +739 -0
  190. package/dist/ui/generators/show.ts +259 -0
  191. package/dist/ui/generators/styles.js +1 -1
  192. package/dist/ui/generators/styles.ts +670 -0
  193. package/dist/ui/generators/variants.ts +205 -0
  194. package/dist/ui/i18n/catalogs/en.ts +191 -0
  195. package/dist/ui/i18n/format.ts +221 -0
  196. package/dist/ui/i18n/locales.ts +33 -0
  197. package/dist/ui/i18n/parse.ts +315 -0
  198. package/dist/ui/i18n/translator.ts +31 -0
  199. package/dist/ui/i18n/types.ts +96 -0
  200. package/dist/ui/icons.ts +331 -0
  201. package/dist/ui/islands/map.ts +58 -0
  202. package/dist/ui/localizations.ts +75 -0
  203. package/dist/ui/makers/message.ts +292 -0
  204. package/dist/ui/material.ts +236 -0
  205. package/dist/ui/materials/mat_bordered.ts +13 -0
  206. package/dist/ui/materials/mat_ceramic.ts +13 -0
  207. package/dist/ui/materials/mat_clay.ts +13 -0
  208. package/dist/ui/materials/mat_elevated.ts +24 -0
  209. package/dist/ui/materials/mat_flat.ts +34 -0
  210. package/dist/ui/materials/mat_glass.ts +20 -0
  211. package/dist/ui/materials/mat_lit.ts +13 -0
  212. package/dist/ui/materials/mat_moulded.ts +11 -0
  213. package/dist/ui/materials.ts +206 -0
  214. package/dist/ui/modes.ts +44 -0
  215. package/dist/ui/navigation.tsx +32 -0
  216. package/dist/ui/positioning.ts +90 -0
  217. package/dist/ui/presented.tsx +119 -0
  218. package/dist/ui/provider.d.ts +2 -0
  219. package/dist/ui/provider.js +7 -1
  220. package/dist/ui/provider.tsx +182 -0
  221. package/dist/ui/render-loop.ts +133 -0
  222. package/dist/ui/roving-focus.ts +161 -0
  223. package/dist/ui/screens.js +17 -8
  224. package/dist/ui/screens.ts +142 -0
  225. package/dist/ui/scroll-lock.ts +28 -0
  226. package/dist/ui/series.ts +97 -0
  227. package/dist/ui/signals.ts +386 -0
  228. package/dist/ui/styleguide.ts +231 -0
  229. package/dist/ui/styleguides.ts +374 -0
  230. package/dist/ui/themes.ts +22 -0
  231. package/dist/ui/token.js +1 -1
  232. package/dist/ui/token.ts +78 -0
  233. package/dist/ui/tokens/shadow.ts +25 -0
  234. package/dist/ui/tokens.ts +235 -0
  235. package/dist/ui/validators.ts +232 -0
  236. package/dist/ui/variant.d.ts +1 -0
  237. package/dist/ui/variant.js +3 -0
  238. package/dist/ui/variant.ts +352 -0
  239. package/dist/ui/variants/var_avatar-round.ts +14 -0
  240. package/dist/ui/variants/var_bubble-me.ts +14 -0
  241. package/dist/ui/variants/var_bubble-them.ts +13 -0
  242. package/dist/ui/variants/var_button-border.ts +76 -0
  243. package/dist/ui/variants/var_button-cta.ts +76 -0
  244. package/dist/ui/variants/var_button-destructive-ghost.ts +72 -0
  245. package/dist/ui/variants/var_button-destructive.ts +76 -0
  246. package/dist/ui/variants/var_button-fill.ts +76 -0
  247. package/dist/ui/variants/var_button-ghost.ts +72 -0
  248. package/dist/ui/variants/var_button-glass.ts +55 -0
  249. package/dist/ui/variants/var_button-normal.ts +76 -0
  250. package/dist/ui/variants/var_button-quiet.ts +74 -0
  251. package/dist/ui/variants/var_card.ts +17 -0
  252. package/dist/ui/variants/var_chip.ts +13 -0
  253. package/dist/ui/variants/var_choice.ts +15 -0
  254. package/dist/ui/variants/var_framed.ts +10 -0
  255. package/dist/ui/variants/var_glyph-plain.ts +11 -0
  256. package/dist/ui/variants/var_input.ts +43 -0
  257. package/dist/ui/variants/var_link-inline.ts +29 -0
  258. package/dist/ui/variants/var_list-row.ts +34 -0
  259. package/dist/ui/variants/var_rule.ts +10 -0
  260. package/dist/ui/variants/var_skeleton-block.ts +12 -0
  261. package/dist/ui/variants/var_spinner-turning.ts +12 -0
  262. package/dist/ui/variants/var_stat-tile.ts +13 -0
  263. package/dist/ui/variants/var_tab-bar.ts +15 -0
  264. package/dist/ui/variants/var_tap-target.ts +25 -0
  265. package/dist/ui/variants.ts +64 -0
  266. package/dist/ui/wrappers.d.ts +4 -1
  267. package/dist/ui/wrappers.js +60 -20
  268. package/dist/ui/wrappers.tsx +426 -0
  269. package/package.json +8 -2
@@ -0,0 +1,29 @@
1
+ import { formatValue } from '../validators.ts'
2
+ import { seriesColour } from '../series.ts'
3
+ import { num, str, useRamp, type Row } from '../charts.tsx'
4
+ import type { BarsProps } from './bars.tsx'
5
+
6
+ export function uses(props: BarsProps): {
7
+ readonly holds?: readonly string[]
8
+ readonly animates?: boolean
9
+ readonly on?: Readonly<Record<string, unknown>>
10
+ readonly ramp: readonly string[]
11
+ } {
12
+ const ramp = useRamp(props.rows.length)
13
+ return { ...(props.rows.length === 0 ? { holds: ['empty'] as const } : {}), ramp }
14
+ }
15
+
16
+ export function sized(props: BarsProps, kept: { readonly ramp: readonly string[] }, row: Row, at: number): Readonly<Record<string, string | number>> {
17
+ const most = Math.max(...props.rows.map((one: Row) => num(one, props.value)), 0) || 1
18
+ return {
19
+ series: seriesColour(kept.ramp, at),
20
+ fraction: `${((num(row, props.value) / most) * 100).toFixed(1)}%`,
21
+ }
22
+ }
23
+
24
+ export function shown(props: BarsProps, row: Row, _surface: unknown, _kept?: unknown): Readonly<Record<string, string>> {
25
+ return {
26
+ label: str(row, props.by),
27
+ amount: String(formatValue(props.format ?? 'number', num(row, props.value))),
28
+ }
29
+ }
@@ -6,6 +6,7 @@ export const Box = element('Box', (props, className) => {
6
6
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
7
7
  holds: [
8
8
  ...(props.scrolling === true ? ['scrolling'] : []),
9
- ], });
9
+ ],
10
+ raises: ['scrolling'], });
10
11
  return (_jsx("div", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, ...(props.labelKey === undefined ? {} : { role: 'group' }), ...(props.labelKey === undefined ? {} : { 'aria-label': surface.text(props.labelKey) }), children: props.children }));
11
- }, 'e-box');
12
+ }, 'e-box', { "card": "thread-card", "listRow": "thread-list-row", "bubbleThem": "thread-bubble-them", "bubbleMe": "thread-bubble-me" });
@@ -0,0 +1,35 @@
1
+ 'use client'
2
+
3
+ import type { ReactNode } from 'react'
4
+ import type { MessageKey } from '../content.tsx'
5
+
6
+ import { type Element, element, useSurface } from '../wrappers.tsx'
7
+
8
+
9
+ export interface BoxProps {
10
+ readonly children: ReactNode
11
+ readonly labelKey?: MessageKey
12
+ readonly scrolling?: boolean
13
+ readonly dispatch?: string
14
+ readonly input?: Readonly<Record<string, unknown>>
15
+ readonly invokeOn?: 'press' | 'shown'
16
+ }
17
+
18
+ export const Box: Element<'Box', BoxProps> = element(
19
+ 'Box',
20
+ (props: BoxProps, className) => {
21
+ const surface = useSurface({ className,
22
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
23
+ holds: [
24
+ ...(props.scrolling === true ? ['scrolling' as const] : []),
25
+ ],
26
+ raises: ['scrolling' as const], })
27
+ return (
28
+ <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(props.labelKey === undefined ? {} : { role: 'group' as const })} {...(props.labelKey === undefined ? {} : { 'aria-label': surface.text(props.labelKey) })}>
29
+ {props.children}
30
+ </div>
31
+ )
32
+ },
33
+ 'e-box',
34
+ {"card":"thread-card","listRow":"thread-list-row","bubbleThem":"thread-bubble-them","bubbleMe":"thread-bubble-me"},
35
+ )
@@ -3,10 +3,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { roleClass } from "../fonts.js";
4
4
  import { Link } from "./link.js";
5
5
  import { element, useSurface } from "../wrappers.js";
6
- import { Each } from "./each.js";
6
+ import { Each } from "../elements/each.js";
7
7
  import { crumb, steps } from "./breadcrumb.works.js";
8
8
  export const Breadcrumb = element('Breadcrumb', (props, className) => {
9
9
  const surface = useSurface({ className: roleClass(undefined, className),
10
10
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, });
11
11
  return (_jsx("nav", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, "aria-label": surface.text('nav.breadcrumb'), children: _jsx(Each, { rows: steps(props), by: 'id', children: (each0, at) => (_jsx(Link.linkInline, { ...crumb(props, each0, at) })) }) }));
12
- }, 'e-breadcrumb');
12
+ }, 'e-breadcrumb', { "tabBar": "thread-tab-bar" });
@@ -0,0 +1,37 @@
1
+ 'use client'
2
+
3
+ import { roleClass } from '../fonts.ts'
4
+ import type { MapIsland } from '../islands/map.ts'
5
+ import { Link } from './link.tsx'
6
+
7
+ import { type Element, element, useSurface } from '../wrappers.tsx'
8
+ import { Each } from '../elements/each.tsx'
9
+ import { crumb, steps } from './breadcrumb.works.ts'
10
+
11
+
12
+ export interface BreadcrumbProps {
13
+ readonly map: MapIsland
14
+ readonly current: string
15
+ readonly dispatch?: string
16
+ readonly input?: Readonly<Record<string, unknown>>
17
+ readonly invokeOn?: 'press' | 'shown'
18
+ }
19
+
20
+ export const Breadcrumb: Element<'Breadcrumb', BreadcrumbProps> = element(
21
+ 'Breadcrumb',
22
+ (props: BreadcrumbProps, className) => {
23
+ const surface = useSurface({ className: roleClass(undefined, className),
24
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
25
+ return (
26
+ <nav className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} aria-label={surface.text('nav.breadcrumb')}>
27
+ <Each rows={steps(props)} by={'id'}>
28
+ {(each0, at) => (
29
+ <Link.linkInline {...crumb(props, each0, at)}></Link.linkInline>
30
+ )}
31
+ </Each>
32
+ </nav>
33
+ )
34
+ },
35
+ 'e-breadcrumb',
36
+ {"tabBar":"thread-tab-bar"},
37
+ )
@@ -0,0 +1,24 @@
1
+ import { trailTo } from '../navigation.tsx'
2
+ import type { Row } from '../charts.tsx'
3
+ import type { BreadcrumbProps } from './breadcrumb.tsx'
4
+ import type { LinkProps } from './link.tsx'
5
+
6
+ export function steps(props: BreadcrumbProps): readonly Row[] {
7
+ const known = new Map(props.map.screens.map((one) => [one.id, one]))
8
+ if (!known.has(props.current)) return []
9
+ const trail = trailTo(props.map, props.current)
10
+ return trail.flatMap((id, at) => {
11
+ const screen = known.get(id)
12
+ if (screen === undefined) return []
13
+ return [{ id, nameKey: screen.nameKey, here: at === trail.length - 1 }]
14
+ })
15
+ }
16
+
17
+ export function crumb(_props: BreadcrumbProps, row: Row, _at: number): LinkProps & { readonly 'aria-current'?: 'page' } {
18
+ return {
19
+ navigateTo: String(row['id']),
20
+ labelKey: String(row['nameKey']),
21
+ is: 'label',
22
+ ...(row['here'] === true ? ({ 'aria-current': 'page' } as const) : {}),
23
+ }
24
+ }
@@ -13,4 +13,4 @@ export const Button = element('Button', (props, className) => {
13
13
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
14
14
  const wired = wires(props, kept, surface);
15
15
  return (_jsxs("button", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), ...(wired.on ?? {}), children: [!iconed(props, kept) ? null : _jsx("span", { className: "e-button-symbol", children: shown(props, surface, kept, wired).symbol }), !worded(props, kept) ? null : _jsx("span", { children: shown(props, surface, kept, wired).wording })] }));
16
- }, 'e-button');
16
+ }, 'e-button', { "buttonFill": "thread-button-fill", "buttonNormal": "thread-button-normal", "buttonGhost": "thread-button-ghost", "buttonBorder": "thread-button-border", "buttonDestructive": "thread-button-destructive", "buttonDestructiveGhost": "thread-button-destructive-ghost", "buttonCta": "thread-button-cta", "buttonQuiet": "thread-button-quiet", "buttonGlass": "thread-button-glass" });
@@ -0,0 +1,45 @@
1
+ 'use client'
2
+
3
+ import type { MessageKey } from '../content.tsx'
4
+ import { roleClass } from '../fonts.ts'
5
+
6
+ import { type Element, element, useSurface } from '../wrappers.tsx'
7
+ import { shown, iconed, worded, uses, wires } from './button.works.tsx'
8
+
9
+
10
+ export interface ButtonProps {
11
+ readonly label: MessageKey
12
+ readonly with?: Readonly<Record<string, unknown>>
13
+ readonly icon?: string
14
+ readonly shows?: string
15
+ readonly type?: string
16
+ readonly disabled?: boolean
17
+ readonly loading?: boolean
18
+ readonly dispatch?: string
19
+ readonly input?: Readonly<Record<string, unknown>>
20
+ readonly navigateTo?: string
21
+ readonly onPress?: () => void
22
+ readonly invokeOn?: 'press' | 'shown'
23
+ }
24
+
25
+ export const Button: Element<'Button', ButtonProps> = element(
26
+ 'Button',
27
+ (props: ButtonProps, className) => {
28
+ const kept = uses(props)
29
+ const surface = useSurface({ className: roleClass(undefined, className),
30
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
31
+ holds: [
32
+ ...(kept.holds ?? []),
33
+ ],
34
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
35
+ const wired = wires(props, kept, surface)
36
+ return (
37
+ <button className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} {...(wired.on ?? {})}>
38
+ {!iconed(props, kept) ? null : <span className="e-button-symbol">{shown(props, surface, kept, wired).symbol}</span>}
39
+ {!worded(props, kept) ? null : <span>{shown(props, surface, kept, wired).wording}</span>}
40
+ </button>
41
+ )
42
+ },
43
+ 'e-button',
44
+ {"buttonFill":"thread-button-fill","buttonNormal":"thread-button-normal","buttonGhost":"thread-button-ghost","buttonBorder":"thread-button-border","buttonDestructive":"thread-button-destructive","buttonDestructiveGhost":"thread-button-destructive-ghost","buttonCta":"thread-button-cta","buttonQuiet":"thread-button-quiet","buttonGlass":"thread-button-glass"},
45
+ )
@@ -0,0 +1,52 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ import { pressOf, usePress } from '../wrappers.tsx'
4
+ import type { Surface } from '../door.ts'
5
+ import { drawn } from './glyph.works.tsx'
6
+ import type { ButtonProps } from './button.tsx'
7
+
8
+ export function uses(props: ButtonProps): {
9
+ readonly holds?: readonly string[]
10
+ readonly animates?: boolean
11
+ readonly on?: Readonly<Record<string, unknown>>
12
+ readonly press: (() => void) | undefined
13
+ } {
14
+ return {
15
+ holds: [
16
+ ...(props.disabled === true ? (['disabled'] as const) : []),
17
+ ...(props.loading === true ? (['loading'] as const) : []),
18
+ ],
19
+ press: usePress(pressOf(props), { element: 'Button', name: props.label }),
20
+ }
21
+ }
22
+
23
+ export function wires(
24
+ props: ButtonProps,
25
+ kept: { readonly press: (() => void) | undefined },
26
+ surface: Surface,
27
+ ): { readonly on: Readonly<Record<string, unknown>> } {
28
+ const inert = surface.marked('disabled') || surface.marked('loading')
29
+ return {
30
+ on: {
31
+ type: props.type ?? 'button',
32
+ disabled: inert,
33
+ ...(props.shows === 'icon' ? { 'aria-label': surface.text(props.label, props.with) } : {}),
34
+ onClick: inert ? undefined : kept.press,
35
+ },
36
+ }
37
+ }
38
+
39
+ export function iconed(props: ButtonProps, _kept?: unknown): boolean {
40
+ return props.icon !== undefined
41
+ }
42
+
43
+ export function worded(props: ButtonProps, _kept?: unknown): boolean {
44
+ return props.shows !== 'icon'
45
+ }
46
+
47
+ export function shown(props: ButtonProps, surface: Surface, _kept: unknown, _wired?: unknown): Readonly<Record<string, ReactNode>> {
48
+ return {
49
+ symbol: props.icon === undefined ? null : drawn(props.icon, { 'aria-hidden': true }),
50
+ wording: props.shows === 'icon' ? null : surface.text(props.label, props.with),
51
+ }
52
+ }
@@ -5,4 +5,4 @@ export const Column = element('Column', (props, className) => {
5
5
  const surface = useSurface({ className,
6
6
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, });
7
7
  return (_jsx("div", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, children: props.children }));
8
- }, 'e-column');
8
+ }, 'e-column', {});
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+
3
+ import type { ReactNode } from 'react'
4
+
5
+ import { type Element, element, useSurface } from '../wrappers.tsx'
6
+
7
+
8
+ export interface ColumnProps {
9
+ readonly children: ReactNode
10
+ readonly dispatch?: string
11
+ readonly input?: Readonly<Record<string, unknown>>
12
+ readonly invokeOn?: 'press' | 'shown'
13
+ }
14
+
15
+ export const Column: Element<'Column', ColumnProps> = element(
16
+ 'Column',
17
+ (props: ColumnProps, className) => {
18
+ const surface = useSurface({ className,
19
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
20
+ return (
21
+ <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
22
+ {props.children}
23
+ </div>
24
+ )
25
+ },
26
+ 'e-column',
27
+ {},
28
+ )
@@ -7,7 +7,7 @@ import { Text } from "./text.js";
7
7
  import { Toggle } from "./toggle.js";
8
8
  import { Button } from "./button.js";
9
9
  import { element, useSurface } from "../wrappers.js";
10
- import { Each } from "./each.js";
10
+ import { Each } from "../elements/each.js";
11
11
  import { title, policy, hasPolicy, categories, label, describe, chooser, optional, fixed, required, withdraw, withdrawable, decline, accept, acceptAll, uses } from "./consent.works.js";
12
12
  export const Consent = element('Consent', (props, className) => {
13
13
  const kept = uses(props);
@@ -18,4 +18,4 @@ export const Consent = element('Consent', (props, className) => {
18
18
  ],
19
19
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
20
20
  return (_jsx(_Fragment, { children: _jsx(Box.card, { children: _jsxs(Column, { children: [_jsx(Text, { ...title(props, kept) }), !hasPolicy(props, kept) ? null : _jsx(Text, { ...policy(props, kept) }), _jsx(Column, { children: _jsx(Each, { rows: categories(props, kept), by: 'id', children: (each0, at) => (_jsxs(Box, { children: [_jsxs(Column, { children: [_jsx(Text, { ...label(props, kept, each0, at) }), _jsx(Text, { ...describe(props, kept, each0, at) })] }), !optional(props, kept, each0) ? null : _jsx(Toggle.input, { ...chooser(props, kept, each0, at) }), !required(props, kept, each0) ? null : _jsx(Text, { ...fixed(props, kept, each0, at) })] })) }) }), _jsxs(Box, { children: [!withdrawable(props, kept) ? null : _jsx(Button.buttonQuiet, { ...withdraw(props, kept) }), _jsx(Button.buttonBorder, { ...decline(props, kept) }), _jsx(Button.buttonBorder, { ...accept(props, kept) }), _jsx(Button.buttonFill, { ...acceptAll(props, kept) })] })] }) }) }));
21
- }, 'e-consent');
21
+ }, 'e-consent', {});
@@ -0,0 +1,70 @@
1
+ 'use client'
2
+
3
+ import type { MessageKey } from '../content.tsx'
4
+ import { roleClass } from '../fonts.ts'
5
+ import type { ConsentDecision } from '../consent.ts'
6
+ import { Box } from './box.tsx'
7
+ import { Column } from './column.tsx'
8
+ import { Text } from './text.tsx'
9
+ import { Toggle } from './toggle.tsx'
10
+ import { Button } from './button.tsx'
11
+
12
+ import { type Element, element, useSurface } from '../wrappers.tsx'
13
+ import { Each } from '../elements/each.tsx'
14
+ import { title, policy, hasPolicy, categories, label, describe, chooser, optional, fixed, required, withdraw, withdrawable, decline, accept, acceptAll, uses } from './consent.works.tsx'
15
+
16
+
17
+ export interface ConsentProps {
18
+ readonly decision?: ConsentDecision
19
+ readonly onDecide: (said: ConsentDecision) => void
20
+ readonly policyKey?: MessageKey
21
+ readonly preselected: readonly string[]
22
+ readonly dispatch?: string
23
+ readonly input?: Readonly<Record<string, unknown>>
24
+ readonly invokeOn?: 'press' | 'shown'
25
+ }
26
+
27
+ export const Consent: Element<'Consent', ConsentProps> = element(
28
+ 'Consent',
29
+ (props: ConsentProps, className) => {
30
+ const kept = uses(props)
31
+ const surface = useSurface({ className: roleClass(undefined, className),
32
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
33
+ holds: [
34
+ ...(kept.holds ?? []),
35
+ ],
36
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
37
+ return (
38
+ <>
39
+ <Box.card>
40
+ <Column>
41
+ <Text {...title(props, kept)}></Text>
42
+ {!hasPolicy(props, kept) ? null : <Text {...policy(props, kept)}></Text>}
43
+ <Column>
44
+ <Each rows={categories(props, kept)} by={'id'}>
45
+ {(each0, at) => (
46
+ <Box>
47
+ <Column>
48
+ <Text {...label(props, kept, each0, at)}></Text>
49
+ <Text {...describe(props, kept, each0, at)}></Text>
50
+ </Column>
51
+ {!optional(props, kept, each0) ? null : <Toggle.input {...chooser(props, kept, each0, at)}></Toggle.input>}
52
+ {!required(props, kept, each0) ? null : <Text {...fixed(props, kept, each0, at)}></Text>}
53
+ </Box>
54
+ )}
55
+ </Each>
56
+ </Column>
57
+ <Box>
58
+ {!withdrawable(props, kept) ? null : <Button.buttonQuiet {...withdraw(props, kept)}></Button.buttonQuiet>}
59
+ <Button.buttonBorder {...decline(props, kept)}></Button.buttonBorder>
60
+ <Button.buttonBorder {...accept(props, kept)}></Button.buttonBorder>
61
+ <Button.buttonFill {...acceptAll(props, kept)}></Button.buttonFill>
62
+ </Box>
63
+ </Column>
64
+ </Box.card>
65
+ </>
66
+ )
67
+ },
68
+ 'e-consent',
69
+ {},
70
+ )
@@ -0,0 +1,132 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+
5
+ import { consentCategories, type ConsentCategory, type ConsentDecision } from '../consent.ts'
6
+ import type { Row } from '../charts.tsx'
7
+ import type { ButtonProps } from './button.tsx'
8
+ import type { ConsentProps } from './consent.tsx'
9
+ import type { TextProps } from './text.tsx'
10
+ import type { ToggleProps } from './toggle.tsx'
11
+
12
+ type Kept = {
13
+ readonly categories: readonly ConsentCategory[]
14
+ readonly selected: readonly string[]
15
+ readonly accepted: boolean
16
+ readonly offered: readonly string[]
17
+ readonly toggle: (id: string, on: boolean) => void
18
+ readonly decide: (decision: ConsentDecision['decision'], accepted: readonly string[]) => void
19
+ }
20
+
21
+ function firstSelection(
22
+ categories: readonly ConsentCategory[],
23
+ decision: ConsentDecision | undefined,
24
+ preselected: readonly string[],
25
+ ): readonly string[] {
26
+ const answered = decision !== undefined
27
+ return categories
28
+ .filter(
29
+ (one) =>
30
+ one.required ||
31
+ (answered
32
+ ? decision.decision === 'accepted' && decision.accepted.includes(one.id)
33
+ : preselected.includes(one.id)),
34
+ )
35
+ .map((one) => one.id)
36
+ }
37
+
38
+ export function uses(props: ConsentProps): {
39
+ readonly holds?: readonly string[]
40
+ readonly animates?: boolean
41
+ readonly on?: Readonly<Record<string, unknown>>
42
+ readonly categories: readonly ConsentCategory[]
43
+ readonly selected: readonly string[]
44
+ readonly accepted: boolean
45
+ readonly offered: readonly string[]
46
+ readonly toggle: (id: string, on: boolean) => void
47
+ readonly decide: (decision: ConsentDecision['decision'], accepted: readonly string[]) => void
48
+ } {
49
+ const categories = consentCategories()
50
+ const [selected, setSelected] = useState<readonly string[]>(() =>
51
+ firstSelection(categories, props.decision, props.preselected ?? []),
52
+ )
53
+ const offered = categories.map((one) => one.id)
54
+
55
+ return {
56
+ categories,
57
+ selected,
58
+ offered,
59
+ accepted: props.decision?.decision === 'accepted',
60
+ toggle: (id: string, on: boolean): void => {
61
+ setSelected((was) => (on ? [...was, id] : was.filter((one) => one !== id)))
62
+ },
63
+ decide: (decision: ConsentDecision['decision'], accepted: readonly string[]): void => {
64
+ props.onDecide({ decision, accepted: [...accepted], offered })
65
+ },
66
+ }
67
+ }
68
+
69
+ export function categories(_props: ConsentProps, kept: Kept): readonly Row[] {
70
+ return kept.categories as unknown as readonly Row[]
71
+ }
72
+
73
+ export function hasPolicy(props: ConsentProps, _kept: Kept): boolean {
74
+ return props.policyKey !== undefined
75
+ }
76
+
77
+ export function withdrawable(_props: ConsentProps, kept: Kept): boolean {
78
+ return kept.accepted
79
+ }
80
+
81
+ export function optional(_props: ConsentProps, _kept: Kept, row: Row): boolean {
82
+ return row['required'] !== true
83
+ }
84
+
85
+ export function required(_props: ConsentProps, _kept: Kept, row: Row): boolean {
86
+ return row['required'] === true
87
+ }
88
+
89
+ export function title(_props: ConsentProps, _kept: Kept, _at?: number): TextProps {
90
+ return { k: 'consent.title', is: 'heading' }
91
+ }
92
+
93
+ export function policy(props: ConsentProps, _kept: Kept, _at?: number): TextProps {
94
+ return { k: props.policyKey ?? 'consent.title', is: 'body' }
95
+ }
96
+
97
+ export function label(_props: ConsentProps, _kept: Kept, row: Row, _at: number): TextProps {
98
+ return { k: String(row['labelKey']), is: 'label' }
99
+ }
100
+
101
+ export function describe(_props: ConsentProps, _kept: Kept, row: Row, _at: number): TextProps {
102
+ return { k: String(row['describeKey']), is: 'body' }
103
+ }
104
+
105
+ export function fixed(_props: ConsentProps, _kept: Kept, _row: Row, _at: number): TextProps {
106
+ return { k: 'consent.required', is: 'label' }
107
+ }
108
+
109
+ export function chooser(_props: ConsentProps, kept: Kept, row: Row, _at?: number): ToggleProps {
110
+ const id = String(row['id'])
111
+ return {
112
+ labelKey: String(row['labelKey']),
113
+ on: kept.selected.includes(id),
114
+ onToggle: (on: boolean): void => kept.toggle(id, on),
115
+ }
116
+ }
117
+
118
+ export function withdraw(_props: ConsentProps, kept: Kept): ButtonProps {
119
+ return { label: 'consent.withdraw', onPress: (): void => kept.decide('withdrawn', []) }
120
+ }
121
+
122
+ export function decline(_props: ConsentProps, kept: Kept): ButtonProps {
123
+ return { label: 'consent.decline', onPress: (): void => kept.decide('declined', []) }
124
+ }
125
+
126
+ export function accept(_props: ConsentProps, kept: Kept): ButtonProps {
127
+ return { label: 'consent.accept', onPress: (): void => kept.decide('accepted', kept.selected) }
128
+ }
129
+
130
+ export function acceptAll(_props: ConsentProps, kept: Kept): ButtonProps {
131
+ return { label: 'consent.acceptAll', onPress: (): void => kept.decide('accepted', kept.offered) }
132
+ }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { roleClass } from "../fonts.js";
4
4
  import { element, useSurface } from "../wrappers.js";
5
- import { Each } from "./each.js";
5
+ import { Each } from "../elements/each.js";
6
6
  import { slice, uses } from "./donut.works.js";
7
7
  export const Donut = element('Donut', (props, className) => {
8
8
  const kept = uses(props);
@@ -13,4 +13,4 @@ export const Donut = element('Donut', (props, className) => {
13
13
  ],
14
14
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
15
15
  return (_jsx("svg", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), role: "img", ...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) }), children: _jsx(Each, { rows: props.rows, by: props.by, children: (each0, at) => (_jsx("circle", { ...slice(props, kept, each0, at) })) }) }));
16
- }, 'e-donut');
16
+ }, 'e-donut', { "card": "thread-card" });
@@ -0,0 +1,44 @@
1
+ 'use client'
2
+
3
+ import type { MessageKey } from '../content.tsx'
4
+ import type { Row } from '../charts.tsx'
5
+ import { roleClass } from '../fonts.ts'
6
+
7
+ import { type Element, element, useSurface } from '../wrappers.tsx'
8
+ import { Each } from '../elements/each.tsx'
9
+ import { slice, uses } from './donut.works.ts'
10
+
11
+
12
+ export interface DonutProps {
13
+ readonly rows: readonly Row[]
14
+ readonly by: string
15
+ readonly value: string
16
+ readonly titleKey?: MessageKey
17
+ readonly dispatch?: string
18
+ readonly input?: Readonly<Record<string, unknown>>
19
+ readonly invokeOn?: 'press' | 'shown'
20
+ }
21
+
22
+ export const Donut: Element<'Donut', DonutProps> = element(
23
+ 'Donut',
24
+ (props: DonutProps, className) => {
25
+ const kept = uses(props)
26
+ const surface = useSurface({ className: roleClass(undefined, className),
27
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
28
+ holds: [
29
+ ...(kept.holds ?? []),
30
+ ],
31
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
32
+ return (
33
+ <svg className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} role="img" {...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) })}>
34
+ <Each rows={props.rows} by={props.by}>
35
+ {(each0, at) => (
36
+ <circle {...slice(props, kept, each0, at)}></circle>
37
+ )}
38
+ </Each>
39
+ </svg>
40
+ )
41
+ },
42
+ 'e-donut',
43
+ {"card":"thread-card"},
44
+ )
@@ -0,0 +1,42 @@
1
+ import { seriesColour } from '../series.ts'
2
+ import { num, useRamp, type Row } from '../charts.tsx'
3
+ import type { DonutProps } from './donut.tsx'
4
+
5
+ const RADIUS = 40
6
+ const ROUND = 2 * Math.PI * RADIUS
7
+
8
+ export function uses(props: DonutProps): {
9
+ readonly holds?: readonly string[]
10
+ readonly animates?: boolean
11
+ readonly on?: Readonly<Record<string, unknown>>
12
+ readonly ramp: readonly string[]
13
+ } {
14
+ const ramp = useRamp(props.rows.length)
15
+ return {
16
+ ...(props.rows.length === 0 ? { holds: ['empty'] as const } : {}),
17
+ on: { viewBox: '0 0 100 100' },
18
+ ramp,
19
+ }
20
+ }
21
+
22
+ export function slice(
23
+ props: DonutProps,
24
+ kept: { readonly ramp: readonly string[] },
25
+ row: Row,
26
+ at: number,
27
+ ): Readonly<Record<string, string | number>> {
28
+ const whole = props.rows.reduce((sum: number, one: Row) => sum + num(one, props.value), 0) || 1
29
+ const share = num(row, props.value) / whole
30
+ const before = props.rows.slice(0, at).reduce((sum: number, one: Row) => sum + num(one, props.value), 0) / whole
31
+ return {
32
+ cx: 50,
33
+ cy: 50,
34
+ r: RADIUS,
35
+ fill: 'none',
36
+ stroke: seriesColour(kept.ramp, at),
37
+ strokeWidth: 16,
38
+ strokeDasharray: `${(share * ROUND).toFixed(2)} ${ROUND.toFixed(2)}`,
39
+ strokeDashoffset: (-before * ROUND).toFixed(2),
40
+ transform: 'rotate(-90 50 50)',
41
+ }
42
+ }
@@ -6,4 +6,4 @@ export const Each = element('Each', (props, className) => {
6
6
  const surface = useSurface({ className: roleClass(undefined, className),
7
7
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, });
8
8
  return (shows(props, surface));
9
- }, 'e-each');
9
+ }, 'e-each', {});
@@ -0,0 +1,33 @@
1
+ 'use client'
2
+
3
+ import type { ReactNode } from 'react'
4
+ import type { Row } from '../charts.tsx'
5
+ import { roleClass } from '../fonts.ts'
6
+
7
+ import { type Element, element, useSurface } from '../wrappers.tsx'
8
+ import { shows } from './each.works.tsx'
9
+
10
+
11
+ export interface EachProps {
12
+ readonly rows: readonly object[]
13
+ readonly by: string
14
+ readonly children: (row: Row, at: number) => ReactNode
15
+ readonly settles?: string
16
+ readonly paced?: string
17
+ readonly dispatch?: string
18
+ readonly input?: Readonly<Record<string, unknown>>
19
+ readonly invokeOn?: 'press' | 'shown'
20
+ }
21
+
22
+ export const Each: Element<'Each', EachProps> = element(
23
+ 'Each',
24
+ (props: EachProps, className) => {
25
+ const surface = useSurface({ className: roleClass(undefined, className),
26
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
27
+ return (
28
+ shows(props, surface)
29
+ )
30
+ },
31
+ 'e-each',
32
+ {},
33
+ )