@santi020k/lumen-react 1.6.0 → 1.7.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 +114 -30
- package/bin/lumen.mjs +2 -0
- package/dist/chart-recipes.d.ts +2 -0
- package/dist/chart-recipes.d.ts.map +1 -0
- package/dist/chart-recipes.js +3 -0
- package/dist/components.d.ts +78 -91
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +295 -79
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +5 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/phone-recipes.d.ts +4 -0
- package/dist/phone-recipes.d.ts.map +1 -0
- package/dist/phone-recipes.js +18 -0
- package/dist/server-components.d.ts +80 -0
- package/dist/server-components.d.ts.map +1 -0
- package/dist/server-components.js +64 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +2 -0
- package/package.json +17 -4
- package/styles/critical.css +2054 -0
package/dist/components.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { Children, cloneElement, createContext, createElement, Fragment, isValidElement, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
|
-
import { alignLumenChartSeries, composeClassName, createLumenBarGeometry, createLumenLineGeometry, createLumenPieGeometry, formatLumenLanguageLabel, getLumenChartCategories, getLumenChartDomain, getLumenChartTicks, getLumenChartToneClassName, getLumenIcon, getLumenPieChartVariantClassName, hasLumenChartData, hasLumenPieData, lumenCodeTokenClassNames, normalizeLumenFormErrors, resolveLumenChartTone, scaleLumenChartValue, tokenizeLumenCode } from '@santi020k/lumen-core';
|
|
4
|
+
import { alignLumenChartSeries, composeClassName, createLumenBarGeometry, createLumenHeatmapGeometry, createLumenLineGeometry, createLumenPieGeometry, createLumenRangeGeometry, createLumenScatterGeometry, formatLumenChartSummary, formatLumenLanguageLabel, getLumenChartCategories, getLumenChartDomain, getLumenChartTicks, getLumenChartToneClassName, getLumenIcon, getLumenPhoneCountries, getLumenPieChartVariantClassName, hasLumenChartData, hasLumenPieData, lumenCodeTokenClassNames, lumenIllustrations, normalizeLumenFormErrors, resolveLumenChartTone, resolveLumenPhoneNumber, scaleLumenChartValue, tokenizeLumenCode } from '@santi020k/lumen-core';
|
|
5
5
|
import { renderSVG } from 'uqr';
|
|
6
|
+
import { formatReactChartTableValue } from './chart-recipes.js';
|
|
6
7
|
import { useCalendar, useDialog, useDropdownMenu, useInputOTP, useLanguageToggle, usePopover, useResizable, useSelect, useTabs, useTooltip } from './hooks.js';
|
|
8
|
+
import { resolveReactPhoneInputCountry, resolveReactPhoneInputValue } from './phone-recipes.js';
|
|
9
|
+
import { Input, Label } from './server-components.js';
|
|
10
|
+
export { Badge, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Container, Direction, Grid, Input, Label, Progress, Separator, Skeleton, Spinner, Stack, Textarea, Typography, VisuallyHidden } from './server-components.js';
|
|
11
|
+
const getChartCategoryKey = (value) => `${typeof value}:${String(value)}`;
|
|
7
12
|
const setRefValue = (ref, value) => {
|
|
8
13
|
if (typeof ref === 'function') {
|
|
9
14
|
ref(value);
|
|
@@ -17,6 +22,9 @@ const emptyStringOptions = [];
|
|
|
17
22
|
const emptyDataTableColumns = [];
|
|
18
23
|
const emptyDataTableRows = [];
|
|
19
24
|
const emptyChartSeries = [];
|
|
25
|
+
const emptyHeatmapData = [];
|
|
26
|
+
const emptyRangeData = [];
|
|
27
|
+
const emptyComboSeries = [];
|
|
20
28
|
const emptyPieSeries = {
|
|
21
29
|
data: [],
|
|
22
30
|
id: 'pie',
|
|
@@ -91,6 +99,18 @@ const getDataTableSortValue = (cell) => {
|
|
|
91
99
|
return undefined;
|
|
92
100
|
return String(cell.sortValue);
|
|
93
101
|
};
|
|
102
|
+
const compareDataTableCells = (left, right, sortType) => {
|
|
103
|
+
const leftValue = getDataTableSortValue(left) ?? formatDataTableCell(left);
|
|
104
|
+
const rightValue = getDataTableSortValue(right) ?? formatDataTableCell(right);
|
|
105
|
+
if (sortType === 'number') {
|
|
106
|
+
return Number(leftValue.replaceAll(',', '')) -
|
|
107
|
+
Number(rightValue.replaceAll(',', ''));
|
|
108
|
+
}
|
|
109
|
+
return leftValue.localeCompare(rightValue, undefined, {
|
|
110
|
+
numeric: true,
|
|
111
|
+
sensitivity: 'base'
|
|
112
|
+
});
|
|
113
|
+
};
|
|
94
114
|
const getDataTableRowValue = (row, index) => String(row.rowValue ?? row.value ?? row.id ?? index);
|
|
95
115
|
const toInputValue = (value) => {
|
|
96
116
|
if (value === undefined)
|
|
@@ -132,7 +152,6 @@ export const Attachment = ({ className, glass = false, href, ...props }) => {
|
|
|
132
152
|
(_jsx("article", { className: nextClassName, ...props }));
|
|
133
153
|
};
|
|
134
154
|
export const Avatar = ({ alt = '', children, className, fallback, src, ...props }) => (_jsxs("span", { className: composeClassName('ui-avatar', className), ...props, children: [src ? _jsx("img", { alt: alt, src: src }) : _jsx("span", { children: fallback }), children] }));
|
|
135
|
-
export const Badge = ({ className, variant = 'default', ...props }) => (_jsx("span", { className: composeClassName('ui-badge', `ui-badge--${variant}`, className), "data-variant": variant, ...props }));
|
|
136
155
|
export const Breadcrumb = ({ 'aria-label': ariaLabel = 'Breadcrumb', className, ...props }) => (_jsx("nav", { "aria-label": ariaLabel, className: composeClassName('ui-breadcrumb', className), ...props }));
|
|
137
156
|
export const Bubble = ({ className, from = 'assistant', glass = false, ...props }) => (_jsx("article", { className: composeClassName('ui-bubble', from === 'user' && 'ui-bubble--user', glassClass('ui-bubble', glass), className), "data-from": from, ...props }));
|
|
138
157
|
/* eslint-disable complexity -- The compatibility path resolves native, slotted, loading, size, and disabled states in one public component. */
|
|
@@ -163,31 +182,21 @@ export const Calendar = ({ className, defaultValue, disabled = false, glass = fa
|
|
|
163
182
|
});
|
|
164
183
|
return (_jsxs("div", { ...props, ...calendar.rootProps, className: composeClassName(calendar.rootProps.className, glassClass('ui-calendar', glass), className), "data-ui-glass-track": glass ? true : undefined, children: [_jsx("input", { ...calendar.inputProps }), _jsxs("div", { className: "ui-calendar__header", children: [_jsx("button", { ...calendar.previousProps, type: "button", children: _jsx("span", { "aria-hidden": "true", children: "\u2039" }) }), _jsx("strong", { ...calendar.labelProps, children: calendar.label }), _jsx("button", { ...calendar.nextProps, type: "button", children: _jsx("span", { "aria-hidden": "true", children: "\u203A" }) })] }), _jsxs("table", { ...calendar.gridProps, children: [_jsx("thead", { children: _jsx("tr", { role: "row", children: calendar.weekdays.map(weekday => (_jsx("th", { role: "columnheader", scope: "col", children: weekday }, weekday))) }) }), _jsx("tbody", { children: calendar.weeks.map(week => (_jsx("tr", { role: "row", children: week.map(day => (_jsx("td", { ...calendar.getDayProps(day), children: day.day }, day.date))) }, week[0]?.date ?? 'week'))) })] })] }));
|
|
165
184
|
};
|
|
166
|
-
export const Card = ({ as, className, glass = false, variant = 'default', ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), className: composeClassName(variant === 'muted' && 'ui-card--muted', variant === 'interactive' && 'ui-card--interactive', variant === 'unstyled' && 'ui-card--unstyled', (glass || variant === 'glass') &&
|
|
167
|
-
composeClassName('ui-card--glass', glassIntensityClass(glass)), className), "data-slot": "card", "data-variant": variant, ...props, uiClassName: "ui-card" }));
|
|
168
|
-
export const CardHeader = ({ as, ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), "data-slot": "card-header", ...props, uiClassName: "ui-card__header" }));
|
|
169
|
-
export const CardTitle = ({ as, ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), "data-slot": "card-title", ...props, uiClassName: "ui-card__title" }));
|
|
170
|
-
export const CardDescription = ({ as, ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), "data-slot": "card-description", ...props, uiClassName: "ui-card__description" }));
|
|
171
|
-
export const CardContent = ({ as, ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), "data-slot": "card-content", ...props, uiClassName: "ui-card__content" }));
|
|
172
|
-
export const CardFooter = ({ as, ...props }) => (_jsx(Primitive, { ...(as ? { as } : {}), "data-slot": "card-footer", ...props, uiClassName: "ui-card__footer" }));
|
|
173
185
|
export const Carousel = ({ className, glass = false, ...props }) => (_jsx("section", { className: composeClassName('ui-carousel', glassClass('ui-carousel', glass), className), "data-ui-carousel": true, ...props }));
|
|
174
186
|
const ChartHeader = ({ description, heading, value }) => {
|
|
175
187
|
if (!heading && !description && !value)
|
|
176
188
|
return null;
|
|
177
189
|
return (_jsxs("header", { children: [_jsxs("div", { className: "ui-chart__heading", children: [heading && _jsx("h3", { children: heading }), description && _jsx("p", { children: description })] }), value && _jsx("strong", { "data-ui-chart-value": true, children: value })] }));
|
|
178
190
|
};
|
|
179
|
-
export const Chart = ({ caption, children, className, description, glass = false, heading, presentation = 'default', value, ...props }) => (_jsxs("figure", { className: composeClassName('ui-chart', presentation === 'bare' && 'ui-chart--bare', glassClass('ui-chart', glass), className), ...props, children: [_jsx(ChartHeader, { description: description, heading: heading, value: value }), children, caption && _jsx("figcaption", { children: caption })] }));
|
|
191
|
+
export const Chart = ({ caption, children, className, description, glass = false, heading, presentation = 'default', summary, value, ...props }) => (_jsxs("figure", { className: composeClassName('ui-chart', presentation === 'bare' && 'ui-chart--bare', glassClass('ui-chart', glass), className), ...props, children: [_jsx(ChartHeader, { description: description, heading: heading, value: value }), summary && _jsx("p", { className: "ui-sr-only", "data-ui-chart-summary": true, children: summary }), children, caption && _jsx("figcaption", { children: caption })] }));
|
|
180
192
|
const ChartLegend = ({ series }) => (_jsx("ul", { "aria-label": "Chart legend", className: "ui-chart__legend", children: series.map((item, index) => (_jsxs("li", { className: getLumenChartToneClassName(item.tone, index), children: [_jsx("span", { "aria-hidden": "true" }), item.label] }, item.id))) }));
|
|
181
193
|
const ChartDataTable = ({ categories, formatCategory = String, formatValue = String, series }) => (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Category" }), series.map(item => (_jsx("th", { scope: "col", children: item.label }, item.id)))] }) }), _jsx("tbody", { children: categories.map(category => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: series
|
|
182
194
|
.flatMap(item => item.data)
|
|
183
195
|
.find(datum => datum.x === category)?.xLabel ??
|
|
184
196
|
formatCategory(category) }), series.map(item => {
|
|
185
197
|
const datum = item.data.find(candidate => candidate.x === category);
|
|
186
|
-
return (_jsx("td", { children: datum?.label ??
|
|
187
|
-
|
|
188
|
-
'Not available' :
|
|
189
|
-
formatValue(datum.y)) }, item.id));
|
|
190
|
-
})] }, `${typeof category}:${String(category)}`))) })] }) })] }));
|
|
198
|
+
return (_jsx("td", { children: datum?.label ?? formatReactChartTableValue(datum?.y, formatValue) }, item.id));
|
|
199
|
+
})] }, getChartCategoryKey(category)))) })] }) })] }));
|
|
191
200
|
const formatChartPercentage = (percentage) => new Intl.NumberFormat(undefined, {
|
|
192
201
|
maximumFractionDigits: percentage < 0.01 ? 1 : 0,
|
|
193
202
|
style: 'percent'
|
|
@@ -200,7 +209,7 @@ export const Sparkline = ({ area = false, className, label = 'Trend', showEndpoi
|
|
|
200
209
|
geometry.areaPaths.map(path => (_jsx("path", { className: "ui-sparkline__area", d: path }, path))), _jsx("path", { className: "ui-sparkline__line", d: geometry.path }), showEndpoint && endpoint && (_jsx("circle", { className: "ui-sparkline__endpoint", cx: endpoint.xCoordinate, cy: endpoint.yCoordinate, r: "2.5" }))] }), _jsx("span", { className: "ui-sr-only", children: label })] }));
|
|
201
210
|
};
|
|
202
211
|
/* eslint-disable complexity -- Chart renderers keep optional semantic and SVG layers colocated. */
|
|
203
|
-
export const BarChart = ({ categoryWidth, className, emptyLabel = 'No chart data available.', formatCategory = String, formatValue = String, layout = 'grouped', orientation = 'vertical', series = emptyChartSeries, showLegend = series.length > 1, showTable = true, ...props }) => {
|
|
212
|
+
export const BarChart = ({ categoryWidth, className, emptyLabel = 'No chart data available.', formatCategory = String, formatValue = String, layout = 'grouped', orientation = 'vertical', series = emptyChartSeries, showLegend = series.length > 1, showTable = true, summary, ...props }) => {
|
|
204
213
|
const geometry = createLumenBarGeometry(series, {
|
|
205
214
|
...(categoryWidth === undefined ? {} : { categoryWidth }),
|
|
206
215
|
layout,
|
|
@@ -217,17 +226,17 @@ export const BarChart = ({ categoryWidth, className, emptyLabel = 'No chart data
|
|
|
217
226
|
top: 16
|
|
218
227
|
} :
|
|
219
228
|
{ bottom: 52, left: 52, right: 16, top: 16 };
|
|
220
|
-
return (_jsxs(Chart, { className: composeClassName('ui-bar-chart', className), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: emptyLabel })), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsxs("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${geometry.width} ${geometry.height}`, children: [_jsx("g", { className: "ui-chart__grid", children: ticks.map(tick => {
|
|
229
|
+
return (_jsxs(Chart, { className: composeClassName('ui-bar-chart', className), summary: summary ?? formatLumenChartSummary(series, formatValue), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: emptyLabel })), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsxs("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${geometry.width} ${geometry.height}`, children: [_jsx("g", { className: "ui-chart__grid", children: ticks.map(tick => {
|
|
221
230
|
const coordinate = orientation === 'horizontal' ?
|
|
222
231
|
scaleLumenChartValue(tick, geometry.domain, margin.left, geometry.width - margin.right) :
|
|
223
232
|
scaleLumenChartValue(tick, geometry.domain, geometry.height - margin.bottom, margin.top);
|
|
224
233
|
return orientation === 'horizontal' ?
|
|
225
234
|
(_jsx("line", { x1: coordinate, x2: coordinate, y1: margin.top, y2: geometry.height - margin.bottom }, tick)) :
|
|
226
235
|
(_jsx("line", { x1: margin.left, x2: geometry.width - margin.right, y1: coordinate, y2: coordinate }, tick));
|
|
227
|
-
}) }), _jsx("g", { className: "ui-chart__axis-labels", children: geometry.categories.map(category => (_jsx("text", { dominantBaseline: orientation === 'horizontal' ? 'middle' : undefined, textAnchor: orientation === 'horizontal' ? 'end' : 'middle', x: category.x, y: category.y, children: String(category.label) },
|
|
236
|
+
}) }), _jsx("g", { className: "ui-chart__axis-labels", children: geometry.categories.map(category => (_jsx("text", { dominantBaseline: orientation === 'horizontal' ? 'middle' : undefined, textAnchor: orientation === 'horizontal' ? 'end' : 'middle', x: category.x, y: category.y, children: String(category.label) }, getChartCategoryKey(category.label)))) }), _jsx("g", { className: "ui-bar-chart__marks", children: geometry.marks.map(mark => (_jsx("rect", { className: getLumenChartToneClassName(mark.tone), height: mark.height, rx: "4", width: mark.width, x: mark.x, y: mark.y, children: _jsx("title", { children: `${series
|
|
228
237
|
.flatMap(item => item.data)
|
|
229
238
|
.find(datum => datum.x === mark.category)?.xLabel ??
|
|
230
|
-
formatCategory(mark.category)} · ${mark.seriesLabel}: ${formatValue(mark.value)}` }) }, `${mark.seriesId}:${
|
|
239
|
+
formatCategory(mark.category)} · ${mark.seriesLabel}: ${formatValue(mark.value)}` }) }, `${mark.seriesId}:${getChartCategoryKey(mark.category)}`))) })] }) }), showTable && hasData && (_jsx(ChartDataTable, { categories: categories, formatCategory: formatCategory, formatValue: formatValue, series: series }))] }));
|
|
231
240
|
};
|
|
232
241
|
const getLineChartMarkerStep = (markers, categoryCount) => {
|
|
233
242
|
if (markers === false || markers === 'none')
|
|
@@ -238,13 +247,16 @@ const getLineChartMarkerStep = (markers, categoryCount) => {
|
|
|
238
247
|
return Math.max(1, Math.ceil(categoryCount / 24));
|
|
239
248
|
return 1;
|
|
240
249
|
};
|
|
241
|
-
export const LineChart = ({ area = false, className, emptyLabel = 'No chart data available.', formatCategory = String, formatValue = String, markers = 'auto', referenceValue, series = emptyChartSeries, showLegend = series.length > 1, showTable = true, ...props }) => {
|
|
250
|
+
export const LineChart = ({ area = false, className, emptyLabel = 'No chart data available.', formatCategory = String, formatValue = String, markers = 'auto', referenceValue, series = emptyChartSeries, showLegend = series.length > 1, showTable = true, summary, ...props }) => {
|
|
242
251
|
const width = 640;
|
|
243
252
|
const height = 320;
|
|
244
253
|
const padding = 44;
|
|
245
254
|
const categories = getLumenChartCategories(series);
|
|
246
255
|
const hasData = hasLumenChartData(series);
|
|
247
|
-
const alignedSeries = series.map(item =>
|
|
256
|
+
const alignedSeries = series.map(item => ({
|
|
257
|
+
...item,
|
|
258
|
+
data: alignLumenChartSeries(item, categories).data
|
|
259
|
+
}));
|
|
248
260
|
const domain = getLumenChartDomain([
|
|
249
261
|
...alignedSeries.flatMap(item => item.data.map(datum => datum.y)),
|
|
250
262
|
referenceValue ?? null
|
|
@@ -262,7 +274,7 @@ export const LineChart = ({ area = false, className, emptyLabel = 'No chart data
|
|
|
262
274
|
const referenceY = referenceValue === undefined ?
|
|
263
275
|
undefined :
|
|
264
276
|
scaleLumenChartValue(referenceValue, domain, height - padding, padding);
|
|
265
|
-
return (_jsxs(Chart, { className: composeClassName('ui-line-chart', className), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: emptyLabel })), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsxs("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${width} ${height}`, children: [_jsx("g", { className: "ui-chart__grid", children: ticks.map(tick => {
|
|
277
|
+
return (_jsxs(Chart, { className: composeClassName('ui-line-chart', className), summary: summary ?? formatLumenChartSummary(series, formatValue), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: emptyLabel })), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsxs("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${width} ${height}`, children: [_jsx("g", { className: "ui-chart__grid", children: ticks.map(tick => {
|
|
266
278
|
const y = scaleLumenChartValue(tick, domain, height - padding, padding);
|
|
267
279
|
return (_jsxs(Fragment, { children: [_jsx("line", { x1: padding, x2: width - padding, y1: y, y2: y }), _jsx("text", { x: padding - 8, y: y, children: formatValue(tick) })] }, tick));
|
|
268
280
|
}) }), _jsx("g", { className: "ui-chart__axis-labels", children: categories.map((category, index) => {
|
|
@@ -273,7 +285,7 @@ export const LineChart = ({ area = false, className, emptyLabel = 'No chart data
|
|
|
273
285
|
return (_jsx("text", { textAnchor: "middle", x: x, y: height - 14, children: series
|
|
274
286
|
.flatMap(item => item.data)
|
|
275
287
|
.find(datum => datum.x === category)?.xLabel ??
|
|
276
|
-
formatCategory(category) },
|
|
288
|
+
formatCategory(category) }, getChartCategoryKey(category)));
|
|
277
289
|
}) }), referenceY !== undefined && (_jsx("line", { className: "ui-chart__reference", x1: padding, x2: width - padding, y1: referenceY, y2: referenceY })), geometries.map((geometry, index) => {
|
|
278
290
|
const item = series[index];
|
|
279
291
|
if (!item)
|
|
@@ -281,15 +293,86 @@ export const LineChart = ({ area = false, className, emptyLabel = 'No chart data
|
|
|
281
293
|
const tone = resolveLumenChartTone(item.tone, index);
|
|
282
294
|
return (_jsxs("g", { className: composeClassName('ui-line-chart__series', getLumenChartToneClassName(tone)), children: [area &&
|
|
283
295
|
geometry.areaPaths.map(path => (_jsx("path", { className: "ui-line-chart__area", d: path }, path))), _jsx("path", { className: "ui-line-chart__line", d: geometry.path }), Number.isFinite(markerStep) &&
|
|
284
|
-
geometry.points.map((point, pointIndex) => pointIndex % markerStep === 0 && (_jsx("circle", { className: "ui-line-chart__point", cx: point.xCoordinate, cy: point.yCoordinate, r: "3", children: _jsx("title", { children: `${point.xLabel ?? formatCategory(point.x)} · ${item.label}: ${formatValue(point.y ?? 0)}` }) },
|
|
296
|
+
geometry.points.map((point, pointIndex) => pointIndex % markerStep === 0 && (_jsx("circle", { className: "ui-line-chart__point", cx: point.xCoordinate, cy: point.yCoordinate, r: "3", children: _jsx("title", { children: `${point.xLabel ?? formatCategory(point.x)} · ${item.label}: ${formatValue(point.y ?? 0)}` }) }, getChartCategoryKey(point.x))))] }, item.id));
|
|
285
297
|
})] }) }), showTable && hasData && (_jsx(ChartDataTable, { categories: categories, formatCategory: formatCategory, formatValue: formatValue, series: series }))] }));
|
|
286
298
|
};
|
|
287
|
-
export const PieChart = ({ centerLabel, centerValue, className, series = emptyPieSeries, showLegend = true, showTable = true, valueFormatter = String, variant = 'donut', ...props }) => {
|
|
299
|
+
export const PieChart = ({ centerLabel, centerValue, className, series = emptyPieSeries, showLegend = true, showTable = true, summary, valueFormatter = String, variant = 'donut', ...props }) => {
|
|
288
300
|
const geometry = createLumenPieGeometry(series.data, { variant });
|
|
289
301
|
const hasData = hasLumenPieData(series.data);
|
|
302
|
+
const renderedSeries = {
|
|
303
|
+
...series,
|
|
304
|
+
data: series.data.filter(datum => datum.y !== null && Number.isFinite(datum.y) && datum.y > 0)
|
|
305
|
+
};
|
|
290
306
|
const hasCenterLabel = centerLabel !== null && centerLabel !== undefined;
|
|
291
307
|
const hasCenterValue = centerValue !== null && centerValue !== undefined;
|
|
292
|
-
return (_jsxs(Chart, { className: composeClassName('ui-pie-chart', getLumenPieChartVariantClassName(variant), className), ...props, children: [showLegend && hasData && (_jsx("ul", { "aria-label": "Chart legend", className: "ui-chart__legend", children: geometry.slices.map(slice => (_jsxs("li", { className: getLumenChartToneClassName(slice.tone), children: [_jsx("span", { "aria-hidden": "true" }), slice.label] }, `${typeof slice.x}:${String(slice.x)}`))) })), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." })), _jsxs("div", { className: "ui-chart__plot ui-pie-chart__plot", hidden: !hasData, children: [_jsx("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${geometry.size} ${geometry.size}`, children: _jsx("g", { className: "ui-pie-chart__slices", children: geometry.slices.map(slice => (_jsx("path", { className: getLumenChartToneClassName(slice.tone), d: slice.path, fillRule: "evenodd", children: _jsx("title", { children: `${slice.label}: ${valueFormatter(slice.value)} (${formatChartPercentage(slice.percentage)})` }) }, `${typeof slice.x}:${String(slice.x)}`))) }) }), variant === 'donut' && (hasCenterLabel || hasCenterValue) && (_jsxs(_Fragment, { children: [_jsxs("div", { "aria-hidden": "true", className: "ui-pie-chart__center", children: [hasCenterValue && _jsx("strong", { children: centerValue }), hasCenterLabel && _jsx("span", { children: centerLabel })] }), _jsxs("div", { className: "ui-sr-only", children: [centerValue, ' ', centerLabel] })] }))] }), showTable && hasData && (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Category" }), _jsx("th", { scope: "col", children: "Value" }), _jsx("th", { scope: "col", children: "Share" })] }) }), _jsx("tbody", { children: geometry.slices.map(slice => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: slice.label }), _jsx("td", { children: valueFormatter(slice.value) }), _jsx("td", { children: formatChartPercentage(slice.percentage) })] }, `${typeof slice.x}:${String(slice.x)}`))) })] }) })] }))] }));
|
|
308
|
+
return (_jsxs(Chart, { className: composeClassName('ui-pie-chart', getLumenPieChartVariantClassName(variant), className), summary: summary ?? formatLumenChartSummary([renderedSeries], valueFormatter), ...props, children: [showLegend && hasData && (_jsx("ul", { "aria-label": "Chart legend", className: "ui-chart__legend", children: geometry.slices.map(slice => (_jsxs("li", { className: getLumenChartToneClassName(slice.tone), children: [_jsx("span", { "aria-hidden": "true" }), slice.label] }, `${typeof slice.x}:${String(slice.x)}`))) })), !hasData && (_jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." })), _jsxs("div", { className: "ui-chart__plot ui-pie-chart__plot", hidden: !hasData, children: [_jsx("svg", { "aria-hidden": "true", preserveAspectRatio: "xMidYMid meet", viewBox: `0 0 ${geometry.size} ${geometry.size}`, children: _jsx("g", { className: "ui-pie-chart__slices", children: geometry.slices.map(slice => (_jsx("path", { className: getLumenChartToneClassName(slice.tone), d: slice.path, fillRule: "evenodd", children: _jsx("title", { children: `${slice.label}: ${valueFormatter(slice.value)} (${formatChartPercentage(slice.percentage)})` }) }, `${typeof slice.x}:${String(slice.x)}`))) }) }), variant === 'donut' && (hasCenterLabel || hasCenterValue) && (_jsxs(_Fragment, { children: [_jsxs("div", { "aria-hidden": "true", className: "ui-pie-chart__center", children: [hasCenterValue && _jsx("strong", { children: centerValue }), hasCenterLabel && _jsx("span", { children: centerLabel })] }), _jsxs("div", { className: "ui-sr-only", children: [centerValue, ' ', centerLabel] })] }))] }), showTable && hasData && (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Category" }), _jsx("th", { scope: "col", children: "Value" }), _jsx("th", { scope: "col", children: "Share" })] }) }), _jsx("tbody", { children: geometry.slices.map(slice => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: slice.label }), _jsx("td", { children: valueFormatter(slice.value) }), _jsx("td", { children: formatChartPercentage(slice.percentage) })] }, `${typeof slice.x}:${String(slice.x)}`))) })] }) })] }))] }));
|
|
309
|
+
};
|
|
310
|
+
export const ScatterChart = ({ className, formatValue = String, series = emptyChartSeries, showLegend = series.length > 1, showTable = true, summary, xScale = 'linear', ...props }) => {
|
|
311
|
+
const geometry = createLumenScatterGeometry(series, { xScale });
|
|
312
|
+
const renderedSeries = series.map(item => ({
|
|
313
|
+
...item,
|
|
314
|
+
data: geometry.points.filter(point => point.seriesId === item.id)
|
|
315
|
+
})).filter(item => item.data.length > 0);
|
|
316
|
+
const hasData = geometry.points.length > 0;
|
|
317
|
+
return (_jsxs(Chart, { className: composeClassName('ui-scatter-chart', className), summary: summary ?? formatLumenChartSummary(renderedSeries, formatValue), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && _jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." }), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsx("svg", { "aria-hidden": "true", viewBox: `0 0 ${geometry.width} ${geometry.height}`, children: _jsx("g", { className: "ui-scatter-chart__marks", children: geometry.points.map((point, pointIndex) => (_jsx("circle", { className: getLumenChartToneClassName(point.tone), cx: point.xCoordinate, cy: point.yCoordinate, r: point.radius, children: _jsx("title", { children: `${point.xLabel ?? point.x} · ${point.seriesLabel}: ${point.label ?? formatValue(point.y ?? 0)}` }) }, `${point.seriesId}:${point.id ?? `${getChartCategoryKey(point.x)}:${pointIndex}`}`))) }) }) }), showTable && hasData && (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "X" }), _jsx("th", { scope: "col", children: "Series" }), _jsx("th", { scope: "col", children: "Value" }), _jsx("th", { scope: "col", children: "Size" })] }) }), _jsx("tbody", { children: geometry.points.map((point, pointIndex) => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: point.xLabel ?? point.x }), _jsx("td", { children: point.seriesLabel }), _jsx("td", { children: point.label ?? formatValue(point.y ?? 0) }), _jsx("td", { children: formatReactChartTableValue(point.size, formatValue) })] }, `${point.seriesId}:${point.id ?? `${getChartCategoryKey(point.x)}:${pointIndex}`}`))) })] }) })] }))] }));
|
|
318
|
+
};
|
|
319
|
+
export const Heatmap = ({ className, data = emptyHeatmapData, formatValue = String, showTable = true, summary, ...props }) => {
|
|
320
|
+
const geometry = createLumenHeatmapGeometry(data);
|
|
321
|
+
const availableCells = geometry.cells.filter(cell => cell.value !== null && Number.isFinite(cell.value));
|
|
322
|
+
const hasData = availableCells.length > 0;
|
|
323
|
+
return (_jsxs(Chart, { className: composeClassName('ui-heatmap', className), summary: summary ?? `${availableCells.length} available heatmap cells.`, ...props, children: [!hasData && _jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." }), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsx("svg", { "aria-hidden": "true", viewBox: `0 0 ${geometry.width} ${geometry.height}`, children: _jsx("g", { className: "ui-heatmap__cells", children: availableCells.map(cell => _jsx("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, children: _jsx("title", { children: `${cell.xLabel ?? cell.x} · ${cell.yLabel ?? cell.y}: ${cell.label ?? formatValue(cell.value ?? 0)}` }) }, cell.id ?? `${getChartCategoryKey(cell.x)}:${getChartCategoryKey(cell.y)}`)) }) }) }), showTable && (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Column" }), _jsx("th", { scope: "col", children: "Row" }), _jsx("th", { scope: "col", children: "Value" })] }) }), _jsx("tbody", { children: data.map(cell => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: cell.xLabel ?? cell.x }), _jsx("td", { children: cell.yLabel ?? cell.y }), _jsx("td", { children: cell.label ?? (cell.value === null || !Number.isFinite(cell.value) ? 'Not available' : formatValue(cell.value)) })] }, cell.id ?? `${getChartCategoryKey(cell.x)}:${getChartCategoryKey(cell.y)}`))) })] }) })] }))] }));
|
|
324
|
+
};
|
|
325
|
+
export const RangeChart = ({ className, data = emptyRangeData, formatValue = String, showTable = true, summary, tone = 'series-1', ...props }) => {
|
|
326
|
+
const width = 640;
|
|
327
|
+
const height = 320;
|
|
328
|
+
const padding = 44;
|
|
329
|
+
const geometry = createLumenRangeGeometry(data, { height, padding, width });
|
|
330
|
+
return (_jsxs(Chart, { className: composeClassName('ui-range-chart', getLumenChartToneClassName(tone), className), summary: summary ?? (geometry.points.length === 0 ? 'No chart data available.' : `${geometry.points.length} available ranges.`), ...props, children: [geometry.points.length === 0 && _jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." }), _jsx("div", { className: "ui-chart__plot", hidden: geometry.points.length === 0, children: _jsxs("svg", { "aria-hidden": "true", viewBox: `0 0 ${width} ${height}`, children: [_jsx("path", { className: "ui-range-chart__area", d: geometry.areaPath }), geometry.points.map(point => (_jsx("line", { className: "ui-range-chart__interval", x1: point.xCoordinate, x2: point.xCoordinate, y1: point.highCoordinate, y2: point.lowCoordinate, children: _jsx("title", { children: `${point.xLabel ?? point.x}: ${point.label ?? `${formatValue(point.low ?? 0)}–${formatValue(point.high ?? 0)}`}` }) }, point.id ?? getChartCategoryKey(point.x))))] }) }), showTable && (_jsxs("details", { className: "ui-chart__data", children: [_jsx("summary", { children: "View chart data" }), _jsx("div", { children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Category" }), _jsx("th", { scope: "col", children: "Low" }), _jsx("th", { scope: "col", children: "High" })] }) }), _jsx("tbody", { children: data.map(item => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: item.xLabel ?? item.x }), _jsx("td", { children: item.low === null || !Number.isFinite(item.low) ? 'Not available' : formatValue(item.low) }), _jsx("td", { children: item.high === null || !Number.isFinite(item.high) ? 'Not available' : formatValue(item.high) })] }, item.id ?? getChartCategoryKey(item.x)))) })] }) })] }))] }));
|
|
331
|
+
};
|
|
332
|
+
export const ComboChart = ({ className, formatValue = String, series = emptyComboSeries, showLegend = true, showTable = true, summary, ...props }) => {
|
|
333
|
+
const width = 640;
|
|
334
|
+
const height = 320;
|
|
335
|
+
const padding = 44;
|
|
336
|
+
const categories = getLumenChartCategories(series);
|
|
337
|
+
const alignedSeries = series.map(item => ({
|
|
338
|
+
...item,
|
|
339
|
+
data: alignLumenChartSeries(item, categories).data
|
|
340
|
+
}));
|
|
341
|
+
const domain = getLumenChartDomain(alignedSeries.flatMap(item => item.data.map(datum => datum.y)));
|
|
342
|
+
const barSeries = alignedSeries.filter(item => item.mark === 'bar');
|
|
343
|
+
const lineSeries = alignedSeries.filter(item => item.mark !== 'bar');
|
|
344
|
+
const bars = createLumenBarGeometry(barSeries, { domain, height, width });
|
|
345
|
+
const categoryPositions = new Map(bars.categories.map(category => [getChartCategoryKey(category.category), category.x]));
|
|
346
|
+
const drawableWidth = width - padding * 2;
|
|
347
|
+
const alignComboLineDatum = (datum) => {
|
|
348
|
+
if (barSeries.length === 0)
|
|
349
|
+
return datum;
|
|
350
|
+
return {
|
|
351
|
+
...datum,
|
|
352
|
+
x: ((categoryPositions.get(`${typeof datum.x}:${String(datum.x)}`) ?? padding) - padding) / drawableWidth
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
const lineGeometryOptions = {
|
|
356
|
+
domain,
|
|
357
|
+
height,
|
|
358
|
+
padding,
|
|
359
|
+
width,
|
|
360
|
+
...(barSeries.length === 0 ?
|
|
361
|
+
{} :
|
|
362
|
+
{
|
|
363
|
+
xDomain: { max: 1, min: 0 },
|
|
364
|
+
xScale: 'linear'
|
|
365
|
+
})
|
|
366
|
+
};
|
|
367
|
+
const lines = lineSeries.map(item => createLumenLineGeometry(item.data.map(alignComboLineDatum), lineGeometryOptions));
|
|
368
|
+
const hasData = hasLumenChartData(series);
|
|
369
|
+
return (_jsxs(Chart, { className: composeClassName('ui-combo-chart', className), summary: summary ?? formatLumenChartSummary(series, formatValue), ...props, children: [showLegend && hasData && _jsx(ChartLegend, { series: series }), !hasData && _jsx("p", { className: "ui-chart__empty", role: "status", children: "No chart data available." }), _jsx("div", { className: "ui-chart__plot", hidden: !hasData, children: _jsxs("svg", { "aria-hidden": "true", viewBox: `0 0 ${width} ${height}`, children: [_jsx("g", { className: "ui-bar-chart__marks", children: bars.marks.map(mark => _jsx("rect", { className: getLumenChartToneClassName(mark.tone), height: mark.height, rx: "4", width: mark.width, x: mark.x, y: mark.y, children: _jsx("title", { children: `${mark.seriesLabel}: ${formatValue(mark.value)}` }) }, `${mark.seriesId}:${getChartCategoryKey(mark.category)}`)) }), lines.map((geometry, index) => {
|
|
370
|
+
const item = lineSeries[index];
|
|
371
|
+
if (!item)
|
|
372
|
+
return null;
|
|
373
|
+
const tone = resolveLumenChartTone(item.tone, index + barSeries.length);
|
|
374
|
+
return (_jsxs("g", { className: composeClassName('ui-line-chart__series', getLumenChartToneClassName(tone)), children: [item.mark === 'area' && geometry.areaPaths.map(path => (_jsx("path", { className: "ui-line-chart__area", d: path }, path))), _jsx("path", { className: "ui-line-chart__line", d: geometry.path })] }, item.id));
|
|
375
|
+
})] }) }), showTable && hasData && _jsx(ChartDataTable, { categories: categories, formatValue: formatValue, series: series })] }));
|
|
293
376
|
};
|
|
294
377
|
export const Checkbox = ({ className, ref, ...props }) => (_jsx("input", { className: composeClassName('ui-checkbox', className), ref: ref, type: "checkbox", ...props }));
|
|
295
378
|
export const CheckboxGroup = ({ children, className, invalid = false, legend, orientation = 'vertical', ...props }) => (_jsxs("fieldset", { "aria-invalid": invalid || undefined, className: composeClassName('ui-checkbox-group', `ui-checkbox-group--${orientation}`, className), "data-invalid": invalid ? 'true' : undefined, "data-orientation": orientation, "data-ui-checkbox-group": true, ...props, children: [legend && _jsx("legend", { children: legend }), children] }));
|
|
@@ -367,6 +450,7 @@ export const CopyButton = ({ children = 'Copy', className, copiedLabel = 'Copied
|
|
|
367
450
|
};
|
|
368
451
|
export const Combobox = ({ className, defaultValue, id, label, list, onBlur, onChange, onFocus, onKeyDown, options = emptyStringOptions, type = 'text', value: valueProp, wrapperClassName, ...props }) => {
|
|
369
452
|
const inputId = id ?? `${list}-input`;
|
|
453
|
+
const rootRef = useRef(null);
|
|
370
454
|
const [open, setOpen] = useState(false);
|
|
371
455
|
const [value, setValue] = useState(() => String(defaultValue ?? ''));
|
|
372
456
|
const renderedValue = valueProp ?? value;
|
|
@@ -378,12 +462,33 @@ export const Combobox = ({ className, defaultValue, id, label, list, onBlur, onC
|
|
|
378
462
|
}
|
|
379
463
|
setOpen(false);
|
|
380
464
|
};
|
|
465
|
+
const getVisibleOptions = () => [
|
|
466
|
+
...(rootRef.current?.querySelectorAll('[data-ui-combobox-option]:not([hidden]):not([disabled])') ?? [])
|
|
467
|
+
];
|
|
468
|
+
const focusInputEdgeOption = (key) => {
|
|
469
|
+
const options = getVisibleOptions();
|
|
470
|
+
options[key === 'ArrowUp' ? options.length - 1 : 0]?.focus();
|
|
471
|
+
};
|
|
472
|
+
const focusOption = (option, key) => {
|
|
473
|
+
const options = getVisibleOptions();
|
|
474
|
+
if (!options.length)
|
|
475
|
+
return;
|
|
476
|
+
const currentIndex = Math.max(0, options.indexOf(option));
|
|
477
|
+
let nextIndex = (currentIndex - 1 + options.length) % options.length;
|
|
478
|
+
if (key === 'Home')
|
|
479
|
+
nextIndex = 0;
|
|
480
|
+
else if (key === 'End')
|
|
481
|
+
nextIndex = options.length - 1;
|
|
482
|
+
else if (key === 'ArrowDown')
|
|
483
|
+
nextIndex = (currentIndex + 1) % options.length;
|
|
484
|
+
options[nextIndex]?.focus();
|
|
485
|
+
};
|
|
381
486
|
return (_jsxs("div", { className: composeClassName('ui-combobox', wrapperClassName), "data-ui-combobox": true, onBlur: event => {
|
|
382
487
|
const nextTarget = event.relatedTarget;
|
|
383
488
|
if (!nextTarget || !event.currentTarget.contains(nextTarget)) {
|
|
384
489
|
setOpen(false);
|
|
385
490
|
}
|
|
386
|
-
}, children: [label && (_jsx("label", { className: "ui-label", htmlFor: inputId, children: label })), _jsx("input", { "aria-autocomplete": "list", "aria-controls": list, "aria-expanded": open, className: composeClassName('ui-input', className), id: inputId, role: "combobox", type: type, value: renderedValue, onBlur: onBlur, onChange: event => {
|
|
491
|
+
}, ref: rootRef, children: [label && (_jsx("label", { className: "ui-label", htmlFor: inputId, children: label })), _jsx("input", { "aria-autocomplete": "list", "aria-controls": list, "aria-expanded": open, className: composeClassName('ui-input', className), id: inputId, role: "combobox", type: type, value: renderedValue, onBlur: onBlur, onChange: event => {
|
|
387
492
|
if (valueProp === undefined) {
|
|
388
493
|
setValue(event.currentTarget.value);
|
|
389
494
|
}
|
|
@@ -396,13 +501,37 @@ export const Combobox = ({ className, defaultValue, id, label, list, onBlur, onC
|
|
|
396
501
|
if (event.key === 'Escape') {
|
|
397
502
|
setOpen(false);
|
|
398
503
|
}
|
|
504
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
505
|
+
const key = event.key;
|
|
506
|
+
event.preventDefault();
|
|
507
|
+
setOpen(true);
|
|
508
|
+
globalThis.queueMicrotask(() => {
|
|
509
|
+
focusInputEdgeOption(key);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
399
512
|
if (event.key === 'Enter' && visibleOptions[0]) {
|
|
400
513
|
event.preventDefault();
|
|
401
514
|
selectOption(visibleOptions[0]);
|
|
402
515
|
}
|
|
403
516
|
onKeyDown?.(event);
|
|
404
|
-
}, ...props }), _jsx("div", { className: "ui-combobox__list", hidden: !open, id: list, role: "listbox", children: visibleOptions.map(option => (_jsx("button", { "data-ui-combobox-option": true, "data-value": option, role: "option", type: "button", onClick: () => {
|
|
517
|
+
}, ...props }), _jsx("div", { className: "ui-combobox__list", hidden: !open, id: list, role: "listbox", children: visibleOptions.map(option => (_jsx("button", { "data-ui-combobox-option": true, "data-value": option, role: "option", tabIndex: -1, type: "button", onClick: () => {
|
|
405
518
|
selectOption(option);
|
|
519
|
+
}, onKeyDown: event => {
|
|
520
|
+
if (event.key === 'Escape') {
|
|
521
|
+
setOpen(false);
|
|
522
|
+
rootRef.current?.querySelector('input[role="combobox"]')?.focus();
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
526
|
+
event.preventDefault();
|
|
527
|
+
rootRef.current?.querySelector('input[role="combobox"]')?.focus();
|
|
528
|
+
selectOption(option);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key))
|
|
532
|
+
return;
|
|
533
|
+
event.preventDefault();
|
|
534
|
+
focusOption(event.currentTarget, event.key);
|
|
406
535
|
}, onMouseDown: event => {
|
|
407
536
|
event.preventDefault();
|
|
408
537
|
}, children: option }, option))) })] }));
|
|
@@ -410,9 +539,39 @@ export const Combobox = ({ className, defaultValue, id, label, list, onBlur, onC
|
|
|
410
539
|
export const Command = ({ className, glass = false, ...props }) => (_jsx("div", { className: composeClassName('ui-command', glassClass('ui-command', glass), className), "data-ui-command": true, ...props }));
|
|
411
540
|
export const ContextMenu = ({ className, glass = false, ...props }) => (_jsx("menu", { className: composeClassName('ui-menu', glassSurfaceClass('ui-menu', glass), className), "data-surface": resolveSurface(glass), "data-ui-context-menu": true, role: props.role ?? 'menu', ...props }));
|
|
412
541
|
export const ColorPicker = ({ className, type = 'color', ...props }) => (_jsx("input", { className: composeClassName('ui-color-picker', className), type: type, ...props }));
|
|
413
|
-
export const DataTable = ({ children, className, columns = emptyDataTableColumns, glass = false, name, rows = emptyDataTableRows, selectable = false, ...props }) =>
|
|
414
|
-
|
|
415
|
-
|
|
542
|
+
export const DataTable = ({ children, className, columns = emptyDataTableColumns, glass = false, name, rows = emptyDataTableRows, selectable = false, ...props }) => {
|
|
543
|
+
const [sort, setSort] = useState(null);
|
|
544
|
+
const sortedRows = useMemo(() => {
|
|
545
|
+
if (!sort)
|
|
546
|
+
return rows;
|
|
547
|
+
const column = columns.find(candidate => candidate.key === sort.key);
|
|
548
|
+
if (!column)
|
|
549
|
+
return rows;
|
|
550
|
+
const direction = sort.direction === 'ascending' ? 1 : -1;
|
|
551
|
+
return [...rows].sort((left, right) => compareDataTableCells(left[column.key], right[column.key], column.sort) * direction);
|
|
552
|
+
}, [columns, rows, sort]);
|
|
553
|
+
const toggleSort = (column) => {
|
|
554
|
+
setSort(current => ({
|
|
555
|
+
direction: current?.key === column.key && current.direction === 'ascending' ?
|
|
556
|
+
'descending' :
|
|
557
|
+
'ascending',
|
|
558
|
+
key: column.key
|
|
559
|
+
}));
|
|
560
|
+
};
|
|
561
|
+
return (_jsx("div", { className: composeClassName('ui-data-table', glassClass('ui-data-table', glass), className), "data-ui-datatable": true, "data-ui-datatable-name": name, "data-ui-datatable-selectable": selectable ? 'true' : undefined, "data-ui-glass-track": glass ? true : undefined, ...props, children: columns.length > 0 ?
|
|
562
|
+
(_jsxs("table", { children: [_jsx("thead", { children: _jsx("tr", { children: columns.map(column => {
|
|
563
|
+
const direction = sort?.key === column.key ?
|
|
564
|
+
sort.direction :
|
|
565
|
+
undefined;
|
|
566
|
+
const label = column.header ?? column.label ?? column.key;
|
|
567
|
+
return (_jsx("th", { "aria-sort": direction ?? (column.sortable ? 'none' : undefined), "data-ui-datatable-sort-type": column.sort, "data-ui-datatable-sortable": column.sortable ? 'true' : undefined, scope: "col", children: column.sortable ?
|
|
568
|
+
(_jsx("button", { className: "ui-data-table__sort", "data-ui-datatable-sort": true, onClick: () => {
|
|
569
|
+
toggleSort(column);
|
|
570
|
+
}, type: "button", children: label })) :
|
|
571
|
+
label }, column.key));
|
|
572
|
+
}) }) }), _jsx("tbody", { children: sortedRows.map((row, rowIndex) => (_jsx("tr", { "data-ui-datatable-row": true, "data-value": getDataTableRowValue(row, rowIndex), children: columns.map(column => (_jsx("td", { "data-sort-value": getDataTableSortValue(row[column.key]), children: formatDataTableCell(row[column.key]) }, column.key))) }, getDataTableRowValue(row, rowIndex)))) })] })) :
|
|
573
|
+
children }));
|
|
574
|
+
};
|
|
416
575
|
const formatDatePickerDisplayValue = (value, placeholder) => {
|
|
417
576
|
if (!value || !/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
418
577
|
return placeholder;
|
|
@@ -545,33 +704,6 @@ export const Dialog = ({ className, defaultOpen, glass = false, layout = 'center
|
|
|
545
704
|
const dialog = useDialog({ defaultOpen, onOpenChange, open });
|
|
546
705
|
return (_jsx("dialog", { ...dialog.dialogProps, ...props, className: composeClassName('ui-dialog', layout === 'fullscreen' && 'ui-dialog--fullscreen', glassSurfaceClass('ui-dialog', glass), className), "data-layout": layout, "data-surface": resolveSurface(glass), onClick: composeHandlers(onClick, dialog.dialogProps.onClick), onClose: composeHandlers(onClose, dialog.dialogProps.onClose) }));
|
|
547
706
|
};
|
|
548
|
-
export const Direction = ({ className, dir = 'ltr', ...props }) => (_jsx("div", { className: composeClassName('ui-direction', className), dir: dir, ...props }));
|
|
549
|
-
export const Container = ({ as = 'div', className, size = 'lg', ...props }) => createElement(as, {
|
|
550
|
-
className: composeClassName('ui-container', `ui-container--${size}`, className),
|
|
551
|
-
'data-size': size,
|
|
552
|
-
'data-ui-container': true,
|
|
553
|
-
...props
|
|
554
|
-
});
|
|
555
|
-
export const Grid = ({ as = 'div', className, columns = 'auto', gap = 'md', minItemWidth, style, ...props }) => {
|
|
556
|
-
const gridStyle = {
|
|
557
|
-
...style,
|
|
558
|
-
'--ui-grid-min': minItemWidth
|
|
559
|
-
};
|
|
560
|
-
return createElement(as, {
|
|
561
|
-
className: composeClassName('ui-grid', `ui-grid--columns-${columns}`, `ui-grid--gap-${gap}`, className),
|
|
562
|
-
'data-columns': columns,
|
|
563
|
-
'data-ui-grid': true,
|
|
564
|
-
style: gridStyle,
|
|
565
|
-
...props
|
|
566
|
-
});
|
|
567
|
-
};
|
|
568
|
-
export const Stack = ({ align = 'stretch', as = 'div', className, direction = 'vertical', gap = 'md', justify = 'start', wrap = false, ...props }) => createElement(as, {
|
|
569
|
-
className: composeClassName('ui-stack', `ui-stack--${direction}`, `ui-stack--gap-${gap}`, `ui-stack--align-${align}`, `ui-stack--justify-${justify}`, wrap && 'ui-stack--wrap', className),
|
|
570
|
-
'data-direction': direction,
|
|
571
|
-
'data-ui-stack': true,
|
|
572
|
-
...props
|
|
573
|
-
});
|
|
574
|
-
export const VisuallyHidden = ({ className, focusable = false, ...props }) => (_jsx("span", { className: composeClassName('ui-visually-hidden', focusable && 'ui-visually-hidden--focusable', className), "data-ui-visually-hidden": true, ...props }));
|
|
575
707
|
export const Drawer = ({ className, glass = false, ...props }) => (_jsx("dialog", { className: composeClassName('ui-drawer', glassSurfaceClass('ui-drawer', glass), className), "data-surface": resolveSurface(glass), "data-ui-drawer": true, ...props }));
|
|
576
708
|
export const DropdownMenu = ({ children, className, defaultOpen, glass = false, onOpenChange, open, ...props }) => {
|
|
577
709
|
const menu = useDropdownMenu({ defaultOpen, onOpenChange, open });
|
|
@@ -595,6 +727,59 @@ export const DropdownMenuItem = ({ children, className, disabled = false, onClic
|
|
|
595
727
|
};
|
|
596
728
|
export const DropdownMenuSeparator = ({ className, ...props }) => (_jsx("div", { className: composeClassName('ui-menu__separator', className), role: props.role ?? 'separator', ...props }));
|
|
597
729
|
export const Empty = ({ className, glass = false, variant = 'default', ...props }) => (_jsx("section", { className: composeClassName('ui-empty', variant === 'compact' && 'ui-empty--compact', glassClass('ui-empty', glass), className), "data-variant": variant, ...props }));
|
|
730
|
+
const renderIllustrationElement = (element, index) => {
|
|
731
|
+
if (element.kind === 'circle') {
|
|
732
|
+
return _jsx("circle", { cx: element.cx, cy: element.cy, r: element.r }, index);
|
|
733
|
+
}
|
|
734
|
+
if (element.kind === 'rounded-rect') {
|
|
735
|
+
return (_jsx("rect", { height: element.height, rx: element.radius, width: element.width, x: element.x, y: element.y }, index));
|
|
736
|
+
}
|
|
737
|
+
const pointPairs = [];
|
|
738
|
+
for (let pointIndex = 0; pointIndex < element.points.length; pointIndex += 2) {
|
|
739
|
+
const x = element.points[pointIndex];
|
|
740
|
+
const y = element.points[pointIndex + 1];
|
|
741
|
+
if (x === undefined || y === undefined)
|
|
742
|
+
break;
|
|
743
|
+
pointPairs.push(`${x},${y}`);
|
|
744
|
+
}
|
|
745
|
+
return createElement(element.kind, { key: index, points: pointPairs.join(' ') });
|
|
746
|
+
};
|
|
747
|
+
export const Illustration = ({ className, label, size = 'md', tone = 'auto', variant = 'empty', ...props }) => (_jsx("span", { "aria-hidden": label ? undefined : true, "aria-label": label, className: composeClassName('ui-illustration', `ui-illustration--${variant}`, `ui-illustration--${tone}`, `ui-illustration--${size}`, className), role: label ? 'img' : undefined, ...props, children: _jsxs("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 120 120", children: [_jsx("circle", { className: "ui-illustration__wash", cx: "60", cy: "60", r: "48" }), lumenIllustrations[variant].elements.map(renderIllustrationElement)] }) }));
|
|
748
|
+
const resolveErrorStateAnnouncement = (announce, ariaLive, role) => {
|
|
749
|
+
if (announce === 'assertive') {
|
|
750
|
+
return { 'aria-live': ariaLive ?? 'assertive', role: role ?? 'alert' };
|
|
751
|
+
}
|
|
752
|
+
if (announce === 'polite') {
|
|
753
|
+
return { 'aria-live': ariaLive ?? 'polite', role: role ?? 'status' };
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
...(ariaLive ? { 'aria-live': ariaLive } : {}),
|
|
757
|
+
...(role ? { role } : {})
|
|
758
|
+
};
|
|
759
|
+
};
|
|
760
|
+
const ErrorStateGraphic = ({ graphic, kind, layout }) => {
|
|
761
|
+
if (graphic === false)
|
|
762
|
+
return null;
|
|
763
|
+
return (_jsx("div", { "aria-hidden": "true", className: "ui-error-state__graphic", "data-slot": "error-state-graphic", children: graphic ?? (_jsx(Illustration, { size: layout === 'compact' ? 'sm' : 'md', variant: kind })) }));
|
|
764
|
+
};
|
|
765
|
+
const ErrorStateContent = ({ children, description, headingLevel, reference, referenceLabel, title, titleId }) => (_jsxs("div", { className: "ui-error-state__content", "data-slot": "error-state-content", children: [createElement(`h${headingLevel}`, {
|
|
766
|
+
className: 'ui-error-state__title',
|
|
767
|
+
'data-slot': 'error-state-title',
|
|
768
|
+
id: titleId
|
|
769
|
+
}, title), description && (_jsx("p", { className: "ui-error-state__description", "data-slot": "error-state-description", children: description })), children && (_jsx("div", { className: "ui-error-state__details", "data-slot": "error-state-details", children: children })), reference && (_jsxs("p", { className: "ui-error-state__reference", "data-slot": "error-state-reference", children: [_jsxs("span", { children: [referenceLabel, ":"] }), ' ', _jsx("code", { children: reference })] }))] }));
|
|
770
|
+
const ErrorStateActions = ({ actions }) => actions ?
|
|
771
|
+
(_jsx("div", { className: "ui-error-state__actions", "data-slot": "error-state-actions", children: actions })) :
|
|
772
|
+
null;
|
|
773
|
+
export const ErrorState = ({ 'aria-live': ariaLive, actions, announce, children, className, description, graphic, headingLevel, id, kind, layout, reference, referenceLabel, role, title, ...props }) => {
|
|
774
|
+
const resolvedAnnounce = announce ?? 'off';
|
|
775
|
+
const resolvedHeadingLevel = headingLevel ?? 2;
|
|
776
|
+
const resolvedKind = kind ?? 'error';
|
|
777
|
+
const resolvedLayout = layout ?? 'default';
|
|
778
|
+
const resolvedReferenceLabel = referenceLabel ?? 'Reference';
|
|
779
|
+
const titleId = id ? `${id}-title` : undefined;
|
|
780
|
+
const announcementProps = resolveErrorStateAnnouncement(resolvedAnnounce, ariaLive, role);
|
|
781
|
+
return (_jsxs("section", { "aria-label": titleId ? undefined : title, "aria-labelledby": titleId, className: composeClassName('ui-error-state', `ui-error-state--${resolvedKind}`, `ui-error-state--${resolvedLayout}`, className), "data-kind": resolvedKind, "data-layout": resolvedLayout, "data-ui-error-state": true, id: id, ...announcementProps, ...props, children: [_jsx(ErrorStateGraphic, { graphic: graphic, kind: resolvedKind, layout: resolvedLayout }), _jsx(ErrorStateContent, { description: description, headingLevel: resolvedHeadingLevel, reference: reference, referenceLabel: resolvedReferenceLabel, title: title, titleId: titleId, children: children }), _jsx(ErrorStateActions, { actions: actions })] }));
|
|
782
|
+
};
|
|
598
783
|
export const KanbanBoard = ({ className, tabIndex = 0, ...props }) => (_jsx("section", { "aria-orientation": "horizontal", className: composeClassName('ui-kanban-board ui-kanban', className), "data-ui-kanban": true, tabIndex: tabIndex, ...props }));
|
|
599
784
|
export const KanbanColumn = ({ className, value, ...props }) => (_jsx("section", { className: composeClassName('ui-kanban__column', className), "data-ui-kanban-column": value, ...props }));
|
|
600
785
|
export const ErrorSummary = ({ className, errors, heading = 'There is a problem', id = 'ui-error-summary', ...props }) => {
|
|
@@ -629,8 +814,6 @@ export const Icon = ({ 'aria-hidden': ariaHidden, 'aria-label': ariaLabel, child
|
|
|
629
814
|
});
|
|
630
815
|
return (_jsx("span", { "aria-hidden": accessibility.ariaHidden, "aria-label": accessibility.ariaLabel, className: composeClassName('ui-icon', iconSizeClass(size), className), role: accessibility.role, ...props, children: icon ? renderNamedIcon(icon) : children }));
|
|
631
816
|
};
|
|
632
|
-
export const Input = ({ className, ref, type = 'text', visualSize = 'default', ...props }) => (_jsx("input", { className: composeClassName('ui-input', visualSize === 'sm' && 'ui-input--sm', visualSize === 'lg' && 'ui-input--lg', className), ref: ref, type: type, ...props }));
|
|
633
|
-
export const Label = ({ className, ...props }) => (_jsx("label", { className: composeClassName('ui-label', className), ...props }));
|
|
634
817
|
const getPasswordFieldDescribedBy = (ariaDescribedBy, hintId, errorId) => [ariaDescribedBy, hintId, errorId].filter(Boolean).join(' ') || undefined;
|
|
635
818
|
const usePasswordVisibility = (inputRef) => {
|
|
636
819
|
const [visible, setVisible] = useState(false);
|
|
@@ -725,10 +908,56 @@ const phoneInputSizeModifiers = (size) => {
|
|
|
725
908
|
}
|
|
726
909
|
return { inputClass: undefined, selectClass: undefined };
|
|
727
910
|
};
|
|
728
|
-
|
|
911
|
+
const getPhoneInputOptions = (locale) => locale === undefined ? {} : { locale };
|
|
912
|
+
const getBooleanAttribute = (value) => value ? true : undefined;
|
|
913
|
+
const getPhoneErrorId = (invalid, name) => (invalid ? `${name}-error` : undefined);
|
|
914
|
+
const PhoneInputError = ({ invalid, message, name }) => invalid ?
|
|
915
|
+
(_jsx("span", { className: "ui-visually-hidden", id: `${name}-error`, role: "alert", children: message })) :
|
|
916
|
+
null;
|
|
917
|
+
const MetadataPhoneInput = ({ className, countryOptions, countryLabel, countryName, defaultCountryValue, defaultValue, invalidNumberMessage, locale, name, onValueChange, placeholder, showValidationError, size, value, ...props }) => {
|
|
729
918
|
const { selectClass, inputClass } = phoneInputSizeModifiers(size);
|
|
919
|
+
const phoneOptions = useMemo(() => getPhoneInputOptions(locale), [locale]);
|
|
920
|
+
const metadataCountries = useMemo(() => countryOptions ?? getLumenPhoneCountries(phoneOptions), [countryOptions, phoneOptions]);
|
|
921
|
+
const initialCountry = useMemo(() => resolveReactPhoneInputCountry(metadataCountries, defaultCountryValue, locale, value), [defaultCountryValue, locale, metadataCountries, value]);
|
|
922
|
+
const [internalValue, setInternalValue] = useState(() => (defaultValue ?
|
|
923
|
+
resolveReactPhoneInputValue(metadataCountries, initialCountry, defaultValue, phoneOptions) :
|
|
924
|
+
{ country: initialCountry, e164: null, isValid: false, nationalNumber: '' }));
|
|
925
|
+
const phoneValue = value === undefined || value.country.regionCode === initialCountry.regionCode ?
|
|
926
|
+
value ?? internalValue :
|
|
927
|
+
resolveReactPhoneInputValue(metadataCountries, initialCountry, value.nationalNumber, phoneOptions);
|
|
928
|
+
const resolvedOptions = metadataCountries.map(country => ({
|
|
929
|
+
disabled: false,
|
|
930
|
+
label: country.pickerLabel,
|
|
931
|
+
value: country.regionCode
|
|
932
|
+
}));
|
|
933
|
+
const commitValue = (nextValue) => {
|
|
934
|
+
if (value === undefined)
|
|
935
|
+
setInternalValue(nextValue);
|
|
936
|
+
onValueChange?.(nextValue);
|
|
937
|
+
};
|
|
938
|
+
const handleCountryChange = (event) => {
|
|
939
|
+
const selectedCountry = metadataCountries.find(country => (country.regionCode === event.currentTarget.value ||
|
|
940
|
+
country.callingCode === event.currentTarget.value));
|
|
941
|
+
if (selectedCountry) {
|
|
942
|
+
commitValue(resolveLumenPhoneNumber(selectedCountry, phoneValue.nationalNumber, phoneOptions));
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
const handleNumberChange = (event) => {
|
|
946
|
+
commitValue(resolveReactPhoneInputValue(metadataCountries, phoneValue.country, event.currentTarget.value, phoneOptions));
|
|
947
|
+
};
|
|
948
|
+
const invalid = showValidationError && phoneValue.nationalNumber.length > 0 && !phoneValue.isValid;
|
|
949
|
+
return (_jsxs("div", { className: composeClassName('ui-phone-input ui-input-group', className), "data-invalid": getBooleanAttribute(invalid), ...props, children: [_jsx("select", { "aria-label": countryLabel, className: composeClassName('ui-select ui-phone-input__country', selectClass), name: countryName, onChange: handleCountryChange, value: phoneValue.country.regionCode, children: resolvedOptions.map(option => (_jsx("option", { disabled: option.disabled, value: option.value, children: option.label }, option.value))) }), _jsx("input", { autoComplete: "tel", "aria-errormessage": getPhoneErrorId(invalid, name), "aria-invalid": getBooleanAttribute(invalid), className: composeClassName('ui-input ui-phone-input__number', inputClass), inputMode: "tel", name: name, onChange: handleNumberChange, placeholder: placeholder, type: "tel", value: phoneValue.nationalNumber }), _jsx(PhoneInputError, { invalid: invalid, message: invalidNumberMessage, name: name })] }));
|
|
950
|
+
};
|
|
951
|
+
const LegacyPhoneInput = ({ className, countries, countryOptions: _countryOptions, countryLabel = 'Country code', countryName = 'country', defaultCountryValue, defaultValue, invalidNumberMessage: _invalidNumberMessage, locale: _locale, name = 'phone', onValueChange: _onValueChange, placeholder = 'Phone number', showValidationError: _showValidationError, size = 'default', value: _value, ...props }) => {
|
|
952
|
+
const { inputClass, selectClass } = phoneInputSizeModifiers(size);
|
|
730
953
|
return (_jsxs("div", { className: composeClassName('ui-phone-input ui-input-group', className), ...props, children: [_jsx("select", { "aria-label": countryLabel, className: composeClassName('ui-select ui-phone-input__country', selectClass), defaultValue: defaultCountryValue, name: countryName, children: countries.map(normalizeOption).map(option => (_jsx("option", { disabled: option.disabled, value: option.value, children: option.label }, option.value))) }), _jsx("input", { autoComplete: "tel", className: composeClassName('ui-input ui-phone-input__number', inputClass), defaultValue: defaultValue, inputMode: "tel", name: name, placeholder: placeholder, type: "tel" })] }));
|
|
731
954
|
};
|
|
955
|
+
export const PhoneInput = (props) => {
|
|
956
|
+
if (props.countries) {
|
|
957
|
+
return _jsx(LegacyPhoneInput, { ...props, countries: props.countries });
|
|
958
|
+
}
|
|
959
|
+
return (_jsx(MetadataPhoneInput, { ...props, countryLabel: props.countryLabel ?? 'Country code', countryName: props.countryName ?? 'country', defaultCountryValue: props.defaultCountryValue ?? 'US', invalidNumberMessage: props.invalidNumberMessage ?? 'Enter a complete phone number.', name: props.name ?? 'phone', placeholder: props.placeholder ?? 'Phone number', showValidationError: props.showValidationError ?? true, size: props.size ?? 'default' }));
|
|
960
|
+
};
|
|
732
961
|
export const NavigationMenu = ({ className, glass = false, variant = 'default', ...props }) => (_jsx("nav", { className: composeClassName('ui-navigation-menu', variant === 'unstyled' && 'ui-navigation-menu--unstyled', glassSurfaceClass('ui-navigation-menu', glass), className), "data-slot": "navigation-menu", "data-surface": resolveSurface(glass), "data-ui-navigation-menu": true, "data-variant": variant, ...props }));
|
|
733
962
|
export const ContextNavigation = ({ children, className, context, variant = 'default', ...props }) => (_jsxs("div", { className: composeClassName('ui-context-navigation', variant === 'unstyled' && 'ui-context-navigation--unstyled', className), "data-slot": "context-navigation", "data-variant": variant, ...props, children: [context && (_jsx("div", { className: "ui-context-navigation__context", "data-slot": "context-navigation-context", children: context })), children] }));
|
|
734
963
|
export const Pagination = ({ 'aria-label': ariaLabel = 'Pagination', className, ...props }) => (_jsx("nav", { "aria-label": ariaLabel, className: composeClassName('ui-pagination', className), ...props }));
|
|
@@ -744,12 +973,6 @@ export const PopoverPanel = ({ onKeyDown, ...props }) => {
|
|
|
744
973
|
const popover = requireContext(useContext(PopoverContext), 'PopoverPanel');
|
|
745
974
|
return (_jsx("div", { ...popover.panelProps, ...props, onKeyDown: composeHandlers(onKeyDown, popover.panelProps.onKeyDown) }));
|
|
746
975
|
};
|
|
747
|
-
export const Progress = ({ className, max = 100, value = 0, ...props }) => {
|
|
748
|
-
const safeMax = max > 0 ? max : 100;
|
|
749
|
-
const safeValue = Math.min(safeMax, Math.max(0, value));
|
|
750
|
-
const percentage = (safeValue / safeMax) * 100;
|
|
751
|
-
return (_jsx("div", { "aria-valuemax": safeMax, "aria-valuemin": 0, "aria-valuenow": safeValue, className: composeClassName('ui-progress', className), role: "progressbar", ...props, children: _jsx("span", { className: "ui-progress__bar", "data-slot": "progress-indicator", style: { width: `${percentage}%` } }) }));
|
|
752
|
-
};
|
|
753
976
|
export const RadioGroup = ({ className, ...props }) => (_jsx("fieldset", { className: composeClassName('ui-radio-group', className), "data-ui-radio-group": true, ...props }));
|
|
754
977
|
const renderResizablePane = (child, index, panelProps) => {
|
|
755
978
|
if (isValidElement(child)) {
|
|
@@ -1055,16 +1278,12 @@ export const ListBox = (inputProps) => {
|
|
|
1055
1278
|
(_jsx("p", { className: "ui-list-box__status", role: "status", children: loadingMessage })) :
|
|
1056
1279
|
null] }));
|
|
1057
1280
|
};
|
|
1058
|
-
export const Separator = ({ className, orientation = 'horizontal', ...props }) => (_jsx("hr", { "aria-orientation": orientation, className: composeClassName('ui-separator', `ui-separator--${orientation}`, className), "data-orientation": orientation, ...props }));
|
|
1059
1281
|
export const Sheet = ({ className, glass = false, ...props }) => (_jsx("dialog", { className: composeClassName('ui-sheet', glassSurfaceClass('ui-sheet', glass), className), "data-surface": resolveSurface(glass), "data-ui-sheet": true, ...props }));
|
|
1060
1282
|
export const Sidebar = ({ className, glass = false, variant = 'default', ...props }) => (_jsx("aside", { className: composeClassName('ui-sidebar', variant === 'unstyled' && 'ui-sidebar--unstyled', glassSurfaceClass('ui-sidebar', glass), className), "data-slot": "sidebar", "data-surface": resolveSurface(glass), "data-variant": variant, ...props }));
|
|
1061
|
-
export const Skeleton = ({ className, ...props }) => (_jsx("div", { className: composeClassName('ui-skeleton', className), ...props }));
|
|
1062
1283
|
export const Slider = ({ className, ref, type = 'range', ...props }) => (_jsx("input", { className: composeClassName('ui-slider', className), ref: ref, type: type, ...props }));
|
|
1063
|
-
export const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
return (_jsx("span", { "aria-hidden": ariaHidden ?? (isAccessible ? undefined : true), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className: composeClassName('ui-spinner', className), role: role ?? (isAccessible ? 'status' : undefined), ...props }));
|
|
1067
|
-
};
|
|
1284
|
+
export const ToastViewport = ({ 'aria-atomic': ariaAtomic = 'false', 'aria-label': ariaLabel = 'Notifications', 'aria-live': ariaLive = 'polite', className, maxCount = 3, placement = 'bottom-right', ...props }) => (_jsx("div", { "aria-atomic": ariaAtomic, "aria-label": ariaLabel, "aria-live": ariaLive, className: composeClassName('ui-tvp', className), "data-placement": placement, "data-ui-toast-viewport": true, "data-ui-toast-max": maxCount, ...props }));
|
|
1285
|
+
/** @deprecated Use ToastViewport instead. */
|
|
1286
|
+
export const Sonner = ({ className, ...props }) => (_jsx(ToastViewport, { className: composeClassName('ui-sonner', className), "data-ui-sonner": true, ...props }));
|
|
1068
1287
|
export const Switch = ({ className, ref, role = 'switch', ...props }) => (_jsx("input", { className: composeClassName('ui-switch', className), ref: ref, role: role, type: "checkbox", ...props }));
|
|
1069
1288
|
export const Table = ({ className, glass = false, ...props }) => (_jsx("div", { className: composeClassName('ui-table-wrap', glassClass('ui-table-wrap', glass), className), "data-slot": "table", ...props }));
|
|
1070
1289
|
export const Tabs = ({ children, className, defaultValue, glass = false, onValueChange, orientation, value, ...props }) => {
|
|
@@ -1134,7 +1353,6 @@ export const CodeTabs = ({ ariaLabel = 'Code examples', className, copy = true,
|
|
|
1134
1353
|
{ language: item.language }), theme: theme, variant: "block", wrap: wrap }) }, item.value)))] }));
|
|
1135
1354
|
};
|
|
1136
1355
|
export const TagGroup = ({ className, role = 'list', ...props }) => (_jsx("div", { className: composeClassName('ui-tag-group', className), role: role, ...props }));
|
|
1137
|
-
export const Textarea = ({ className, ref, rows = 4, ...props }) => (_jsx("textarea", { className: composeClassName('ui-textarea', className), ref: ref, rows: rows, ...props }));
|
|
1138
1356
|
export const ThemeBuilder = ({ className, glass = false, ...props }) => (_jsx("section", { className: composeClassName('ui-theme-builder', glassClass('ui-theme-builder', glass), className), "data-ui-theme-builder": true, ...props }));
|
|
1139
1357
|
export const TimeField = ({ className, ref, type = 'time', ...props }) => (_jsx("input", { className: composeClassName('ui-input ui-time-field', className), ref: ref, type: type, ...props }));
|
|
1140
1358
|
export const Toast = ({ 'aria-live': ariaLive, className, glass = false, role, variant = 'default', ...props }) => (_jsx("aside", { "aria-live": ariaLive ?? (variant === 'destructive' ? 'assertive' : 'polite'), className: composeClassName('ui-toast', variantClass('ui-toast', variant), glassSurfaceClass('ui-toast', glass), className), "data-surface": resolveSurface(glass), "data-ui-toast": true, "data-variant": variant, role: role ?? (variant === 'destructive' ? 'alert' : 'status'), ...props }));
|
|
@@ -1150,19 +1368,18 @@ export const TooltipContent = ({ ...props }) => {
|
|
|
1150
1368
|
};
|
|
1151
1369
|
export const Tree = ({ className, glass = false, role = 'tree', ...props }) => (_jsx("div", { className: composeClassName('ui-tree', glassClass('ui-tree', glass), className), role: role, ...props }));
|
|
1152
1370
|
export const TreeGrid = ({ className, glass = false, role = 'treegrid', ...props }) => (_jsx("div", { className: composeClassName('ui-tree-grid', glassClass('ui-tree-grid', glass), className), role: role, ...props }));
|
|
1153
|
-
export const Typography = ({ className, ...props }) => (_jsx("div", { className: composeClassName('ui-typography', className), ...props }));
|
|
1154
1371
|
export const VirtualList = ({ className, glass = false, itemSize, overscan, ...props }) => (_jsx("div", { className: composeClassName('ui-virtual-list', glassClass('ui-virtual-list', glass), className), "data-ui-item-size": itemSize, "data-ui-overscan": overscan, "data-ui-virtual-list": true, ...props }));
|
|
1155
1372
|
export const BackToTop = ({ className, type = 'button', ...props }) => (_jsx("button", { className: composeClassName('ui-back-to-top', className), type: type, ...props }));
|
|
1156
1373
|
export const Callout = ({ className, ...props }) => (_jsx("aside", { className: composeClassName('ui-callout', className), ...props }));
|
|
1157
1374
|
export const Eyebrow = ({ className, ...props }) => (_jsx("p", { className: composeClassName('ui-eyebrow', className), ...props }));
|
|
1158
1375
|
export const FloatingBadge = ({ className, ...props }) => (_jsx("span", { className: composeClassName('ui-floating-badge', className), ...props }));
|
|
1159
1376
|
export const FormattedDate = ({ className, ...props }) => (_jsx("time", { className: composeClassName('ui-formatted-date', className), ...props }));
|
|
1160
|
-
export const Image = ({ as, className, invertOnDark = false, loading, ...props }) => {
|
|
1377
|
+
export const Image = ({ as, className, fit = 'cover', invertOnDark = false, loading, radius = 'lg', ...props }) => {
|
|
1161
1378
|
const Component = as ?? 'img';
|
|
1162
1379
|
const resolvedLoading = loading ?? (as ? undefined : 'lazy');
|
|
1163
1380
|
return createElement(Component, {
|
|
1164
1381
|
...props,
|
|
1165
|
-
className: composeClassName('ui-image', invertOnDark && 'ui-image--invert-dark', className),
|
|
1382
|
+
className: composeClassName('ui-image', invertOnDark && 'ui-image--invert-dark', `ui-image--fit-${fit}`, `ui-image--radius-${radius}`, className),
|
|
1166
1383
|
...(resolvedLoading ? { loading: resolvedLoading } : {})
|
|
1167
1384
|
});
|
|
1168
1385
|
};
|
|
@@ -1374,7 +1591,6 @@ export const TimelineItem = ({ className, children, dot, ...props }) => (_jsxs("
|
|
|
1374
1591
|
export const AnimatedLogo = ({ animation = 'reveal', className, ...props }) => (_jsx("span", { className: composeClassName('ui-animated-logo', className), "data-animation": animation, "data-ui-animated-logo": true, ...props }));
|
|
1375
1592
|
export const Graphic = ({ children, className, label, size = 'md', tone = 'brand', variant = 'orbit', ...props }) => (_jsx("div", { "aria-hidden": label ? undefined : true, "aria-label": label, className: composeClassName('ui-graphic', `ui-graphic--${variant}`, `ui-graphic--${tone}`, `ui-graphic--${size}`, className), role: label ? 'img' : undefined, ...props, children: _jsx("div", { className: "ui-graphic__content", children: children }) }));
|
|
1376
1593
|
export const Backdrop = ({ children, className, intensity = 'medium', tone = 'brand', variant = 'aurora', ...props }) => (_jsx("div", { className: composeClassName('ui-backdrop', `ui-backdrop--${variant}`, `ui-backdrop--${tone}`, `ui-backdrop--${intensity}`, className), ...props, children: _jsx("div", { className: "ui-backdrop__content", children: children }) }));
|
|
1377
|
-
export const Illustration = ({ className, label, size = 'md', tone = 'auto', variant = 'empty', ...props }) => (_jsx("span", { "aria-hidden": label ? undefined : true, "aria-label": label, className: composeClassName('ui-illustration', `ui-illustration--${variant}`, `ui-illustration--${tone}`, `ui-illustration--${size}`, className), role: label ? 'img' : undefined, ...props, children: _jsxs("svg", { "aria-hidden": "true", fill: "none", viewBox: "0 0 120 120", children: [_jsx("circle", { className: "ui-illustration__wash", cx: "60", cy: "60", r: "48" }), variant === 'empty' && (_jsxs("g", { children: [_jsx("path", { d: "M32 48h56l-7 35H39l-7-35Z" }), _jsx("path", { d: "M43 48 49 36h22l6 12M47 66h26" })] })), variant === 'success' && (_jsxs("g", { children: [_jsx("circle", { cx: "60", cy: "60", r: "28" }), _jsx("path", { d: "m45 60 10 10 21-23" })] })), variant === 'error' && (_jsxs("g", { children: [_jsx("circle", { cx: "60", cy: "60", r: "28" }), _jsx("path", { d: "m49 49 22 22m0-22L49 71" })] })), variant === 'offline' && (_jsxs("g", { children: [_jsx("path", { d: "M37 74h44a14 14 0 0 0 1-28 23 23 0 0 0-42-4 16 16 0 0 0-3 32Z" }), _jsx("path", { d: "m38 34 44 52" })] }))] }) }));
|
|
1378
1594
|
export const AnimatedPortrait = ({ className, ...props }) => (_jsx("div", { className: composeClassName('ui-animated-portrait relative isolate w-full animate-reveal-lcp motion-reduce:animate-none', className), ...props }));
|
|
1379
1595
|
const getButtonLinkVariantClass = (variant) => {
|
|
1380
1596
|
if (variant === 'unstyled')
|