@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,35 @@
1
+ 'use client'
2
+
3
+ import type { ReactNode } from 'react'
4
+
5
+ import { type Element, element, useSurface } from '../wrappers.tsx'
6
+ import { uses } from './surface.works.ts'
7
+
8
+
9
+ export interface SurfaceProps {
10
+ readonly children: ReactNode
11
+ readonly dispatch?: string
12
+ readonly input?: Readonly<Record<string, unknown>>
13
+ readonly invokeOn?: 'press' | 'shown'
14
+ }
15
+
16
+ export const Surface: Element<'Surface', SurfaceProps> = element(
17
+ 'Surface',
18
+ (props: SurfaceProps, className) => {
19
+ const kept = uses(props)
20
+ const surface = useSurface({ className,
21
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
22
+ holds: [
23
+ ...(kept.holds ?? []),
24
+ ],
25
+ animates: true,
26
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
27
+ return (
28
+ <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})}>
29
+ {props.children}
30
+ </div>
31
+ )
32
+ },
33
+ 'e-surface',
34
+ {"card":"thread-card"},
35
+ )
@@ -0,0 +1,9 @@
1
+ import { useVisibility } from '../wrappers.tsx'
2
+
3
+ export function uses(_props: unknown): {
4
+ readonly holds?: readonly string[]
5
+ readonly animates?: boolean
6
+ readonly on: { readonly ref: (node: HTMLElement | null) => void }
7
+ } {
8
+ return { on: { ref: useVisibility(true) } }
9
+ }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } 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 { shown, heading, uses } from "./table.works.js";
7
7
  export const Table = element('Table', (props, className) => {
8
8
  const kept = uses(props);
@@ -13,4 +13,4 @@ export const Table = element('Table', (props, className) => {
13
13
  ],
14
14
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
15
15
  return (_jsxs("table", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), ...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) }), children: [_jsx("thead", { children: _jsx("tr", { children: _jsx(Each, { rows: props.columns, by: 'field', children: (each0, at) => (_jsx("th", { ...heading(props, kept, each0, at), children: shown(props, each0, surface, kept).heading })) }) }) }), _jsx("tbody", { children: _jsx(Each, { rows: props.rows, by: props.by, children: (each0, at) => (_jsx("tr", { children: _jsx(Each, { rows: props.columns, by: 'field', children: (each1, at) => (_jsx("td", { children: shown(props, each0, each1, surface, kept).cell })) }) })) }) })] }));
16
- }, 'e-table');
16
+ }, 'e-table', { "card": "thread-card" });
@@ -0,0 +1,61 @@
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 { shown, heading, uses } from './table.works.ts'
10
+
11
+
12
+ export interface TableProps {
13
+ readonly rows: readonly Row[]
14
+ readonly columns: readonly Row[]
15
+ readonly by: 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 Table: Element<'Table', TableProps> = element(
23
+ 'Table',
24
+ (props: TableProps, 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
+ <table className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} {...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) })}>
34
+ <thead>
35
+ <tr>
36
+ <Each rows={props.columns} by={'field'}>
37
+ {(each0, at) => (
38
+ <th {...heading(props, kept, each0, at)}>{shown(props, each0, surface, kept).heading}</th>
39
+ )}
40
+ </Each>
41
+ </tr>
42
+ </thead>
43
+ <tbody>
44
+ <Each rows={props.rows} by={props.by}>
45
+ {(each0, at) => (
46
+ <tr>
47
+ <Each rows={props.columns} by={'field'}>
48
+ {(each1, at) => (
49
+ <td>{shown(props, each0, each1, surface, kept).cell}</td>
50
+ )}
51
+ </Each>
52
+ </tr>
53
+ )}
54
+ </Each>
55
+ </tbody>
56
+ </table>
57
+ )
58
+ },
59
+ 'e-table',
60
+ {"card":"thread-card"},
61
+ )
@@ -0,0 +1,30 @@
1
+ import { formatValue } from '../validators.ts'
2
+ import type { ReactNode } from 'react'
3
+
4
+ import type { Row } from '../charts.tsx'
5
+ import type { Surface } from '../door.ts'
6
+ import type { TableProps } from './table.tsx'
7
+
8
+ export function uses(props: TableProps): {
9
+ readonly holds?: readonly string[]
10
+ readonly animates?: boolean
11
+ readonly on?: Readonly<Record<string, unknown>>
12
+ } {
13
+ return props.rows.length === 0 ? { holds: ['empty'] } : {}
14
+ }
15
+
16
+ export function shown(
17
+ _props: TableProps,
18
+ ...rest: readonly [Row, Surface, unknown] | readonly [Row, Row, Surface, unknown]
19
+ ): Readonly<Record<string, ReactNode>> {
20
+ if (rest.length === 3) {
21
+ const [column, surface] = rest
22
+ return { heading: surface.text(String(column['labelKey'])) }
23
+ }
24
+ const [row, column] = rest
25
+ return { cell: formatValue(String(column['format'] ?? 'text'), row[String(column['field'])]) }
26
+ }
27
+
28
+ export function heading(_props: TableProps, _kept: unknown, _column: Row, _at: number): Readonly<Record<string, string>> {
29
+ return { scope: 'col' }
30
+ }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } 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 { shown, strip, tab, panel, opened, uses } from "./tabs.works.js";
7
7
  export const Tabs = element('Tabs', (props, className) => {
8
8
  const kept = uses(props);
@@ -13,4 +13,4 @@ export const Tabs = element('Tabs', (props, className) => {
13
13
  ],
14
14
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
15
15
  return (_jsxs("div", { ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), children: [_jsx("div", { className: `e-tabs-strip ${surface.className ?? ''}`, ...strip(props, kept), children: _jsx(Each, { rows: props.items, by: 'id', children: (each0, at) => (_jsx("button", { className: "e-tabs-tab", ...tab(props, kept, each0, at), children: shown(props, each0, surface, kept).label })) }) }), !opened(props, kept) ? null : _jsx("div", { ...panel(props, kept), children: shown(props, surface, kept).inside })] }));
16
- }, 'e-tabs');
16
+ }, 'e-tabs', { "tabBar": "thread-tab-bar" });
@@ -0,0 +1,47 @@
1
+ 'use client'
2
+
3
+ import type { MessageKey } from '../content.tsx'
4
+ import { roleClass } from '../fonts.ts'
5
+ import type { TabItem } from '../disclosure.tsx'
6
+
7
+ import { type Element, element, useSurface } from '../wrappers.tsx'
8
+ import { Each } from '../elements/each.tsx'
9
+ import { shown, strip, tab, panel, opened, uses } from './tabs.works.ts'
10
+
11
+
12
+ export interface TabsProps {
13
+ readonly items: readonly TabItem[]
14
+ readonly initial?: string
15
+ readonly onChange?: (said: string) => void
16
+ readonly orientation?: string
17
+ readonly dispatch?: string
18
+ readonly input?: Readonly<Record<string, unknown>>
19
+ readonly invokeOn?: 'press' | 'shown'
20
+ }
21
+
22
+ export const Tabs: Element<'Tabs', TabsProps> = element(
23
+ 'Tabs',
24
+ (props: TabsProps, 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
+ <div {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})}>
34
+ <div className={`e-tabs-strip ${surface.className ?? ''}`} {...strip(props, kept)}>
35
+ <Each rows={props.items} by={'id'}>
36
+ {(each0, at) => (
37
+ <button className="e-tabs-tab" {...tab(props, kept, each0, at)}>{shown(props, each0, surface, kept).label}</button>
38
+ )}
39
+ </Each>
40
+ </div>
41
+ {!opened(props, kept) ? null : <div {...panel(props, kept)}>{shown(props, surface, kept).inside}</div>}
42
+ </div>
43
+ )
44
+ },
45
+ 'e-tabs',
46
+ {"tabBar":"thread-tab-bar"},
47
+ )
@@ -0,0 +1,84 @@
1
+ import { useId, useRef, useState } from 'react'
2
+
3
+ import { ITEM_ATTR, useRovingFocus } from '../roving-focus.ts'
4
+ import type { ReactNode, RefObject } from 'react'
5
+
6
+ import type { Row } from '../charts.tsx'
7
+ import type { Surface } from '../door.ts'
8
+ import type { TabsProps } from './tabs.tsx'
9
+
10
+ type Kept = {
11
+ readonly list: RefObject<HTMLDivElement | null>
12
+ readonly base: string
13
+ readonly open: string | undefined
14
+ readonly choose: (id: string) => void
15
+ }
16
+
17
+ export function uses(props: TabsProps): {
18
+ readonly holds?: readonly string[]
19
+ readonly animates?: boolean
20
+ readonly on?: Readonly<Record<string, unknown>>
21
+ readonly list: RefObject<HTMLDivElement | null>
22
+ readonly base: string
23
+ readonly open: string | undefined
24
+ readonly choose: (id: string) => void
25
+ } {
26
+ const list = useRef<HTMLDivElement>(null)
27
+ const base = useId()
28
+ const first = props.items.find((one) => one.disabled !== true)?.id
29
+ const [active, setActive] = useState<string | undefined>(props.initial ?? first)
30
+ useRovingFocus(list, { orientation: props.orientation === 'vertical' ? 'vertical' : 'horizontal' })
31
+
32
+ const open = props.items.find((one) => one.id === active) ?? props.items.find((one) => one.disabled !== true)
33
+ return {
34
+ list,
35
+ base,
36
+ open: open?.id,
37
+ choose: (id: string): void => {
38
+ setActive(id)
39
+ props.onChange?.(id)
40
+ },
41
+ }
42
+ }
43
+
44
+ export function strip(props: TabsProps, kept: Kept): Readonly<Record<string, unknown>> {
45
+ return { ref: kept.list, role: 'tablist', 'aria-orientation': props.orientation === 'vertical' ? 'vertical' : 'horizontal' }
46
+ }
47
+
48
+ export function tab(_props: TabsProps, kept: Kept, row: Row, _at: number): Readonly<Record<string, unknown>> {
49
+ const id = String(row['id'])
50
+ return {
51
+ ...{ [ITEM_ATTR]: '' },
52
+ type: 'button',
53
+ role: 'tab',
54
+ id: `${kept.base}-tab-${id}`,
55
+ 'aria-controls': `${kept.base}-panel-${id}`,
56
+ 'aria-selected': id === kept.open,
57
+ disabled: row['disabled'] === true,
58
+ onClick: (): void => kept.choose(id),
59
+ }
60
+ }
61
+
62
+ export function opened(_props: TabsProps, kept: Kept): boolean {
63
+ return kept.open !== undefined
64
+ }
65
+
66
+ export function panel(_props: TabsProps, kept: Kept): Readonly<Record<string, unknown>> {
67
+ return {
68
+ role: 'tabpanel',
69
+ id: `${kept.base}-panel-${String(kept.open)}`,
70
+ 'aria-labelledby': `${kept.base}-tab-${String(kept.open)}`,
71
+ }
72
+ }
73
+
74
+ export function shown(
75
+ props: TabsProps,
76
+ ...rest: readonly [Surface, Kept] | readonly [Row, Surface, Kept]
77
+ ): Readonly<Record<string, ReactNode>> {
78
+ if (rest.length === 3) {
79
+ const [row, surface] = rest
80
+ return { label: surface.text(String(row['labelKey'])) }
81
+ }
82
+ const [, kept] = rest
83
+ return { inside: props.items.find((one) => one.id === kept.open)?.content ?? null }
84
+ }
@@ -6,4 +6,4 @@ export const Text = element('Text', (props, className) => {
6
6
  const surface = useSurface({ className: roleClass(props.is, 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 (_jsx("span", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, role: props.announce, children: surface.text(props.k, props.with) }));
9
- }, 'e-text');
9
+ }, 'e-text', {});
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+
3
+ import type { MessageKey } from '../content.tsx'
4
+ import { roleClass, type FontRoleId } from '../fonts.ts'
5
+
6
+ import { type Element, element, useSurface } from '../wrappers.tsx'
7
+
8
+
9
+ export interface TextProps {
10
+ readonly k: MessageKey
11
+ readonly with?: Readonly<Record<string, unknown>>
12
+ readonly is?: FontRoleId
13
+ readonly announce?: 'alert' | 'status'
14
+ readonly dispatch?: string
15
+ readonly input?: Readonly<Record<string, unknown>>
16
+ readonly invokeOn?: 'press' | 'shown'
17
+ }
18
+
19
+ export const Text: Element<'Text', TextProps> = element(
20
+ 'Text',
21
+ (props: TextProps, className) => {
22
+ const surface = useSurface({ className: roleClass(props.is, className),
23
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
24
+ return (
25
+ <span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} role={props.announce}>
26
+ {surface.text(props.k, props.with)}
27
+ </span>
28
+ )
29
+ },
30
+ 'e-text',
31
+ {},
32
+ )
@@ -8,4 +8,4 @@ export const Textarea = element('Textarea', (props, className) => {
8
8
  const surface = useSurface({ className: roleClass(undefined, className),
9
9
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, });
10
10
  return (_jsxs("label", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, children: [_jsx("span", { children: surface.text(props.labelKey) }), props.value === undefined ? null : _jsx("textarea", { name: props.name, rows: props.rows ?? 4, ...limited(props.validator), disabled: surface.marked('disabled'), value: props.value ?? '', onChange: (event) => does(props).wrote(event.target.value) })] }));
11
- }, 'e-textarea');
11
+ }, 'e-textarea', { "input": "thread-input" });
@@ -0,0 +1,37 @@
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 { limited } from '../validators.ts'
8
+ import { does } from './textarea.works.ts'
9
+
10
+
11
+ export interface TextareaProps {
12
+ readonly labelKey: MessageKey
13
+ readonly name?: string
14
+ readonly value?: string
15
+ readonly onValue?: (said: string) => void
16
+ readonly validator?: string
17
+ readonly rows?: number
18
+ readonly dispatch?: string
19
+ readonly input?: Readonly<Record<string, unknown>>
20
+ readonly invokeOn?: 'press' | 'shown'
21
+ }
22
+
23
+ export const Textarea: Element<'Textarea', TextareaProps> = element(
24
+ 'Textarea',
25
+ (props: TextareaProps, className) => {
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
+ return (
29
+ <label className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
30
+ <span>{surface.text(props.labelKey)}</span>
31
+ {props.value === undefined ? null : <textarea name={props.name} rows={props.rows ?? 4} {...limited(props.validator)} disabled={surface.marked('disabled')} value={props.value ?? ''} onChange={(event) => does(props).wrote(event.target.value)}></textarea>}
32
+ </label>
33
+ )
34
+ },
35
+ 'e-textarea',
36
+ {"input":"thread-input"},
37
+ )
@@ -0,0 +1,5 @@
1
+ import type { TextareaProps } from './textarea.tsx'
2
+
3
+ export function does(props: TextareaProps): { readonly wrote: (said: string) => void } {
4
+ return { wrote: (said: string) => props.onValue?.(said) }
5
+ }
@@ -11,4 +11,4 @@ export const Time = element('Time', (props, className) => {
11
11
  ],
12
12
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
13
13
  return (shows(props, surface, kept));
14
- }, 'e-time');
14
+ }, 'e-time', {});
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+
3
+ import { roleClass, type FontRoleId } from '../fonts.ts'
4
+
5
+ import { type Element, element, useSurface } from '../wrappers.tsx'
6
+ import { shows, uses } from './time.works.ts'
7
+
8
+
9
+ export interface TimeProps {
10
+ readonly value?: unknown
11
+ readonly relative?: boolean
12
+ readonly is?: FontRoleId
13
+ readonly dispatch?: string
14
+ readonly input?: Readonly<Record<string, unknown>>
15
+ readonly invokeOn?: 'press' | 'shown'
16
+ }
17
+
18
+ export const Time: Element<'Time', TimeProps> = element(
19
+ 'Time',
20
+ (props: TimeProps, className) => {
21
+ const kept = uses(props)
22
+ const surface = useSurface({ className: roleClass(props.is, className),
23
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
24
+ holds: [
25
+ ...(kept.holds ?? []),
26
+ ],
27
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
28
+ return (
29
+ shows(props, surface, kept)
30
+ )
31
+ },
32
+ 'e-time',
33
+ {},
34
+ )
@@ -0,0 +1,25 @@
1
+ import { useCallback, useSyncExternalStore, type ReactNode } from 'react'
2
+
3
+ import { renderValue } from '../content.tsx'
4
+ import type { Surface } from '../door.ts'
5
+ import { useUi } from '../wrappers.tsx'
6
+ import type { TimeProps } from './time.tsx'
7
+
8
+ const NO_CLOCK_YET = (): number | undefined => undefined
9
+
10
+ export function uses(props: TimeProps): { readonly holds?: readonly string[]; readonly animates?: boolean; readonly at: number | undefined } {
11
+ const { now, ticker } = useUi()
12
+ const subscribe = useCallback(
13
+ (onChange: () => void) => (props.relative === true && ticker !== undefined ? ticker.subscribe(onChange) : () => undefined),
14
+ [props.relative, ticker],
15
+ )
16
+ const read = useCallback(() => now?.(), [now])
17
+ return { at: useSyncExternalStore(subscribe, read, NO_CLOCK_YET) }
18
+ }
19
+
20
+ export function shows(props: TimeProps, surface: Surface, kept: { readonly at: number | undefined }): ReactNode {
21
+ if (props.relative !== true || kept.at === undefined) {
22
+ return renderValue({ validator: 'datetime', value: props.value }, surface)
23
+ }
24
+ return renderValue({ validator: 'relativeTime', value: props.value, context: { now: kept.at } }, surface)
25
+ }
@@ -7,4 +7,4 @@ export const Toggle = element('Toggle', (props, className) => {
7
7
  const surface = useSurface({ className: roleClass(undefined, className),
8
8
  invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, });
9
9
  return (_jsxs("label", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, children: [props.on === undefined ? null : _jsx("input", { type: "checkbox", disabled: surface.marked('disabled'), checked: props.on === true, onChange: (event) => does(props).changed(event.target.checked) }), _jsx("span", { children: surface.text(props.labelKey) })] }));
10
- }, 'e-toggle');
10
+ }, 'e-toggle', { "input": "thread-input" });
@@ -0,0 +1,33 @@
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 { does } from './toggle.works.ts'
8
+
9
+
10
+ export interface ToggleProps {
11
+ readonly labelKey: MessageKey
12
+ readonly on?: boolean
13
+ readonly onToggle?: (said: boolean) => void
14
+ readonly dispatch?: string
15
+ readonly input?: Readonly<Record<string, unknown>>
16
+ readonly invokeOn?: 'press' | 'shown'
17
+ }
18
+
19
+ export const Toggle: Element<'Toggle', ToggleProps> = element(
20
+ 'Toggle',
21
+ (props: ToggleProps, className) => {
22
+ const surface = useSurface({ className: roleClass(undefined, className),
23
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
24
+ return (
25
+ <label className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
26
+ {props.on === undefined ? null : <input type="checkbox" disabled={surface.marked('disabled')} checked={props.on === true} onChange={(event) => does(props).changed(event.target.checked)} />}
27
+ <span>{surface.text(props.labelKey)}</span>
28
+ </label>
29
+ )
30
+ },
31
+ 'e-toggle',
32
+ {"input":"thread-input"},
33
+ )
@@ -0,0 +1,5 @@
1
+ import type { ToggleProps } from './toggle.tsx'
2
+
3
+ export function does(props: ToggleProps): { readonly changed: (on: boolean) => void } {
4
+ return { changed: (on: boolean) => props.onToggle?.(on) }
5
+ }
@@ -12,4 +12,4 @@ export const Tooltip = element('Tooltip', (props, className) => {
12
12
  measures: measured(props, kept),
13
13
  ...(kept.animates === undefined ? {} : { animates: kept.animates }), });
14
14
  return (_jsxs("span", { ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), style: surface.measures, children: [props.children, !showing(props, kept) ? null : _jsx("span", { className: `e-tooltip-bubble ${surface.className ?? ''}`, ...bubble(props, kept), children: surface.text(props.labelKey) })] }));
15
- }, 'e-tooltip');
15
+ }, 'e-tooltip', { "card": "thread-card" });
@@ -0,0 +1,39 @@
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
+ import { measured, bubble, showing, uses } from './tooltip.works.ts'
8
+
9
+
10
+ export interface TooltipProps {
11
+ readonly children: ReactNode
12
+ readonly labelKey: MessageKey
13
+ readonly side?: string
14
+ readonly dispatch?: string
15
+ readonly input?: Readonly<Record<string, unknown>>
16
+ readonly invokeOn?: 'press' | 'shown'
17
+ }
18
+
19
+ export const Tooltip: Element<'Tooltip', TooltipProps> = element(
20
+ 'Tooltip',
21
+ (props: TooltipProps, className) => {
22
+ const kept = uses(props)
23
+ const surface = useSurface({ className,
24
+ invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
25
+ holds: [
26
+ ...(kept.holds ?? []),
27
+ ],
28
+ measures: measured(props, kept),
29
+ ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
30
+ return (
31
+ <span {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} style={surface.measures}>
32
+ {props.children}
33
+ {!showing(props, kept) ? null : <span className={`e-tooltip-bubble ${surface.className ?? ''}`} {...bubble(props, kept)}>{surface.text(props.labelKey)}</span>}
34
+ </span>
35
+ )
36
+ },
37
+ 'e-tooltip',
38
+ {"card":"thread-card"},
39
+ )
@@ -0,0 +1,77 @@
1
+ import { useEffect, useRef, useState } from 'react'
2
+
3
+ import { useDismissLayer } from '../dismiss-layer.ts'
4
+ import { positionOf, type AnchorOptions } from '../positioning.ts'
5
+ import type { TooltipProps } from './tooltip.tsx'
6
+
7
+ type Kept = {
8
+ readonly trigger: React.RefObject<HTMLSpanElement | null>
9
+ readonly layer: React.RefObject<HTMLSpanElement | null>
10
+ readonly open: boolean
11
+ readonly at: { readonly x: number; readonly y: number } | null
12
+ readonly show: (to: boolean) => void
13
+ }
14
+
15
+ export function uses(props: TooltipProps): {
16
+ readonly holds?: readonly string[]
17
+ readonly animates?: boolean
18
+ readonly on: Readonly<Record<string, unknown>>
19
+ readonly trigger: React.RefObject<HTMLSpanElement | null>
20
+ readonly layer: React.RefObject<HTMLSpanElement | null>
21
+ readonly open: boolean
22
+ readonly at: { readonly x: number; readonly y: number } | null
23
+ readonly show: (to: boolean) => void
24
+ } {
25
+ const trigger = useRef<HTMLSpanElement>(null)
26
+ const layer = useRef<HTMLSpanElement>(null)
27
+ const [open, setOpen] = useState(false)
28
+ const [at, setAt] = useState<{ x: number; y: number } | null>(null)
29
+
30
+ useDismissLayer(layer, {
31
+ active: open,
32
+ dismissOnEscape: true,
33
+ dismissOnOutside: true,
34
+ onDismiss: () => setOpen(false),
35
+ })
36
+
37
+ useEffect(() => {
38
+ if (!open) return undefined
39
+ const anchor = trigger.current
40
+ const floating = layer.current
41
+ if (anchor === null || floating === null) return undefined
42
+ let live = true
43
+ void positionOf(anchor, floating, { placement: (props.side ?? 'top') as NonNullable<AnchorOptions['placement']> }).then((position) => {
44
+ if (live) setAt({ x: position.x, y: position.y })
45
+ })
46
+ return () => {
47
+ live = false
48
+ }
49
+ }, [open, props.side])
50
+
51
+ return {
52
+ on: {
53
+ ref: trigger,
54
+ onPointerEnter: () => setOpen(true),
55
+ onPointerLeave: () => setOpen(false),
56
+ onFocus: () => setOpen(true),
57
+ onBlur: () => setOpen(false),
58
+ },
59
+ trigger,
60
+ layer,
61
+ open,
62
+ at,
63
+ show: setOpen,
64
+ }
65
+ }
66
+
67
+ export function showing(_props: TooltipProps, kept: Kept): boolean {
68
+ return kept.open
69
+ }
70
+
71
+ export function bubble(props: TooltipProps, kept: Kept): Readonly<Record<string, unknown>> {
72
+ return { ref: kept.layer, role: 'tooltip', 'data-side': props.side ?? 'top' }
73
+ }
74
+
75
+ export function measured(_props: TooltipProps, kept: Kept): Readonly<Record<string, string | number>> {
76
+ return kept.at === null ? {} : { x: `${String(kept.at.x)}px`, y: `${String(kept.at.y)}px` }
77
+ }
@@ -6,4 +6,4 @@ export const Value = element('Value', (props, className) => {
6
6
  const surface = useSurface({ className: roleClass(props.is, 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-value');
9
+ }, 'e-value', {});