@prestack/thread-ui 0.0.1 → 0.1.0
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 +177 -0
- 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.js +2 -3
- package/dist/ui/animations.ts +316 -0
- package/dist/ui/attach.js +13 -10
- package/dist/ui/attach.ts +607 -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 +11 -2
- package/dist/ui/compositions.js +283 -59
- package/dist/ui/compositions.ts +633 -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.js +2 -1
- package/dist/ui/generators/dev.ts +80 -0
- package/dist/ui/generators/elements.d.ts +1 -11
- package/dist/ui/generators/elements.js +44 -14
- package/dist/ui/generators/elements.ts +794 -0
- package/dist/ui/generators/i18n.js +2 -3
- package/dist/ui/generators/i18n.ts +300 -0
- package/dist/ui/generators/icons.js +3 -12
- package/dist/ui/generators/icons.ts +214 -0
- package/dist/ui/generators/react.js +13 -5
- package/dist/ui/generators/react.ts +269 -0
- package/dist/ui/generators/routes.d.ts +1 -0
- package/dist/ui/generators/routes.js +99 -83
- package/dist/ui/generators/routes.ts +743 -0
- package/dist/ui/generators/show.js +4 -12
- package/dist/ui/generators/show.ts +260 -0
- package/dist/ui/generators/styles.js +3 -4
- package/dist/ui/generators/styles.ts +669 -0
- package/dist/ui/generators/variants.js +2 -3
- package/dist/ui/generators/variants.ts +204 -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/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.js +2 -3
- package/dist/ui/materials.ts +205 -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 +22 -22
- package/dist/ui/screens.ts +141 -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.js +1 -2
- package/dist/ui/tokens.ts +234 -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/makers/message.d.ts +0 -1
- package/dist/ui/makers/message.js +0 -230
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useCallback, useSyncExternalStore, type ReactNode } from 'react'
|
|
4
|
+
import { formatValue, runValidator, validatorFor } from './validators.ts'
|
|
5
|
+
import { ICON_TARGET, strokeFor } from './icons.ts'
|
|
6
|
+
|
|
7
|
+
import { element, useSurface, useUi, useVisibility } from './wrappers.tsx'
|
|
8
|
+
|
|
9
|
+
export type MessageKey = string
|
|
10
|
+
|
|
11
|
+
export interface ValueProps {
|
|
12
|
+
readonly validator: string
|
|
13
|
+
readonly value: unknown
|
|
14
|
+
|
|
15
|
+
readonly context?: Readonly<Record<string, unknown>>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function renderValue(
|
|
19
|
+
{ validator, value, context }: ValueProps,
|
|
20
|
+
surface: ReturnType<typeof useSurface>,
|
|
21
|
+
): ReactNode {
|
|
22
|
+
const entry = validatorFor(validator)
|
|
23
|
+
const result = runValidator(validator, value, context ?? {})
|
|
24
|
+
|
|
25
|
+
if (!result.ok) {
|
|
26
|
+
return (
|
|
27
|
+
<span className={surface.className} {...surface.marks} data-invalid="true">
|
|
28
|
+
{surface.text(result.errorKey)}
|
|
29
|
+
</span>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<span className={surface.className} {...surface.marks} data-validator={entry.name}>
|
|
35
|
+
{formatValue(validator, result.value, context ?? {})}
|
|
36
|
+
</span>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const CONTRAST_LARGE = 3
|
|
2
|
+
|
|
3
|
+
function channel(value: number): number {
|
|
4
|
+
const c = value / 255
|
|
5
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function luminance(hex: string): number {
|
|
9
|
+
const clean = hex.replace('#', '')
|
|
10
|
+
const full =
|
|
11
|
+
clean.length === 3
|
|
12
|
+
? clean
|
|
13
|
+
.split('')
|
|
14
|
+
.map((c) => c + c)
|
|
15
|
+
.join('')
|
|
16
|
+
: clean.slice(0, 6)
|
|
17
|
+
const num = Number.parseInt(full, 16)
|
|
18
|
+
const r = channel((num >> 16) & 255)
|
|
19
|
+
const g = channel((num >> 8) & 255)
|
|
20
|
+
const b = channel(num & 255)
|
|
21
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function contrast(a: string, b: string): number {
|
|
25
|
+
const [light, dark] = [luminance(a), luminance(b)].sort((x, y) => y - x) as [number, number]
|
|
26
|
+
return (light + 0.05) / (dark + 0.05)
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useRef, useState } from 'react'
|
|
4
|
+
import { acceptsKeystroke, applyMask, entryConstraints, evaluateMoney, runValidator } from './validators.ts'
|
|
5
|
+
|
|
6
|
+
import { ITEM_ATTR, useRovingFocus } from './roving-focus.ts'
|
|
7
|
+
import { element, pressOf, useSurface, usePress } from './wrappers.tsx'
|
|
8
|
+
import type { MessageKey } from './content.tsx'
|
|
9
|
+
import type { Dispatching } from './checked.ts'
|
|
10
|
+
|
|
11
|
+
export interface PressProps {
|
|
12
|
+
|
|
13
|
+
readonly dispatch?: [keyof Dispatching] extends [never] ? string : keyof Dispatching & string
|
|
14
|
+
|
|
15
|
+
readonly input?: Readonly<Record<string, unknown>>
|
|
16
|
+
|
|
17
|
+
readonly navigateTo?: string
|
|
18
|
+
|
|
19
|
+
readonly onPress?: () => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Option {
|
|
23
|
+
readonly value: string
|
|
24
|
+
readonly labelKey: MessageKey
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Menu, type MenuProps } from './elements/menu.tsx'
|
|
28
|
+
|
|
29
|
+
export { type MenuItem } from './elements/menu.works.tsx'
|
|
30
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useId, useRef, useState, type ReactNode } from 'react'
|
|
4
|
+
|
|
5
|
+
import { ITEM_ATTR, useRovingFocus } from './roving-focus.ts'
|
|
6
|
+
import { element, useSurface } from './wrappers.tsx'
|
|
7
|
+
import type { MessageKey } from './content.tsx'
|
|
8
|
+
|
|
9
|
+
export interface TabItem {
|
|
10
|
+
readonly id: string
|
|
11
|
+
readonly labelKey: MessageKey
|
|
12
|
+
readonly disabled?: boolean
|
|
13
|
+
readonly content: ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AccordionItem {
|
|
17
|
+
readonly id: string
|
|
18
|
+
readonly labelKey: MessageKey
|
|
19
|
+
readonly disabled?: boolean
|
|
20
|
+
readonly content: ReactNode
|
|
21
|
+
}
|
|
22
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, type RefObject } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface Layer {
|
|
6
|
+
readonly ref: RefObject<HTMLElement | null>
|
|
7
|
+
readonly dismissOnEscape: boolean
|
|
8
|
+
readonly dismissOnOutside: boolean
|
|
9
|
+
readonly onDismiss: () => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const layers: Layer[] = []
|
|
13
|
+
|
|
14
|
+
function ordered(): readonly Layer[] {
|
|
15
|
+
return layers
|
|
16
|
+
.filter((layer) => layer.ref.current !== null)
|
|
17
|
+
.sort((a, b) => {
|
|
18
|
+
const first = a.ref.current as HTMLElement
|
|
19
|
+
const second = b.ref.current as HTMLElement
|
|
20
|
+
if (first === second) return 0
|
|
21
|
+
|
|
22
|
+
return (first.compareDocumentPosition(second) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0 ? -1 : 1
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function target(kind: 'escape' | 'outside'): Layer | undefined {
|
|
27
|
+
const open = ordered()
|
|
28
|
+
for (let i = open.length - 1; i >= 0; i -= 1) {
|
|
29
|
+
const layer = open[i] as Layer
|
|
30
|
+
if (kind === 'escape' ? layer.dismissOnEscape : layer.dismissOnOutside) return layer
|
|
31
|
+
}
|
|
32
|
+
return undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useDismissLayer(
|
|
36
|
+
ref: RefObject<HTMLElement | null>,
|
|
37
|
+
options: {
|
|
38
|
+
readonly active: boolean
|
|
39
|
+
readonly dismissOnEscape: boolean
|
|
40
|
+
readonly dismissOnOutside: boolean
|
|
41
|
+
readonly onDismiss: () => void
|
|
42
|
+
},
|
|
43
|
+
): void {
|
|
44
|
+
const { active, dismissOnEscape, dismissOnOutside, onDismiss } = options
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!active) return
|
|
48
|
+
const layer: Layer = { ref, dismissOnEscape, dismissOnOutside, onDismiss }
|
|
49
|
+
layers.push(layer)
|
|
50
|
+
|
|
51
|
+
const onKeyDown = (event: KeyboardEvent): void => {
|
|
52
|
+
if (event.key !== 'Escape') return
|
|
53
|
+
if (target('escape') !== layer) return
|
|
54
|
+
event.preventDefault()
|
|
55
|
+
|
|
56
|
+
event.stopPropagation()
|
|
57
|
+
layer.onDismiss()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const onPointerDown = (event: Event): void => {
|
|
61
|
+
if (target('outside') !== layer) return
|
|
62
|
+
const root = ref.current
|
|
63
|
+
const node = event.target
|
|
64
|
+
if (root === null || !(node instanceof Node)) return
|
|
65
|
+
if (root.contains(node)) return
|
|
66
|
+
|
|
67
|
+
event.preventDefault()
|
|
68
|
+
event.stopPropagation()
|
|
69
|
+
layer.onDismiss()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
document.addEventListener('keydown', onKeyDown, true)
|
|
73
|
+
document.addEventListener('pointerdown', onPointerDown, true)
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
document.removeEventListener('keydown', onKeyDown, true)
|
|
77
|
+
document.removeEventListener('pointerdown', onPointerDown, true)
|
|
78
|
+
const at = layers.indexOf(layer)
|
|
79
|
+
|
|
80
|
+
if (at !== -1) layers.splice(at, 1)
|
|
81
|
+
}
|
|
82
|
+
}, [active, dismissOnEscape, dismissOnOutside, onDismiss, ref])
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function openLayers(): number {
|
|
86
|
+
return layers.length
|
|
87
|
+
}
|
package/dist/ui/door.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
|
|
2
|
+
export const PRESENTATIONS = ['page', 'sheet', 'popover', 'overlay', 'toast'] as const
|
|
3
|
+
export type Presentation = (typeof PRESENTATIONS)[number]
|
|
4
|
+
|
|
5
|
+
export const PRESENTATION_BEHAVIOUR: Readonly<Record<Presentation, {
|
|
6
|
+
readonly portal: boolean
|
|
7
|
+
readonly backdrop: boolean
|
|
8
|
+
readonly trapFocus: boolean
|
|
9
|
+
readonly returnFocus: boolean
|
|
10
|
+
readonly dismissOnEscape: boolean
|
|
11
|
+
readonly dismissOnOutside: boolean
|
|
12
|
+
}>> = {
|
|
13
|
+
page: { portal: false, backdrop: false, trapFocus: false, returnFocus: false, dismissOnEscape: false, dismissOnOutside: false },
|
|
14
|
+
sheet: { portal: true, backdrop: true, trapFocus: true, returnFocus: true, dismissOnEscape: true, dismissOnOutside: true },
|
|
15
|
+
overlay: { portal: true, backdrop: true, trapFocus: true, returnFocus: true, dismissOnEscape: true, dismissOnOutside: true },
|
|
16
|
+
|
|
17
|
+
popover: { portal: true, backdrop: false, trapFocus: false, returnFocus: true, dismissOnEscape: true, dismissOnOutside: true },
|
|
18
|
+
|
|
19
|
+
toast: { portal: true, backdrop: false, trapFocus: false, returnFocus: false, dismissOnEscape: false, dismissOnOutside: false },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ClockSubscriber {
|
|
23
|
+
|
|
24
|
+
(t: number): void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class Ticker {
|
|
28
|
+
#subscribers = new Set<() => void>()
|
|
29
|
+
#stop: (() => void) | undefined
|
|
30
|
+
readonly #every: (fn: () => void) => () => void
|
|
31
|
+
|
|
32
|
+
constructor(every?: (fn: () => void) => () => void) {
|
|
33
|
+
this.#every =
|
|
34
|
+
every ??
|
|
35
|
+
((fn) => {
|
|
36
|
+
const id = setInterval(fn, 1000)
|
|
37
|
+
return () => clearInterval(id)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get running(): boolean {
|
|
42
|
+
return this.#stop !== undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
subscribe(fn: () => void): () => void {
|
|
46
|
+
this.#subscribers.add(fn)
|
|
47
|
+
if (this.#stop === undefined) this.#stop = this.#every(() => this.tick())
|
|
48
|
+
return () => {
|
|
49
|
+
this.#subscribers.delete(fn)
|
|
50
|
+
|
|
51
|
+
if (this.#subscribers.size === 0) {
|
|
52
|
+
this.#stop?.()
|
|
53
|
+
this.#stop = undefined
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
tick(): void {
|
|
59
|
+
for (const fn of this.#subscribers) fn()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class Clock {
|
|
64
|
+
#subscribers = new Set<ClockSubscriber>()
|
|
65
|
+
#visible = true
|
|
66
|
+
#running = false
|
|
67
|
+
#t = 0
|
|
68
|
+
#ticks = 0
|
|
69
|
+
readonly #schedule: (fn: () => void) => void
|
|
70
|
+
|
|
71
|
+
constructor(schedule?: (fn: () => void) => void) {
|
|
72
|
+
this.#schedule =
|
|
73
|
+
schedule ??
|
|
74
|
+
((fn) => {
|
|
75
|
+
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => fn())
|
|
76
|
+
else setTimeout(fn, 16)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get ticks(): number {
|
|
81
|
+
return this.#ticks
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get running(): boolean {
|
|
85
|
+
return this.#running
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
subscribe(fn: ClockSubscriber): () => void {
|
|
89
|
+
this.#subscribers.add(fn)
|
|
90
|
+
this.#maybeStart()
|
|
91
|
+
return () => {
|
|
92
|
+
this.#subscribers.delete(fn)
|
|
93
|
+
if (this.#subscribers.size === 0) this.#running = false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setVisible(visible: boolean): void {
|
|
98
|
+
this.#visible = visible
|
|
99
|
+
if (visible) this.#maybeStart()
|
|
100
|
+
else this.#running = false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
tick(dt: number): void {
|
|
104
|
+
if (!this.#visible) return
|
|
105
|
+
this.#t += dt
|
|
106
|
+
this.#ticks += 1
|
|
107
|
+
for (const fn of this.#subscribers) fn(this.#t)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#maybeStart(): void {
|
|
111
|
+
if (this.#running || !this.#visible || this.#subscribers.size === 0) return
|
|
112
|
+
this.#running = true
|
|
113
|
+
const loop = (): void => {
|
|
114
|
+
if (!this.#running) return
|
|
115
|
+
this.tick(1 / 60)
|
|
116
|
+
this.#schedule(loop)
|
|
117
|
+
}
|
|
118
|
+
this.#schedule(loop)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface Surface {
|
|
123
|
+
readonly className?: string
|
|
124
|
+
|
|
125
|
+
readonly holds: readonly string[]
|
|
126
|
+
|
|
127
|
+
readonly marks: Readonly<Record<string, boolean>>
|
|
128
|
+
|
|
129
|
+
readonly invokes: Readonly<Record<string, unknown>>
|
|
130
|
+
|
|
131
|
+
readonly marked: (signal: string) => boolean
|
|
132
|
+
|
|
133
|
+
readonly text: (key: string, params?: Readonly<Record<string, unknown>>) => string
|
|
134
|
+
|
|
135
|
+
readonly a11y: Readonly<Record<string, string | boolean | number>>
|
|
136
|
+
|
|
137
|
+
readonly measures: Readonly<Record<string, string | number>>
|
|
138
|
+
|
|
139
|
+
readonly t: number
|
|
140
|
+
}
|
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" });
|