@prestack/thread-ui 0.1.9 → 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.
- package/CHANGELOG.md +366 -0
- package/dist/ui/attach.js +6 -7
- package/dist/ui/compositions.d.ts +0 -2
- package/dist/ui/compositions.js +2 -112
- package/dist/ui/generators/routes.js +1 -0
- package/dist/ui/variant.d.ts +1 -3
- package/package.json +2 -2
- package/dist/ui/animations/anm_appear.ts +0 -13
- package/dist/ui/animations/anm_blur_in.ts +0 -19
- package/dist/ui/animations/anm_blur_out.ts +0 -18
- package/dist/ui/animations/anm_dismiss.ts +0 -18
- package/dist/ui/animations/anm_drop.ts +0 -19
- package/dist/ui/animations/anm_fall.ts +0 -18
- package/dist/ui/animations/anm_flash.ts +0 -18
- package/dist/ui/animations/anm_glow.ts +0 -16
- package/dist/ui/animations/anm_lift.ts +0 -16
- package/dist/ui/animations/anm_nudge.ts +0 -16
- package/dist/ui/animations/anm_pop_in.ts +0 -23
- package/dist/ui/animations/anm_pop_out.ts +0 -22
- package/dist/ui/animations/anm_press.ts +0 -12
- package/dist/ui/animations/anm_pulse.ts +0 -13
- package/dist/ui/animations/anm_rise.ts +0 -19
- package/dist/ui/animations/anm_shake.ts +0 -13
- package/dist/ui/animations/anm_slide_in_left.ts +0 -19
- package/dist/ui/animations/anm_slide_in_right.ts +0 -19
- package/dist/ui/animations/anm_slide_out_left.ts +0 -18
- package/dist/ui/animations/anm_slide_out_right.ts +0 -18
- package/dist/ui/animations/anm_spin.ts +0 -12
- package/dist/ui/animations/anm_swell.ts +0 -16
- package/dist/ui/animations/anm_wobble.ts +0 -24
- package/dist/ui/animations/anm_zoom_in.ts +0 -19
- package/dist/ui/animations/anm_zoom_out.ts +0 -18
- package/dist/ui/animations.ts +0 -308
- package/dist/ui/attach.ts +0 -553
- package/dist/ui/charts.tsx +0 -69
- package/dist/ui/checked.ts +0 -32
- package/dist/ui/collector.ts +0 -140
- package/dist/ui/compositions.ts +0 -555
- package/dist/ui/consent.ts +0 -55
- package/dist/ui/content.tsx +0 -27
- package/dist/ui/contrast.ts +0 -27
- package/dist/ui/controls.tsx +0 -25
- package/dist/ui/disclosure.tsx +0 -20
- package/dist/ui/dismiss-layer.ts +0 -87
- package/dist/ui/door.ts +0 -140
- package/dist/ui/drag.ts +0 -316
- package/dist/ui/elements/accordion.tsx +0 -47
- package/dist/ui/elements/accordion.works.ts +0 -66
- package/dist/ui/elements/aspect-ratio.tsx +0 -31
- package/dist/ui/elements/aspect-ratio.works.ts +0 -5
- package/dist/ui/elements/avatar.tsx +0 -34
- package/dist/ui/elements/avatar.works.ts +0 -16
- package/dist/ui/elements/badge.tsx +0 -33
- package/dist/ui/elements/badge.works.ts +0 -9
- package/dist/ui/elements/bars.tsx +0 -50
- package/dist/ui/elements/bars.works.ts +0 -29
- package/dist/ui/elements/box.tsx +0 -36
- package/dist/ui/elements/breadcrumb.tsx +0 -38
- package/dist/ui/elements/breadcrumb.works.ts +0 -24
- package/dist/ui/elements/button.tsx +0 -46
- package/dist/ui/elements/button.works.tsx +0 -52
- package/dist/ui/elements/column.tsx +0 -29
- package/dist/ui/elements/consent.tsx +0 -71
- package/dist/ui/elements/consent.works.tsx +0 -132
- package/dist/ui/elements/donut.tsx +0 -45
- package/dist/ui/elements/donut.works.ts +0 -42
- package/dist/ui/elements/each.tsx +0 -34
- package/dist/ui/elements/each.works.tsx +0 -82
- package/dist/ui/elements/empty.tsx +0 -33
- package/dist/ui/elements/field.tsx +0 -45
- package/dist/ui/elements/field.works.ts +0 -65
- package/dist/ui/elements/funnel.tsx +0 -50
- package/dist/ui/elements/funnel.works.ts +0 -37
- package/dist/ui/elements/gauge.tsx +0 -40
- package/dist/ui/elements/gauge.works.ts +0 -42
- package/dist/ui/elements/glyph.tsx +0 -30
- package/dist/ui/elements/glyph.works.tsx +0 -42
- package/dist/ui/elements/grid.tsx +0 -29
- package/dist/ui/elements/heatmap.tsx +0 -48
- package/dist/ui/elements/heatmap.works.ts +0 -24
- package/dist/ui/elements/hit-box.tsx +0 -47
- package/dist/ui/elements/hit-box.works.tsx +0 -576
- package/dist/ui/elements/image.tsx +0 -29
- package/dist/ui/elements/line-chart.tsx +0 -45
- package/dist/ui/elements/line-chart.works.ts +0 -41
- package/dist/ui/elements/link.tsx +0 -38
- package/dist/ui/elements/link.works.ts +0 -25
- package/dist/ui/elements/media.tsx +0 -57
- package/dist/ui/elements/menu.tsx +0 -51
- package/dist/ui/elements/menu.works.tsx +0 -154
- package/dist/ui/elements/money.tsx +0 -36
- package/dist/ui/elements/money.works.ts +0 -9
- package/dist/ui/elements/pagination.tsx +0 -39
- package/dist/ui/elements/pagination.works.ts +0 -20
- package/dist/ui/elements/progress.tsx +0 -34
- package/dist/ui/elements/progress.works.ts +0 -8
- package/dist/ui/elements/radio-group.tsx +0 -50
- package/dist/ui/elements/radio-group.works.ts +0 -33
- package/dist/ui/elements/row.tsx +0 -29
- package/dist/ui/elements/scatter.tsx +0 -42
- package/dist/ui/elements/scatter.works.ts +0 -38
- package/dist/ui/elements/select.tsx +0 -43
- package/dist/ui/elements/select.works.ts +0 -5
- package/dist/ui/elements/separator.tsx +0 -31
- package/dist/ui/elements/skeleton.tsx +0 -31
- package/dist/ui/elements/slider.tsx +0 -34
- package/dist/ui/elements/slider.works.ts +0 -5
- package/dist/ui/elements/sparkline.tsx +0 -37
- package/dist/ui/elements/sparkline.works.ts +0 -32
- package/dist/ui/elements/spinner.tsx +0 -33
- package/dist/ui/elements/stack.tsx +0 -29
- package/dist/ui/elements/stat.tsx +0 -36
- package/dist/ui/elements/stat.works.ts +0 -14
- package/dist/ui/elements/surface.tsx +0 -36
- package/dist/ui/elements/surface.works.ts +0 -9
- package/dist/ui/elements/table.tsx +0 -62
- package/dist/ui/elements/table.works.ts +0 -30
- package/dist/ui/elements/tabs.tsx +0 -47
- package/dist/ui/elements/tabs.works.ts +0 -84
- package/dist/ui/elements/text.tsx +0 -33
- package/dist/ui/elements/textarea.tsx +0 -38
- package/dist/ui/elements/textarea.works.ts +0 -5
- package/dist/ui/elements/time.tsx +0 -40
- package/dist/ui/elements/time.works.ts +0 -29
- package/dist/ui/elements/toggle.tsx +0 -34
- package/dist/ui/elements/toggle.works.ts +0 -5
- package/dist/ui/elements/tooltip.tsx +0 -40
- package/dist/ui/elements/tooltip.works.ts +0 -77
- package/dist/ui/elements/value.tsx +0 -38
- package/dist/ui/elements/value.works.ts +0 -9
- package/dist/ui/elements.ts +0 -127
- package/dist/ui/focus-scope.ts +0 -121
- package/dist/ui/fonts.ts +0 -355
- package/dist/ui/generators/dev.d.ts +0 -1
- package/dist/ui/generators/dev.js +0 -61
- package/dist/ui/generators/dev.ts +0 -74
- package/dist/ui/generators/elements.ts +0 -796
- package/dist/ui/generators/i18n.ts +0 -283
- package/dist/ui/generators/icons.ts +0 -207
- package/dist/ui/generators/react.ts +0 -267
- package/dist/ui/generators/routes.ts +0 -847
- package/dist/ui/generators/show.ts +0 -261
- package/dist/ui/generators/styles.ts +0 -677
- package/dist/ui/generators/variants.ts +0 -196
- package/dist/ui/i18n/catalogs/en.ts +0 -191
- package/dist/ui/i18n/format.ts +0 -221
- package/dist/ui/i18n/locales.ts +0 -33
- package/dist/ui/i18n/parse.ts +0 -315
- package/dist/ui/i18n/translator.ts +0 -31
- package/dist/ui/i18n/types.ts +0 -96
- package/dist/ui/icons.ts +0 -331
- package/dist/ui/islands/map.ts +0 -58
- package/dist/ui/localizations.ts +0 -75
- package/dist/ui/material.ts +0 -236
- package/dist/ui/materials/mat_bordered.ts +0 -13
- package/dist/ui/materials/mat_ceramic.ts +0 -13
- package/dist/ui/materials/mat_clay.ts +0 -13
- package/dist/ui/materials/mat_elevated.ts +0 -24
- package/dist/ui/materials/mat_flat.ts +0 -34
- package/dist/ui/materials/mat_glass.ts +0 -20
- package/dist/ui/materials/mat_lit.ts +0 -13
- package/dist/ui/materials/mat_moulded.ts +0 -11
- package/dist/ui/materials.ts +0 -197
- package/dist/ui/modes.ts +0 -44
- package/dist/ui/navigation.tsx +0 -29
- package/dist/ui/positioning.ts +0 -90
- package/dist/ui/presented.tsx +0 -119
- package/dist/ui/provider.tsx +0 -184
- package/dist/ui/render-loop.ts +0 -133
- package/dist/ui/roving-focus.ts +0 -161
- package/dist/ui/screens.ts +0 -141
- package/dist/ui/scroll-lock.ts +0 -28
- package/dist/ui/series.ts +0 -97
- package/dist/ui/signals.ts +0 -386
- package/dist/ui/styleguide.ts +0 -231
- package/dist/ui/styleguides.ts +0 -374
- package/dist/ui/themes.ts +0 -22
- package/dist/ui/token.ts +0 -78
- package/dist/ui/tokens/shadow.ts +0 -25
- package/dist/ui/tokens.ts +0 -234
- package/dist/ui/validators.ts +0 -232
- package/dist/ui/variant.ts +0 -352
- package/dist/ui/variants/var_avatar-round.ts +0 -14
- package/dist/ui/variants/var_bubble-me.ts +0 -14
- package/dist/ui/variants/var_bubble-them.ts +0 -13
- package/dist/ui/variants/var_button-border.ts +0 -76
- package/dist/ui/variants/var_button-cta.ts +0 -76
- package/dist/ui/variants/var_button-destructive-ghost.ts +0 -72
- package/dist/ui/variants/var_button-destructive.ts +0 -76
- package/dist/ui/variants/var_button-fill.ts +0 -76
- package/dist/ui/variants/var_button-ghost.ts +0 -72
- package/dist/ui/variants/var_button-glass.ts +0 -55
- package/dist/ui/variants/var_button-normal.ts +0 -76
- package/dist/ui/variants/var_button-quiet.ts +0 -74
- package/dist/ui/variants/var_card.ts +0 -17
- package/dist/ui/variants/var_chip.ts +0 -13
- package/dist/ui/variants/var_choice.ts +0 -15
- package/dist/ui/variants/var_framed.ts +0 -10
- package/dist/ui/variants/var_glyph-plain.ts +0 -11
- package/dist/ui/variants/var_input.ts +0 -43
- package/dist/ui/variants/var_link-inline.ts +0 -29
- package/dist/ui/variants/var_list-row.ts +0 -34
- package/dist/ui/variants/var_rule.ts +0 -10
- package/dist/ui/variants/var_skeleton-block.ts +0 -12
- package/dist/ui/variants/var_spinner-turning.ts +0 -12
- package/dist/ui/variants/var_stat-tile.ts +0 -13
- package/dist/ui/variants/var_tab-bar.ts +0 -15
- package/dist/ui/variants/var_tap-target.ts +0 -25
- package/dist/ui/variants.ts +0 -64
- package/dist/ui/wrappers.tsx +0 -429
|
@@ -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 { shown } from './avatar.works.ts'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export interface AvatarProps {
|
|
12
|
-
readonly labelKey: MessageKey
|
|
13
|
-
readonly src?: string
|
|
14
|
-
readonly initials?: string
|
|
15
|
-
readonly dispatch?: keyof Dispatching
|
|
16
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
17
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const Avatar: Element<'Avatar', AvatarProps> = element(
|
|
21
|
-
'Avatar',
|
|
22
|
-
(props: AvatarProps, className) => {
|
|
23
|
-
const surface = useSurface({ className: roleClass(undefined, className),
|
|
24
|
-
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
|
|
25
|
-
return (
|
|
26
|
-
<span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} role="img" aria-label={surface.text(props.labelKey)}>
|
|
27
|
-
{props.src === undefined ? null : <img src={props.src} alt="" />}
|
|
28
|
-
<span>{shown(props, surface).lettering}</span>
|
|
29
|
-
</span>
|
|
30
|
-
)
|
|
31
|
-
},
|
|
32
|
-
'e-avatar',
|
|
33
|
-
{"avatarRound":"thread-avatar-round"},
|
|
34
|
-
)
|
|
@@ -1,16 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,33 +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 { shows } from './badge.works.ts'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export interface BadgeProps {
|
|
12
|
-
readonly labelKey: MessageKey
|
|
13
|
-
readonly count?: number
|
|
14
|
-
readonly max?: number
|
|
15
|
-
readonly dispatch?: keyof Dispatching
|
|
16
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
17
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const Badge: Element<'Badge', BadgeProps> = element(
|
|
21
|
-
'Badge',
|
|
22
|
-
(props: BadgeProps, className) => {
|
|
23
|
-
const surface = useSurface({ className: roleClass(undefined, className),
|
|
24
|
-
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
|
|
25
|
-
return (
|
|
26
|
-
<span className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y}>
|
|
27
|
-
{shows(props, surface)}
|
|
28
|
-
</span>
|
|
29
|
-
)
|
|
30
|
-
},
|
|
31
|
-
'e-badge',
|
|
32
|
-
{"chip":"thread-chip"},
|
|
33
|
-
)
|
|
@@ -1,9 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -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
|
-
import { measured as marking } from '../charts.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 { shown, sized, uses } from './bars.works.ts'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export interface BarsProps {
|
|
15
|
-
readonly rows: readonly Row[]
|
|
16
|
-
readonly by: string
|
|
17
|
-
readonly value: string
|
|
18
|
-
readonly format?: string
|
|
19
|
-
readonly titleKey?: MessageKey
|
|
20
|
-
readonly dispatch?: keyof Dispatching
|
|
21
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
22
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const Bars: Element<'Bars', BarsProps> = element(
|
|
26
|
-
'Bars',
|
|
27
|
-
(props: BarsProps, 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="img" {...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) })}>
|
|
37
|
-
<Each rows={props.rows} by={props.by}>
|
|
38
|
-
{(each0, at) => (
|
|
39
|
-
<span style={marking(sized(props, kept, each0, at))}>
|
|
40
|
-
<span>{shown(props, each0, surface, kept).label}</span>
|
|
41
|
-
<span>{shown(props, each0, surface, kept).amount}</span>
|
|
42
|
-
</span>
|
|
43
|
-
)}
|
|
44
|
-
</Each>
|
|
45
|
-
</div>
|
|
46
|
-
)
|
|
47
|
-
},
|
|
48
|
-
'e-bars',
|
|
49
|
-
{"card":"thread-card"},
|
|
50
|
-
)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { formatValue } from '../validators.ts'
|
|
2
|
-
import { seriesColour } from '../series.ts'
|
|
3
|
-
import { num, str, useRamp, type Row } from '../charts.tsx'
|
|
4
|
-
import type { BarsProps } from './bars.tsx'
|
|
5
|
-
|
|
6
|
-
export function uses(props: BarsProps): {
|
|
7
|
-
readonly holds?: readonly string[]
|
|
8
|
-
readonly animates?: boolean
|
|
9
|
-
readonly on?: Readonly<Record<string, unknown>>
|
|
10
|
-
readonly ramp: readonly string[]
|
|
11
|
-
} {
|
|
12
|
-
const ramp = useRamp(props.rows.length)
|
|
13
|
-
return { ...(props.rows.length === 0 ? { holds: ['empty'] as const } : {}), ramp }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function sized(props: BarsProps, kept: { readonly ramp: readonly string[] }, row: Row, at: number): Readonly<Record<string, string | number>> {
|
|
17
|
-
const most = Math.max(...props.rows.map((one: Row) => num(one, props.value)), 0) || 1
|
|
18
|
-
return {
|
|
19
|
-
series: seriesColour(kept.ramp, at),
|
|
20
|
-
fraction: `${((num(row, props.value) / most) * 100).toFixed(1)}%`,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function shown(props: BarsProps, row: Row, _surface: unknown, _kept?: unknown): Readonly<Record<string, string>> {
|
|
25
|
-
return {
|
|
26
|
-
label: str(row, props.by),
|
|
27
|
-
amount: String(formatValue(props.format ?? 'number', num(row, props.value))),
|
|
28
|
-
}
|
|
29
|
-
}
|
package/dist/ui/elements/box.tsx
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import type { ReactNode } from 'react'
|
|
4
|
-
import type { MessageKey } from '../content.tsx'
|
|
5
|
-
|
|
6
|
-
import type { Dispatching } from '../checked.ts'
|
|
7
|
-
import { type Element, element, useSurface } from '../wrappers.tsx'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export interface BoxProps {
|
|
11
|
-
readonly children: ReactNode
|
|
12
|
-
readonly labelKey?: MessageKey
|
|
13
|
-
readonly scrolling?: boolean
|
|
14
|
-
readonly dispatch?: keyof Dispatching
|
|
15
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
16
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const Box: Element<'Box', BoxProps> = element(
|
|
20
|
-
'Box',
|
|
21
|
-
(props: BoxProps, className) => {
|
|
22
|
-
const surface = useSurface({ 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.scrolling === true ? ['scrolling' as const] : []),
|
|
26
|
-
],
|
|
27
|
-
raises: ['scrolling' as const], })
|
|
28
|
-
return (
|
|
29
|
-
<div className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(props.labelKey === undefined ? {} : { role: 'group' as const })} {...(props.labelKey === undefined ? {} : { 'aria-label': surface.text(props.labelKey) })}>
|
|
30
|
-
{props.children}
|
|
31
|
-
</div>
|
|
32
|
-
)
|
|
33
|
-
},
|
|
34
|
-
'e-box',
|
|
35
|
-
{"card":"thread-card","listRow":"thread-list-row","bubbleThem":"thread-bubble-them","bubbleMe":"thread-bubble-me"},
|
|
36
|
-
)
|
|
@@ -1,38 +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 { crumb, steps } from './breadcrumb.works.ts'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export interface BreadcrumbProps {
|
|
14
|
-
readonly map: MapIsland
|
|
15
|
-
readonly current: string
|
|
16
|
-
readonly dispatch?: keyof Dispatching
|
|
17
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
18
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const Breadcrumb: Element<'Breadcrumb', BreadcrumbProps> = element(
|
|
22
|
-
'Breadcrumb',
|
|
23
|
-
(props: BreadcrumbProps, className) => {
|
|
24
|
-
const surface = useSurface({ className: roleClass(undefined, className),
|
|
25
|
-
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) }, })
|
|
26
|
-
return (
|
|
27
|
-
<nav className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} aria-label={surface.text('nav.breadcrumb')}>
|
|
28
|
-
<Each rows={steps(props)} by={'id'}>
|
|
29
|
-
{(each0, at) => (
|
|
30
|
-
<Link.linkInline {...crumb(props, each0, at)}></Link.linkInline>
|
|
31
|
-
)}
|
|
32
|
-
</Each>
|
|
33
|
-
</nav>
|
|
34
|
-
)
|
|
35
|
-
},
|
|
36
|
-
'e-breadcrumb',
|
|
37
|
-
{"tabBar":"thread-tab-bar"},
|
|
38
|
-
)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { trailTo } from '../navigation.tsx'
|
|
2
|
-
import type { Row } from '../charts.tsx'
|
|
3
|
-
import type { BreadcrumbProps } from './breadcrumb.tsx'
|
|
4
|
-
import type { LinkProps } from './link.tsx'
|
|
5
|
-
|
|
6
|
-
export function steps(props: BreadcrumbProps): readonly Row[] {
|
|
7
|
-
const known = new Map(props.map.screens.map((one) => [one.id, one]))
|
|
8
|
-
if (!known.has(props.current)) return []
|
|
9
|
-
const trail = trailTo(props.map, props.current)
|
|
10
|
-
return trail.flatMap((id, at) => {
|
|
11
|
-
const screen = known.get(id)
|
|
12
|
-
if (screen === undefined) return []
|
|
13
|
-
return [{ id, nameKey: screen.nameKey, here: at === trail.length - 1 }]
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function crumb(_props: BreadcrumbProps, row: Row, _at: number): LinkProps & { readonly 'aria-current'?: 'page' } {
|
|
18
|
-
return {
|
|
19
|
-
navigateTo: String(row['id']),
|
|
20
|
-
labelKey: String(row['nameKey']),
|
|
21
|
-
is: 'label',
|
|
22
|
-
...(row['here'] === true ? ({ 'aria-current': 'page' } as const) : {}),
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,46 +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 { shown, iconed, worded, uses, wires } from './button.works.tsx'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export interface ButtonProps {
|
|
12
|
-
readonly label: MessageKey
|
|
13
|
-
readonly with?: Readonly<Record<string, unknown>>
|
|
14
|
-
readonly icon?: string
|
|
15
|
-
readonly shows?: string
|
|
16
|
-
readonly type?: string
|
|
17
|
-
readonly disabled?: boolean
|
|
18
|
-
readonly loading?: boolean
|
|
19
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
20
|
-
readonly navigateTo?: string
|
|
21
|
-
readonly onPress?: () => void
|
|
22
|
-
readonly dispatch?: keyof Dispatching
|
|
23
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const Button: Element<'Button', ButtonProps> = element(
|
|
27
|
-
'Button',
|
|
28
|
-
(props: ButtonProps, className) => {
|
|
29
|
-
const kept = uses(props)
|
|
30
|
-
const surface = useSurface({ className: roleClass(undefined, className),
|
|
31
|
-
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
|
|
32
|
-
holds: [
|
|
33
|
-
...(kept.holds ?? []),
|
|
34
|
-
],
|
|
35
|
-
...(kept.animates === undefined ? {} : { animates: kept.animates }), })
|
|
36
|
-
const wired = wires(props, kept, surface)
|
|
37
|
-
return (
|
|
38
|
-
<button className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} {...(wired.on ?? {})}>
|
|
39
|
-
{!iconed(props, kept) ? null : <span className="e-button-symbol">{shown(props, surface, kept, wired).symbol}</span>}
|
|
40
|
-
{!worded(props, kept) ? null : <span>{shown(props, surface, kept, wired).wording}</span>}
|
|
41
|
-
</button>
|
|
42
|
-
)
|
|
43
|
-
},
|
|
44
|
-
'e-button',
|
|
45
|
-
{"buttonFill":"thread-button-fill","buttonNormal":"thread-button-normal","buttonGhost":"thread-button-ghost","buttonBorder":"thread-button-border","buttonDestructive":"thread-button-destructive","buttonDestructiveGhost":"thread-button-destructive-ghost","buttonCta":"thread-button-cta","buttonQuiet":"thread-button-quiet","buttonGlass":"thread-button-glass"},
|
|
46
|
-
)
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
import { pressOf, usePress } from '../wrappers.tsx'
|
|
4
|
-
import type { Surface } from '../door.ts'
|
|
5
|
-
import { drawn } from './glyph.works.tsx'
|
|
6
|
-
import type { ButtonProps } from './button.tsx'
|
|
7
|
-
|
|
8
|
-
export function uses(props: ButtonProps): {
|
|
9
|
-
readonly holds?: readonly string[]
|
|
10
|
-
readonly animates?: boolean
|
|
11
|
-
readonly on?: Readonly<Record<string, unknown>>
|
|
12
|
-
readonly press: (() => void) | undefined
|
|
13
|
-
} {
|
|
14
|
-
return {
|
|
15
|
-
holds: [
|
|
16
|
-
...(props.disabled === true ? (['disabled'] as const) : []),
|
|
17
|
-
...(props.loading === true ? (['loading'] as const) : []),
|
|
18
|
-
],
|
|
19
|
-
press: usePress(pressOf(props), { element: 'Button', name: props.label }),
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function wires(
|
|
24
|
-
props: ButtonProps,
|
|
25
|
-
kept: { readonly press: (() => void) | undefined },
|
|
26
|
-
surface: Surface,
|
|
27
|
-
): { readonly on: Readonly<Record<string, unknown>> } {
|
|
28
|
-
const inert = surface.marked('disabled') || surface.marked('loading')
|
|
29
|
-
return {
|
|
30
|
-
on: {
|
|
31
|
-
type: props.type ?? 'button',
|
|
32
|
-
disabled: inert,
|
|
33
|
-
...(props.shows === 'icon' ? { 'aria-label': surface.text(props.label, props.with) } : {}),
|
|
34
|
-
onClick: inert ? undefined : kept.press,
|
|
35
|
-
},
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function iconed(props: ButtonProps, _kept?: unknown): boolean {
|
|
40
|
-
return props.icon !== undefined
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function worded(props: ButtonProps, _kept?: unknown): boolean {
|
|
44
|
-
return props.shows !== 'icon'
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function shown(props: ButtonProps, surface: Surface, _kept: unknown, _wired?: unknown): Readonly<Record<string, ReactNode>> {
|
|
48
|
-
return {
|
|
49
|
-
symbol: props.icon === undefined ? null : drawn(props.icon, { 'aria-hidden': true }),
|
|
50
|
-
wording: props.shows === 'icon' ? null : surface.text(props.label, props.with),
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -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 ColumnProps {
|
|
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 Column: Element<'Column', ColumnProps> = element(
|
|
17
|
-
'Column',
|
|
18
|
-
(props: ColumnProps, 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-column',
|
|
28
|
-
{},
|
|
29
|
-
)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import type { MessageKey } from '../content.tsx'
|
|
4
|
-
import { roleClass } from '../fonts.ts'
|
|
5
|
-
import type { ConsentDecision } from '../consent.ts'
|
|
6
|
-
import { Box } from './box.tsx'
|
|
7
|
-
import { Column } from './column.tsx'
|
|
8
|
-
import { Text } from './text.tsx'
|
|
9
|
-
import { Toggle } from './toggle.tsx'
|
|
10
|
-
import { Button } from './button.tsx'
|
|
11
|
-
|
|
12
|
-
import type { Dispatching } from '../checked.ts'
|
|
13
|
-
import { type Element, element, useSurface } from '../wrappers.tsx'
|
|
14
|
-
import { Each } from '../elements/each.tsx'
|
|
15
|
-
import { title, policy, hasPolicy, categories, label, describe, chooser, optional, fixed, required, withdraw, withdrawable, decline, accept, acceptAll, uses } from './consent.works.tsx'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export interface ConsentProps {
|
|
19
|
-
readonly decision?: ConsentDecision
|
|
20
|
-
readonly onDecide: (said: ConsentDecision) => void
|
|
21
|
-
readonly policyKey?: MessageKey
|
|
22
|
-
readonly preselected: readonly string[]
|
|
23
|
-
readonly dispatch?: keyof Dispatching
|
|
24
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
25
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const Consent: Element<'Consent', ConsentProps> = element(
|
|
29
|
-
'Consent',
|
|
30
|
-
(props: ConsentProps, className) => {
|
|
31
|
-
const kept = uses(props)
|
|
32
|
-
useSurface({ className: roleClass(undefined, className),
|
|
33
|
-
invokes: { ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }), ...(props.input === undefined ? {} : { input: props.input }), ...(props.invokeOn === undefined ? {} : { on: props.invokeOn }) },
|
|
34
|
-
holds: [
|
|
35
|
-
...(kept.holds ?? []),
|
|
36
|
-
],
|
|
37
|
-
...(kept.animates === undefined ? {} : { animates: kept.animates }), })
|
|
38
|
-
return (
|
|
39
|
-
<>
|
|
40
|
-
<Box.card>
|
|
41
|
-
<Column>
|
|
42
|
-
<Text {...title(props, kept)}></Text>
|
|
43
|
-
{!hasPolicy(props, kept) ? null : <Text {...policy(props, kept)}></Text>}
|
|
44
|
-
<Column>
|
|
45
|
-
<Each rows={categories(props, kept)} by={'id'}>
|
|
46
|
-
{(each0, at) => (
|
|
47
|
-
<Box>
|
|
48
|
-
<Column>
|
|
49
|
-
<Text {...label(props, kept, each0, at)}></Text>
|
|
50
|
-
<Text {...describe(props, kept, each0, at)}></Text>
|
|
51
|
-
</Column>
|
|
52
|
-
{!optional(props, kept, each0) ? null : <Toggle.input {...chooser(props, kept, each0, at)}></Toggle.input>}
|
|
53
|
-
{!required(props, kept, each0) ? null : <Text {...fixed(props, kept, each0, at)}></Text>}
|
|
54
|
-
</Box>
|
|
55
|
-
)}
|
|
56
|
-
</Each>
|
|
57
|
-
</Column>
|
|
58
|
-
<Box>
|
|
59
|
-
{!withdrawable(props, kept) ? null : <Button.buttonQuiet {...withdraw(props, kept)}></Button.buttonQuiet>}
|
|
60
|
-
<Button.buttonBorder {...decline(props, kept)}></Button.buttonBorder>
|
|
61
|
-
<Button.buttonBorder {...accept(props, kept)}></Button.buttonBorder>
|
|
62
|
-
<Button.buttonFill {...acceptAll(props, kept)}></Button.buttonFill>
|
|
63
|
-
</Box>
|
|
64
|
-
</Column>
|
|
65
|
-
</Box.card>
|
|
66
|
-
</>
|
|
67
|
-
)
|
|
68
|
-
},
|
|
69
|
-
'e-consent',
|
|
70
|
-
{},
|
|
71
|
-
)
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
|
|
5
|
-
import { consentCategories, type ConsentCategory, type ConsentDecision } from '../consent.ts'
|
|
6
|
-
import type { Row } from '../charts.tsx'
|
|
7
|
-
import type { ButtonProps } from './button.tsx'
|
|
8
|
-
import type { ConsentProps } from './consent.tsx'
|
|
9
|
-
import type { TextProps } from './text.tsx'
|
|
10
|
-
import type { ToggleProps } from './toggle.tsx'
|
|
11
|
-
|
|
12
|
-
type Kept = {
|
|
13
|
-
readonly categories: readonly ConsentCategory[]
|
|
14
|
-
readonly selected: readonly string[]
|
|
15
|
-
readonly accepted: boolean
|
|
16
|
-
readonly offered: readonly string[]
|
|
17
|
-
readonly toggle: (id: string, on: boolean) => void
|
|
18
|
-
readonly decide: (decision: ConsentDecision['decision'], accepted: readonly string[]) => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function firstSelection(
|
|
22
|
-
categories: readonly ConsentCategory[],
|
|
23
|
-
decision: ConsentDecision | undefined,
|
|
24
|
-
preselected: readonly string[],
|
|
25
|
-
): readonly string[] {
|
|
26
|
-
const answered = decision !== undefined
|
|
27
|
-
return categories
|
|
28
|
-
.filter(
|
|
29
|
-
(one) =>
|
|
30
|
-
one.required ||
|
|
31
|
-
(answered
|
|
32
|
-
? decision.decision === 'accepted' && decision.accepted.includes(one.id)
|
|
33
|
-
: preselected.includes(one.id)),
|
|
34
|
-
)
|
|
35
|
-
.map((one) => one.id)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function uses(props: ConsentProps): {
|
|
39
|
-
readonly holds?: readonly string[]
|
|
40
|
-
readonly animates?: boolean
|
|
41
|
-
readonly on?: Readonly<Record<string, unknown>>
|
|
42
|
-
readonly categories: readonly ConsentCategory[]
|
|
43
|
-
readonly selected: readonly string[]
|
|
44
|
-
readonly accepted: boolean
|
|
45
|
-
readonly offered: readonly string[]
|
|
46
|
-
readonly toggle: (id: string, on: boolean) => void
|
|
47
|
-
readonly decide: (decision: ConsentDecision['decision'], accepted: readonly string[]) => void
|
|
48
|
-
} {
|
|
49
|
-
const categories = consentCategories()
|
|
50
|
-
const [selected, setSelected] = useState<readonly string[]>(() =>
|
|
51
|
-
firstSelection(categories, props.decision, props.preselected ?? []),
|
|
52
|
-
)
|
|
53
|
-
const offered = categories.map((one) => one.id)
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
categories,
|
|
57
|
-
selected,
|
|
58
|
-
offered,
|
|
59
|
-
accepted: props.decision?.decision === 'accepted',
|
|
60
|
-
toggle: (id: string, on: boolean): void => {
|
|
61
|
-
setSelected((was) => (on ? [...was, id] : was.filter((one) => one !== id)))
|
|
62
|
-
},
|
|
63
|
-
decide: (decision: ConsentDecision['decision'], accepted: readonly string[]): void => {
|
|
64
|
-
props.onDecide({ decision, accepted: [...accepted], offered })
|
|
65
|
-
},
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function categories(_props: ConsentProps, kept: Kept): readonly Row[] {
|
|
70
|
-
return kept.categories as unknown as readonly Row[]
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function hasPolicy(props: ConsentProps, _kept: Kept): boolean {
|
|
74
|
-
return props.policyKey !== undefined
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function withdrawable(_props: ConsentProps, kept: Kept): boolean {
|
|
78
|
-
return kept.accepted
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function optional(_props: ConsentProps, _kept: Kept, row: Row): boolean {
|
|
82
|
-
return row['required'] !== true
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function required(_props: ConsentProps, _kept: Kept, row: Row): boolean {
|
|
86
|
-
return row['required'] === true
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function title(_props: ConsentProps, _kept: Kept, _at?: number): TextProps {
|
|
90
|
-
return { k: 'consent.title', is: 'heading' }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function policy(props: ConsentProps, _kept: Kept, _at?: number): TextProps {
|
|
94
|
-
return { k: props.policyKey ?? 'consent.title', is: 'body' }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function label(_props: ConsentProps, _kept: Kept, row: Row, _at: number): TextProps {
|
|
98
|
-
return { k: String(row['labelKey']), is: 'label' }
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function describe(_props: ConsentProps, _kept: Kept, row: Row, _at: number): TextProps {
|
|
102
|
-
return { k: String(row['describeKey']), is: 'body' }
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function fixed(_props: ConsentProps, _kept: Kept, _row: Row, _at: number): TextProps {
|
|
106
|
-
return { k: 'consent.required', is: 'label' }
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function chooser(_props: ConsentProps, kept: Kept, row: Row, _at?: number): ToggleProps {
|
|
110
|
-
const id = String(row['id'])
|
|
111
|
-
return {
|
|
112
|
-
labelKey: String(row['labelKey']),
|
|
113
|
-
on: kept.selected.includes(id),
|
|
114
|
-
onToggle: (on: boolean): void => kept.toggle(id, on),
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function withdraw(_props: ConsentProps, kept: Kept): ButtonProps {
|
|
119
|
-
return { label: 'consent.withdraw', onPress: (): void => kept.decide('withdrawn', []) }
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function decline(_props: ConsentProps, kept: Kept): ButtonProps {
|
|
123
|
-
return { label: 'consent.decline', onPress: (): void => kept.decide('declined', []) }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function accept(_props: ConsentProps, kept: Kept): ButtonProps {
|
|
127
|
-
return { label: 'consent.accept', onPress: (): void => kept.decide('accepted', kept.selected) }
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function acceptAll(_props: ConsentProps, kept: Kept): ButtonProps {
|
|
131
|
-
return { label: 'consent.acceptAll', onPress: (): void => kept.decide('accepted', kept.offered) }
|
|
132
|
-
}
|
|
@@ -1,45 +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 { slice, uses } from './donut.works.ts'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export interface DonutProps {
|
|
14
|
-
readonly rows: readonly Row[]
|
|
15
|
-
readonly by: string
|
|
16
|
-
readonly value: string
|
|
17
|
-
readonly titleKey?: MessageKey
|
|
18
|
-
readonly dispatch?: keyof Dispatching
|
|
19
|
-
readonly input?: Readonly<Record<string, unknown>>
|
|
20
|
-
readonly invokeOn?: 'press' | 'shown'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const Donut: Element<'Donut', DonutProps> = element(
|
|
24
|
-
'Donut',
|
|
25
|
-
(props: DonutProps, 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
|
-
...(kept.animates === undefined ? {} : { animates: kept.animates }), })
|
|
33
|
-
return (
|
|
34
|
-
<svg className={surface.className} {...surface.marks} {...surface.invokes} {...surface.a11y} {...(kept.on ?? {})} role="img" {...(props.titleKey === undefined ? {} : { 'aria-label': surface.text(props.titleKey) })}>
|
|
35
|
-
<Each rows={props.rows} by={props.by}>
|
|
36
|
-
{(each0, at) => (
|
|
37
|
-
<circle {...slice(props, kept, each0, at)}></circle>
|
|
38
|
-
)}
|
|
39
|
-
</Each>
|
|
40
|
-
</svg>
|
|
41
|
-
)
|
|
42
|
-
},
|
|
43
|
-
'e-donut',
|
|
44
|
-
{"card":"thread-card"},
|
|
45
|
-
)
|