@santi020k/lumen-astro 2.0.0 → 3.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 +21 -6
- package/components/BarChart.astro +13 -7
- package/components/ComboChart.astro +10 -5
- package/components/CopyButton.astro +19 -2
- package/components/Heatmap.astro +7 -4
- package/components/LineChart.astro +13 -7
- package/components/PieChart.astro +12 -8
- package/components/RangeChart.astro +8 -6
- package/components/RevealGroup.astro +4 -2
- package/components/ScatterChart.astro +10 -5
- package/components/ScrollReveal.astro +4 -2
- package/components/SkipLink.astro +1 -0
- package/components/Table.astro +3 -0
- package/package.json +8 -8
- package/runtime/UIPrimitives.astro +17 -3
- package/styles/critical.css +57 -2
package/README.md
CHANGED
|
@@ -253,9 +253,17 @@ non-code content `Code` semantics.
|
|
|
253
253
|
|
|
254
254
|
```astro
|
|
255
255
|
<p id="invite">Join the Lumen workspace</p>
|
|
256
|
-
<CopyButton target="#invite" toast
|
|
256
|
+
<CopyButton size="sm" target="#invite" toast variant="default">
|
|
257
|
+
Copy invite
|
|
258
|
+
<span slot="copied">Invite copied</span>
|
|
259
|
+
<span slot="error">Copy failed</span>
|
|
260
|
+
</CopyButton>
|
|
257
261
|
```
|
|
258
262
|
|
|
263
|
+
`CopyButton` accepts the same presentation `variant` and `size` vocabulary as `Button`. Its stable
|
|
264
|
+
`copy-idle`, `copy-copied`, and `copy-error` slots keep visible feedback in
|
|
265
|
+
sync with the accessible label; free-form default children remain the idle presentation.
|
|
266
|
+
|
|
259
267
|
## Data visualization
|
|
260
268
|
|
|
261
269
|
Use `Sparkline` beside a metric, `BarChart` for categorical comparison, `LineChart` for ordered
|
|
@@ -374,14 +382,14 @@ animates a formatted metric while preserving a stable accessible value. All thre
|
|
|
374
382
|
content readable without JavaScript and honor reduced-motion preferences.
|
|
375
383
|
|
|
376
384
|
```astro
|
|
377
|
-
<ScrollReveal animation="slide-up" duration="slow">
|
|
385
|
+
<ScrollReveal animation="slide-up" as="section" duration="slow">
|
|
378
386
|
<h2>Release highlights</h2>
|
|
379
387
|
</ScrollReveal>
|
|
380
388
|
|
|
381
|
-
<RevealGroup stagger={80}>
|
|
382
|
-
<Card>Plan</Card>
|
|
383
|
-
<Card>Build</Card>
|
|
384
|
-
<Card>Ship</Card>
|
|
389
|
+
<RevealGroup as="ul" stagger={80}>
|
|
390
|
+
<li><Card>Plan</Card></li>
|
|
391
|
+
<li><Card>Build</Card></li>
|
|
392
|
+
<li><Card>Ship</Card></li>
|
|
385
393
|
</RevealGroup>
|
|
386
394
|
|
|
387
395
|
<AnimatedNumber decimals={1} suffix="%" value={99.8} />
|
|
@@ -414,3 +422,10 @@ form a standalone item, or `as="section"` when it is a labeled region in a large
|
|
|
414
422
|
|
|
415
423
|
Use `variant="default"` for the original neutral surface, `variant="accent"` for a featured metric,
|
|
416
424
|
or `variant="glass"` for selective translucency.
|
|
425
|
+
|
|
426
|
+
## Consumer composition recipes
|
|
427
|
+
|
|
428
|
+
See [consumer UI recipes](../../docs/consumer-ui-recipes.md) for static React icons, responsive
|
|
429
|
+
record tables, keyboard-aware native sheets, whole-unit amount fields, adaptive editors, and
|
|
430
|
+
asynchronous action states. Each recipe identifies the public primitives and the behavior that
|
|
431
|
+
remains owned by the application.
|
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
getLumenChartToneClassName,
|
|
9
9
|
hasLumenChartData,
|
|
10
10
|
type LumenBarChartLayout,
|
|
11
|
+
type LumenChartLabels,
|
|
11
12
|
type LumenChartOrientation,
|
|
12
13
|
type LumenChartSeries,
|
|
14
|
+
resolveLumenChartLabels,
|
|
13
15
|
scaleLumenChartValue
|
|
14
16
|
} from '@santi020k/lumen-core'
|
|
15
17
|
|
|
@@ -26,6 +28,7 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
26
28
|
formatValue?: (value: number) => string
|
|
27
29
|
glass?: boolean | 'subtle' | 'strong'
|
|
28
30
|
heading?: string
|
|
31
|
+
labels?: Partial<LumenChartLabels>
|
|
29
32
|
layout?: LumenBarChartLayout
|
|
30
33
|
orientation?: LumenChartOrientation
|
|
31
34
|
presentation?: 'bare' | 'default'
|
|
@@ -41,20 +44,23 @@ const {
|
|
|
41
44
|
class: classProp = '',
|
|
42
45
|
className = '',
|
|
43
46
|
description,
|
|
44
|
-
emptyLabel
|
|
47
|
+
emptyLabel,
|
|
45
48
|
formatCategory = String,
|
|
46
49
|
formatValue = String,
|
|
47
50
|
glass = false,
|
|
48
51
|
heading,
|
|
52
|
+
labels,
|
|
49
53
|
layout = 'grouped',
|
|
50
54
|
orientation = 'vertical',
|
|
51
55
|
series,
|
|
52
56
|
showLegend = series.length > 1,
|
|
53
57
|
showTable = true,
|
|
54
|
-
summary
|
|
58
|
+
summary: summaryProp,
|
|
55
59
|
...rest
|
|
56
60
|
} = Astro.props
|
|
57
61
|
|
|
62
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
63
|
+
const summary = summaryProp ?? formatLumenChartSummary(series, formatValue, resolvedLabels)
|
|
58
64
|
const geometry = createLumenBarGeometry(series, { categoryWidth, layout, orientation })
|
|
59
65
|
const hasData = hasLumenChartData(series)
|
|
60
66
|
const ticks = getLumenChartTicks(geometry.domain)
|
|
@@ -75,7 +81,7 @@ const labelFor = (item: LumenChartSeries, category: number | string) => (
|
|
|
75
81
|
const formattedValueFor = (item: LumenChartSeries, category: number | string) => {
|
|
76
82
|
const value = valueFor(item, category)
|
|
77
83
|
|
|
78
|
-
return value === null || !Number.isFinite(value) ?
|
|
84
|
+
return value === null || !Number.isFinite(value) ? resolvedLabels.notAvailable : formatValue(value)
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
const categoryLabelFor = (category: number | string) => {
|
|
@@ -100,7 +106,7 @@ const margin = orientation === 'horizontal' ?
|
|
|
100
106
|
>
|
|
101
107
|
{
|
|
102
108
|
showLegend && hasData && (
|
|
103
|
-
<ul class="ui-chart__legend" aria-label=
|
|
109
|
+
<ul class="ui-chart__legend" aria-label={resolvedLabels.chartLegend}>
|
|
104
110
|
{series.map((item, index) => (
|
|
105
111
|
<li class={getLumenChartToneClassName(item.tone, index)}>
|
|
106
112
|
<span aria-hidden="true" />
|
|
@@ -110,7 +116,7 @@ const margin = orientation === 'horizontal' ?
|
|
|
110
116
|
</ul>
|
|
111
117
|
)
|
|
112
118
|
}
|
|
113
|
-
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel}</p>}
|
|
119
|
+
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel ?? resolvedLabels.empty}</p>}
|
|
114
120
|
<div class="ui-chart__plot" hidden={!hasData}>
|
|
115
121
|
<svg
|
|
116
122
|
aria-hidden="true"
|
|
@@ -186,12 +192,12 @@ const margin = orientation === 'horizontal' ?
|
|
|
186
192
|
{
|
|
187
193
|
showTable && hasData && (
|
|
188
194
|
<details class="ui-chart__data">
|
|
189
|
-
<summary>
|
|
195
|
+
<summary>{resolvedLabels.viewData}</summary>
|
|
190
196
|
<div>
|
|
191
197
|
<table>
|
|
192
198
|
<thead>
|
|
193
199
|
<tr>
|
|
194
|
-
<th scope="col">
|
|
200
|
+
<th scope="col">{resolvedLabels.category}</th>
|
|
195
201
|
{series.map(item => <th scope="col">{item.label}</th>)}
|
|
196
202
|
</tr>
|
|
197
203
|
</thead>
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
getLumenChartToneClassName,
|
|
12
12
|
hasLumenChartData,
|
|
13
13
|
type LumenChartDatum,
|
|
14
|
+
type LumenChartLabels,
|
|
14
15
|
type LumenComboSeries,
|
|
16
|
+
resolveLumenChartLabels,
|
|
15
17
|
resolveLumenChartTone } from '@santi020k/lumen-core'
|
|
16
18
|
|
|
17
19
|
import Chart from './Chart.astro'
|
|
@@ -23,13 +25,16 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
23
25
|
description?: string
|
|
24
26
|
formatValue?: (value: number) => string
|
|
25
27
|
heading?: string
|
|
28
|
+
labels?: Partial<LumenChartLabels>
|
|
26
29
|
series: readonly LumenComboSeries[]
|
|
27
30
|
showLegend?: boolean
|
|
28
31
|
showTable?: boolean
|
|
29
32
|
summary?: string
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
const { caption, class: classProp = '', className = '', description, formatValue = String, heading, series, showLegend = true, showTable = true, summary
|
|
35
|
+
const { caption, class: classProp = '', className = '', description, formatValue = String, heading, labels, series, showLegend = true, showTable = true, summary: summaryProp, ...rest } = Astro.props
|
|
36
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
37
|
+
const summary = summaryProp ?? formatLumenChartSummary(series, formatValue, resolvedLabels)
|
|
33
38
|
const width = 640
|
|
34
39
|
const height = 320
|
|
35
40
|
const padding = 44
|
|
@@ -82,8 +87,8 @@ const hasData = hasLumenChartData(series)
|
|
|
82
87
|
---
|
|
83
88
|
|
|
84
89
|
<Chart class:list={['ui-combo-chart', classProp, className]} {caption} {description} {heading} {summary} {...rest}>
|
|
85
|
-
{showLegend && hasData && <ul class="ui-chart__legend" aria-label=
|
|
86
|
-
{!hasData && <p class="ui-chart__empty" role="status">
|
|
90
|
+
{showLegend && hasData && <ul class="ui-chart__legend" aria-label={resolvedLabels.chartLegend}>{series.map((item, index) => <li class={getLumenChartToneClassName(item.tone, index)}><span aria-hidden="true" />{item.label}</li>)}</ul>}
|
|
91
|
+
{!hasData && <p class="ui-chart__empty" role="status">{resolvedLabels.empty}</p>}
|
|
87
92
|
<div class="ui-chart__plot" hidden={!hasData}><svg aria-hidden="true" viewBox={`0 0 ${width} ${height}`}><g class="
|
|
88
93
|
ui-bar-chart__marks
|
|
89
94
|
"
|
|
@@ -107,11 +112,11 @@ d={geometry.path}
|
|
|
107
112
|
)
|
|
108
113
|
})}</svg></div>
|
|
109
114
|
{showTable && hasData && (
|
|
110
|
-
<details class="ui-chart__data"><summary>
|
|
115
|
+
<details class="ui-chart__data"><summary>{resolvedLabels.viewData}</summary><div><table><thead><tr><th scope="col">{resolvedLabels.category}</th>{series.map(item => <th scope="col">{item.label}</th>)}</tr></thead><tbody>{categories.map(category => (
|
|
111
116
|
<tr><th scope="row">{String(category)}</th>{series.map(item => {
|
|
112
117
|
const datum = item.data.find(point => point.x === category)
|
|
113
118
|
|
|
114
|
-
return <td>{datum?.label ?? (datum?.y === undefined || datum.y === null || !Number.isFinite(datum.y) ?
|
|
119
|
+
return <td>{datum?.label ?? (datum?.y === undefined || datum.y === null || !Number.isFinite(datum.y) ? resolvedLabels.notAvailable : formatValue(datum.y))}</td>
|
|
115
120
|
})}</tr>
|
|
116
121
|
))}</tbody></table></div></details>
|
|
117
122
|
)}
|
|
@@ -10,9 +10,11 @@ interface Props extends HTMLAttributes<'button'> {
|
|
|
10
10
|
errorLabel?: string
|
|
11
11
|
label?: string
|
|
12
12
|
resetAfter?: number
|
|
13
|
+
size?: 'default' | 'sm' | 'lg' | 'icon'
|
|
13
14
|
target?: string
|
|
14
15
|
toast?: boolean
|
|
15
16
|
value?: string
|
|
17
|
+
variant?: 'default' | 'destructive' | 'ghost' | 'link' | 'outline' | 'secondary'
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const {
|
|
@@ -22,16 +24,22 @@ const {
|
|
|
22
24
|
errorLabel = 'Could not copy to clipboard',
|
|
23
25
|
label = 'Copy to clipboard',
|
|
24
26
|
resetAfter = 2000,
|
|
27
|
+
size = 'default',
|
|
25
28
|
target,
|
|
26
29
|
toast = false,
|
|
27
30
|
type = 'button',
|
|
28
31
|
value,
|
|
32
|
+
variant = 'outline',
|
|
29
33
|
...rest
|
|
30
34
|
} = Astro.props
|
|
31
35
|
|
|
32
36
|
const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
33
37
|
'ui-button',
|
|
34
|
-
|
|
38
|
+
`ui-button--${variant}`,
|
|
39
|
+
size === 'default' && 'ui-button--default-size',
|
|
40
|
+
size === 'sm' && 'ui-button--sm',
|
|
41
|
+
size === 'lg' && 'ui-button--lg',
|
|
42
|
+
size === 'icon' && 'ui-button--icon',
|
|
35
43
|
'ui-copy-button'
|
|
36
44
|
], classProp, className)
|
|
37
45
|
---
|
|
@@ -46,10 +54,19 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
46
54
|
data-copy-target={target}
|
|
47
55
|
data-copy-toast={toast ? 'true' : undefined}
|
|
48
56
|
data-copy-value={value}
|
|
57
|
+
data-size={size}
|
|
58
|
+
data-slot="copy-button"
|
|
49
59
|
data-state="idle"
|
|
50
60
|
data-ui-copy-button
|
|
61
|
+
data-variant={variant}
|
|
51
62
|
type={type}
|
|
52
63
|
{...passthrough}
|
|
53
64
|
>
|
|
54
|
-
<slot>Copy</slot>
|
|
65
|
+
<span data-slot="copy-idle"><slot>Copy</slot></span>
|
|
66
|
+
<span aria-hidden="true" data-slot="copy-copied" hidden>
|
|
67
|
+
<slot name="copied">{copiedLabel}</slot>
|
|
68
|
+
</span>
|
|
69
|
+
<span aria-hidden="true" data-slot="copy-error" hidden>
|
|
70
|
+
<slot name="error">{errorLabel}</slot>
|
|
71
|
+
</span>
|
|
55
72
|
</button>
|
package/components/Heatmap.astro
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types'
|
|
3
3
|
|
|
4
|
-
import { createLumenHeatmapGeometry, type LumenHeatmapDatum } from '@santi020k/lumen-core'
|
|
4
|
+
import { createLumenHeatmapGeometry, type LumenChartLabels, type LumenHeatmapDatum, resolveLumenChartLabels } from '@santi020k/lumen-core'
|
|
5
5
|
|
|
6
6
|
import Chart from './Chart.astro'
|
|
7
7
|
|
|
@@ -13,20 +13,23 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
13
13
|
description?: string
|
|
14
14
|
formatValue?: (value: number) => string
|
|
15
15
|
heading?: string
|
|
16
|
+
labels?: Partial<LumenChartLabels>
|
|
16
17
|
showTable?: boolean
|
|
17
18
|
summary?: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
const { caption, class: classProp = '', className = '', data, description, formatValue = String, heading, showTable = true, summary
|
|
21
|
+
const { caption, class: classProp = '', className = '', data, description, formatValue = String, heading, labels, showTable = true, summary: summaryProp, ...rest } = Astro.props
|
|
21
22
|
const geometry = createLumenHeatmapGeometry(data)
|
|
22
23
|
const hasData = geometry.cells.some(cell => cell.value !== null && Number.isFinite(cell.value))
|
|
24
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
25
|
+
const summary = summaryProp ?? resolvedLabels.formatHeatmapSummary(geometry.cells.filter(cell => cell.value !== null && Number.isFinite(cell.value)).length)
|
|
23
26
|
---
|
|
24
27
|
|
|
25
28
|
<Chart class:list={['ui-heatmap', classProp, className]} {caption} {description} {heading} {summary} {...rest}>
|
|
26
|
-
{!hasData && <p class="ui-chart__empty" role="status">
|
|
29
|
+
{!hasData && <p class="ui-chart__empty" role="status">{resolvedLabels.empty}</p>}
|
|
27
30
|
<div class="ui-chart__plot" hidden={!hasData}><svg aria-hidden="true" viewBox={`0 0 ${geometry.width} ${geometry.height}`}><g class="
|
|
28
31
|
ui-heatmap__cells
|
|
29
32
|
"
|
|
30
33
|
>{geometry.cells.filter(cell => cell.value !== null && Number.isFinite(cell.value)).map(cell => <rect height={Math.max(0, cell.height - 2)} opacity={Math.max(0.12, cell.ratio)} width={Math.max(0, cell.width - 2)} x={cell.xCoordinate + 1} y={cell.yCoordinate + 1}><title>{`${cell.xLabel ?? cell.x} · ${cell.yLabel ?? cell.y}: ${cell.label ?? formatValue(cell.value ?? 0)}`}</title></rect>)}</g></svg></div>
|
|
31
|
-
{showTable && <details class="ui-chart__data"><summary>
|
|
34
|
+
{showTable && <details class="ui-chart__data"><summary>{resolvedLabels.viewData}</summary><div><table><thead><tr><th scope="col">{resolvedLabels.column}</th><th scope="col">{resolvedLabels.row}</th><th scope="col">{resolvedLabels.value}</th></tr></thead><tbody>{data.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>}
|
|
32
35
|
</Chart>
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
getLumenChartTicks,
|
|
11
11
|
getLumenChartToneClassName,
|
|
12
12
|
hasLumenChartData,
|
|
13
|
+
type LumenChartLabels,
|
|
13
14
|
type LumenChartSeries,
|
|
15
|
+
resolveLumenChartLabels,
|
|
14
16
|
resolveLumenChartTone,
|
|
15
17
|
scaleLumenChartValue
|
|
16
18
|
} from '@santi020k/lumen-core'
|
|
@@ -28,6 +30,7 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
28
30
|
formatValue?: (value: number) => string
|
|
29
31
|
glass?: boolean | 'subtle' | 'strong'
|
|
30
32
|
heading?: string
|
|
33
|
+
labels?: Partial<LumenChartLabels>
|
|
31
34
|
markers?: 'all' | 'auto' | 'none' | boolean | number
|
|
32
35
|
presentation?: 'bare' | 'default'
|
|
33
36
|
referenceValue?: number
|
|
@@ -43,20 +46,23 @@ const {
|
|
|
43
46
|
class: classProp = '',
|
|
44
47
|
className = '',
|
|
45
48
|
description,
|
|
46
|
-
emptyLabel
|
|
49
|
+
emptyLabel,
|
|
47
50
|
formatCategory = String,
|
|
48
51
|
formatValue = String,
|
|
49
52
|
glass = false,
|
|
50
53
|
heading,
|
|
54
|
+
labels,
|
|
51
55
|
markers = 'auto',
|
|
52
56
|
referenceValue,
|
|
53
57
|
series,
|
|
54
58
|
showLegend = series.length > 1,
|
|
55
59
|
showTable = true,
|
|
56
|
-
summary
|
|
60
|
+
summary: summaryProp,
|
|
57
61
|
...rest
|
|
58
62
|
} = Astro.props
|
|
59
63
|
|
|
64
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
65
|
+
const summary = summaryProp ?? formatLumenChartSummary(series, formatValue, resolvedLabels)
|
|
60
66
|
const width = 640
|
|
61
67
|
const height = 320
|
|
62
68
|
const padding = 44
|
|
@@ -107,7 +113,7 @@ const referenceY =
|
|
|
107
113
|
>
|
|
108
114
|
{
|
|
109
115
|
showLegend && hasData && (
|
|
110
|
-
<ul class="ui-chart__legend" aria-label=
|
|
116
|
+
<ul class="ui-chart__legend" aria-label={resolvedLabels.chartLegend}>
|
|
111
117
|
{series.map((item, index) => (
|
|
112
118
|
<li class={getLumenChartToneClassName(item.tone, index)}>
|
|
113
119
|
<span aria-hidden="true" />
|
|
@@ -117,7 +123,7 @@ const referenceY =
|
|
|
117
123
|
</ul>
|
|
118
124
|
)
|
|
119
125
|
}
|
|
120
|
-
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel}</p>}
|
|
126
|
+
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel ?? resolvedLabels.empty}</p>}
|
|
121
127
|
<div class="ui-chart__plot" hidden={!hasData}>
|
|
122
128
|
<svg
|
|
123
129
|
aria-hidden="true"
|
|
@@ -212,12 +218,12 @@ const referenceY =
|
|
|
212
218
|
{
|
|
213
219
|
showTable && hasData && (
|
|
214
220
|
<details class="ui-chart__data">
|
|
215
|
-
<summary>
|
|
221
|
+
<summary>{resolvedLabels.viewData}</summary>
|
|
216
222
|
<div>
|
|
217
223
|
<table>
|
|
218
224
|
<thead>
|
|
219
225
|
<tr>
|
|
220
|
-
<th scope="col">
|
|
226
|
+
<th scope="col">{resolvedLabels.category}</th>
|
|
221
227
|
{series.map(item => <th scope="col">{item.label}</th>)}
|
|
222
228
|
</tr>
|
|
223
229
|
</thead>
|
|
@@ -232,7 +238,7 @@ const referenceY =
|
|
|
232
238
|
<td>
|
|
233
239
|
{datum?.label ??
|
|
234
240
|
(datum?.y === undefined || datum.y === null || !Number.isFinite(datum.y) ?
|
|
235
|
-
|
|
241
|
+
resolvedLabels.notAvailable :
|
|
236
242
|
formatValue(datum.y))}
|
|
237
243
|
</td>
|
|
238
244
|
)
|
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
getLumenChartToneClassName,
|
|
8
8
|
getLumenPieChartVariantClassName,
|
|
9
9
|
hasLumenPieData,
|
|
10
|
+
type LumenChartLabels,
|
|
10
11
|
type LumenChartSeries,
|
|
11
|
-
type LumenPieChartVariant
|
|
12
|
-
} from '@santi020k/lumen-core'
|
|
12
|
+
type LumenPieChartVariant,
|
|
13
|
+
resolveLumenChartLabels } from '@santi020k/lumen-core'
|
|
13
14
|
|
|
14
15
|
import Chart from './Chart.astro'
|
|
15
16
|
|
|
@@ -22,6 +23,7 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
22
23
|
description?: string
|
|
23
24
|
glass?: boolean | 'subtle' | 'strong'
|
|
24
25
|
heading?: string
|
|
26
|
+
labels?: Partial<LumenChartLabels>
|
|
25
27
|
series: LumenChartSeries
|
|
26
28
|
showLegend?: boolean
|
|
27
29
|
showTable?: boolean
|
|
@@ -39,6 +41,7 @@ const {
|
|
|
39
41
|
description,
|
|
40
42
|
glass = false,
|
|
41
43
|
heading,
|
|
44
|
+
labels,
|
|
42
45
|
series,
|
|
43
46
|
showLegend = true,
|
|
44
47
|
showTable = true,
|
|
@@ -49,6 +52,7 @@ const {
|
|
|
49
52
|
} = Astro.props
|
|
50
53
|
|
|
51
54
|
const geometry = createLumenPieGeometry(series.data, { variant })
|
|
55
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
52
56
|
const hasData = hasLumenPieData(series.data)
|
|
53
57
|
|
|
54
58
|
const renderedSeries = {
|
|
@@ -56,7 +60,7 @@ const renderedSeries = {
|
|
|
56
60
|
data: series.data.filter(datum => datum.y !== null && Number.isFinite(datum.y) && datum.y > 0)
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
const summary = summaryProp ?? formatLumenChartSummary([renderedSeries], valueFormatter)
|
|
63
|
+
const summary = summaryProp ?? formatLumenChartSummary([renderedSeries], valueFormatter, resolvedLabels)
|
|
60
64
|
|
|
61
65
|
const percentageFor = (percentage: number) => new Intl.NumberFormat(undefined, {
|
|
62
66
|
maximumFractionDigits: percentage < 0.01 ? 1 : 0,
|
|
@@ -75,7 +79,7 @@ const percentageFor = (percentage: number) => new Intl.NumberFormat(undefined, {
|
|
|
75
79
|
>
|
|
76
80
|
{
|
|
77
81
|
showLegend && hasData && (
|
|
78
|
-
<ul class="ui-chart__legend" aria-label=
|
|
82
|
+
<ul class="ui-chart__legend" aria-label={resolvedLabels.chartLegend}>
|
|
79
83
|
{geometry.slices.map(slice => (
|
|
80
84
|
<li class={getLumenChartToneClassName(slice.tone)}>
|
|
81
85
|
<span aria-hidden="true" />
|
|
@@ -85,7 +89,7 @@ const percentageFor = (percentage: number) => new Intl.NumberFormat(undefined, {
|
|
|
85
89
|
</ul>
|
|
86
90
|
)
|
|
87
91
|
}
|
|
88
|
-
{!hasData && <p class="ui-chart__empty" role="status">
|
|
92
|
+
{!hasData && <p class="ui-chart__empty" role="status">{resolvedLabels.empty}</p>}
|
|
89
93
|
<div class="ui-chart__plot ui-pie-chart__plot" hidden={!hasData}>
|
|
90
94
|
<svg
|
|
91
95
|
aria-hidden="true"
|
|
@@ -125,13 +129,13 @@ const percentageFor = (percentage: number) => new Intl.NumberFormat(undefined, {
|
|
|
125
129
|
{
|
|
126
130
|
showTable && hasData && (
|
|
127
131
|
<details class="ui-chart__data">
|
|
128
|
-
<summary>
|
|
132
|
+
<summary>{resolvedLabels.viewData}</summary>
|
|
129
133
|
<div>
|
|
130
134
|
<table>
|
|
131
135
|
<thead>
|
|
132
136
|
<tr>
|
|
133
|
-
<th scope="col">
|
|
134
|
-
<th scope="col">
|
|
137
|
+
<th scope="col">{resolvedLabels.category}</th>
|
|
138
|
+
<th scope="col">{resolvedLabels.value}</th>
|
|
135
139
|
<th scope="col">Share</th>
|
|
136
140
|
</tr>
|
|
137
141
|
</thead>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types'
|
|
3
3
|
|
|
4
|
-
import { createLumenRangeGeometry, getLumenChartTicks, getLumenChartToneClassName, type LumenChartTone, type LumenRangeDatum, scaleLumenChartValue } from '@santi020k/lumen-core'
|
|
4
|
+
import { createLumenRangeGeometry, getLumenChartTicks, getLumenChartToneClassName, type LumenChartLabels, type LumenChartTone, type LumenRangeDatum, resolveLumenChartLabels, scaleLumenChartValue } from '@santi020k/lumen-core'
|
|
5
5
|
|
|
6
6
|
import Chart from './Chart.astro'
|
|
7
7
|
|
|
@@ -13,28 +13,30 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
13
13
|
description?: string
|
|
14
14
|
formatValue?: (value: number) => string
|
|
15
15
|
heading?: string
|
|
16
|
+
labels?: Partial<LumenChartLabels>
|
|
16
17
|
showTable?: boolean
|
|
17
18
|
summary?: string
|
|
18
19
|
tone?: LumenChartTone
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const { caption, class: classProp = '', className = '', data, description, formatValue = String, heading, showTable = true, summary: summaryProp, tone = 'series-1', ...rest } = Astro.props
|
|
22
|
+
const { caption, class: classProp = '', className = '', data, description, formatValue = String, heading, labels, showTable = true, summary: summaryProp, tone = 'series-1', ...rest } = Astro.props
|
|
22
23
|
const width = 640
|
|
23
24
|
const height = 320
|
|
24
25
|
const padding = 44
|
|
25
26
|
const geometry = createLumenRangeGeometry(data, { height, padding, width })
|
|
27
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
26
28
|
|
|
27
29
|
const summary = summaryProp ?? (
|
|
28
30
|
geometry.points.length === 0 ?
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
resolvedLabels.formatRangeSummary(0) :
|
|
32
|
+
resolvedLabels.formatRangeSummary(geometry.points.length)
|
|
31
33
|
)
|
|
32
34
|
|
|
33
35
|
const ticks = getLumenChartTicks(geometry.domain)
|
|
34
36
|
---
|
|
35
37
|
|
|
36
38
|
<Chart class:list={['ui-range-chart', getLumenChartToneClassName(tone), classProp, className]} {caption} {description} {heading} {summary} {...rest}>
|
|
37
|
-
{geometry.points.length === 0 && <p class="ui-chart__empty" role="status">
|
|
39
|
+
{geometry.points.length === 0 && <p class="ui-chart__empty" role="status">{resolvedLabels.empty}</p>}
|
|
38
40
|
<div class="ui-chart__plot" hidden={geometry.points.length === 0}><svg aria-hidden="true" viewBox={`0 0 ${width} ${height}`}><g class="
|
|
39
41
|
ui-chart__grid
|
|
40
42
|
"
|
|
@@ -54,5 +56,5 @@ y1={point.highCoordinate}
|
|
|
54
56
|
y2={point.lowCoordinate}
|
|
55
57
|
><title>{`${point.xLabel ?? point.x}: ${point.label ?? `${formatValue(point.low ?? 0)}–${formatValue(point.high ?? 0)}`}`}</title></line>
|
|
56
58
|
))}</svg></div>
|
|
57
|
-
{showTable && <details class="ui-chart__data"><summary>
|
|
59
|
+
{showTable && <details class="ui-chart__data"><summary>{resolvedLabels.viewData}</summary><div><table><thead><tr><th scope="col">{resolvedLabels.category}</th><th scope="col">{resolvedLabels.low}</th><th scope="col">{resolvedLabels.high}</th></tr></thead><tbody>{data.map(item => <tr><th scope="row">{item.xLabel ?? item.x}</th><td>{item.low === null || !Number.isFinite(item.low) ? resolvedLabels.notAvailable : formatValue(item.low)}</td><td>{item.high === null || !Number.isFinite(item.high) ? resolvedLabels.notAvailable : formatValue(item.high)}</td></tr>)}</tbody></table></div></details>}
|
|
58
60
|
</Chart>
|
|
@@ -5,6 +5,7 @@ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLAttributes<'div'> {
|
|
7
7
|
animation?: 'fade' | 'slide-up' | 'scale'
|
|
8
|
+
as?: 'div' | 'ol' | 'section' | 'ul'
|
|
8
9
|
class?: string | null
|
|
9
10
|
className?: string
|
|
10
11
|
delay?: number
|
|
@@ -16,6 +17,7 @@ interface Props extends HTMLAttributes<'div'> {
|
|
|
16
17
|
|
|
17
18
|
const {
|
|
18
19
|
animation = 'slide-up',
|
|
20
|
+
as: Tag = 'div',
|
|
19
21
|
class: classProp = '',
|
|
20
22
|
className = '',
|
|
21
23
|
delay = 0,
|
|
@@ -44,7 +46,7 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
44
46
|
], classProp, className)
|
|
45
47
|
---
|
|
46
48
|
|
|
47
|
-
<
|
|
49
|
+
<Tag
|
|
48
50
|
class:list={classList}
|
|
49
51
|
data-ui-reveal-group
|
|
50
52
|
data-ui-reveal-once={String(once)}
|
|
@@ -53,4 +55,4 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
53
55
|
{...passthrough}
|
|
54
56
|
>
|
|
55
57
|
<slot />
|
|
56
|
-
</
|
|
58
|
+
</Tag>
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
formatLumenChartSummary,
|
|
7
7
|
getLumenChartTicks,
|
|
8
8
|
getLumenChartToneClassName,
|
|
9
|
+
type LumenChartLabels,
|
|
9
10
|
type LumenChartScaleType,
|
|
10
11
|
type LumenChartSeries,
|
|
12
|
+
resolveLumenChartLabels,
|
|
11
13
|
scaleLumenChartValue } from '@santi020k/lumen-core'
|
|
12
14
|
|
|
13
15
|
import Chart from './Chart.astro'
|
|
@@ -20,6 +22,7 @@ interface Props extends HTMLAttributes<'figure'> {
|
|
|
20
22
|
emptyLabel?: string
|
|
21
23
|
formatValue?: (value: number) => string
|
|
22
24
|
heading?: string
|
|
25
|
+
labels?: Partial<LumenChartLabels>
|
|
23
26
|
series: readonly LumenChartSeries[]
|
|
24
27
|
showLegend?: boolean
|
|
25
28
|
showTable?: boolean
|
|
@@ -32,9 +35,10 @@ const {
|
|
|
32
35
|
class: classProp = '',
|
|
33
36
|
className = '',
|
|
34
37
|
description,
|
|
35
|
-
emptyLabel
|
|
38
|
+
emptyLabel,
|
|
36
39
|
formatValue = String,
|
|
37
40
|
heading,
|
|
41
|
+
labels,
|
|
38
42
|
series,
|
|
39
43
|
showLegend = series.length > 1,
|
|
40
44
|
showTable = true,
|
|
@@ -44,6 +48,7 @@ const {
|
|
|
44
48
|
} = Astro.props
|
|
45
49
|
|
|
46
50
|
const geometry = createLumenScatterGeometry(series, { xScale })
|
|
51
|
+
const resolvedLabels = resolveLumenChartLabels(labels)
|
|
47
52
|
|
|
48
53
|
const projectedSeries = series.map(item => ({
|
|
49
54
|
...item,
|
|
@@ -51,14 +56,14 @@ const projectedSeries = series.map(item => ({
|
|
|
51
56
|
})).filter(item => item.data.length > 0)
|
|
52
57
|
|
|
53
58
|
const hasData = geometry.points.length > 0
|
|
54
|
-
const summary = summaryProp ?? formatLumenChartSummary(projectedSeries, formatValue)
|
|
59
|
+
const summary = summaryProp ?? formatLumenChartSummary(projectedSeries, formatValue, resolvedLabels)
|
|
55
60
|
const xTicks = getLumenChartTicks(geometry.xDomain)
|
|
56
61
|
const yTicks = getLumenChartTicks(geometry.domain)
|
|
57
62
|
---
|
|
58
63
|
|
|
59
64
|
<Chart class:list={['ui-scatter-chart', classProp, className]} {caption} {description} {heading} {summary} {...rest}>
|
|
60
|
-
{showLegend && hasData && <ul class="ui-chart__legend" aria-label=
|
|
61
|
-
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel}</p>}
|
|
65
|
+
{showLegend && hasData && <ul class="ui-chart__legend" aria-label={resolvedLabels.chartLegend}>{series.map((item, index) => <li class={getLumenChartToneClassName(item.tone, index)}><span aria-hidden="true" />{item.label}</li>)}</ul>}
|
|
66
|
+
{!hasData && <p class="ui-chart__empty" role="status">{emptyLabel ?? resolvedLabels.empty}</p>}
|
|
62
67
|
<div class="ui-chart__plot" hidden={!hasData}>
|
|
63
68
|
<svg aria-hidden="true" viewBox={`0 0 ${geometry.width} ${geometry.height}`}>
|
|
64
69
|
<g class="ui-chart__grid">{yTicks.map(tick => {
|
|
@@ -74,5 +79,5 @@ const yTicks = getLumenChartTicks(geometry.domain)
|
|
|
74
79
|
<g class="ui-scatter-chart__marks">{geometry.points.map(point => <circle class={getLumenChartToneClassName(point.tone)} cx={point.xCoordinate} cy={point.yCoordinate} r={point.radius}><title>{`${point.xLabel ?? point.x} · ${point.seriesLabel}: ${point.label ?? formatValue(point.y ?? 0)}`}</title></circle>)}</g>
|
|
75
80
|
</svg>
|
|
76
81
|
</div>
|
|
77
|
-
{showTable && hasData && <details class="ui-chart__data"><summary>
|
|
82
|
+
{showTable && hasData && <details class="ui-chart__data"><summary>{resolvedLabels.viewData}</summary><div><table><thead><tr><th scope="col">{resolvedLabels.x}</th><th scope="col">{resolvedLabels.series}</th><th scope="col">{resolvedLabels.value}</th><th scope="col">{resolvedLabels.size}</th></tr></thead><tbody>{geometry.points.map(point => <tr><th scope="row">{point.xLabel ?? point.x}</th><td>{point.seriesLabel}</td><td>{point.label ?? formatValue(point.y ?? 0)}</td><td>{point.size === undefined || point.size === null || !Number.isFinite(point.size) ? resolvedLabels.notAvailable : formatValue(point.size)}</td></tr>)}</tbody></table></div></details>}
|
|
78
83
|
</Chart>
|
|
@@ -5,6 +5,7 @@ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
|
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLAttributes<'div'> {
|
|
7
7
|
animation?: 'fade' | 'slide-up' | 'scale'
|
|
8
|
+
as?: 'article' | 'div' | 'section'
|
|
8
9
|
class?: string | null
|
|
9
10
|
className?: string
|
|
10
11
|
delay?: number
|
|
@@ -15,6 +16,7 @@ interface Props extends HTMLAttributes<'div'> {
|
|
|
15
16
|
|
|
16
17
|
const {
|
|
17
18
|
animation = 'fade',
|
|
19
|
+
as: Tag = 'div',
|
|
18
20
|
class: classProp = '',
|
|
19
21
|
className = '',
|
|
20
22
|
delay = 0,
|
|
@@ -40,7 +42,7 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
40
42
|
], classProp, className)
|
|
41
43
|
---
|
|
42
44
|
|
|
43
|
-
<
|
|
45
|
+
<Tag
|
|
44
46
|
class:list={classList}
|
|
45
47
|
data-ui-reveal-once={String(once)}
|
|
46
48
|
data-ui-reveal-threshold={safeThreshold}
|
|
@@ -49,4 +51,4 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
|
49
51
|
{...passthrough}
|
|
50
52
|
>
|
|
51
53
|
<slot />
|
|
52
|
-
</
|
|
54
|
+
</Tag>
|
package/components/Table.astro
CHANGED
|
@@ -7,17 +7,20 @@ interface Props extends HTMLAttributes<'div'> {
|
|
|
7
7
|
class?: string | null
|
|
8
8
|
className?: string
|
|
9
9
|
glass?: boolean | 'subtle' | 'strong'
|
|
10
|
+
layout?: 'records' | 'scroll'
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const {
|
|
13
14
|
class: classProp = '',
|
|
14
15
|
className = '',
|
|
15
16
|
glass = false,
|
|
17
|
+
layout = 'scroll',
|
|
16
18
|
...rest
|
|
17
19
|
} = Astro.props
|
|
18
20
|
|
|
19
21
|
const { classList, passthrough } = resolveLumenAstroProps(rest, [
|
|
20
22
|
'ui-table-wrap',
|
|
23
|
+
layout === 'records' && 'ui-table-wrap--records',
|
|
21
24
|
glass && 'ui-table-wrap--glass',
|
|
22
25
|
glass === 'subtle' && 'ui-glass-subtle',
|
|
23
26
|
glass === 'strong' && 'ui-glass-strong'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@santi020k/lumen-astro",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"lumen": "./bin/lumen.mjs"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"
|
|
46
|
-
"@santi020k/lumen-core": "^
|
|
47
|
-
"
|
|
45
|
+
"@santi020k/lumen": "^3.0.0",
|
|
46
|
+
"@santi020k/lumen-core": "^3.0.0",
|
|
47
|
+
"uqr": "^0.1.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@astrojs/ts-plugin": "^1.10.
|
|
51
|
-
"astro": "^7.
|
|
52
|
-
"typescript": "
|
|
53
|
-
"vitest": "^
|
|
50
|
+
"@astrojs/ts-plugin": "^1.10.12",
|
|
51
|
+
"astro": "^7.3.5",
|
|
52
|
+
"typescript": "~6.0.3",
|
|
53
|
+
"vitest": "^5.0.1"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"astro": ">=5"
|
|
@@ -1456,6 +1456,20 @@ const initCopyButtons = (scope: ParentNode): void => {
|
|
|
1456
1456
|
|
|
1457
1457
|
let resetTimer = 0
|
|
1458
1458
|
|
|
1459
|
+
const setCopyButtonState = (state: 'copied' | 'error' | 'idle'): void => {
|
|
1460
|
+
button.dataset.state = state
|
|
1461
|
+
|
|
1462
|
+
for (const part of button.querySelectorAll<HTMLElement>('[data-slot^="copy-"]')) {
|
|
1463
|
+
const isActive = part.dataset.slot === `copy-${state}`
|
|
1464
|
+
|
|
1465
|
+
part.hidden = !isActive
|
|
1466
|
+
|
|
1467
|
+
part.setAttribute('aria-hidden', String(!isActive))
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
setCopyButtonState('idle')
|
|
1472
|
+
|
|
1459
1473
|
button.addEventListener('click', async () => {
|
|
1460
1474
|
const label = button.dataset.copyLabel ?? 'Copy to clipboard'
|
|
1461
1475
|
|
|
@@ -1474,7 +1488,7 @@ const initCopyButtons = (scope: ParentNode): void => {
|
|
|
1474
1488
|
|
|
1475
1489
|
await navigator.clipboard.writeText(value)
|
|
1476
1490
|
|
|
1477
|
-
|
|
1491
|
+
setCopyButtonState('copied')
|
|
1478
1492
|
|
|
1479
1493
|
button.setAttribute('aria-label', copiedLabel)
|
|
1480
1494
|
|
|
@@ -1491,7 +1505,7 @@ const initCopyButtons = (scope: ParentNode): void => {
|
|
|
1491
1505
|
}))
|
|
1492
1506
|
}
|
|
1493
1507
|
} catch (error) {
|
|
1494
|
-
|
|
1508
|
+
setCopyButtonState('error')
|
|
1495
1509
|
|
|
1496
1510
|
button.setAttribute('aria-label', errorLabel)
|
|
1497
1511
|
|
|
@@ -1518,7 +1532,7 @@ const initCopyButtons = (scope: ParentNode): void => {
|
|
|
1518
1532
|
2000
|
|
1519
1533
|
|
|
1520
1534
|
resetTimer = window.setTimeout(() => {
|
|
1521
|
-
|
|
1535
|
+
setCopyButtonState('idle')
|
|
1522
1536
|
|
|
1523
1537
|
button.setAttribute('aria-label', label)
|
|
1524
1538
|
|
package/styles/critical.css
CHANGED
|
@@ -698,7 +698,7 @@
|
|
|
698
698
|
.ui-badge--warning {
|
|
699
699
|
background: hsl(var(--warning) / 0.12);
|
|
700
700
|
border-color: hsl(var(--warning) / 0.36);
|
|
701
|
-
color: hsl(var(--
|
|
701
|
+
color: hsl(var(--ink));
|
|
702
702
|
}
|
|
703
703
|
|
|
704
704
|
.ui-input,
|
|
@@ -893,7 +893,7 @@
|
|
|
893
893
|
.ui-field > p,
|
|
894
894
|
.ui-field > small {
|
|
895
895
|
margin: 0;
|
|
896
|
-
color: hsl(var(--ink-
|
|
896
|
+
color: hsl(var(--ink-soft));
|
|
897
897
|
font-size: 0.8125rem;
|
|
898
898
|
line-height: 1.5;
|
|
899
899
|
}
|
|
@@ -1190,6 +1190,61 @@
|
|
|
1190
1190
|
font-size: 0.875rem;
|
|
1191
1191
|
}
|
|
1192
1192
|
|
|
1193
|
+
.ui-table__label {
|
|
1194
|
+
display: none;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
@media (max-width: 48rem) {
|
|
1198
|
+
.ui-table-wrap--records table,
|
|
1199
|
+
.ui-table-wrap--records tbody {
|
|
1200
|
+
display: block;
|
|
1201
|
+
min-width: 0;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
.ui-table-wrap--records thead {
|
|
1205
|
+
position: absolute;
|
|
1206
|
+
width: 1px;
|
|
1207
|
+
height: 1px;
|
|
1208
|
+
padding: 0;
|
|
1209
|
+
overflow: hidden;
|
|
1210
|
+
clip-path: inset(50%);
|
|
1211
|
+
white-space: nowrap;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
.ui-table-wrap--records tbody tr {
|
|
1215
|
+
display: grid;
|
|
1216
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
|
|
1217
|
+
gap: 1rem;
|
|
1218
|
+
padding: 1rem;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.ui-table-wrap--records tbody tr + tr {
|
|
1222
|
+
border-top: 1px solid hsl(var(--line));
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.ui-table-wrap--records tbody td {
|
|
1226
|
+
display: block;
|
|
1227
|
+
min-width: 0;
|
|
1228
|
+
padding: 0;
|
|
1229
|
+
border: 0;
|
|
1230
|
+
overflow-wrap: anywhere;
|
|
1231
|
+
white-space: normal;
|
|
1232
|
+
text-align: start;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.ui-table-wrap--records .ui-table__label {
|
|
1236
|
+
display: block;
|
|
1237
|
+
margin-bottom: 0.25rem;
|
|
1238
|
+
color: hsl(var(--ink-soft));
|
|
1239
|
+
font-size: 0.75rem;
|
|
1240
|
+
font-weight: 600;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.ui-table-wrap--records .ui-table__cell--wide {
|
|
1244
|
+
grid-column: 1 / -1;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1193
1248
|
.ui-table-wrap th,
|
|
1194
1249
|
.ui-data-table th {
|
|
1195
1250
|
border-bottom: 1px solid hsl(var(--line));
|