@santi020k/lumen-astro 3.0.1 → 4.0.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/README.md +403 -7
- package/components/AmountField.astro +21 -0
- package/components/AnimatedNumber.astro +1 -1
- package/components/ApprovalCard.astro +30 -0
- package/components/AttachmentList.astro +15 -0
- package/components/AttachmentPreview.astro +51 -0
- package/components/Avatar.astro +2 -0
- package/components/BarChart.astro +95 -31
- package/components/BoxPlot.astro +77 -0
- package/components/Breadcrumb.astro +2 -1
- package/components/BulletChart.astro +64 -0
- package/components/Button.astro +1 -1
- package/components/Calendar.astro +54 -65
- package/components/CalendarHeatmap.astro +76 -0
- package/components/Card.astro +4 -0
- package/components/ChangeSummary.astro +36 -0
- package/components/ChartDatumActions.astro +24 -0
- package/components/ChartMotion.astro +11 -0
- package/components/Code.astro +18 -3
- package/components/CodeTabs.astro +12 -0
- package/components/ComboChart.astro +93 -11
- package/components/CountryFlag.astro +23 -0
- package/components/DataTable.astro +15 -7
- package/components/DatePicker.astro +24 -17
- package/components/DescriptionDetail.astro +18 -0
- package/components/DescriptionItem.astro +18 -0
- package/components/DescriptionTerm.astro +18 -0
- package/components/DeviceFrame.astro +79 -0
- package/components/DialogBody.astro +20 -0
- package/components/DialogClose.astro +21 -0
- package/components/DialogFooter.astro +20 -0
- package/components/DialogHeader.astro +20 -0
- package/components/DialogTitle.astro +21 -0
- package/components/DumbbellChart.astro +8 -0
- package/components/FileUpload.astro +3 -1
- package/components/FilterBar.astro +25 -0
- package/components/FunnelChart.astro +50 -0
- package/components/Grid.astro +2 -2
- package/components/Heatmap.astro +61 -12
- package/components/Histogram.astro +30 -0
- package/components/Icon.astro +7 -3
- package/components/ImageComparison.astro +74 -0
- package/components/Input.astro +2 -2
- package/components/LineChart.astro +122 -66
- package/components/LollipopChart.astro +8 -0
- package/components/MediaFilmstrip.astro +19 -0
- package/components/MediaThumbnail.astro +29 -0
- package/components/MediaViewport.astro +38 -0
- package/components/Mentions.astro +2 -1
- package/components/MessageScroller.astro +6 -0
- package/components/MotionGroup.astro +19 -0
- package/components/NativeSelect.astro +2 -2
- package/components/Pagination.astro +2 -1
- package/components/PasswordField.astro +1 -1
- package/components/PhoneInput.astro +60 -9
- package/components/PhoneNumber.astro +19 -0
- package/components/PieChart.astro +26 -3
- package/components/PromptComposer.astro +36 -0
- package/components/RangeChart.astro +38 -8
- package/components/ScatterChart.astro +62 -14
- package/components/Segmented.astro +5 -5
- package/components/Select.astro +8 -8
- package/components/SourceCitation.astro +18 -0
- package/components/Sparkline.astro +9 -10
- package/components/Stack.astro +2 -2
- package/components/StreamMessage.astro +26 -0
- package/components/Tabs.astro +3 -0
- package/components/ToolActivity.astro +17 -0
- package/components/TreeSelect.astro +1 -0
- package/components/VirtualList.astro +5 -2
- package/components/VisualEffect.astro +21 -0
- package/components/WaterfallChart.astro +27 -0
- package/components/WorldMap.astro +213 -0
- package/forms.ts +17 -4
- package/index.ts +37 -0
- package/internal/ChartInspection.astro +27 -0
- package/internal/ComparisonChart.astro +69 -0
- package/internal/IntervalChart.astro +66 -0
- package/package.json +6 -4
- package/runtime/UIPrimitives.astro +670 -647
- package/runtime/chart-actions.ts +19 -0
- package/runtime/controllers/amount-field.ts +12 -0
- package/runtime/controllers/attachments.ts +13 -0
- package/runtime/controllers/chart-activation.ts +33 -0
- package/runtime/controllers/charts.ts +33 -0
- package/runtime/controllers/combobox.ts +39 -0
- package/runtime/controllers/comparison-reset.ts +20 -0
- package/runtime/controllers/data-table.ts +142 -0
- package/runtime/controllers/dialogs.ts +32 -32
- package/runtime/controllers/document-navigation.ts +54 -22
- package/runtime/controllers/file-upload.ts +89 -0
- package/runtime/controllers/image-comparison.ts +53 -0
- package/runtime/controllers/media-selection.ts +20 -0
- package/runtime/controllers/media-viewport.ts +54 -0
- package/runtime/controllers/media-workspace.ts +8 -0
- package/runtime/controllers/message-scroller.ts +13 -0
- package/runtime/controllers/motion.ts +15 -16
- package/runtime/controllers/optional-media.ts +29 -0
- package/runtime/controllers/phone-input.ts +128 -39
- package/runtime/controllers/visual-interactions.ts +75 -0
- package/runtime/controllers/world-map.ts +154 -0
- package/styles/critical.css +634 -61
- package/styles/lumen.css +101 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'div'> {
|
|
7
|
+
class?: string | null
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
12
|
+
|
|
13
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
14
|
+
rest, ['ui-description-item', 'ui-descriptions__item'], classProp, className
|
|
15
|
+
)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<div class:list={classList} data-slot="description-item" {...passthrough}><slot /></div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'dt'> {
|
|
7
|
+
class?: string | null
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
12
|
+
|
|
13
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
14
|
+
rest, ['ui-description-term', 'ui-descriptions__term'], classProp, className
|
|
15
|
+
)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<dt class:list={classList} data-slot="description-term" {...passthrough}><slot /></dt>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
type LumenDeviceFrameColor, type LumenDeviceFrameDevice, type LumenDeviceFrameOrientation, type LumenDeviceFrameTone,
|
|
6
|
+
resolveLumenAstroProps, resolveLumenDeviceFrame, resolveLumenDeviceFrameColor
|
|
7
|
+
} from '@santi020k/lumen-core'
|
|
8
|
+
|
|
9
|
+
interface Props extends HTMLAttributes<'div'> {
|
|
10
|
+
device?: LumenDeviceFrameDevice
|
|
11
|
+
orientation?: LumenDeviceFrameOrientation
|
|
12
|
+
tone?: LumenDeviceFrameTone
|
|
13
|
+
color?: LumenDeviceFrameColor
|
|
14
|
+
screenWidth?: number
|
|
15
|
+
screenHeight?: number
|
|
16
|
+
scroll?: boolean
|
|
17
|
+
className?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { device = 'laptop', orientation, tone = 'dark', color, screenWidth, screenHeight, scroll = true,
|
|
21
|
+
class: classProp, className, style: consumerStyle, ...rest } = Astro.props
|
|
22
|
+
|
|
23
|
+
const size = resolveLumenDeviceFrame(device, orientation, screenWidth, screenHeight)
|
|
24
|
+
const resolvedColor = resolveLumenDeviceFrameColor(color)
|
|
25
|
+
|
|
26
|
+
const frameStyle = typeof consumerStyle === 'string' ?
|
|
27
|
+
`${consumerStyle}${resolvedColor ? `;--ui-device-color:${resolvedColor}` : ''}` :
|
|
28
|
+
{ ...consumerStyle, ...(resolvedColor ? { '--ui-device-color': resolvedColor } : {}) }
|
|
29
|
+
|
|
30
|
+
const { classList, passthrough } = resolveLumenAstroProps(rest, ['ui-device-frame'], classProp, className)
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<div class:list={classList} data-device={device} data-tone={tone} data-orientation={orientation} style={frameStyle} {...passthrough}>
|
|
34
|
+
<div class="ui-device-frame__shell">
|
|
35
|
+
<span class="ui-device-frame__hardware" aria-hidden="true">
|
|
36
|
+
<span class="ui-device-frame__action" />
|
|
37
|
+
<span class="ui-device-frame__volume-up" />
|
|
38
|
+
<span class="ui-device-frame__volume-down" />
|
|
39
|
+
<span class="ui-device-frame__power" />
|
|
40
|
+
<span class="ui-device-frame__rail-left" />
|
|
41
|
+
<span class="ui-device-frame__rail-right" />
|
|
42
|
+
</span>
|
|
43
|
+
<div class="ui-device-frame__glass">
|
|
44
|
+
<span aria-hidden="true" class="ui-device-frame__camera"></span>
|
|
45
|
+
<lumen-device-screen
|
|
46
|
+
class="ui-device-frame__screen"
|
|
47
|
+
data-scroll={String(scroll)}
|
|
48
|
+
data-ui-device-screen
|
|
49
|
+
data-screen-width={size.width}
|
|
50
|
+
style={`--ui-device-frame-width: ${size.width}px; --ui-device-frame-height: ${size.height}px; aspect-ratio: ${size.width} / ${size.height}`}
|
|
51
|
+
>
|
|
52
|
+
<slot />
|
|
53
|
+
</lumen-device-screen>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<span aria-hidden="true" class="ui-device-frame__base"></span>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<script>
|
|
60
|
+
import { observeLumenDeviceFrame } from '@santi020k/lumen-core'
|
|
61
|
+
|
|
62
|
+
class LumenDeviceScreen extends HTMLElement {
|
|
63
|
+
private cleanup: (() => void) | undefined
|
|
64
|
+
|
|
65
|
+
connectedCallback(): void {
|
|
66
|
+
this.cleanup?.()
|
|
67
|
+
|
|
68
|
+
this.cleanup = observeLumenDeviceFrame(this, Number(this.dataset.screenWidth))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
disconnectedCallback(): void {
|
|
72
|
+
this.cleanup?.()
|
|
73
|
+
|
|
74
|
+
this.cleanup = undefined
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!customElements.get('lumen-device-screen')) customElements.define('lumen-device-screen', LumenDeviceScreen)
|
|
79
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'div'> {
|
|
7
|
+
class?: string | null
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
12
|
+
|
|
13
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
14
|
+
rest, ['ui-dialog-body'], classProp, className
|
|
15
|
+
)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<div class:list={classList} data-slot="dialog-body" {...passthrough}>
|
|
19
|
+
<slot />
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { composeClassName } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
import Button from './Button.astro'
|
|
7
|
+
|
|
8
|
+
interface Props extends HTMLAttributes<'button'> {
|
|
9
|
+
class?: string | null
|
|
10
|
+
className?: string
|
|
11
|
+
loading?: boolean
|
|
12
|
+
size?: 'default' | 'sm' | 'lg' | 'icon'
|
|
13
|
+
variant?: 'default' | 'destructive' | 'ghost' | 'link' | 'outline' | 'secondary'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<Button {...rest} class={composeClassName('ui-dialog-close', classProp, className)} data-slot="dialog-close" data-ui-dialog-close>
|
|
20
|
+
<slot />
|
|
21
|
+
</Button>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'footer'> {
|
|
7
|
+
class?: string | null
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
12
|
+
|
|
13
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
14
|
+
rest, ['ui-dialog-footer'], classProp, className
|
|
15
|
+
)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<footer class:list={classList} data-slot="dialog-footer" {...passthrough}>
|
|
19
|
+
<slot />
|
|
20
|
+
</footer>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'header'> {
|
|
7
|
+
class?: string | null
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { class: classProp = '', className = '', ...rest } = Astro.props
|
|
12
|
+
|
|
13
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
14
|
+
rest, ['ui-dialog-header'], classProp, className
|
|
15
|
+
)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<header class:list={classList} data-slot="dialog-header" {...passthrough}>
|
|
19
|
+
<slot />
|
|
20
|
+
</header>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'h2'> {
|
|
7
|
+
as?: 'h2' | 'h3' | 'h4'
|
|
8
|
+
class?: string | null
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { as: Tag = 'h2', class: classProp = '', className = '', ...rest } = Astro.props
|
|
13
|
+
|
|
14
|
+
const { classList, passthrough } = resolveLumenAstroProps(
|
|
15
|
+
rest, ['ui-dialog-title'], classProp, className
|
|
16
|
+
)
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<Tag class:list={classList} data-slot="dialog-title" {...passthrough}>
|
|
20
|
+
<slot />
|
|
21
|
+
</Tag>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import ComparisonChart from '../internal/ComparisonChart.astro'
|
|
5
|
+
|
|
6
|
+
type Props = Omit<ComponentProps<typeof ComparisonChart>, 'paired'>
|
|
7
|
+
---
|
|
8
|
+
<ComparisonChart {...Astro.props} class:list={['ui-dumbbell-chart', Astro.props.class, Astro.props.className]} paired={true} />
|
|
@@ -8,6 +8,7 @@ interface Props extends Omit<HTMLAttributes<'input'>, 'type' | 'size'> {
|
|
|
8
8
|
className?: string
|
|
9
9
|
label?: string
|
|
10
10
|
hint?: string
|
|
11
|
+
selectedFilesLabel?: string
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const {
|
|
@@ -15,6 +16,7 @@ const {
|
|
|
15
16
|
className = '',
|
|
16
17
|
label = 'Choose a file or drag it here',
|
|
17
18
|
hint,
|
|
19
|
+
selectedFilesLabel = '{count} files selected',
|
|
18
20
|
id,
|
|
19
21
|
...rest
|
|
20
22
|
} = Astro.props
|
|
@@ -24,7 +26,7 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
24
26
|
], classProp, className)
|
|
25
27
|
---
|
|
26
28
|
|
|
27
|
-
<label class:list={classList} data-ui-file-upload for={id}>
|
|
29
|
+
<label class:list={classList} data-ui-file-upload data-ui-selected-files-label={selectedFilesLabel} for={id}>
|
|
28
30
|
<input class="ui-file-upload__input" data-ui-file-upload-input id={id} type="file" {...passthrough} />
|
|
29
31
|
<svg
|
|
30
32
|
aria-hidden="true"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
interface Props extends HTMLAttributes<'section'> {
|
|
7
|
+
label?: string
|
|
8
|
+
resultLabel?: string
|
|
9
|
+
pending?: boolean
|
|
10
|
+
open?: boolean
|
|
11
|
+
class?: string | null
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { label = 'Filters', resultLabel, pending = false, open = true, class: classProp, className, ...rest } = Astro.props
|
|
16
|
+
const { classList, passthrough } = resolveLumenAstroProps(rest, ['ui-filter-bar'], classProp, className)
|
|
17
|
+
---
|
|
18
|
+
<section class:list={classList} aria-label={label} aria-busy={pending} {...passthrough}>
|
|
19
|
+
<details open={open}>
|
|
20
|
+
<summary>{label}</summary>
|
|
21
|
+
<div class="ui-filter-bar__controls"><slot /></div>
|
|
22
|
+
</details>
|
|
23
|
+
<div class="ui-filter-bar__active"><slot name="active" /><slot name="actions" /></div>
|
|
24
|
+
<p class="ui-filter-bar__results" role="status" aria-live="polite" aria-atomic="true">{resultLabel}</p>
|
|
25
|
+
</section>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { createLumenFunnelGeometry, getLumenChartToneClassName, type LumenChartLabels, type LumenFunnelDatum, resolveLumenChartLabels } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
import Chart from './Chart.astro'
|
|
7
|
+
|
|
8
|
+
interface Props extends HTMLAttributes<'figure'> {
|
|
9
|
+
data: readonly LumenFunnelDatum[]
|
|
10
|
+
className?: string
|
|
11
|
+
heading?: string
|
|
12
|
+
description?: string
|
|
13
|
+
caption?: string
|
|
14
|
+
presentation?: 'bare' | 'default'
|
|
15
|
+
summary?: string
|
|
16
|
+
formatValue?: (value: number) => string
|
|
17
|
+
labels?: Partial<LumenChartLabels>
|
|
18
|
+
showTable?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { data, formatValue = String, labels, showTable = true, summary, class: classProp, className, ...props } = Astro.props
|
|
22
|
+
const text = resolveLumenChartLabels(labels)
|
|
23
|
+
const model = createLumenFunnelGeometry(data)
|
|
24
|
+
const format = (value: number | null) => value === null ? text.notAvailable : formatValue(value)
|
|
25
|
+
const fallback = model.valid ? text.empty : text.invalidData
|
|
26
|
+
const factual = !model.valid || model.rows.length === 0 ? fallback : model.rows.map(row => `${row.label}: ${format(row.value)}`).join('. ')
|
|
27
|
+
---
|
|
28
|
+
<Chart {...props} class:list={['ui-funnel-chart', classProp, className]} summary={summary ?? factual}>
|
|
29
|
+
{!model.valid || model.rows.length === 0 ?
|
|
30
|
+
<p class="ui-chart__empty" role="status">{model.valid ? text.empty : text.invalidData}</p> :
|
|
31
|
+
(
|
|
32
|
+
<>
|
|
33
|
+
<ol class="ui-funnel-chart__rows">{model.rows.map((row, index) => (
|
|
34
|
+
<li class={getLumenChartToneClassName(row.tone, index)}><div class="
|
|
35
|
+
ui-funnel-chart__label
|
|
36
|
+
"
|
|
37
|
+
><span>{row.label}</span><strong>{format(row.value)}</strong></div><div
|
|
38
|
+
class="ui-funnel-chart__track"
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
>{row.ratio !== null && (
|
|
41
|
+
<span
|
|
42
|
+
class="ui-funnel-chart__bar"
|
|
43
|
+
style={{ width: `${row.ratio * 100}%` }}
|
|
44
|
+
/>
|
|
45
|
+
)}</div></li>
|
|
46
|
+
))}</ol>
|
|
47
|
+
{showTable && <details class="ui-chart__data"><summary>{text.viewData}</summary><div role="group" tabindex="0" aria-label={text.chartData}><table><thead><tr><th scope="col">{text.category}</th><th scope="col">{text.value}</th></tr></thead><tbody>{model.rows.map(row => <tr><th scope="row">{row.label}</th><td>{format(row.value)}</td></tr>)}</tbody></table></div></details>}
|
|
48
|
+
</>
|
|
49
|
+
)}
|
|
50
|
+
</Chart>
|
package/components/Grid.astro
CHANGED
|
@@ -8,7 +8,7 @@ interface Props extends HTMLAttributes<'div'> {
|
|
|
8
8
|
class?: string | null
|
|
9
9
|
className?: string
|
|
10
10
|
columns?: 1 | 2 | 3 | 4 | 6 | 12 | 'auto'
|
|
11
|
-
gap?: 'lg' | 'md' | 'none' | 'sm' | 'xl'
|
|
11
|
+
gap?: '2xl' | '3xl' | 'group' | 'lg' | 'md' | 'none' | 'related' | 'section' | 'sm' | 'xl' | 'xs'
|
|
12
12
|
minItemWidth?: string
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
class: classProp = '',
|
|
18
18
|
className = '',
|
|
19
19
|
columns = 'auto',
|
|
20
|
-
gap = '
|
|
20
|
+
gap = 'group',
|
|
21
21
|
minItemWidth,
|
|
22
22
|
style,
|
|
23
23
|
...rest
|
package/components/Heatmap.astro
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { createLumenHeatmapDatumActivation, createLumenHeatmapModel, getLumenHeatmapColor, type LumenChartLabels, type LumenHeatmapDatum, type LumenHeatmapOptions, resolveLumenChartLabels } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
import { createChartDatumAction } from '../runtime/chart-actions'
|
|
5
7
|
|
|
6
8
|
import Chart from './Chart.astro'
|
|
9
|
+
import ChartDatumActions from './ChartDatumActions.astro'
|
|
7
10
|
|
|
8
|
-
interface Props extends HTMLAttributes<'figure'
|
|
11
|
+
interface Props extends HTMLAttributes<'figure'>, LumenHeatmapOptions {
|
|
12
|
+
showLegend?: boolean
|
|
9
13
|
caption?: string
|
|
10
14
|
class?: string | null
|
|
11
15
|
className?: string
|
|
12
16
|
data: readonly LumenHeatmapDatum[]
|
|
13
17
|
description?: string
|
|
18
|
+
drilldown?: boolean
|
|
14
19
|
formatValue?: (value: number) => string
|
|
15
20
|
heading?: string
|
|
16
21
|
labels?: Partial<LumenChartLabels>
|
|
@@ -18,18 +23,62 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
18
23
|
summary?: string
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
const { caption, class: classProp = '', className = '', data, description, formatValue = String, heading, labels, showTable = true, summary: summaryProp, ...rest } = Astro.props
|
|
22
|
-
const geometry =
|
|
23
|
-
const
|
|
26
|
+
const { colorScale = 'sequential', midpoint = 0, domain, showLegend = true, caption, class: classProp = '', className = '', data, description, drilldown = false, formatValue = String, heading, labels, showTable = true, summary: summaryProp, ...rest } = Astro.props
|
|
27
|
+
const geometry = createLumenHeatmapModel(data, { colorScale, midpoint, ...(domain ? { domain } : {}) })
|
|
28
|
+
const availableCells = geometry.cells.filter(cell => cell.value !== null && Number.isFinite(cell.value))
|
|
29
|
+
const hasData = availableCells.length > 0
|
|
24
30
|
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
25
|
-
const summary = summaryProp ?? resolvedLabels.formatHeatmapSummary(
|
|
31
|
+
const summary = summaryProp ?? resolvedLabels.formatHeatmapSummary(availableCells.length)
|
|
32
|
+
|
|
33
|
+
const datumActions = drilldown ?
|
|
34
|
+
availableCells.map(cell => createChartDatumAction(
|
|
35
|
+
createLumenHeatmapDatumActivation(cell),
|
|
36
|
+
`${cell.xLabel ?? cell.x} · ${cell.yLabel ?? cell.y}: ${cell.label ?? formatValue(cell.value ?? 0)}`,
|
|
37
|
+
resolvedLabels
|
|
38
|
+
)) :
|
|
39
|
+
[]
|
|
40
|
+
|
|
41
|
+
const datumActionByCell = new Map(availableCells.map((cell, index) => [cell, datumActions[index]]))
|
|
42
|
+
|
|
26
43
|
---
|
|
27
44
|
|
|
28
|
-
<Chart class:list={['ui-heatmap', classProp, className]} {caption} {description} {heading} {summary} {...rest}>
|
|
45
|
+
<Chart class:list={['ui-heatmap', classProp, className]} {caption} {description} {heading} {summary} {...rest} data-ui-chart-activation={drilldown || undefined}>
|
|
29
46
|
{!hasData && <p class="ui-chart__empty" role="status">{resolvedLabels.empty}</p>}
|
|
30
|
-
<div
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
<div
|
|
48
|
+
aria-label={rest['aria-label'] ?? heading ?? resolvedLabels.chartData}
|
|
49
|
+
class="ui-chart__plot"
|
|
50
|
+
role="region"
|
|
51
|
+
tabindex="0"
|
|
52
|
+
hidden={geometry.cells.length === 0}
|
|
53
|
+
>
|
|
54
|
+
<svg aria-hidden="true" viewBox={`0 0 ${geometry.width} ${geometry.height}`}>
|
|
55
|
+
<g class="ui-chart__axis-labels">
|
|
56
|
+
{geometry.xTicks.map(tick => <text text-anchor={tick.textAnchor} x={tick.position} y="298">{tick.label}</text>)}
|
|
57
|
+
{geometry.yTicks.map(tick => <text class="ui-heatmap__row-label" text-anchor="end" dominant-baseline="middle" x="108" y={tick.position}>{tick.label}</text>)}
|
|
58
|
+
</g>
|
|
59
|
+
<g class="ui-heatmap__cells">{geometry.cells.map(cell => {
|
|
60
|
+
const missing = cell.value === null || !Number.isFinite(cell.value)
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<g>
|
|
64
|
+
<rect data-ui-chart-datum={datumActionByCell.get(cell)?.serialized} height={Math.max(0, cell.height - 2)} width={Math.max(0, cell.width - 2)} x={cell.xCoordinate + 1} y={cell.yCoordinate + 1} style={{ fill: getLumenHeatmapColor(cell.value, geometry.domain, colorScale, geometry.midpoint) }}>
|
|
65
|
+
<title>{`${cell.xLabel ?? cell.x} · ${cell.yLabel ?? cell.y}: ${missing ? resolvedLabels.notAvailable : cell.label ?? formatValue(cell.value ?? 0)}`}</title>
|
|
66
|
+
</rect>
|
|
67
|
+
{missing && <text class="ui-heatmap__missing" text-anchor="middle" dominant-baseline="middle" x={cell.xCoordinate + cell.width / 2} y={cell.yCoordinate + cell.height / 2}>×</text>}
|
|
68
|
+
</g>
|
|
69
|
+
)
|
|
70
|
+
})}</g>
|
|
71
|
+
</svg>
|
|
72
|
+
</div>
|
|
73
|
+
{showLegend && geometry.cells.length > 0 && (
|
|
74
|
+
<div class="ui-heatmap__legend" aria-label={resolvedLabels.chartLegend}>
|
|
75
|
+
<span>{formatValue(geometry.domain.min)}</span><span
|
|
76
|
+
style={{ background: geometry.legendBackground }}
|
|
77
|
+
class="ui-heatmap__scale"
|
|
78
|
+
>{colorScale === 'diverging' && <span style={{ left: `${geometry.midpointPercent}%` }}>{formatValue(geometry.midpoint)}</span>}</span><span>{formatValue(geometry.domain.max)}</span>
|
|
79
|
+
<span>× {resolvedLabels.notAvailable}</span>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
{showTable && <details class="ui-chart__data"><summary>{resolvedLabels.viewData}</summary><div role="group" tabindex="0" aria-label={resolvedLabels.chartData}><table><thead><tr><th scope="col">{resolvedLabels.column}</th><th scope="col">{resolvedLabels.row}</th><th scope="col">{resolvedLabels.value}</th></tr></thead><tbody>{geometry.cells.map(cell => <tr><th scope="row">{cell.xLabel ?? cell.x}</th><td>{cell.yLabel ?? cell.y}</td><td>{cell.label ?? (cell.value === null || !Number.isFinite(cell.value) ? resolvedLabels.notAvailable : formatValue(cell.value))}</td></tr>)}</tbody></table></div></details>}
|
|
83
|
+
{drilldown && <ChartDatumActions actions={datumActions} label={resolvedLabels.exploreData} />}
|
|
35
84
|
</Chart>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import { createLumenHistogramGeometry, type LumenChartLabels, type LumenChartTone, type LumenHistogramBin, resolveLumenChartLabels } from '@santi020k/lumen-core'
|
|
5
|
+
|
|
6
|
+
import IntervalChart from '../internal/IntervalChart.astro'
|
|
7
|
+
|
|
8
|
+
interface Props extends HTMLAttributes<'figure'> {
|
|
9
|
+
bins: readonly LumenHistogramBin[]
|
|
10
|
+
caption?: string
|
|
11
|
+
class?: string | null
|
|
12
|
+
className?: string
|
|
13
|
+
description?: string
|
|
14
|
+
formatBoundary?: (value: number) => string
|
|
15
|
+
formatValue?: (value: number) => string
|
|
16
|
+
frequency?: 'count' | 'density'
|
|
17
|
+
heading?: string
|
|
18
|
+
labels?: Partial<LumenChartLabels>
|
|
19
|
+
presentation?: 'bare' | 'default'
|
|
20
|
+
showTable?: boolean
|
|
21
|
+
summary?: string
|
|
22
|
+
tone?: LumenChartTone
|
|
23
|
+
valueLabel?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { bins, class: classProp, className, formatBoundary = String, formatValue = String, frequency = 'count', labels, tone = 'series-1', valueLabel = resolveLumenChartLabels(labels)[frequency === 'density' ? 'density' : 'count'], ...rest } = Astro.props
|
|
27
|
+
const model = createLumenHistogramGeometry(bins, { formatBoundary, formatValue, frequency, tone })
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<IntervalChart {...rest} class:list={['ui-histogram', classProp, className]} {model} {labels} {formatBoundary} {formatValue} {valueLabel} />
|
package/components/Icon.astro
CHANGED
|
@@ -18,16 +18,20 @@ interface Props extends HTMLAttributes<'span'> {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const {
|
|
21
|
+
'aria-hidden': ariaHidden,
|
|
22
|
+
'aria-label': ariaLabel,
|
|
21
23
|
class: classProp = '',
|
|
22
24
|
className = '',
|
|
23
25
|
decorative,
|
|
24
26
|
label,
|
|
25
27
|
name,
|
|
28
|
+
role,
|
|
26
29
|
size = 'default',
|
|
27
30
|
...rest
|
|
28
31
|
} = Astro.props
|
|
29
32
|
|
|
30
|
-
const
|
|
33
|
+
const accessibleLabel = label ?? ariaLabel
|
|
34
|
+
const isDecorative = decorative ?? (ariaHidden === undefined ? !accessibleLabel : ariaHidden === true || ariaHidden === 'true')
|
|
31
35
|
const iconSvg = name ? renderLumenIconSvg(name) : ''
|
|
32
36
|
|
|
33
37
|
if (name && !iconSvg && import.meta.env.DEV) {
|
|
@@ -47,9 +51,9 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
47
51
|
|
|
48
52
|
<span
|
|
49
53
|
aria-hidden={isDecorative ? 'true' : undefined}
|
|
50
|
-
aria-label={!isDecorative ?
|
|
54
|
+
aria-label={!isDecorative ? accessibleLabel : undefined}
|
|
51
55
|
class:list={classList}
|
|
52
|
-
role={!isDecorative ? 'img' : undefined}
|
|
56
|
+
role={!isDecorative ? role ?? 'img' : undefined}
|
|
53
57
|
{...passthrough}
|
|
54
58
|
>
|
|
55
59
|
{name ? <Fragment set:html={iconSvg} /> : <slot />}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
formatLumenImageComparisonValue,
|
|
6
|
+
type LumenImageComparisonMode,
|
|
7
|
+
normalizeLumenImageComparisonMode,
|
|
8
|
+
normalizeLumenImageComparisonRatio,
|
|
9
|
+
normalizeLumenImageComparisonValue,
|
|
10
|
+
resolveLumenAstroProps
|
|
11
|
+
} from '@santi020k/lumen-core'
|
|
12
|
+
|
|
13
|
+
interface Props extends HTMLAttributes<'figure'> {
|
|
14
|
+
afterLabel?: string
|
|
15
|
+
beforeLabel?: string
|
|
16
|
+
class?: string | null
|
|
17
|
+
className?: string
|
|
18
|
+
disabled?: boolean
|
|
19
|
+
fit?: 'contain' | 'cover'
|
|
20
|
+
label: string
|
|
21
|
+
locale?: string
|
|
22
|
+
mode?: LumenImageComparisonMode
|
|
23
|
+
name?: string
|
|
24
|
+
ratio?: number
|
|
25
|
+
value?: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
afterLabel = 'After', beforeLabel = 'Before', class: classProp = '', className = '',
|
|
30
|
+
disabled = false, fit = 'cover', label, locale, mode: requestedMode = 'reveal', name, ratio = 16 / 9, value = 50,
|
|
31
|
+
...rest
|
|
32
|
+
} = Astro.props
|
|
33
|
+
|
|
34
|
+
const mode = normalizeLumenImageComparisonMode(requestedMode)
|
|
35
|
+
const position = normalizeLumenImageComparisonValue(value)
|
|
36
|
+
const aspectRatio = normalizeLumenImageComparisonRatio(ratio)
|
|
37
|
+
const { classList, passthrough } = resolveLumenAstroProps(rest, ['ui-image-comparison'], classProp, className)
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<figure
|
|
41
|
+
class:list={classList}
|
|
42
|
+
data-ui-image-comparison
|
|
43
|
+
data-after-label={afterLabel}
|
|
44
|
+
data-disabled={disabled ? 'true' : undefined}
|
|
45
|
+
data-fit={fit}
|
|
46
|
+
data-mode={mode}
|
|
47
|
+
data-locale={locale}
|
|
48
|
+
{...passthrough}
|
|
49
|
+
>
|
|
50
|
+
<div class="ui-image-comparison__frame" style={`--ui-image-comparison-position: ${position}%; --ui-image-comparison-ratio: ${aspectRatio}`}>
|
|
51
|
+
<div class="ui-image-comparison__before" hidden={mode === 'after'}><slot name="before" /></div>
|
|
52
|
+
<div class="ui-image-comparison__after" hidden={mode === 'before'}><slot name="after" /></div>
|
|
53
|
+
<div aria-hidden="true" class="ui-image-comparison__divider"></div>
|
|
54
|
+
</div>
|
|
55
|
+
<div aria-hidden="true" class="ui-image-comparison__labels"><span hidden={mode === 'after'}>{beforeLabel}</span><span hidden={mode === 'before'}>{afterLabel}</span></div>
|
|
56
|
+
<figcaption class="ui-image-comparison__caption">
|
|
57
|
+
<label class="ui-image-comparison__control" hidden={mode !== 'reveal'}>
|
|
58
|
+
<span>{label}</span>
|
|
59
|
+
<input
|
|
60
|
+
aria-valuetext={formatLumenImageComparisonValue(position, afterLabel, locale)}
|
|
61
|
+
class="ui-slider ui-image-comparison__range"
|
|
62
|
+
data-ui-image-comparison-input
|
|
63
|
+
disabled
|
|
64
|
+
max="100"
|
|
65
|
+
min="0"
|
|
66
|
+
name={name}
|
|
67
|
+
step="1"
|
|
68
|
+
type="range"
|
|
69
|
+
value={position}
|
|
70
|
+
/>
|
|
71
|
+
</label>
|
|
72
|
+
<slot />
|
|
73
|
+
</figcaption>
|
|
74
|
+
</figure>
|
package/components/Input.astro
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types'
|
|
3
3
|
|
|
4
|
-
import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
4
|
+
import { type LumenControlVisualSize, resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
5
5
|
|
|
6
6
|
interface Props extends Omit<HTMLAttributes<'input'>, 'size'> {
|
|
7
7
|
class?: string | null
|
|
8
8
|
className?: string
|
|
9
9
|
size?: HTMLAttributes<'input'>['size']
|
|
10
|
-
visualSize?:
|
|
10
|
+
visualSize?: LumenControlVisualSize
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const {
|