@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.
- package/dist/ui/animations/anm_appear.ts +13 -0
- package/dist/ui/animations/anm_blur_in.ts +19 -0
- package/dist/ui/animations/anm_blur_out.ts +18 -0
- package/dist/ui/animations/anm_dismiss.ts +18 -0
- package/dist/ui/animations/anm_drop.ts +19 -0
- package/dist/ui/animations/anm_fall.ts +18 -0
- package/dist/ui/animations/anm_flash.ts +18 -0
- package/dist/ui/animations/anm_glow.ts +16 -0
- package/dist/ui/animations/anm_lift.ts +16 -0
- package/dist/ui/animations/anm_nudge.ts +16 -0
- package/dist/ui/animations/anm_pop_in.ts +23 -0
- package/dist/ui/animations/anm_pop_out.ts +22 -0
- package/dist/ui/animations/anm_press.ts +12 -0
- package/dist/ui/animations/anm_pulse.ts +13 -0
- package/dist/ui/animations/anm_rise.ts +19 -0
- package/dist/ui/animations/anm_shake.ts +13 -0
- package/dist/ui/animations/anm_slide_in_left.ts +19 -0
- package/dist/ui/animations/anm_slide_in_right.ts +19 -0
- package/dist/ui/animations/anm_slide_out_left.ts +18 -0
- package/dist/ui/animations/anm_slide_out_right.ts +18 -0
- package/dist/ui/animations/anm_spin.ts +12 -0
- package/dist/ui/animations/anm_swell.ts +16 -0
- package/dist/ui/animations/anm_wobble.ts +24 -0
- package/dist/ui/animations/anm_zoom_in.ts +19 -0
- package/dist/ui/animations/anm_zoom_out.ts +18 -0
- package/dist/ui/animations.ts +317 -0
- package/dist/ui/attach.js +13 -4
- package/dist/ui/attach.ts +613 -0
- package/dist/ui/charts.tsx +74 -0
- package/dist/ui/checked.d.ts +2 -2
- package/dist/ui/checked.ts +32 -0
- package/dist/ui/collector.ts +140 -0
- package/dist/ui/compositions.d.ts +10 -1
- package/dist/ui/compositions.js +262 -23
- package/dist/ui/compositions.ts +640 -0
- package/dist/ui/consent.ts +55 -0
- package/dist/ui/content.tsx +39 -0
- package/dist/ui/contrast.ts +27 -0
- package/dist/ui/controls.tsx +30 -0
- package/dist/ui/disclosure.tsx +22 -0
- package/dist/ui/dismiss-layer.ts +87 -0
- package/dist/ui/door.ts +140 -0
- package/dist/ui/drag.ts +316 -0
- package/dist/ui/elements/accordion.js +2 -2
- package/dist/ui/elements/accordion.tsx +47 -0
- package/dist/ui/elements/accordion.works.ts +66 -0
- package/dist/ui/elements/aspect-ratio.js +1 -1
- package/dist/ui/elements/aspect-ratio.tsx +30 -0
- package/dist/ui/elements/aspect-ratio.works.ts +5 -0
- package/dist/ui/elements/avatar.js +1 -1
- package/dist/ui/elements/avatar.tsx +33 -0
- package/dist/ui/elements/avatar.works.ts +16 -0
- package/dist/ui/elements/badge.js +1 -1
- package/dist/ui/elements/badge.tsx +32 -0
- package/dist/ui/elements/badge.works.ts +9 -0
- package/dist/ui/elements/bars.js +2 -2
- package/dist/ui/elements/bars.tsx +49 -0
- package/dist/ui/elements/bars.works.ts +29 -0
- package/dist/ui/elements/box.js +3 -2
- package/dist/ui/elements/box.tsx +35 -0
- package/dist/ui/elements/breadcrumb.js +2 -2
- package/dist/ui/elements/breadcrumb.tsx +37 -0
- package/dist/ui/elements/breadcrumb.works.ts +24 -0
- package/dist/ui/elements/button.js +1 -1
- package/dist/ui/elements/button.tsx +45 -0
- package/dist/ui/elements/button.works.tsx +52 -0
- package/dist/ui/elements/column.js +1 -1
- package/dist/ui/elements/column.tsx +28 -0
- package/dist/ui/elements/consent.js +2 -2
- package/dist/ui/elements/consent.tsx +70 -0
- package/dist/ui/elements/consent.works.tsx +132 -0
- package/dist/ui/elements/donut.js +2 -2
- package/dist/ui/elements/donut.tsx +44 -0
- package/dist/ui/elements/donut.works.ts +42 -0
- package/dist/ui/elements/each.js +1 -1
- package/dist/ui/elements/each.tsx +33 -0
- package/dist/ui/elements/each.works.tsx +82 -0
- package/dist/ui/elements/empty.js +1 -1
- package/dist/ui/elements/empty.tsx +32 -0
- package/dist/ui/elements/field.js +1 -1
- package/dist/ui/elements/field.tsx +44 -0
- package/dist/ui/elements/field.works.ts +65 -0
- package/dist/ui/elements/funnel.js +2 -2
- package/dist/ui/elements/funnel.tsx +49 -0
- package/dist/ui/elements/funnel.works.ts +37 -0
- package/dist/ui/elements/gauge.js +1 -1
- package/dist/ui/elements/gauge.tsx +39 -0
- package/dist/ui/elements/gauge.works.ts +42 -0
- package/dist/ui/elements/glyph.js +1 -1
- package/dist/ui/elements/glyph.tsx +29 -0
- package/dist/ui/elements/glyph.works.tsx +42 -0
- package/dist/ui/elements/grid.js +1 -1
- package/dist/ui/elements/grid.tsx +28 -0
- package/dist/ui/elements/heatmap.js +2 -2
- package/dist/ui/elements/heatmap.tsx +47 -0
- package/dist/ui/elements/heatmap.works.ts +24 -0
- package/dist/ui/elements/hit-box.js +1 -1
- package/dist/ui/elements/hit-box.tsx +46 -0
- package/dist/ui/elements/hit-box.works.tsx +576 -0
- package/dist/ui/elements/image.js +1 -1
- package/dist/ui/elements/image.tsx +28 -0
- package/dist/ui/elements/line-chart.js +2 -2
- package/dist/ui/elements/line-chart.tsx +44 -0
- package/dist/ui/elements/line-chart.works.ts +41 -0
- package/dist/ui/elements/link.js +1 -1
- package/dist/ui/elements/link.tsx +37 -0
- package/dist/ui/elements/link.works.ts +25 -0
- package/dist/ui/elements/media.js +1 -1
- package/dist/ui/elements/media.tsx +56 -0
- package/dist/ui/elements/menu.js +2 -2
- package/dist/ui/elements/menu.tsx +50 -0
- package/dist/ui/elements/menu.works.tsx +153 -0
- package/dist/ui/elements/money.js +1 -1
- package/dist/ui/elements/money.tsx +28 -0
- package/dist/ui/elements/money.works.ts +9 -0
- package/dist/ui/elements/pagination.js +2 -2
- package/dist/ui/elements/pagination.tsx +38 -0
- package/dist/ui/elements/pagination.works.ts +20 -0
- package/dist/ui/elements/progress.js +1 -1
- package/dist/ui/elements/progress.tsx +33 -0
- package/dist/ui/elements/progress.works.ts +8 -0
- package/dist/ui/elements/radio-group.js +2 -2
- package/dist/ui/elements/radio-group.tsx +49 -0
- package/dist/ui/elements/radio-group.works.ts +33 -0
- package/dist/ui/elements/row.js +1 -1
- package/dist/ui/elements/row.tsx +28 -0
- package/dist/ui/elements/scatter.js +1 -1
- package/dist/ui/elements/scatter.tsx +41 -0
- package/dist/ui/elements/scatter.works.ts +38 -0
- package/dist/ui/elements/select.js +2 -2
- package/dist/ui/elements/select.tsx +42 -0
- package/dist/ui/elements/select.works.ts +5 -0
- package/dist/ui/elements/separator.js +1 -1
- package/dist/ui/elements/separator.tsx +30 -0
- package/dist/ui/elements/skeleton.js +1 -1
- package/dist/ui/elements/skeleton.tsx +30 -0
- package/dist/ui/elements/slider.js +1 -1
- package/dist/ui/elements/slider.tsx +33 -0
- package/dist/ui/elements/slider.works.ts +5 -0
- package/dist/ui/elements/sparkline.js +1 -1
- package/dist/ui/elements/sparkline.tsx +36 -0
- package/dist/ui/elements/sparkline.works.ts +32 -0
- package/dist/ui/elements/spinner.js +1 -1
- package/dist/ui/elements/spinner.tsx +32 -0
- package/dist/ui/elements/stack.js +1 -1
- package/dist/ui/elements/stack.tsx +28 -0
- package/dist/ui/elements/stat.js +1 -1
- package/dist/ui/elements/stat.tsx +35 -0
- package/dist/ui/elements/stat.works.ts +14 -0
- package/dist/ui/elements/surface.js +1 -1
- package/dist/ui/elements/surface.tsx +35 -0
- package/dist/ui/elements/surface.works.ts +9 -0
- package/dist/ui/elements/table.js +2 -2
- package/dist/ui/elements/table.tsx +61 -0
- package/dist/ui/elements/table.works.ts +30 -0
- package/dist/ui/elements/tabs.js +2 -2
- package/dist/ui/elements/tabs.tsx +47 -0
- package/dist/ui/elements/tabs.works.ts +84 -0
- package/dist/ui/elements/text.js +1 -1
- package/dist/ui/elements/text.tsx +32 -0
- package/dist/ui/elements/textarea.js +1 -1
- package/dist/ui/elements/textarea.tsx +37 -0
- package/dist/ui/elements/textarea.works.ts +5 -0
- package/dist/ui/elements/time.js +1 -1
- package/dist/ui/elements/time.tsx +34 -0
- package/dist/ui/elements/time.works.ts +25 -0
- package/dist/ui/elements/toggle.js +1 -1
- package/dist/ui/elements/toggle.tsx +33 -0
- package/dist/ui/elements/toggle.works.ts +5 -0
- package/dist/ui/elements/tooltip.js +1 -1
- package/dist/ui/elements/tooltip.tsx +39 -0
- package/dist/ui/elements/tooltip.works.ts +77 -0
- package/dist/ui/elements/value.js +1 -1
- package/dist/ui/elements/value.tsx +30 -0
- package/dist/ui/elements/value.works.ts +9 -0
- package/dist/ui/elements.ts +127 -0
- package/dist/ui/focus-scope.ts +121 -0
- package/dist/ui/fonts.ts +355 -0
- package/dist/ui/generators/dev.ts +79 -0
- package/dist/ui/generators/elements.d.ts +1 -11
- package/dist/ui/generators/elements.js +43 -13
- package/dist/ui/generators/elements.ts +794 -0
- package/dist/ui/generators/i18n.ts +301 -0
- package/dist/ui/generators/icons.ts +214 -0
- package/dist/ui/generators/react.js +10 -3
- package/dist/ui/generators/react.ts +268 -0
- package/dist/ui/generators/routes.d.ts +1 -0
- package/dist/ui/generators/routes.js +89 -69
- package/dist/ui/generators/routes.ts +739 -0
- package/dist/ui/generators/show.ts +259 -0
- package/dist/ui/generators/styles.js +1 -1
- package/dist/ui/generators/styles.ts +670 -0
- package/dist/ui/generators/variants.ts +205 -0
- package/dist/ui/i18n/catalogs/en.ts +191 -0
- package/dist/ui/i18n/format.ts +221 -0
- package/dist/ui/i18n/locales.ts +33 -0
- package/dist/ui/i18n/parse.ts +315 -0
- package/dist/ui/i18n/translator.ts +31 -0
- package/dist/ui/i18n/types.ts +96 -0
- package/dist/ui/icons.ts +331 -0
- package/dist/ui/islands/map.ts +58 -0
- package/dist/ui/localizations.ts +75 -0
- package/dist/ui/makers/message.ts +292 -0
- package/dist/ui/material.ts +236 -0
- package/dist/ui/materials/mat_bordered.ts +13 -0
- package/dist/ui/materials/mat_ceramic.ts +13 -0
- package/dist/ui/materials/mat_clay.ts +13 -0
- package/dist/ui/materials/mat_elevated.ts +24 -0
- package/dist/ui/materials/mat_flat.ts +34 -0
- package/dist/ui/materials/mat_glass.ts +20 -0
- package/dist/ui/materials/mat_lit.ts +13 -0
- package/dist/ui/materials/mat_moulded.ts +11 -0
- package/dist/ui/materials.ts +206 -0
- package/dist/ui/modes.ts +44 -0
- package/dist/ui/navigation.tsx +32 -0
- package/dist/ui/positioning.ts +90 -0
- package/dist/ui/presented.tsx +119 -0
- package/dist/ui/provider.d.ts +2 -0
- package/dist/ui/provider.js +7 -1
- package/dist/ui/provider.tsx +182 -0
- package/dist/ui/render-loop.ts +133 -0
- package/dist/ui/roving-focus.ts +161 -0
- package/dist/ui/screens.js +17 -8
- package/dist/ui/screens.ts +142 -0
- package/dist/ui/scroll-lock.ts +28 -0
- package/dist/ui/series.ts +97 -0
- package/dist/ui/signals.ts +386 -0
- package/dist/ui/styleguide.ts +231 -0
- package/dist/ui/styleguides.ts +374 -0
- package/dist/ui/themes.ts +22 -0
- package/dist/ui/token.js +1 -1
- package/dist/ui/token.ts +78 -0
- package/dist/ui/tokens/shadow.ts +25 -0
- package/dist/ui/tokens.ts +235 -0
- package/dist/ui/validators.ts +232 -0
- package/dist/ui/variant.d.ts +1 -0
- package/dist/ui/variant.js +3 -0
- package/dist/ui/variant.ts +352 -0
- package/dist/ui/variants/var_avatar-round.ts +14 -0
- package/dist/ui/variants/var_bubble-me.ts +14 -0
- package/dist/ui/variants/var_bubble-them.ts +13 -0
- package/dist/ui/variants/var_button-border.ts +76 -0
- package/dist/ui/variants/var_button-cta.ts +76 -0
- package/dist/ui/variants/var_button-destructive-ghost.ts +72 -0
- package/dist/ui/variants/var_button-destructive.ts +76 -0
- package/dist/ui/variants/var_button-fill.ts +76 -0
- package/dist/ui/variants/var_button-ghost.ts +72 -0
- package/dist/ui/variants/var_button-glass.ts +55 -0
- package/dist/ui/variants/var_button-normal.ts +76 -0
- package/dist/ui/variants/var_button-quiet.ts +74 -0
- package/dist/ui/variants/var_card.ts +17 -0
- package/dist/ui/variants/var_chip.ts +13 -0
- package/dist/ui/variants/var_choice.ts +15 -0
- package/dist/ui/variants/var_framed.ts +10 -0
- package/dist/ui/variants/var_glyph-plain.ts +11 -0
- package/dist/ui/variants/var_input.ts +43 -0
- package/dist/ui/variants/var_link-inline.ts +29 -0
- package/dist/ui/variants/var_list-row.ts +34 -0
- package/dist/ui/variants/var_rule.ts +10 -0
- package/dist/ui/variants/var_skeleton-block.ts +12 -0
- package/dist/ui/variants/var_spinner-turning.ts +12 -0
- package/dist/ui/variants/var_stat-tile.ts +13 -0
- package/dist/ui/variants/var_tab-bar.ts +15 -0
- package/dist/ui/variants/var_tap-target.ts +25 -0
- package/dist/ui/variants.ts +64 -0
- package/dist/ui/wrappers.d.ts +4 -1
- package/dist/ui/wrappers.js +60 -20
- package/dist/ui/wrappers.tsx +426 -0
- package/package.json +8 -2
package/dist/ui/drag.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export const EDGE_SCROLL_DEFAULTS = {
|
|
4
|
+
|
|
5
|
+
band: 48,
|
|
6
|
+
|
|
7
|
+
speed: 900,
|
|
8
|
+
} as const
|
|
9
|
+
|
|
10
|
+
export interface Subject {
|
|
11
|
+
readonly kind: string
|
|
12
|
+
readonly id: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DragSession {
|
|
16
|
+
|
|
17
|
+
readonly gesture: string
|
|
18
|
+
|
|
19
|
+
readonly subject: readonly Subject[]
|
|
20
|
+
|
|
21
|
+
readonly from: string
|
|
22
|
+
|
|
23
|
+
readonly x: number
|
|
24
|
+
readonly y: number
|
|
25
|
+
|
|
26
|
+
readonly startedAt: number
|
|
27
|
+
|
|
28
|
+
readonly at: number
|
|
29
|
+
|
|
30
|
+
readonly over?: string
|
|
31
|
+
readonly overSince: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let SESSION: DragSession | undefined
|
|
35
|
+
|
|
36
|
+
export function dragSession(): DragSession | undefined {
|
|
37
|
+
return SESSION
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const LISTENERS = new Set<() => void>()
|
|
41
|
+
|
|
42
|
+
export function subscribeDrag(listener: () => void): () => void {
|
|
43
|
+
LISTENERS.add(listener)
|
|
44
|
+
return () => {
|
|
45
|
+
LISTENERS.delete(listener)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function announce(): void {
|
|
50
|
+
for (const listener of LISTENERS) listener()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type DragStatus = 'idle' | 'carrying' | 'over' | 'refusing' | 'elsewhere'
|
|
54
|
+
|
|
55
|
+
export function dragStatusOf(hitBox: string, accepts: readonly string[] | undefined): DragStatus {
|
|
56
|
+
const session = SESSION
|
|
57
|
+
if (session === undefined) return 'idle'
|
|
58
|
+
if (session.from === hitBox) return 'carrying'
|
|
59
|
+
if (session.over !== hitBox) return 'elsewhere'
|
|
60
|
+
return accepted(accepts, session) ? 'over' : 'refusing'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Scroller {
|
|
64
|
+
|
|
65
|
+
readonly top: number
|
|
66
|
+
readonly bottom: number
|
|
67
|
+
readonly left: number
|
|
68
|
+
readonly right: number
|
|
69
|
+
|
|
70
|
+
readonly scrollsVertically: boolean
|
|
71
|
+
readonly scrollsHorizontally: boolean
|
|
72
|
+
|
|
73
|
+
readonly scrollBy: (dx: number, dy: number) => void
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface Layout {
|
|
77
|
+
|
|
78
|
+
readonly hitBoxesAt: (x: number, y: number) => readonly string[]
|
|
79
|
+
|
|
80
|
+
readonly scrollersAt: (x: number, y: number) => readonly Scroller[]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const DOM_LAYOUT: Layout = {
|
|
84
|
+
hitBoxesAt: (x, y) => {
|
|
85
|
+
if (typeof document === 'undefined' || typeof document.elementsFromPoint !== 'function') return []
|
|
86
|
+
const found: string[] = []
|
|
87
|
+
for (const el of document.elementsFromPoint(x, y)) {
|
|
88
|
+
const id = el.getAttribute('data-hitbox')
|
|
89
|
+
if (id !== null) found.push(id)
|
|
90
|
+
}
|
|
91
|
+
return found
|
|
92
|
+
},
|
|
93
|
+
scrollersAt: (x, y) => {
|
|
94
|
+
if (typeof document === 'undefined' || typeof document.elementsFromPoint !== 'function') return []
|
|
95
|
+
const found: Scroller[] = []
|
|
96
|
+
for (const el of document.elementsFromPoint(x, y)) {
|
|
97
|
+
if (!(el instanceof HTMLElement)) continue
|
|
98
|
+
const box = el.getBoundingClientRect()
|
|
99
|
+
found.push({
|
|
100
|
+
top: box.top,
|
|
101
|
+
bottom: box.bottom,
|
|
102
|
+
left: box.left,
|
|
103
|
+
right: box.right,
|
|
104
|
+
scrollsVertically: el.scrollHeight > el.clientHeight,
|
|
105
|
+
scrollsHorizontally: el.scrollWidth > el.clientWidth,
|
|
106
|
+
scrollBy: (dx, dy) => {
|
|
107
|
+
el.scrollLeft += dx
|
|
108
|
+
el.scrollTop += dy
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
return found
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let LAYOUT: Layout = DOM_LAYOUT
|
|
117
|
+
|
|
118
|
+
export function setLayout(layout: Layout): () => void {
|
|
119
|
+
const previous = LAYOUT
|
|
120
|
+
LAYOUT = layout
|
|
121
|
+
return () => {
|
|
122
|
+
LAYOUT = previous
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function currentLayout(): Layout {
|
|
127
|
+
return LAYOUT
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let CLAIM: string | undefined
|
|
131
|
+
|
|
132
|
+
export function claimGesture(hitBox: string): boolean {
|
|
133
|
+
if (CLAIM !== undefined && CLAIM !== hitBox) return false
|
|
134
|
+
CLAIM = hitBox
|
|
135
|
+
return true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function releaseGesture(hitBox: string): void {
|
|
139
|
+
if (CLAIM === hitBox) CLAIM = undefined
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function gestureClaim(): string | undefined {
|
|
143
|
+
return CLAIM
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface DropTarget {
|
|
147
|
+
readonly id: string
|
|
148
|
+
|
|
149
|
+
readonly accepts?: readonly string[]
|
|
150
|
+
|
|
151
|
+
readonly collects?: () => Subject | readonly Subject[]
|
|
152
|
+
|
|
153
|
+
readonly dwell?: number
|
|
154
|
+
|
|
155
|
+
readonly onDrop?: (session: DragSession) => void
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const TARGETS = new Map<string, DropTarget>()
|
|
159
|
+
|
|
160
|
+
export function registerTarget(target: DropTarget): () => void {
|
|
161
|
+
TARGETS.set(target.id, target)
|
|
162
|
+
return () => {
|
|
163
|
+
TARGETS.delete(target.id)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function targetFor(id: string): DropTarget | undefined {
|
|
168
|
+
return TARGETS.get(id)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function innermostTarget(stack: readonly string[], session: DragSession | undefined = SESSION): DropTarget | undefined {
|
|
172
|
+
if (session === undefined) return undefined
|
|
173
|
+
for (const id of stack) {
|
|
174
|
+
const target = TARGETS.get(id)
|
|
175
|
+
if (target !== undefined && accepted(target.accepts, session)) return target
|
|
176
|
+
}
|
|
177
|
+
return undefined
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface BeginDrag {
|
|
181
|
+
readonly gesture: string
|
|
182
|
+
readonly subject: Subject | readonly Subject[]
|
|
183
|
+
readonly from: string
|
|
184
|
+
readonly x: number
|
|
185
|
+
readonly y: number
|
|
186
|
+
|
|
187
|
+
readonly t: number
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function beginDrag(input: BeginDrag): DragSession {
|
|
191
|
+
if (SESSION !== undefined) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`a drag from "${SESSION.from}" is already in progress, so "${input.from}" cannot start one. ` +
|
|
194
|
+
'Two live sessions would both receive moves and the drop would commit whichever wrote last.',
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
const subject = Array.isArray(input.subject) ? [...(input.subject as readonly Subject[])] : [input.subject as Subject]
|
|
198
|
+
if (subject.length === 0) throw new Error('a drag carries something — beginDrag was given an empty subject')
|
|
199
|
+
|
|
200
|
+
SESSION = {
|
|
201
|
+
gesture: input.gesture,
|
|
202
|
+
subject,
|
|
203
|
+
from: input.from,
|
|
204
|
+
x: input.x,
|
|
205
|
+
y: input.y,
|
|
206
|
+
startedAt: input.t,
|
|
207
|
+
at: input.t,
|
|
208
|
+
overSince: input.t,
|
|
209
|
+
}
|
|
210
|
+
announce()
|
|
211
|
+
return SESSION
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface MoveDrag {
|
|
215
|
+
readonly x: number
|
|
216
|
+
readonly y: number
|
|
217
|
+
|
|
218
|
+
readonly over?: string
|
|
219
|
+
readonly t: number
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function moveDrag(input: MoveDrag): DragSession | undefined {
|
|
223
|
+
if (SESSION === undefined) return undefined
|
|
224
|
+
const arrived = input.over !== SESSION.over
|
|
225
|
+
SESSION = {
|
|
226
|
+
...SESSION,
|
|
227
|
+
x: input.x,
|
|
228
|
+
y: input.y,
|
|
229
|
+
at: input.t,
|
|
230
|
+
...(input.over === undefined ? { over: undefined } : { over: input.over }),
|
|
231
|
+
overSince: arrived ? input.t : SESSION.overSince,
|
|
232
|
+
}
|
|
233
|
+
announce()
|
|
234
|
+
return SESSION
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function collect(more: Subject | readonly Subject[]): DragSession | undefined {
|
|
238
|
+
if (SESSION === undefined) return undefined
|
|
239
|
+
const added = Array.isArray(more) ? (more as readonly Subject[]) : [more as Subject]
|
|
240
|
+
const have = new Set(SESSION.subject.map((s) => `${s.kind}:${s.id}`))
|
|
241
|
+
const fresh = added.filter((s) => !have.has(`${s.kind}:${s.id}`))
|
|
242
|
+
if (fresh.length === 0) return SESSION
|
|
243
|
+
SESSION = { ...SESSION, subject: [...SESSION.subject, ...fresh] }
|
|
244
|
+
announce()
|
|
245
|
+
return SESSION
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function endDrag(): DragSession | undefined {
|
|
249
|
+
const finished = SESSION
|
|
250
|
+
SESSION = undefined
|
|
251
|
+
announce()
|
|
252
|
+
return finished
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function resetDrag(): void {
|
|
256
|
+
SESSION = undefined
|
|
257
|
+
CLAIM = undefined
|
|
258
|
+
TARGETS.clear()
|
|
259
|
+
announce()
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function dwell(session: DragSession | undefined = SESSION): number {
|
|
263
|
+
if (session?.over === undefined) return 0
|
|
264
|
+
return Math.max(0, session.at - session.overSince)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function accepted(kinds: readonly string[] | undefined, session: DragSession | undefined = SESSION): boolean {
|
|
268
|
+
if (kinds === undefined || session === undefined) return false
|
|
269
|
+
return session.subject.every((s) => kinds.includes(s.kind))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface EdgeScrollTuning {
|
|
273
|
+
readonly band?: number
|
|
274
|
+
readonly speed?: number
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function edgeScroll(
|
|
278
|
+
pointer: number,
|
|
279
|
+
start: number,
|
|
280
|
+
end: number,
|
|
281
|
+
dt: number,
|
|
282
|
+
{ band = EDGE_SCROLL_DEFAULTS.band, speed = EDGE_SCROLL_DEFAULTS.speed }: EdgeScrollTuning = {},
|
|
283
|
+
): number {
|
|
284
|
+
const extent = end - start
|
|
285
|
+
if (extent <= 0 || speed <= 0 || band <= 0 || dt <= 0) return 0
|
|
286
|
+
|
|
287
|
+
const reach = Math.min(band, extent / 2)
|
|
288
|
+
|
|
289
|
+
const intoStart = start + reach - pointer
|
|
290
|
+
if (intoStart > 0) return -Math.min(1, intoStart / reach) * speed * dt
|
|
291
|
+
|
|
292
|
+
const intoEnd = pointer - (end - reach)
|
|
293
|
+
if (intoEnd > 0) return Math.min(1, intoEnd / reach) * speed * dt
|
|
294
|
+
|
|
295
|
+
return 0
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export function pullEdges(x: number, y: number, dt: number, tuning: EdgeScrollTuning = {}, layout: Layout = LAYOUT): { dx: number; dy: number } {
|
|
299
|
+
for (const scroller of layout.scrollersAt(x, y)) {
|
|
300
|
+
if (scroller.scrollsVertically) {
|
|
301
|
+
const dy = edgeScroll(y, scroller.top, scroller.bottom, dt, tuning)
|
|
302
|
+
if (dy !== 0) {
|
|
303
|
+
scroller.scrollBy(0, dy)
|
|
304
|
+
return { dx: 0, dy }
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (scroller.scrollsHorizontally) {
|
|
308
|
+
const dx = edgeScroll(x, scroller.left, scroller.right, dt, tuning)
|
|
309
|
+
if (dx !== 0) {
|
|
310
|
+
scroller.scrollBy(dx, 0)
|
|
311
|
+
return { dx, dy: 0 }
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return { dx: 0, dy: 0 }
|
|
316
|
+
}
|
|
@@ -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 "
|
|
5
|
+
import { Each } from "../elements/each.js";
|
|
6
6
|
import { shown, section, header, region, uses } from "./accordion.works.js";
|
|
7
7
|
export const Accordion = element('Accordion', (props, className) => {
|
|
8
8
|
const kept = uses(props);
|
|
@@ -13,4 +13,4 @@ export const Accordion = element('Accordion', (props, className) => {
|
|
|
13
13
|
],
|
|
14
14
|
...(kept.animates === undefined ? {} : { animates: kept.animates }), });
|
|
15
15
|
return (_jsx("div", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, ...(kept.on ?? {}), children: _jsx(Each, { rows: props.items, by: 'id', children: (each0, at) => (_jsxs("div", { ...section(props, kept, each0, at), children: [_jsx("button", { ...header(props, kept, each0, at), children: shown(props, each0, surface, kept).label }), _jsx("div", { ...region(props, kept, each0, at), children: shown(props, each0, surface, kept).inside })] })) }) }));
|
|
16
|
-
}, 'e-accordion');
|
|
16
|
+
}, 'e-accordion', { "card": "thread-card" });
|
|
@@ -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, section, header, region, uses } from './accordion.works.ts'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export interface AccordionProps {
|
|
13
|
+
readonly items: readonly TabItem[]
|
|
14
|
+
readonly initial: readonly string[]
|
|
15
|
+
readonly exclusive?: boolean
|
|
16
|
+
readonly onChange?: (said: readonly string[]) => void
|
|
17
|
+
readonly dispatch?: string
|
|
18
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
19
|
+
readonly invokeOn?: 'press' | 'shown'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const Accordion: Element<'Accordion', AccordionProps> = element(
|
|
23
|
+
'Accordion',
|
|
24
|
+
(props: AccordionProps, 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 className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})}>
|
|
34
|
+
<Each rows={props.items} by={'id'}>
|
|
35
|
+
{(each0, at) => (
|
|
36
|
+
<div {...section(props, kept, each0, at)}>
|
|
37
|
+
<button {...header(props, kept, each0, at)}>{shown(props, each0, surface, kept).label}</button>
|
|
38
|
+
<div {...region(props, kept, each0, at)}>{shown(props, each0, surface, kept).inside}</div>
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
41
|
+
</Each>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
'e-accordion',
|
|
46
|
+
{"card":"thread-card"},
|
|
47
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useId, useState, type ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { Row } from '../charts.tsx'
|
|
4
|
+
import type { Surface } from '../door.ts'
|
|
5
|
+
import type { AccordionProps } from './accordion.tsx'
|
|
6
|
+
|
|
7
|
+
type Kept = {
|
|
8
|
+
readonly base: string
|
|
9
|
+
readonly open: readonly string[]
|
|
10
|
+
readonly toggle: (id: string) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function uses(props: AccordionProps): {
|
|
14
|
+
readonly holds?: readonly string[]
|
|
15
|
+
readonly animates?: boolean
|
|
16
|
+
readonly on?: Readonly<Record<string, unknown>>
|
|
17
|
+
readonly base: string
|
|
18
|
+
readonly open: readonly string[]
|
|
19
|
+
readonly toggle: (id: string) => void
|
|
20
|
+
} {
|
|
21
|
+
const base = useId()
|
|
22
|
+
const [open, setOpen] = useState<readonly string[]>(props.initial ?? [])
|
|
23
|
+
return {
|
|
24
|
+
base,
|
|
25
|
+
open,
|
|
26
|
+
toggle: (id: string): void => {
|
|
27
|
+
const next = open.includes(id)
|
|
28
|
+
? open.filter((one) => one !== id)
|
|
29
|
+
: props.exclusive === true
|
|
30
|
+
? [id]
|
|
31
|
+
: [...open, id]
|
|
32
|
+
setOpen(next)
|
|
33
|
+
props.onChange?.(next)
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function section(_props: AccordionProps, kept: Kept, row: Row, _at: number): Readonly<Record<string, unknown>> {
|
|
39
|
+
return { 'data-open': kept.open.includes(String(row['id'])) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function header(_props: AccordionProps, kept: Kept, row: Row, _at: number): Readonly<Record<string, unknown>> {
|
|
43
|
+
const id = String(row['id'])
|
|
44
|
+
return {
|
|
45
|
+
type: 'button',
|
|
46
|
+
id: `${kept.base}-header-${id}`,
|
|
47
|
+
'aria-controls': `${kept.base}-region-${id}`,
|
|
48
|
+
'aria-expanded': kept.open.includes(id),
|
|
49
|
+
disabled: row['disabled'] === true,
|
|
50
|
+
onClick: (): void => kept.toggle(id),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function region(_props: AccordionProps, kept: Kept, row: Row, _at: number): Readonly<Record<string, unknown>> {
|
|
55
|
+
const id = String(row['id'])
|
|
56
|
+
return {
|
|
57
|
+
role: 'region',
|
|
58
|
+
id: `${kept.base}-region-${id}`,
|
|
59
|
+
'aria-labelledby': `${kept.base}-header-${id}`,
|
|
60
|
+
hidden: !kept.open.includes(id),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function shown(_props: AccordionProps, row: Row, surface: Surface, _kept: unknown): Readonly<Record<string, ReactNode>> {
|
|
65
|
+
return { label: surface.text(String(row['labelKey'])), inside: row['content'] as ReactNode }
|
|
66
|
+
}
|
|
@@ -6,4 +6,4 @@ export const AspectRatio = element('AspectRatio', (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
|
measures: { "ratio": String(props.ratio ?? '') }, });
|
|
8
8
|
return (_jsx("div", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, style: surface.measures, children: props.children }));
|
|
9
|
-
}, 'e-aspect-ratio');
|
|
9
|
+
}, 'e-aspect-ratio', { "framed": "thread-framed" });
|
|
@@ -0,0 +1,30 @@
|
|
|
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 AspectRatioProps {
|
|
9
|
+
readonly children: ReactNode
|
|
10
|
+
readonly ratio: number
|
|
11
|
+
readonly dispatch?: string
|
|
12
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
13
|
+
readonly invokeOn?: 'press' | 'shown'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const AspectRatio: Element<'AspectRatio', AspectRatioProps> = element(
|
|
17
|
+
'AspectRatio',
|
|
18
|
+
(props: AspectRatioProps, 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
|
+
measures: { "ratio": String(props.ratio ?? '') }, })
|
|
22
|
+
return (
|
|
23
|
+
<div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} style={surface.measures}>
|
|
24
|
+
{props.children}
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
},
|
|
28
|
+
'e-aspect-ratio',
|
|
29
|
+
{"framed":"thread-framed"},
|
|
30
|
+
)
|
|
@@ -7,4 +7,4 @@ export const Avatar = element('Avatar', (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("span", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, role: "img", "aria-label": surface.text(props.labelKey), children: [props.src === undefined ? null : _jsx("img", { src: props.src, alt: "" }), _jsx("span", { children: shown(props, surface).lettering })] }));
|
|
10
|
-
}, 'e-avatar');
|
|
10
|
+
}, 'e-avatar', { "avatarRound": "thread-avatar-round" });
|
|
@@ -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 { shown } from './avatar.works.ts'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export interface AvatarProps {
|
|
11
|
+
readonly labelKey: MessageKey
|
|
12
|
+
readonly src?: string
|
|
13
|
+
readonly initials?: string
|
|
14
|
+
readonly dispatch?: string
|
|
15
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
16
|
+
readonly invokeOn?: 'press' | 'shown'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const Avatar: Element<'Avatar', AvatarProps> = element(
|
|
20
|
+
'Avatar',
|
|
21
|
+
(props: AvatarProps, 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
|
+
<span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} role="img" aria-label={surface.text(props.labelKey)}>
|
|
26
|
+
{props.src === undefined ? null : <img src={props.src} alt="" />}
|
|
27
|
+
<span>{shown(props, surface).lettering}</span>
|
|
28
|
+
</span>
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
'e-avatar',
|
|
32
|
+
{"avatarRound":"thread-avatar-round"},
|
|
33
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AvatarProps } from './avatar.tsx'
|
|
2
|
+
|
|
3
|
+
export function shown(props: AvatarProps, surface: { readonly text: (key: AvatarProps['labelKey']) => string }): Readonly<Record<string, string | null>> {
|
|
4
|
+
if (props.src !== undefined) return { lettering: null }
|
|
5
|
+
const said = props.initials
|
|
6
|
+
if (said !== undefined) return { lettering: said }
|
|
7
|
+
return {
|
|
8
|
+
lettering: surface
|
|
9
|
+
.text(props.labelKey)
|
|
10
|
+
.split(/\s+/)
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.slice(0, 2)
|
|
13
|
+
.map((part) => part.charAt(0).toUpperCase())
|
|
14
|
+
.join(''),
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -7,4 +7,4 @@ export const Badge = element('Badge', (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 (_jsx("span", { className: surface.className, ...surface.marks, ...surface.invokes, ...surface.a11y, children: shows(props, surface) }));
|
|
10
|
-
}, 'e-badge');
|
|
10
|
+
}, 'e-badge', { "chip": "thread-chip" });
|
|
@@ -0,0 +1,32 @@
|
|
|
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 { shows } from './badge.works.ts'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export interface BadgeProps {
|
|
11
|
+
readonly labelKey: MessageKey
|
|
12
|
+
readonly count?: number
|
|
13
|
+
readonly max?: number
|
|
14
|
+
readonly dispatch?: string
|
|
15
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
16
|
+
readonly invokeOn?: 'press' | 'shown'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const Badge: Element<'Badge', BadgeProps> = element(
|
|
20
|
+
'Badge',
|
|
21
|
+
(props: BadgeProps, 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
|
+
<span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
|
|
26
|
+
{shows(props, surface)}
|
|
27
|
+
</span>
|
|
28
|
+
)
|
|
29
|
+
},
|
|
30
|
+
'e-badge',
|
|
31
|
+
{"chip":"thread-chip"},
|
|
32
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { BadgeProps } from './badge.tsx'
|
|
4
|
+
|
|
5
|
+
export function shows(props: BadgeProps, surface: { readonly text: (key: BadgeProps['labelKey']) => string }): ReactNode {
|
|
6
|
+
const max = props.max ?? 99
|
|
7
|
+
if (props.count === undefined) return surface.text(props.labelKey)
|
|
8
|
+
return props.count > max ? `${max}+` : String(props.count)
|
|
9
|
+
}
|
package/dist/ui/elements/bars.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { roleClass } from "../fonts.js";
|
|
4
4
|
import { measured as marking } from "../charts.js";
|
|
5
5
|
import { element, useSurface } from "../wrappers.js";
|
|
6
|
-
import { Each } from "
|
|
6
|
+
import { Each } from "../elements/each.js";
|
|
7
7
|
import { shown, sized, uses } from "./bars.works.js";
|
|
8
8
|
export const Bars = element('Bars', (props, className) => {
|
|
9
9
|
const kept = uses(props);
|
|
@@ -14,4 +14,4 @@ export const Bars = element('Bars', (props, className) => {
|
|
|
14
14
|
],
|
|
15
15
|
...(kept.animates === undefined ? {} : { animates: kept.animates }), });
|
|
16
16
|
return (_jsx("div", { 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) => (_jsxs("span", { style: marking(sized(props, kept, each0, at)), children: [_jsx("span", { children: shown(props, each0, surface, kept).label }), _jsx("span", { children: shown(props, each0, surface, kept).amount })] })) }) }));
|
|
17
|
-
}, 'e-bars');
|
|
17
|
+
}, 'e-bars', { "card": "thread-card" });
|
|
@@ -0,0 +1,49 @@
|
|
|
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 { measured as marking } from '../charts.tsx'
|
|
7
|
+
|
|
8
|
+
import { type Element, element, useSurface } from '../wrappers.tsx'
|
|
9
|
+
import { Each } from '../elements/each.tsx'
|
|
10
|
+
import { shown, sized, uses } from './bars.works.ts'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export interface BarsProps {
|
|
14
|
+
readonly rows: readonly Row[]
|
|
15
|
+
readonly by: string
|
|
16
|
+
readonly value: string
|
|
17
|
+
readonly format?: string
|
|
18
|
+
readonly titleKey?: MessageKey
|
|
19
|
+
readonly dispatch?: string
|
|
20
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
21
|
+
readonly invokeOn?: 'press' | 'shown'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const Bars: Element<'Bars', BarsProps> = element(
|
|
25
|
+
'Bars',
|
|
26
|
+
(props: BarsProps, className) => {
|
|
27
|
+
const kept = uses(props)
|
|
28
|
+
const surface = useSurface({ className: roleClass(undefined, className),
|
|
29
|
+
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
|
|
30
|
+
holds: [
|
|
31
|
+
...(kept.holds ?? []),
|
|
32
|
+
],
|
|
33
|
+
...(kept.animates === undefined ? {} : { animates: kept.animates }), })
|
|
34
|
+
return (
|
|
35
|
+
<div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} role="img" {...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) })}>
|
|
36
|
+
<Each rows={props.rows} by={props.by}>
|
|
37
|
+
{(each0, at) => (
|
|
38
|
+
<span style={marking(sized(props, kept, each0, at))}>
|
|
39
|
+
<span>{shown(props, each0, surface, kept).label}</span>
|
|
40
|
+
<span>{shown(props, each0, surface, kept).amount}</span>
|
|
41
|
+
</span>
|
|
42
|
+
)}
|
|
43
|
+
</Each>
|
|
44
|
+
</div>
|
|
45
|
+
)
|
|
46
|
+
},
|
|
47
|
+
'e-bars',
|
|
48
|
+
{"card":"thread-card"},
|
|
49
|
+
)
|