@prestack/thread-ui 0.1.10 → 0.1.11

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 (209) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/dist/ui/attach.js +6 -7
  3. package/dist/ui/compositions.d.ts +0 -8
  4. package/dist/ui/compositions.js +3 -166
  5. package/dist/ui/generators/routes.js +1 -0
  6. package/package.json +2 -2
  7. package/dist/ui/animations/anm_appear.ts +0 -13
  8. package/dist/ui/animations/anm_blur_in.ts +0 -19
  9. package/dist/ui/animations/anm_blur_out.ts +0 -18
  10. package/dist/ui/animations/anm_dismiss.ts +0 -18
  11. package/dist/ui/animations/anm_drop.ts +0 -19
  12. package/dist/ui/animations/anm_fall.ts +0 -18
  13. package/dist/ui/animations/anm_flash.ts +0 -18
  14. package/dist/ui/animations/anm_glow.ts +0 -16
  15. package/dist/ui/animations/anm_lift.ts +0 -16
  16. package/dist/ui/animations/anm_nudge.ts +0 -16
  17. package/dist/ui/animations/anm_pop_in.ts +0 -23
  18. package/dist/ui/animations/anm_pop_out.ts +0 -22
  19. package/dist/ui/animations/anm_press.ts +0 -12
  20. package/dist/ui/animations/anm_pulse.ts +0 -13
  21. package/dist/ui/animations/anm_rise.ts +0 -19
  22. package/dist/ui/animations/anm_shake.ts +0 -13
  23. package/dist/ui/animations/anm_slide_in_left.ts +0 -19
  24. package/dist/ui/animations/anm_slide_in_right.ts +0 -19
  25. package/dist/ui/animations/anm_slide_out_left.ts +0 -18
  26. package/dist/ui/animations/anm_slide_out_right.ts +0 -18
  27. package/dist/ui/animations/anm_spin.ts +0 -12
  28. package/dist/ui/animations/anm_swell.ts +0 -16
  29. package/dist/ui/animations/anm_wobble.ts +0 -24
  30. package/dist/ui/animations/anm_zoom_in.ts +0 -19
  31. package/dist/ui/animations/anm_zoom_out.ts +0 -18
  32. package/dist/ui/animations.ts +0 -308
  33. package/dist/ui/attach.ts +0 -553
  34. package/dist/ui/charts.tsx +0 -69
  35. package/dist/ui/checked.ts +0 -32
  36. package/dist/ui/collector.ts +0 -140
  37. package/dist/ui/compositions.ts +0 -613
  38. package/dist/ui/consent.ts +0 -55
  39. package/dist/ui/content.tsx +0 -27
  40. package/dist/ui/contrast.ts +0 -27
  41. package/dist/ui/controls.tsx +0 -25
  42. package/dist/ui/disclosure.tsx +0 -20
  43. package/dist/ui/dismiss-layer.ts +0 -87
  44. package/dist/ui/door.ts +0 -140
  45. package/dist/ui/drag.ts +0 -316
  46. package/dist/ui/elements/accordion.tsx +0 -47
  47. package/dist/ui/elements/accordion.works.ts +0 -66
  48. package/dist/ui/elements/aspect-ratio.tsx +0 -31
  49. package/dist/ui/elements/aspect-ratio.works.ts +0 -5
  50. package/dist/ui/elements/avatar.tsx +0 -34
  51. package/dist/ui/elements/avatar.works.ts +0 -16
  52. package/dist/ui/elements/badge.tsx +0 -33
  53. package/dist/ui/elements/badge.works.ts +0 -9
  54. package/dist/ui/elements/bars.tsx +0 -50
  55. package/dist/ui/elements/bars.works.ts +0 -29
  56. package/dist/ui/elements/box.tsx +0 -36
  57. package/dist/ui/elements/breadcrumb.tsx +0 -38
  58. package/dist/ui/elements/breadcrumb.works.ts +0 -24
  59. package/dist/ui/elements/button.tsx +0 -46
  60. package/dist/ui/elements/button.works.tsx +0 -52
  61. package/dist/ui/elements/column.tsx +0 -29
  62. package/dist/ui/elements/consent.tsx +0 -71
  63. package/dist/ui/elements/consent.works.tsx +0 -132
  64. package/dist/ui/elements/donut.tsx +0 -45
  65. package/dist/ui/elements/donut.works.ts +0 -42
  66. package/dist/ui/elements/each.tsx +0 -34
  67. package/dist/ui/elements/each.works.tsx +0 -82
  68. package/dist/ui/elements/empty.tsx +0 -33
  69. package/dist/ui/elements/field.tsx +0 -45
  70. package/dist/ui/elements/field.works.ts +0 -65
  71. package/dist/ui/elements/funnel.tsx +0 -50
  72. package/dist/ui/elements/funnel.works.ts +0 -37
  73. package/dist/ui/elements/gauge.tsx +0 -40
  74. package/dist/ui/elements/gauge.works.ts +0 -42
  75. package/dist/ui/elements/glyph.tsx +0 -30
  76. package/dist/ui/elements/glyph.works.tsx +0 -42
  77. package/dist/ui/elements/grid.tsx +0 -29
  78. package/dist/ui/elements/heatmap.tsx +0 -48
  79. package/dist/ui/elements/heatmap.works.ts +0 -24
  80. package/dist/ui/elements/hit-box.tsx +0 -47
  81. package/dist/ui/elements/hit-box.works.tsx +0 -576
  82. package/dist/ui/elements/image.tsx +0 -29
  83. package/dist/ui/elements/line-chart.tsx +0 -45
  84. package/dist/ui/elements/line-chart.works.ts +0 -41
  85. package/dist/ui/elements/link.tsx +0 -38
  86. package/dist/ui/elements/link.works.ts +0 -25
  87. package/dist/ui/elements/media.tsx +0 -57
  88. package/dist/ui/elements/menu.tsx +0 -51
  89. package/dist/ui/elements/menu.works.tsx +0 -154
  90. package/dist/ui/elements/money.tsx +0 -36
  91. package/dist/ui/elements/money.works.ts +0 -9
  92. package/dist/ui/elements/pagination.tsx +0 -39
  93. package/dist/ui/elements/pagination.works.ts +0 -20
  94. package/dist/ui/elements/progress.tsx +0 -34
  95. package/dist/ui/elements/progress.works.ts +0 -8
  96. package/dist/ui/elements/radio-group.tsx +0 -50
  97. package/dist/ui/elements/radio-group.works.ts +0 -33
  98. package/dist/ui/elements/row.tsx +0 -29
  99. package/dist/ui/elements/scatter.tsx +0 -42
  100. package/dist/ui/elements/scatter.works.ts +0 -38
  101. package/dist/ui/elements/select.tsx +0 -43
  102. package/dist/ui/elements/select.works.ts +0 -5
  103. package/dist/ui/elements/separator.tsx +0 -31
  104. package/dist/ui/elements/skeleton.tsx +0 -31
  105. package/dist/ui/elements/slider.tsx +0 -34
  106. package/dist/ui/elements/slider.works.ts +0 -5
  107. package/dist/ui/elements/sparkline.tsx +0 -37
  108. package/dist/ui/elements/sparkline.works.ts +0 -32
  109. package/dist/ui/elements/spinner.tsx +0 -33
  110. package/dist/ui/elements/stack.tsx +0 -29
  111. package/dist/ui/elements/stat.tsx +0 -36
  112. package/dist/ui/elements/stat.works.ts +0 -14
  113. package/dist/ui/elements/surface.tsx +0 -36
  114. package/dist/ui/elements/surface.works.ts +0 -9
  115. package/dist/ui/elements/table.tsx +0 -62
  116. package/dist/ui/elements/table.works.ts +0 -30
  117. package/dist/ui/elements/tabs.tsx +0 -47
  118. package/dist/ui/elements/tabs.works.ts +0 -84
  119. package/dist/ui/elements/text.tsx +0 -33
  120. package/dist/ui/elements/textarea.tsx +0 -38
  121. package/dist/ui/elements/textarea.works.ts +0 -5
  122. package/dist/ui/elements/time.tsx +0 -40
  123. package/dist/ui/elements/time.works.ts +0 -29
  124. package/dist/ui/elements/toggle.tsx +0 -34
  125. package/dist/ui/elements/toggle.works.ts +0 -5
  126. package/dist/ui/elements/tooltip.tsx +0 -40
  127. package/dist/ui/elements/tooltip.works.ts +0 -77
  128. package/dist/ui/elements/value.tsx +0 -38
  129. package/dist/ui/elements/value.works.ts +0 -9
  130. package/dist/ui/elements.ts +0 -127
  131. package/dist/ui/focus-scope.ts +0 -121
  132. package/dist/ui/fonts.ts +0 -355
  133. package/dist/ui/generators/dev.d.ts +0 -1
  134. package/dist/ui/generators/dev.js +0 -62
  135. package/dist/ui/generators/dev.ts +0 -75
  136. package/dist/ui/generators/elements.ts +0 -796
  137. package/dist/ui/generators/i18n.ts +0 -283
  138. package/dist/ui/generators/icons.ts +0 -207
  139. package/dist/ui/generators/react.ts +0 -267
  140. package/dist/ui/generators/routes.ts +0 -847
  141. package/dist/ui/generators/show.ts +0 -261
  142. package/dist/ui/generators/styles.ts +0 -677
  143. package/dist/ui/generators/variants.ts +0 -196
  144. package/dist/ui/i18n/catalogs/en.ts +0 -191
  145. package/dist/ui/i18n/format.ts +0 -221
  146. package/dist/ui/i18n/locales.ts +0 -33
  147. package/dist/ui/i18n/parse.ts +0 -315
  148. package/dist/ui/i18n/translator.ts +0 -31
  149. package/dist/ui/i18n/types.ts +0 -96
  150. package/dist/ui/icons.ts +0 -331
  151. package/dist/ui/islands/map.ts +0 -58
  152. package/dist/ui/localizations.ts +0 -75
  153. package/dist/ui/material.ts +0 -236
  154. package/dist/ui/materials/mat_bordered.ts +0 -13
  155. package/dist/ui/materials/mat_ceramic.ts +0 -13
  156. package/dist/ui/materials/mat_clay.ts +0 -13
  157. package/dist/ui/materials/mat_elevated.ts +0 -24
  158. package/dist/ui/materials/mat_flat.ts +0 -34
  159. package/dist/ui/materials/mat_glass.ts +0 -20
  160. package/dist/ui/materials/mat_lit.ts +0 -13
  161. package/dist/ui/materials/mat_moulded.ts +0 -11
  162. package/dist/ui/materials.ts +0 -197
  163. package/dist/ui/modes.ts +0 -44
  164. package/dist/ui/navigation.tsx +0 -29
  165. package/dist/ui/positioning.ts +0 -90
  166. package/dist/ui/presented.tsx +0 -119
  167. package/dist/ui/provider.tsx +0 -184
  168. package/dist/ui/render-loop.ts +0 -133
  169. package/dist/ui/roving-focus.ts +0 -161
  170. package/dist/ui/screens.ts +0 -141
  171. package/dist/ui/scroll-lock.ts +0 -28
  172. package/dist/ui/series.ts +0 -97
  173. package/dist/ui/signals.ts +0 -386
  174. package/dist/ui/styleguide.ts +0 -231
  175. package/dist/ui/styleguides.ts +0 -374
  176. package/dist/ui/themes.ts +0 -22
  177. package/dist/ui/token.ts +0 -78
  178. package/dist/ui/tokens/shadow.ts +0 -25
  179. package/dist/ui/tokens.ts +0 -234
  180. package/dist/ui/validators.ts +0 -232
  181. package/dist/ui/variant.ts +0 -349
  182. package/dist/ui/variants/var_avatar-round.ts +0 -14
  183. package/dist/ui/variants/var_bubble-me.ts +0 -14
  184. package/dist/ui/variants/var_bubble-them.ts +0 -13
  185. package/dist/ui/variants/var_button-border.ts +0 -76
  186. package/dist/ui/variants/var_button-cta.ts +0 -76
  187. package/dist/ui/variants/var_button-destructive-ghost.ts +0 -72
  188. package/dist/ui/variants/var_button-destructive.ts +0 -76
  189. package/dist/ui/variants/var_button-fill.ts +0 -76
  190. package/dist/ui/variants/var_button-ghost.ts +0 -72
  191. package/dist/ui/variants/var_button-glass.ts +0 -55
  192. package/dist/ui/variants/var_button-normal.ts +0 -76
  193. package/dist/ui/variants/var_button-quiet.ts +0 -74
  194. package/dist/ui/variants/var_card.ts +0 -17
  195. package/dist/ui/variants/var_chip.ts +0 -13
  196. package/dist/ui/variants/var_choice.ts +0 -15
  197. package/dist/ui/variants/var_framed.ts +0 -10
  198. package/dist/ui/variants/var_glyph-plain.ts +0 -11
  199. package/dist/ui/variants/var_input.ts +0 -43
  200. package/dist/ui/variants/var_link-inline.ts +0 -29
  201. package/dist/ui/variants/var_list-row.ts +0 -34
  202. package/dist/ui/variants/var_rule.ts +0 -10
  203. package/dist/ui/variants/var_skeleton-block.ts +0 -12
  204. package/dist/ui/variants/var_spinner-turning.ts +0 -12
  205. package/dist/ui/variants/var_stat-tile.ts +0 -13
  206. package/dist/ui/variants/var_tab-bar.ts +0 -15
  207. package/dist/ui/variants/var_tap-target.ts +0 -25
  208. package/dist/ui/variants.ts +0 -64
  209. package/dist/ui/wrappers.tsx +0 -429
@@ -1,38 +0,0 @@
1
- 'use client'
2
-
3
- import type { MessageKey } from '../content.tsx'
4
- import { roleClass, type FontRoleId } from '../fonts.ts'
5
-
6
- import type { Dispatching } from '../checked.ts'
7
- import { type Element, element, useSurface } from '../wrappers.tsx'
8
- import { uses } from './link.works.ts'
9
-
10
-
11
- export interface LinkProps {
12
- readonly navigateTo: string
13
- readonly labelKey: MessageKey
14
- readonly is?: FontRoleId
15
- readonly dispatch?: keyof Dispatching
16
- readonly input?: Readonly<Record<string, unknown>>
17
- readonly invokeOn?: 'press' | 'shown'
18
- }
19
-
20
- export const Link: Element<'Link', LinkProps> = element(
21
- 'Link',
22
- (props: LinkProps, className) => {
23
- const kept = uses(props)
24
- const surface = useSurface({ className: roleClass(props.is, className),
25
- invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
26
- holds: [
27
- ...(kept.holds ?? []),
28
- ],
29
- ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
30
- return (
31
- <a className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})}>
32
- {surface.text(props.labelKey)}
33
- </a>
34
- )
35
- },
36
- 'e-link',
37
- {"linkInline":"thread-link-inline"},
38
- )
@@ -1,25 +0,0 @@
1
- import type { MouseEvent } from 'react'
2
-
3
- import { usePress } from '../wrappers.tsx'
4
- import type { LinkProps } from './link.tsx'
5
-
6
- export function uses(props: LinkProps): {
7
- readonly holds?: readonly string[]
8
- readonly animates?: boolean
9
- readonly on: {
10
- readonly href: string
11
- readonly onClick: (event: MouseEvent<HTMLAnchorElement>) => void
12
- }
13
- } {
14
- const press = usePress({ navigateTo: props.navigateTo }, { element: 'Link', name: props.labelKey })
15
- return {
16
- on: {
17
- href: `#${props.navigateTo}`,
18
- onClick: (event: MouseEvent<HTMLAnchorElement>): void => {
19
- if (event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0) return
20
- event.preventDefault()
21
- press?.()
22
- },
23
- },
24
- }
25
- }
@@ -1,57 +0,0 @@
1
- 'use client'
2
-
3
- import type { MessageKey } from '../content.tsx'
4
- import { roleClass } from '../fonts.ts'
5
-
6
- import type { Dispatching } from '../checked.ts'
7
- import { type Element, element, useSurface } from '../wrappers.tsx'
8
-
9
-
10
- export interface MediaProps {
11
- readonly as: 'image' | 'video' | 'audio' | 'file'
12
- readonly src: string
13
- readonly altKey: MessageKey
14
- readonly dispatch?: keyof Dispatching
15
- readonly input?: Readonly<Record<string, unknown>>
16
- readonly invokeOn?: 'press' | 'shown'
17
- }
18
-
19
- export const Media: Element<'Media', MediaProps> = element(
20
- 'Media',
21
- (props: MediaProps, 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
- (() => {
26
- switch (props.as) {
27
- case 'image':
28
- return (
29
- <img className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} src={props.src} alt={surface.text(props.altKey)} />
30
- )
31
- case 'video':
32
- return (
33
- <video className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} src={props.src} aria-label={surface.text(props.altKey)} controls preload="metadata">
34
- {null}
35
- </video>
36
- )
37
- case 'audio':
38
- return (
39
- <audio className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} src={props.src} aria-label={surface.text(props.altKey)} controls preload="metadata">
40
- {null}
41
- </audio>
42
- )
43
- case 'file':
44
- return (
45
- <a className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} href={props.src} download>
46
- {surface.text(props.altKey)}
47
- </a>
48
- )
49
- default:
50
- return null
51
- }
52
- })()
53
- )
54
- },
55
- 'e-media',
56
- {"card":"thread-card","framed":"thread-framed"},
57
- )
@@ -1,51 +0,0 @@
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
- import { Presented, MenuRow } from './menu.works.tsx'
7
-
8
- import type { Dispatching } from '../checked.ts'
9
- import { type Element, element, useSurface } from '../wrappers.tsx'
10
- import { Each } from '../elements/each.tsx'
11
- import { measured, opener, portal, listing, row, uses } from './menu.works.tsx'
12
-
13
-
14
- export interface MenuProps {
15
- readonly labelKey: MessageKey
16
- readonly items: readonly Row[]
17
- readonly side?: string
18
- readonly dispatch?: keyof Dispatching
19
- readonly input?: Readonly<Record<string, unknown>>
20
- readonly invokeOn?: 'press' | 'shown'
21
- }
22
-
23
- export const Menu: Element<'Menu', MenuProps> = element(
24
- 'Menu',
25
- (props: MenuProps, className) => {
26
- const kept = uses(props)
27
- const surface = useSurface({ className: roleClass(undefined, className),
28
- invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
29
- holds: [
30
- ...(kept.holds ?? []),
31
- ],
32
- measures: measured(props, kept),
33
- ...(kept.animates === undefined ? {} : { animates: kept.animates }), })
34
- return (
35
- <span {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} style={surface.measures}>
36
- <button className={`e-menu-opener ${surface.className ?? ''}`} {...opener(props, kept)}>{surface.text(props.labelKey)}</button>
37
- <Presented {...portal(props, kept)}>
38
- <div className="e-menu-layer" {...listing(props, kept)}>
39
- <Each rows={props.items} by={props.labelKey}>
40
- {(each0, at) => (
41
- <MenuRow {...row(props, kept, each0, at)}></MenuRow>
42
- )}
43
- </Each>
44
- </div>
45
- </Presented>
46
- </span>
47
- )
48
- },
49
- 'e-menu',
50
- {"card":"thread-card"},
51
- )
@@ -1,154 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect, useId, useRef, useState, type ReactNode } from 'react'
4
-
5
- import type { Dispatching } from '../checked.ts'
6
- import type { MessageKey } from '../content.tsx'
7
- import { positionOf, type AnchorOptions, type Position } from '../positioning.ts'
8
- import { ITEM_ATTR, useRovingFocus } from '../roving-focus.ts'
9
- import { pressOf, usePress, useSurface } from '../wrappers.tsx'
10
- import { drawn } from './glyph.works.tsx'
11
- import type { MenuProps } from './menu.tsx'
12
-
13
- export interface MenuItem {
14
- readonly labelKey: MessageKey
15
- readonly dispatch?: keyof Dispatching
16
- readonly navigateTo?: string
17
- readonly icon?: string
18
- readonly disabled?: boolean
19
- }
20
-
21
- export { Presented } from '../presented.tsx'
22
- import type { PresentedProps } from '../presented.tsx'
23
-
24
- const SIDE = 'bottom'
25
-
26
- export function MenuRow({
27
- item,
28
- onDone,
29
- }: {
30
- readonly item: MenuItem
31
- readonly onDone: () => void
32
- }): ReactNode {
33
-
34
- const { text } = useSurface({})
35
- const press = usePress(pressOf(item), { element: 'Menu', name: item.labelKey })
36
- return (
37
- <button
38
- {...{ [ITEM_ATTR]: '' }}
39
- type="button"
40
- role="menuitem"
41
- disabled={item.disabled === true}
42
- onClick={() => {
43
- press?.()
44
- onDone()
45
- }}
46
- >
47
- {item.icon === undefined ? null : drawn(item.icon, { 'aria-hidden': true })}
48
- {text(item.labelKey)}
49
- </button>
50
- )
51
- }
52
-
53
- type Kept = {
54
- readonly trigger: React.RefObject<HTMLButtonElement | null>
55
- readonly layer: React.RefObject<HTMLDivElement | null>
56
- readonly open: boolean
57
- readonly at: Position | null
58
- readonly names: { readonly trigger: string; readonly menu: string }
59
- readonly show: (to: boolean | ((was: boolean) => boolean)) => void
60
- }
61
-
62
- export function uses(props: MenuProps): {
63
- readonly holds?: readonly string[]
64
- readonly animates?: boolean
65
- readonly on?: Readonly<Record<string, unknown>>
66
- readonly trigger: React.RefObject<HTMLButtonElement | null>
67
- readonly layer: React.RefObject<HTMLDivElement | null>
68
- readonly open: boolean
69
- readonly at: Position | null
70
- readonly names: { readonly trigger: string; readonly menu: string }
71
- readonly show: (to: boolean | ((was: boolean) => boolean)) => void
72
- } {
73
- const trigger = useRef<HTMLButtonElement>(null)
74
- const layer = useRef<HTMLDivElement>(null)
75
- const [open, setOpen] = useState(false)
76
- const [at, setAt] = useState<Position | null>(null)
77
- const base = useId()
78
-
79
- useRovingFocus(layer, { orientation: 'vertical', wrap: true, active: open })
80
-
81
- useEffect(() => {
82
- if (!open) return undefined
83
- const anchor = trigger.current
84
- const floating = layer.current
85
- if (anchor === null || floating === null) return undefined
86
- let live = true
87
- void positionOf(anchor, floating, {
88
- placement: (props.side ?? SIDE) as NonNullable<AnchorOptions['placement']>,
89
- }).then((position) => {
90
- if (live) setAt(position)
91
- })
92
- return () => {
93
- live = false
94
- }
95
- }, [open, props.side])
96
-
97
- return {
98
- trigger,
99
- layer,
100
- open,
101
- at,
102
- names: { trigger: `${base}-trigger`, menu: `${base}-menu` },
103
- show: setOpen,
104
- }
105
- }
106
-
107
- export function opener(_props: MenuProps, kept: Kept): Readonly<Record<string, unknown>> {
108
- return {
109
- ref: kept.trigger,
110
- type: 'button',
111
- id: kept.names.trigger,
112
- 'aria-haspopup': 'menu',
113
- 'aria-expanded': kept.open,
114
- ...(kept.open ? { 'aria-controls': kept.names.menu } : {}),
115
- onPointerDown: (event: React.PointerEvent<HTMLButtonElement>): void => {
116
- if (event.button > 0 || event.ctrlKey) return
117
- event.currentTarget.focus()
118
- event.preventDefault()
119
- kept.show((was) => !was)
120
- },
121
- onKeyDown: (event: React.KeyboardEvent<HTMLButtonElement>): void => {
122
- if (event.key !== 'Enter' && event.key !== ' ' && event.key !== 'ArrowDown') return
123
- event.preventDefault()
124
- if (event.key === 'ArrowDown') kept.show(true)
125
- else kept.show((was) => !was)
126
- },
127
- }
128
- }
129
-
130
- export function portal(_props: MenuProps, kept: Kept): PresentedProps {
131
- return { presentation: 'popover', open: kept.open, onDismiss: () => kept.show(false), children: null }
132
- }
133
-
134
- export function listing(props: MenuProps, kept: Kept): Readonly<Record<string, unknown>> {
135
- return {
136
- ref: kept.layer,
137
- id: kept.names.menu,
138
- role: 'menu',
139
- 'aria-labelledby': kept.names.trigger,
140
- 'data-side': kept.at?.placement ?? props.side ?? SIDE,
141
- onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>): void => {
142
- if (event.key !== 'Tab') return
143
- kept.show(false)
144
- },
145
- }
146
- }
147
-
148
- export function row(_props: MenuProps, kept: Kept, item: Record<string, unknown>, _at: number): { readonly item: MenuItem; readonly onDone: () => void } {
149
- return { item: item as unknown as MenuItem, onDone: () => kept.show(false) }
150
- }
151
-
152
- export function measured(_props: MenuProps, kept: Kept): Readonly<Record<string, string | number>> {
153
- return kept.at === null ? {} : { x: `${String(kept.at.x)}px`, y: `${String(kept.at.y)}px` }
154
- }
@@ -1,36 +0,0 @@
1
- 'use client'
2
-
3
- import { roleClass, type FontRoleId } from '../fonts.ts'
4
-
5
- import type { Dispatching } from '../checked.ts'
6
- import { type Element, element, useSurface } from '../wrappers.tsx'
7
- import { shows } from './money.works.ts'
8
-
9
-
10
- export interface MoneyProps {
11
- readonly value?: unknown
12
- readonly is?: FontRoleId
13
- readonly invalid?: boolean
14
- readonly dispatch?: keyof Dispatching
15
- readonly input?: Readonly<Record<string, unknown>>
16
- readonly invokeOn?: 'press' | 'shown'
17
- }
18
-
19
- export const Money: Element<'Money', MoneyProps> = element(
20
- 'Money',
21
- (props: MoneyProps, 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
- holds: [
25
- ...(props.invalid === true ? ['invalid' as const] : []),
26
- ],
27
- raises: ['invalid' as const], })
28
- return (
29
- <span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
30
- {shows(props, surface)}
31
- </span>
32
- )
33
- },
34
- 'e-money',
35
- {},
36
- )
@@ -1,9 +0,0 @@
1
- import type { ReactNode } from 'react'
2
-
3
- import { renderValue } from '../content.tsx'
4
- import type { Surface } from '../door.ts'
5
- import type { MoneyProps } from './money.tsx'
6
-
7
- export function shows(props: MoneyProps, surface: Surface): ReactNode {
8
- return renderValue({ validator: 'money', value: props.value }, surface)
9
- }
@@ -1,39 +0,0 @@
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 { Dispatching } from '../checked.ts'
8
- import { type Element, element, useSurface } from '../wrappers.tsx'
9
- import { Each } from '../elements/each.tsx'
10
- import { step, steps } from './pagination.works.ts'
11
-
12
-
13
- export interface PaginationProps {
14
- readonly map: MapIsland
15
- readonly sequence: readonly string[]
16
- readonly current: string
17
- readonly dispatch?: keyof Dispatching
18
- readonly input?: Readonly<Record<string, unknown>>
19
- readonly invokeOn?: 'press' | 'shown'
20
- }
21
-
22
- export const Pagination: Element<'Pagination', PaginationProps> = element(
23
- 'Pagination',
24
- (props: PaginationProps, 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
- <nav className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} aria-label={surface.text('nav.pagination')}>
29
- <Each rows={steps(props)} by={'id'}>
30
- {(each0, at) => (
31
- <Link.linkInline {...step(props, each0, at)}></Link.linkInline>
32
- )}
33
- </Each>
34
- </nav>
35
- )
36
- },
37
- 'e-pagination',
38
- {"tabBar":"thread-tab-bar"},
39
- )
@@ -1,20 +0,0 @@
1
- import type { Row } from '../charts.tsx'
2
- import type { LinkProps } from './link.tsx'
3
- import type { PaginationProps } from './pagination.tsx'
4
-
5
- export function steps(props: PaginationProps): readonly Row[] {
6
- const known = new Map(props.map.screens.map((one) => [one.id, one]))
7
- const walk = props.sequence.filter((id) => known.has(id))
8
- const at = walk.indexOf(props.current)
9
- if (at === -1) return []
10
-
11
- const either = [
12
- ...(at > 0 ? [{ id: walk[at - 1] as string, way: 'previous' }] : []),
13
- ...(at < walk.length - 1 ? [{ id: walk[at + 1] as string, way: 'next' }] : []),
14
- ]
15
- return either.map((one) => ({ ...one, nameKey: known.get(one.id)?.nameKey ?? `nav.${one.way}` }))
16
- }
17
-
18
- export function step(_props: PaginationProps, row: Row, _at: number): LinkProps {
19
- return { navigateTo: String(row['id']), labelKey: String(row['nameKey']), is: 'label' }
20
- }
@@ -1,34 +0,0 @@
1
- 'use client'
2
-
3
- import type { MessageKey } from '../content.tsx'
4
- import { roleClass } from '../fonts.ts'
5
-
6
- import type { Dispatching } from '../checked.ts'
7
- import { type Element, element, useSurface } from '../wrappers.tsx'
8
- import { measured } from './progress.works.ts'
9
-
10
-
11
- export interface ProgressProps {
12
- readonly value?: number
13
- readonly target?: number
14
- readonly labelKey: MessageKey
15
- readonly dispatch?: keyof Dispatching
16
- readonly input?: Readonly<Record<string, unknown>>
17
- readonly invokeOn?: 'press' | 'shown'
18
- }
19
-
20
- export const Progress: Element<'Progress', ProgressProps> = element(
21
- 'Progress',
22
- (props: ProgressProps, 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
- measures: measured(props), })
26
- return (
27
- <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} role="progressbar" aria-valuenow={Number(measured(props).fraction)} aria-valuemin={0} aria-valuemax={100} style={surface.measures} aria-label={surface.text(props.labelKey)}>
28
- <span className="e-progress-bar"></span>
29
- </div>
30
- )
31
- },
32
- 'e-progress',
33
- {"statTile":"thread-stat-tile"},
34
- )
@@ -1,8 +0,0 @@
1
- import type { ProgressProps } from './progress.tsx'
2
-
3
- export function measured(props: ProgressProps): Readonly<Record<string, string | number>> {
4
- const target = props.target ?? 0
5
- const part = target <= 0 ? 0 : Math.min(1, Math.max(0, (props.value ?? 0) / target))
6
- const whole = Math.round(part * 100)
7
- return { fraction: whole, span: `${String(whole)}%` }
8
- }
@@ -1,50 +0,0 @@
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 { Dispatching } from '../checked.ts'
8
- import { type Element, element, useSurface } from '../wrappers.tsx'
9
- import { Each } from '../elements/each.tsx'
10
- import { shown, option, uses } from './radio-group.works.ts'
11
-
12
-
13
- export interface RadioGroupProps {
14
- readonly name: string
15
- readonly labelKey: MessageKey
16
- readonly options: readonly Row[]
17
- readonly chosen?: string
18
- readonly onValue?: (said: string) => void
19
- readonly disabled?: boolean
20
- readonly dispatch?: keyof Dispatching
21
- readonly input?: Readonly<Record<string, unknown>>
22
- readonly invokeOn?: 'press' | 'shown'
23
- }
24
-
25
- export const RadioGroup: Element<'RadioGroup', RadioGroupProps> = element(
26
- 'RadioGroup',
27
- (props: RadioGroupProps, 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
- return (
36
- <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} role="radiogroup" aria-label={surface.text(props.labelKey)}>
37
- <Each rows={props.options} by={'value'}>
38
- {(each0, at) => (
39
- <label>
40
- <input {...option(props, kept, each0, at)} type="radio" disabled={surface.marked('disabled')} />
41
- <span>{shown(props, each0, surface, kept).caption}</span>
42
- </label>
43
- )}
44
- </Each>
45
- </div>
46
- )
47
- },
48
- 'e-radio-group',
49
- {"choice":"thread-choice"},
50
- )
@@ -1,33 +0,0 @@
1
- import { useRef } from 'react'
2
-
3
- import { ITEM_ATTR, useRovingFocus } from '../roving-focus.ts'
4
- import type { Row } from '../charts.tsx'
5
- import type { Surface } from '../door.ts'
6
- import type { RadioGroupProps } from './radio-group.tsx'
7
-
8
- export function uses(props: RadioGroupProps): {
9
- readonly holds?: readonly string[]
10
- readonly animates?: boolean
11
- readonly on: Readonly<Record<string, unknown>>
12
- } {
13
- const group = useRef<HTMLDivElement>(null)
14
- useRovingFocus(group, { orientation: 'vertical' })
15
- return {
16
- ...(props.disabled === true ? { holds: ['disabled'] as const } : {}),
17
- on: { ref: group },
18
- }
19
- }
20
-
21
- export function option(props: RadioGroupProps, _kept: unknown, row: Row, _at: number): Readonly<Record<string, unknown>> {
22
- return {
23
- ...{ [ITEM_ATTR]: '' },
24
- name: props.name,
25
- value: String(row['value']),
26
- checked: props.chosen === row['value'],
27
- onChange: (): void => props.onValue?.(String(row['value'])),
28
- }
29
- }
30
-
31
- export function shown(_props: RadioGroupProps, row: Row, surface: Surface, _kept?: unknown): Readonly<Record<string, string>> {
32
- return { caption: surface.text(String(row['labelKey'])) }
33
- }
@@ -1,29 +0,0 @@
1
- 'use client'
2
-
3
- import type { ReactNode } from 'react'
4
-
5
- import type { Dispatching } from '../checked.ts'
6
- import { type Element, element, useSurface } from '../wrappers.tsx'
7
-
8
-
9
- export interface RowProps {
10
- readonly children: ReactNode
11
- readonly dispatch?: keyof Dispatching
12
- readonly input?: Readonly<Record<string, unknown>>
13
- readonly invokeOn?: 'press' | 'shown'
14
- }
15
-
16
- export const Row: Element<'Row', RowProps> = element(
17
- 'Row',
18
- (props: RowProps, className) => {
19
- const surface = useSurface({ className,
20
- invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
21
- return (
22
- <div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
23
- {props.children}
24
- </div>
25
- )
26
- },
27
- 'e-row',
28
- {},
29
- )
@@ -1,42 +0,0 @@
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 { Dispatching } from '../checked.ts'
8
- import { type Element, element, useSurface } from '../wrappers.tsx'
9
- import { point, uses } from './scatter.works.ts'
10
-
11
-
12
- export interface ScatterProps {
13
- readonly rows: readonly Row[]
14
- readonly x: string
15
- readonly y: string
16
- readonly titleKey?: MessageKey
17
- readonly dispatch?: keyof Dispatching
18
- readonly input?: Readonly<Record<string, unknown>>
19
- readonly invokeOn?: 'press' | 'shown'
20
- }
21
-
22
- export const Scatter: Element<'Scatter', ScatterProps> = element(
23
- 'Scatter',
24
- (props: ScatterProps, 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
- {props.rows.map((each0, at) => (
35
- <circle key={at} {...point(props, kept, each0, at)}></circle>
36
- ))}
37
- </svg>
38
- )
39
- },
40
- 'e-scatter',
41
- {"card":"thread-card"},
42
- )
@@ -1,38 +0,0 @@
1
- import { num, useRamp, type Row } from '../charts.tsx'
2
- import type { ScatterProps } from './scatter.tsx'
3
-
4
- const SIDE = 100
5
-
6
- export function uses(props: ScatterProps): {
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(1)
13
- return {
14
- ...(props.rows.length === 0 ? { holds: ['empty'] as const } : {}),
15
- on: { viewBox: `0 0 ${String(SIDE)} ${String(SIDE)}` },
16
- ramp,
17
- }
18
- }
19
-
20
- export function point(
21
- props: ScatterProps,
22
- kept: { readonly ramp: readonly string[] },
23
- row: Row,
24
- _at: number,
25
- ): Readonly<Record<string, string | number>> {
26
- const xs = props.rows.map((one: Row) => num(one, props.x))
27
- const ys = props.rows.map((one: Row) => num(one, props.y))
28
- const leastX = Math.min(...xs)
29
- const leastY = Math.min(...ys)
30
- const spanX = Math.max(...xs) - leastX || 1
31
- const spanY = Math.max(...ys) - leastY || 1
32
- return {
33
- cx: (((num(row, props.x) - leastX) / spanX) * SIDE).toFixed(2),
34
- cy: (SIDE - ((num(row, props.y) - leastY) / spanY) * SIDE).toFixed(2),
35
- r: 2,
36
- fill: kept.ramp[0] ?? 'currentColor',
37
- }
38
- }