@rojaostudio/ds 2.0.0-next.3 → 2.0.0-next.30
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 +42 -2
- package/THIRD_PARTY_NOTICES.md +66 -0
- package/dist/components/avatar.d.ts +20 -12
- package/dist/components/avatar.js +8 -6
- package/dist/components/badge.d.ts +7 -6
- package/dist/components/badge.js +2 -1
- package/dist/components/breadcrumb.d.ts +4 -4
- package/dist/components/breadcrumb.js +1 -1
- package/dist/components/bubble.d.ts +26 -11
- package/dist/components/bubble.js +3 -3
- package/dist/components/button.d.ts +1 -1
- package/dist/components/card.d.ts +28 -12
- package/dist/components/card.js +4 -2
- package/dist/components/chart.d.ts +18 -8
- package/dist/components/chart.js +89 -25
- package/dist/components/choice-carousel.d.ts +1 -1
- package/dist/components/choice-carousel.js +2 -4
- package/dist/components/choice-list.d.ts +40 -0
- package/dist/components/choice-list.js +122 -0
- package/dist/components/choice-preview-card.d.ts +1 -7
- package/dist/components/color-input.d.ts +1 -1
- package/dist/components/context-menu.d.ts +5 -2
- package/dist/components/currency-input.d.ts +0 -2
- package/dist/components/data-table-header.d.ts +55 -18
- package/dist/components/data-table-header.js +148 -101
- package/dist/components/date-picker.d.ts +1 -1
- package/dist/components/dialog.d.ts +6 -3
- package/dist/components/dialog.js +2 -2
- package/dist/components/dropdown-menu.d.ts +5 -2
- package/dist/components/dropzone.d.ts +2 -2
- package/dist/components/dropzone.js +1 -1
- package/dist/components/file-input.d.ts +13 -8
- package/dist/components/file-input.js +24 -21
- package/dist/components/filter-chip.d.ts +11 -5
- package/dist/components/filter-chip.js +15 -6
- package/dist/components/floating-stepper.d.ts +11 -28
- package/dist/components/floating-stepper.js +2 -30
- package/dist/components/form-actions.d.ts +37 -15
- package/dist/components/form-actions.js +5 -14
- package/dist/components/heading.d.ts +42 -0
- package/dist/components/heading.js +25 -0
- package/dist/components/icon-button.d.ts +1 -1
- package/dist/components/image-crop-dialog.d.ts +60 -0
- package/dist/components/image-crop-dialog.js +240 -0
- package/dist/components/image-crop-modal.d.ts +12 -55
- package/dist/components/image-crop-modal.js +2 -249
- package/dist/components/image-upload.d.ts +8 -17
- package/dist/components/image-upload.js +3 -3
- package/dist/components/index.d.ts +15 -10
- package/dist/components/index.js +10 -0
- package/dist/components/internal/bottom-bar.d.ts +30 -0
- package/dist/components/internal/bottom-bar.js +25 -0
- package/dist/components/internal/button.d.ts +1 -1
- package/dist/components/internal/icons.d.ts +9 -1
- package/dist/components/internal/icons.js +16 -0
- package/dist/components/internal/menu.d.ts +3 -2
- package/dist/components/internal/menu.js +1 -1
- package/dist/components/internal/modal.js +9 -0
- package/dist/components/internal/toggle.d.ts +1 -1
- package/dist/components/internal/use-on-screen-keyboard.d.ts +12 -0
- package/dist/components/internal/use-on-screen-keyboard.js +49 -0
- package/dist/components/item.d.ts +14 -7
- package/dist/components/item.js +5 -2
- package/dist/components/loading-overlay.d.ts +43 -0
- package/dist/components/loading-overlay.js +81 -0
- package/dist/components/marker.d.ts +11 -3
- package/dist/components/marker.js +4 -3
- package/dist/components/number-input.d.ts +1 -1
- package/dist/components/progress.d.ts +3 -3
- package/dist/components/progress.js +2 -2
- package/dist/components/row-actions.d.ts +3 -0
- package/dist/components/row-actions.js +8 -4
- package/dist/components/saving-bar.d.ts +36 -10
- package/dist/components/saving-bar.js +14 -6
- package/dist/components/section-header.d.ts +4 -3
- package/dist/components/selectable-card.d.ts +2 -10
- package/dist/components/sidebar.d.ts +8 -11
- package/dist/components/sidebar.js +4 -5
- package/dist/components/spinner.d.ts +9 -6
- package/dist/components/spinner.js +3 -3
- package/dist/components/star-rating.d.ts +3 -3
- package/dist/components/star-rating.js +2 -2
- package/dist/components/stat.d.ts +18 -6
- package/dist/components/stat.js +9 -3
- package/dist/components/status.d.ts +4 -4
- package/dist/components/status.js +2 -2
- package/dist/components/stepper.d.ts +33 -0
- package/dist/components/stepper.js +36 -0
- package/dist/components/summary-bar.d.ts +3 -2
- package/dist/components/summary-bar.js +10 -1
- package/dist/components/tile.d.ts +5 -5
- package/dist/components/tile.js +2 -2
- package/dist/components/time-picker.d.ts +1 -1
- package/dist/components/toast.d.ts +17 -6
- package/dist/components/toast.js +5 -3
- package/dist/components/toggle-card-compact.d.ts +6 -25
- package/dist/components/toggle-card-compact.js +8 -35
- package/dist/components/toggle-card.d.ts +23 -9
- package/dist/components/toggle-card.js +38 -2
- package/dist/components/toggle.d.ts +1 -1
- package/dist/components/typing-indicator.d.ts +2 -2
- package/dist/components/typing-indicator.js +1 -1
- package/package.json +4 -4
- package/styles/base.css +13 -1
- package/styles/rds/components-styles.css +767 -281
- package/styles/rds/components.css +56 -31
- package/styles/rds/foundation.css +1 -1
- package/styles/rds/theme.css +40 -29
- package/styles/rds.css +1 -1
package/dist/components/chart.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
__spreadValues
|
|
6
6
|
} from "../chunk-ORMEWXMH.js";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { useId, useState } from "react";
|
|
8
|
+
import { useId, useMemo, useState } from "react";
|
|
9
9
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./table.js";
|
|
10
10
|
const compact = new Intl.NumberFormat("pt-BR", { notation: "compact", maximumFractionDigits: 1 });
|
|
11
11
|
const defaultFormat = (value) => compact.format(value);
|
|
@@ -25,6 +25,20 @@ function scaleOf(values) {
|
|
|
25
25
|
const max = min + step * 4;
|
|
26
26
|
return { min, max, ticks: [4, 3, 2, 1, 0].map((i) => min + step * i) };
|
|
27
27
|
}
|
|
28
|
+
const SAFE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
29
|
+
function safeHref(href) {
|
|
30
|
+
if (!href) return void 0;
|
|
31
|
+
if (href.startsWith("#")) return href;
|
|
32
|
+
try {
|
|
33
|
+
const base = typeof window !== "undefined" && SAFE_PROTOCOLS.has(window.location.protocol) ? window.location.href : "https://example.invalid/";
|
|
34
|
+
if (SAFE_PROTOCOLS.has(new URL(href, base).protocol)) return href;
|
|
35
|
+
} catch (e) {
|
|
36
|
+
}
|
|
37
|
+
if (process.env.NODE_ENV !== "production") {
|
|
38
|
+
console.warn(`Chart: href "${href}" ignored. Only http(s) URLs, relative paths and #fragments are followed.`);
|
|
39
|
+
}
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
28
42
|
function Chart(_a) {
|
|
29
43
|
var _b = _a, {
|
|
30
44
|
label,
|
|
@@ -36,7 +50,11 @@ function Chart(_a) {
|
|
|
36
50
|
showRightAxis = true,
|
|
37
51
|
showLegend = true,
|
|
38
52
|
showTooltip = true,
|
|
39
|
-
|
|
53
|
+
dates,
|
|
54
|
+
dateEvery,
|
|
55
|
+
showAllDates,
|
|
56
|
+
hrefs: hrefsProp,
|
|
57
|
+
onSelect,
|
|
40
58
|
showTable = false,
|
|
41
59
|
height = 200,
|
|
42
60
|
className
|
|
@@ -50,13 +68,18 @@ function Chart(_a) {
|
|
|
50
68
|
"showRightAxis",
|
|
51
69
|
"showLegend",
|
|
52
70
|
"showTooltip",
|
|
71
|
+
"dates",
|
|
72
|
+
"dateEvery",
|
|
53
73
|
"showAllDates",
|
|
74
|
+
"hrefs",
|
|
75
|
+
"onSelect",
|
|
54
76
|
"showTable",
|
|
55
77
|
"height",
|
|
56
78
|
"className"
|
|
57
79
|
]);
|
|
58
80
|
var _a2;
|
|
59
81
|
const [active, setActive] = useState(null);
|
|
82
|
+
const hrefs = useMemo(() => hrefsProp == null ? void 0 : hrefsProp.map(safeHref), [hrefsProp]);
|
|
60
83
|
const tooltipId = useId();
|
|
61
84
|
const count = labels.length;
|
|
62
85
|
const shown = type === "bar" ? series.slice(0, 1) : series.slice(0, 5);
|
|
@@ -78,7 +101,17 @@ function Chart(_a) {
|
|
|
78
101
|
return `${s.name} ${formatFor(s)((_a3 = s.data[index]) != null ? _a3 : 0)}`;
|
|
79
102
|
}).join(", ");
|
|
80
103
|
const legendName = (s) => dual ? `${s.name} (${onRight(s) ? "direita" : "esquerda"})` : s.name;
|
|
81
|
-
const
|
|
104
|
+
const every = dateEvery && dateEvery > 1 ? Math.floor(dateEvery) : null;
|
|
105
|
+
const allDates = (dates != null ? dates : showAllDates === void 0 ? "edges" : showAllDates ? "all" : "edges") === "all";
|
|
106
|
+
const labelIndexes = every ? labels.map((_, i) => i).filter((i) => i % every === 0) : allDates || count <= 3 ? labels.map((_, i) => i) : [0, Math.floor((count - 1) / 2), count - 1];
|
|
107
|
+
const linked = type !== "line" && Boolean(onSelect || (hrefs == null ? void 0 : hrefs.some(Boolean)));
|
|
108
|
+
const choose = (index) => {
|
|
109
|
+
if (onSelect) onSelect(index);
|
|
110
|
+
else {
|
|
111
|
+
const href = safeHref(hrefs == null ? void 0 : hrefs[index]);
|
|
112
|
+
if (href) window.location.assign(href);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
82
115
|
const onPointerMove = (event) => {
|
|
83
116
|
const box = event.currentTarget.getBoundingClientRect();
|
|
84
117
|
const ratio = Math.min(1, Math.max(0, (event.clientX - box.left) / box.width));
|
|
@@ -94,6 +127,11 @@ function Chart(_a) {
|
|
|
94
127
|
Home: 0,
|
|
95
128
|
End: count - 1
|
|
96
129
|
};
|
|
130
|
+
if (linked && event.key === "Enter" && active !== null) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
choose(active);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
97
135
|
if (!(event.key in keys)) return;
|
|
98
136
|
event.preventDefault();
|
|
99
137
|
setActive(keys[event.key]);
|
|
@@ -133,6 +171,7 @@ function Chart(_a) {
|
|
|
133
171
|
onPointerLeave: (event) => {
|
|
134
172
|
if (document.activeElement !== event.currentTarget) setActive(null);
|
|
135
173
|
},
|
|
174
|
+
onClick: linked ? () => active !== null && choose(active) : void 0,
|
|
136
175
|
onFocus: () => setActive((current) => current != null ? current : 0),
|
|
137
176
|
onBlur: () => setActive(null),
|
|
138
177
|
onKeyDown
|
|
@@ -142,19 +181,37 @@ function Chart(_a) {
|
|
|
142
181
|
if (type === "bar") {
|
|
143
182
|
const s = shown[0];
|
|
144
183
|
const top = Math.max(0, ...(_a2 = s == null ? void 0 : s.data) != null ? _a2 : [0]);
|
|
145
|
-
body = /* @__PURE__ */ jsx("div", { className: "rds-chart__bars", "aria-hidden":
|
|
184
|
+
body = /* @__PURE__ */ jsx("div", { className: "rds-chart__bars", "aria-hidden": linked ? void 0 : true, children: labels.map((name, i) => {
|
|
146
185
|
var _a3, _b2;
|
|
147
|
-
|
|
186
|
+
const value = s ? formatLeft((_a3 = s.data[i]) != null ? _a3 : 0) : "";
|
|
187
|
+
const parts = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
148
188
|
/* @__PURE__ */ jsx("span", { className: "rds-chart__bar-label", children: name }),
|
|
149
189
|
/* @__PURE__ */ jsx("span", { className: "rds-chart__track", children: /* @__PURE__ */ jsx(
|
|
150
190
|
"span",
|
|
151
191
|
{
|
|
152
192
|
className: "rds-chart__bar",
|
|
153
|
-
style: __spreadProps(__spreadValues({}, seriesStyle(i + 1)), { width: `${top ? ((
|
|
193
|
+
style: __spreadProps(__spreadValues({}, seriesStyle(i + 1)), { width: `${top ? ((_b2 = s == null ? void 0 : s.data[i]) != null ? _b2 : 0) / top * 100 : 0}%` })
|
|
154
194
|
}
|
|
155
195
|
) }),
|
|
156
|
-
/* @__PURE__ */ jsx("span", { className: "rds-chart__bar-value", children:
|
|
157
|
-
] }
|
|
196
|
+
/* @__PURE__ */ jsx("span", { className: "rds-chart__bar-value", children: value })
|
|
197
|
+
] });
|
|
198
|
+
const href = hrefs == null ? void 0 : hrefs[i];
|
|
199
|
+
const accessibleName = `${name}: ${value}`;
|
|
200
|
+
if (linked && href && !onSelect)
|
|
201
|
+
return /* @__PURE__ */ jsx("a", { href, className: "rds-chart__bar-row rds-chart__bar-row--link", "aria-label": accessibleName, children: parts }, name);
|
|
202
|
+
if (linked && onSelect)
|
|
203
|
+
return /* @__PURE__ */ jsx(
|
|
204
|
+
"button",
|
|
205
|
+
{
|
|
206
|
+
type: "button",
|
|
207
|
+
className: "rds-chart__bar-row rds-chart__bar-row--link",
|
|
208
|
+
"aria-label": accessibleName,
|
|
209
|
+
onClick: () => onSelect(i),
|
|
210
|
+
children: parts
|
|
211
|
+
},
|
|
212
|
+
name
|
|
213
|
+
);
|
|
214
|
+
return /* @__PURE__ */ jsx("div", { className: "rds-chart__bar-row", children: parts }, name);
|
|
158
215
|
}) });
|
|
159
216
|
} else {
|
|
160
217
|
body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -208,7 +265,10 @@ function Chart(_a) {
|
|
|
208
265
|
] })),
|
|
209
266
|
rightScale && /* @__PURE__ */ jsx(Axis, { ticks: rightScale.ticks, format: formatRight, side: "right" })
|
|
210
267
|
] }),
|
|
211
|
-
/* @__PURE__ */ jsx("div", { className: "rds-chart__labels", "aria-hidden": "true", children: /* @__PURE__ */
|
|
268
|
+
/* @__PURE__ */ jsx("div", { className: "rds-chart__labels", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("div", { className: `rds-chart__labels-track rds-chart__labels-track--${type}${every ? " rds-chart__labels-track--ticks" : ""}`, children: [
|
|
269
|
+
every && labels.map((_, i) => /* @__PURE__ */ jsx("i", { className: "rds-chart__tick", style: { left: `${x(i)}%` } }, `t${i}`)),
|
|
270
|
+
labelIndexes.map((i) => /* @__PURE__ */ jsx("span", { className: "rds-chart__label", style: { left: `${x(i)}%` }, children: labels[i] }, i))
|
|
271
|
+
] }) })
|
|
212
272
|
] });
|
|
213
273
|
}
|
|
214
274
|
const firstColumn = type === "line" ? "Data" : "Categoria";
|
|
@@ -216,7 +276,7 @@ function Chart(_a) {
|
|
|
216
276
|
"figure",
|
|
217
277
|
__spreadProps(__spreadValues({}, rest), {
|
|
218
278
|
"aria-label": label,
|
|
219
|
-
className: ["rds-chart", `rds-chart--${type}`, dual && "rds-chart--dual", className].filter(Boolean).join(" "),
|
|
279
|
+
className: ["rds-chart", `rds-chart--${type}`, dual && "rds-chart--dual", linked && "rds-chart--linked", className].filter(Boolean).join(" "),
|
|
220
280
|
children: [
|
|
221
281
|
body,
|
|
222
282
|
showLegend && type !== "bar" && /* @__PURE__ */ jsx("ul", { className: "rds-chart__legend", "aria-hidden": "true", children: shown.map((s, n) => /* @__PURE__ */ jsxs("li", { children: [
|
|
@@ -229,26 +289,30 @@ function Chart(_a) {
|
|
|
229
289
|
shown.map((s) => /* @__PURE__ */ jsx(TableHead, { align: "end", children: legendName(s) }, s.name))
|
|
230
290
|
] }) }),
|
|
231
291
|
/* @__PURE__ */ jsx(TableBody, { children: labels.map((name, i) => /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
232
|
-
/* @__PURE__ */ jsx(TableCell, { children: name }),
|
|
292
|
+
/* @__PURE__ */ jsx(TableCell, { children: linked && onSelect ? /* @__PURE__ */ jsx("button", { type: "button", className: "rds-chart__table-link", onClick: () => onSelect(i), children: name }) : linked && (hrefs == null ? void 0 : hrefs[i]) ? /* @__PURE__ */ jsx("a", { className: "rds-chart__table-link", href: hrefs[i], children: name }) : name }),
|
|
233
293
|
shown.map((s) => {
|
|
234
294
|
var _a3;
|
|
235
295
|
return /* @__PURE__ */ jsx(TableCell, { align: "end", children: formatFor(s)((_a3 = s.data[i]) != null ? _a3 : 0) }, s.name);
|
|
236
296
|
})
|
|
237
297
|
] }, name)) })
|
|
238
|
-
] }) :
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
298
|
+
] }) : (
|
|
299
|
+
// The clip goes on a wrapper: a <table> ignores the 1px box and overflow of .rds-visually-hidden, so it
|
|
300
|
+
// kept its full size, anchored to the page and stretched the page scroll.
|
|
301
|
+
/* @__PURE__ */ jsx("div", { className: "rds-visually-hidden", children: /* @__PURE__ */ jsxs("table", { children: [
|
|
302
|
+
/* @__PURE__ */ jsx("caption", { children: label }),
|
|
303
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
304
|
+
/* @__PURE__ */ jsx("th", { scope: "col", children: firstColumn }),
|
|
305
|
+
shown.map((s) => /* @__PURE__ */ jsx("th", { scope: "col", children: legendName(s) }, s.name))
|
|
306
|
+
] }) }),
|
|
307
|
+
/* @__PURE__ */ jsx("tbody", { children: labels.map((name, i) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
308
|
+
/* @__PURE__ */ jsx("th", { scope: "row", children: name }),
|
|
309
|
+
shown.map((s) => {
|
|
310
|
+
var _a3;
|
|
311
|
+
return /* @__PURE__ */ jsx("td", { children: formatFor(s)((_a3 = s.data[i]) != null ? _a3 : 0) }, s.name);
|
|
312
|
+
})
|
|
313
|
+
] }, name)) })
|
|
314
|
+
] }) })
|
|
315
|
+
)
|
|
252
316
|
]
|
|
253
317
|
})
|
|
254
318
|
);
|
|
@@ -18,7 +18,7 @@ interface ChoiceCarouselProps<T> {
|
|
|
18
18
|
/**
|
|
19
19
|
* ChoiceCarousel — a horizontal, scroll-snapped row of options to pick one (radiogroup) or several (group of
|
|
20
20
|
* checkboxes); the options are drawn by `renderCard`. On a wide screen two outline IconButtons (with their Tooltips)
|
|
21
|
-
* scroll it by one option; the arrow keys do the same on the row. Styles: choice-carousel.css.
|
|
21
|
+
* scroll it by one option, each one there only while there is more that way; the arrow keys do the same on the row. Styles: choice-carousel.css.
|
|
22
22
|
*/
|
|
23
23
|
declare function ChoiceCarousel<T>({ options, getKey, renderCard, value, onChange, multiple, ariaLabel, isDisabled, }: ChoiceCarouselProps<T>): react.JSX.Element;
|
|
24
24
|
|
|
@@ -75,7 +75,7 @@ function ChoiceCarousel({
|
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
return /* @__PURE__ */ jsxs("div", { className: "rds-choice-carousel", children: [
|
|
78
|
-
/* @__PURE__ */ jsx(Tooltip, { text: "Anterior", children: /* @__PURE__ */ jsx(
|
|
78
|
+
canScrollLeft && /* @__PURE__ */ jsx(Tooltip, { text: "Anterior", children: /* @__PURE__ */ jsx(
|
|
79
79
|
IconButton,
|
|
80
80
|
{
|
|
81
81
|
className: "rds-choice-carousel__arrow rds-choice-carousel__arrow--prev",
|
|
@@ -84,7 +84,6 @@ function ChoiceCarousel({
|
|
|
84
84
|
variant: "outline",
|
|
85
85
|
tone: "neutral",
|
|
86
86
|
onClick: () => scrollByAmount(-1),
|
|
87
|
-
disabled: !canScrollLeft,
|
|
88
87
|
tabIndex: -1
|
|
89
88
|
}
|
|
90
89
|
) }),
|
|
@@ -123,7 +122,7 @@ function ChoiceCarousel({
|
|
|
123
122
|
})
|
|
124
123
|
}
|
|
125
124
|
),
|
|
126
|
-
/* @__PURE__ */ jsx(Tooltip, { text: "Pr\xF3ximo", children: /* @__PURE__ */ jsx(
|
|
125
|
+
canScrollRight && /* @__PURE__ */ jsx(Tooltip, { text: "Pr\xF3ximo", children: /* @__PURE__ */ jsx(
|
|
127
126
|
IconButton,
|
|
128
127
|
{
|
|
129
128
|
className: "rds-choice-carousel__arrow rds-choice-carousel__arrow--next",
|
|
@@ -132,7 +131,6 @@ function ChoiceCarousel({
|
|
|
132
131
|
variant: "outline",
|
|
133
132
|
tone: "neutral",
|
|
134
133
|
onClick: () => scrollByAmount(1),
|
|
135
|
-
disabled: !canScrollRight,
|
|
136
134
|
tabIndex: -1
|
|
137
135
|
}
|
|
138
136
|
) })
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ChoiceListProps extends Omit<ComponentPropsWithRef<'ul'>, 'children' | 'defaultValue' | 'onChange'> {
|
|
5
|
+
/** The ChoiceListItems (Figma: the slot `items`). */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** Controlled: the chosen row's value. */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Uncontrolled: the row chosen at first. */
|
|
10
|
+
defaultValue?: string;
|
|
11
|
+
onValueChange?: (value: string) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* ChoiceList — Figma [RDS] Content/ChoiceList. A dense list to choose one thing from: a client, a product, an
|
|
15
|
+
* order. Each row is media, a title, a muted description and a trailing value; a line under each row, dozens on
|
|
16
|
+
* screen. One chosen at a time, marked by the tint and a bar on the left (role listbox, aria-selected). The list
|
|
17
|
+
* takes the focus: the arrows move the active row past disabled ones, Home and End go to the ends, Enter or Space
|
|
18
|
+
* choose, a click chooses. Name it with aria-label or aria-labelledby. Styles: choice-list.css.
|
|
19
|
+
*
|
|
20
|
+
* Not for 2 to 4 options that need an explanation (ChoiceCard), nor for a list that only shows (Item).
|
|
21
|
+
*/
|
|
22
|
+
declare function ChoiceList({ children, value, defaultValue, onValueChange, className, onKeyDown, onFocus, ref, ...rest }: ChoiceListProps): react.JSX.Element;
|
|
23
|
+
interface ChoiceListItemProps {
|
|
24
|
+
/** The value it stands for. */
|
|
25
|
+
value: string;
|
|
26
|
+
/** The name, one line (Figma: `title`). It is the row's accessible name. */
|
|
27
|
+
title: ReactNode;
|
|
28
|
+
/** One muted line under the title (Figma: `showDescription` + `description`). */
|
|
29
|
+
description?: ReactNode;
|
|
30
|
+
/** An Avatar for a person, a Tile for a thing, 32 (Figma: `showMedia` + `media`). Decorative: hidden from screen readers. */
|
|
31
|
+
media?: ReactNode;
|
|
32
|
+
/** A value or a date on the right (Figma: `showTrailing` + `trailing`). */
|
|
33
|
+
trailing?: ReactNode;
|
|
34
|
+
/** Cannot be chosen now: skipped by the arrows, read as unavailable. */
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** One row of the ChoiceList (Figma: .choice-list/item). The whole row is the target. */
|
|
38
|
+
declare function ChoiceListItem({ value, title, description, media, trailing, disabled }: ChoiceListItemProps): react.JSX.Element;
|
|
39
|
+
|
|
40
|
+
export { ChoiceList, ChoiceListItem, type ChoiceListItemProps, type ChoiceListProps };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
__objRest,
|
|
4
|
+
__spreadProps,
|
|
5
|
+
__spreadValues
|
|
6
|
+
} from "../chunk-ORMEWXMH.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import {
|
|
9
|
+
createContext,
|
|
10
|
+
useContext,
|
|
11
|
+
useId,
|
|
12
|
+
useRef,
|
|
13
|
+
useState
|
|
14
|
+
} from "react";
|
|
15
|
+
import { warnIfUnlabelled } from "./internal/field.js";
|
|
16
|
+
const ChoiceListContext = createContext(null);
|
|
17
|
+
function ChoiceList(_a) {
|
|
18
|
+
var _b = _a, { children, value, defaultValue, onValueChange, className, onKeyDown, onFocus, ref } = _b, rest = __objRest(_b, ["children", "value", "defaultValue", "onValueChange", "className", "onKeyDown", "onFocus", "ref"]);
|
|
19
|
+
warnIfUnlabelled("ChoiceList", void 0, rest["aria-label"], rest["aria-labelledby"]);
|
|
20
|
+
const [own, setOwn] = useState(defaultValue);
|
|
21
|
+
const selected = value !== void 0 ? value : own;
|
|
22
|
+
const [activeId, setActiveId] = useState(null);
|
|
23
|
+
const list = useRef(null);
|
|
24
|
+
const rows = () => {
|
|
25
|
+
var _a2, _b2;
|
|
26
|
+
return Array.from((_b2 = (_a2 = list.current) == null ? void 0 : _a2.querySelectorAll('[role="option"]')) != null ? _b2 : []).filter(
|
|
27
|
+
(o) => o.getAttribute("aria-disabled") !== "true"
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
function choose(next) {
|
|
31
|
+
if (value === void 0) setOwn(next);
|
|
32
|
+
onValueChange == null ? void 0 : onValueChange(next);
|
|
33
|
+
}
|
|
34
|
+
function activate(row) {
|
|
35
|
+
if (!row) return;
|
|
36
|
+
setActiveId(row.id);
|
|
37
|
+
row.scrollIntoView({ block: "nearest" });
|
|
38
|
+
}
|
|
39
|
+
function keyDown(event) {
|
|
40
|
+
var _a2;
|
|
41
|
+
onKeyDown == null ? void 0 : onKeyDown(event);
|
|
42
|
+
if (event.defaultPrevented) return;
|
|
43
|
+
const all = rows();
|
|
44
|
+
const index = all.findIndex((o) => o.id === activeId);
|
|
45
|
+
const moves = {
|
|
46
|
+
ArrowDown: () => all[Math.min(index + 1, all.length - 1)],
|
|
47
|
+
ArrowUp: () => all[Math.max(index - 1, 0)],
|
|
48
|
+
Home: () => all[0],
|
|
49
|
+
End: () => all[all.length - 1]
|
|
50
|
+
};
|
|
51
|
+
if (moves[event.key]) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
activate(moves[event.key]());
|
|
54
|
+
} else if ((event.key === "Enter" || event.key === " ") && index >= 0) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
choose((_a2 = all[index].dataset.value) != null ? _a2 : "");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function setRef(node) {
|
|
60
|
+
list.current = node;
|
|
61
|
+
if (typeof ref === "function") ref(node);
|
|
62
|
+
else if (ref) ref.current = node;
|
|
63
|
+
}
|
|
64
|
+
return /* @__PURE__ */ jsx(ChoiceListContext.Provider, { value: { selected, activeId, setActiveId, choose }, children: /* @__PURE__ */ jsx(
|
|
65
|
+
"ul",
|
|
66
|
+
__spreadProps(__spreadValues({
|
|
67
|
+
tabIndex: 0
|
|
68
|
+
}, rest), {
|
|
69
|
+
ref: setRef,
|
|
70
|
+
role: "listbox",
|
|
71
|
+
"aria-activedescendant": activeId != null ? activeId : void 0,
|
|
72
|
+
className: ["rds-choice-list", className].filter(Boolean).join(" "),
|
|
73
|
+
onKeyDown: keyDown,
|
|
74
|
+
onFocus: (event) => {
|
|
75
|
+
var _a2;
|
|
76
|
+
onFocus == null ? void 0 : onFocus(event);
|
|
77
|
+
if (activeId && document.getElementById(activeId)) return;
|
|
78
|
+
const all = rows();
|
|
79
|
+
activate((_a2 = all.find((o) => o.dataset.value === selected)) != null ? _a2 : all[0]);
|
|
80
|
+
},
|
|
81
|
+
children
|
|
82
|
+
})
|
|
83
|
+
) });
|
|
84
|
+
}
|
|
85
|
+
function ChoiceListItem({ value, title, description, media, trailing, disabled }) {
|
|
86
|
+
const context = useContext(ChoiceListContext);
|
|
87
|
+
const id = useId();
|
|
88
|
+
if (!context) throw new Error("[@rojaostudio/ds] ChoiceListItem goes inside a ChoiceList.");
|
|
89
|
+
const selected = context.selected === value;
|
|
90
|
+
const describedBy = [description != null && `${id}-description`, trailing != null && `${id}-trailing`].filter(Boolean).join(" ");
|
|
91
|
+
return /* @__PURE__ */ jsxs(
|
|
92
|
+
"li",
|
|
93
|
+
{
|
|
94
|
+
id,
|
|
95
|
+
role: "option",
|
|
96
|
+
"data-value": value,
|
|
97
|
+
"aria-selected": selected,
|
|
98
|
+
"aria-disabled": disabled || void 0,
|
|
99
|
+
"aria-labelledby": `${id}-title`,
|
|
100
|
+
"aria-describedby": describedBy || void 0,
|
|
101
|
+
"data-active": context.activeId === id ? "" : void 0,
|
|
102
|
+
className: "rds-choice-list__item",
|
|
103
|
+
onClick: () => {
|
|
104
|
+
if (disabled) return;
|
|
105
|
+
context.setActiveId(id);
|
|
106
|
+
context.choose(value);
|
|
107
|
+
},
|
|
108
|
+
children: [
|
|
109
|
+
media != null && /* @__PURE__ */ jsx("span", { className: "rds-choice-list__media", "aria-hidden": "true", children: media }),
|
|
110
|
+
/* @__PURE__ */ jsxs("span", { className: "rds-choice-list__content", children: [
|
|
111
|
+
/* @__PURE__ */ jsx("span", { id: `${id}-title`, className: "rds-choice-list__title", children: title }),
|
|
112
|
+
description != null && /* @__PURE__ */ jsx("span", { id: `${id}-description`, className: "rds-choice-list__description", children: description })
|
|
113
|
+
] }),
|
|
114
|
+
trailing != null && /* @__PURE__ */ jsx("span", { id: `${id}-trailing`, className: "rds-choice-list__trailing", children: trailing })
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
ChoiceList,
|
|
121
|
+
ChoiceListItem
|
|
122
|
+
};
|
|
@@ -9,18 +9,12 @@ interface ChoicePreviewCardProps {
|
|
|
9
9
|
preview: ReactNode;
|
|
10
10
|
label: string;
|
|
11
11
|
description?: string;
|
|
12
|
-
/** Ignored: the ChoiceCard has no locked state. */
|
|
13
|
-
locked?: boolean;
|
|
14
12
|
disabled?: boolean;
|
|
15
|
-
/** Ignored: the ChoiceCard has no badge on the picture. */
|
|
16
|
-
badge?: ReactNode;
|
|
17
|
-
/** Ignored: the picture is always 16:9. */
|
|
18
|
-
previewAspect?: 'square' | 'video' | 'wide';
|
|
19
13
|
className?: string;
|
|
20
14
|
}
|
|
21
15
|
/**
|
|
22
16
|
* @deprecated Use ChoiceCard with layout="preview" (Figma [RDS] Content/ChoiceCard). A thin wrapper over it: `label`
|
|
23
|
-
* is the children. It is a native radio now, not a toggle button
|
|
17
|
+
* is the children. It is a native radio now, not a toggle button (`locked`, `badge` and `previewAspect` left in 2.0).
|
|
24
18
|
*/
|
|
25
19
|
declare function ChoicePreviewCard({ selected, onSelect, preview, label, description, disabled, className }: ChoicePreviewCardProps): react.JSX.Element;
|
|
26
20
|
|
|
@@ -35,7 +35,7 @@ declare function normalizeHex(text: string): string | null;
|
|
|
35
35
|
/**
|
|
36
36
|
* ColorInput — Figma [RDS] Forms/ColorInput. One colour, chosen or typed: the swatch shows it and the hex beside it
|
|
37
37
|
* is editable (#RRGGBB, with or without #). The swatch opens a popover with the palette the caller passes (Figma:
|
|
38
|
-
*
|
|
38
|
+
* open=true); without one, the system's colour picker. Enter or leaving the field confirms the hex; an invalid hex
|
|
39
39
|
* goes back to the last valid one. The swatch's colour is the person's data, not a token: it is the one inline
|
|
40
40
|
* style the DS allows (style.backgroundColor of the swatch and of each palette colour). Choosing among a few fixed
|
|
41
41
|
* colours without a hex is the ToggleGroup or the ChoiceCard. Styles: color-input.css and internal/field.css.
|
|
@@ -28,8 +28,11 @@ declare function ContextMenu({ children, items, disabled, onOpenChange, classNam
|
|
|
28
28
|
interface ContextMenuItemProps extends MenuItemContentProps {
|
|
29
29
|
/** Runs when the item is chosen; the menu then closes. */
|
|
30
30
|
onSelect?: () => void;
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* neutral (default), or danger for what destroys: last, after a separator (Figma: `tone`). `'default'` is
|
|
33
|
+
* deprecated (2.0.0-next): it is `'neutral'`.
|
|
34
|
+
*/
|
|
35
|
+
tone?: ContextMenuItemTone | 'default';
|
|
33
36
|
disabled?: boolean;
|
|
34
37
|
textValue?: string;
|
|
35
38
|
}
|
|
@@ -30,8 +30,6 @@ interface CurrencyInputProps {
|
|
|
30
30
|
maxDigits?: number;
|
|
31
31
|
/** Shows 0,00 instead of the placeholder when the value is zero. */
|
|
32
32
|
showZero?: boolean;
|
|
33
|
-
/** @deprecated The [RDS] Input has one height (44). Ignored. */
|
|
34
|
-
size?: 'sm' | 'md' | 'lg';
|
|
35
33
|
id?: string;
|
|
36
34
|
className?: string;
|
|
37
35
|
}
|
|
@@ -4,8 +4,10 @@ import { ReactNode } from 'react';
|
|
|
4
4
|
type DataTableHeaderSearch = {
|
|
5
5
|
value: string;
|
|
6
6
|
onChange: (v: string) => void;
|
|
7
|
-
/**
|
|
7
|
+
/** What the field shows while empty, saying what is searched ("Buscar produtos…"). Default "Buscar…". */
|
|
8
8
|
placeholder?: string;
|
|
9
|
+
/** The field's accessible name, apart from the placeholder ("Buscar produtos"). Default "Buscar". */
|
|
10
|
+
label?: string;
|
|
9
11
|
};
|
|
10
12
|
type DataTableFilterOption = {
|
|
11
13
|
value: string;
|
|
@@ -20,35 +22,70 @@ type DataTableFilterDef = {
|
|
|
20
22
|
options: DataTableFilterOption[];
|
|
21
23
|
onChange: (v: string) => void;
|
|
22
24
|
};
|
|
23
|
-
type DataTablePillDef = {
|
|
24
|
-
key: string;
|
|
25
|
-
label: string;
|
|
26
|
-
active: boolean;
|
|
27
|
-
count?: number;
|
|
28
|
-
onClick: () => void;
|
|
29
|
-
};
|
|
30
25
|
type DataTableHeaderProps = {
|
|
31
26
|
search?: DataTableHeaderSearch;
|
|
32
27
|
filters?: DataTableFilterDef[];
|
|
33
|
-
/**
|
|
34
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Quick filters, always in view (Figma: `showQuickFilters` + the `quickFilters` slot): up to three, a
|
|
30
|
+
* FilterChipGroup with its FilterChips; four or more, one Button with a menu (DropdownMenu), "Categoria: Todas".
|
|
31
|
+
* No quick filters: do not pass the slot (Figma: `showQuickFilters` false). Wrapped in a group "Filtros rápidos".
|
|
32
|
+
*/
|
|
33
|
+
quickFilters?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Clears the `filters` (Figma: `clear`, "Limpar filtros" at the end of the active filters line, shown while a
|
|
36
|
+
* filter is on). The focus goes back to the search.
|
|
37
|
+
*/
|
|
35
38
|
onClear?: () => void;
|
|
39
|
+
/**
|
|
40
|
+
* A view control after the filters (Figma: `showView` + the `view` slot), such as a Checkbox "Agrupar por
|
|
41
|
+
* produto". In view in the compact arrangement too.
|
|
42
|
+
*/
|
|
43
|
+
view?: ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* How many results (Figma: `showCount` + `count`), at the end of the tools: "128 resultados". A live region
|
|
46
|
+
* (aria-live polite), so the total is announced as the list is filtered.
|
|
47
|
+
*/
|
|
48
|
+
count?: ReactNode;
|
|
49
|
+
/**
|
|
50
|
+
* The list's action (Figma: `showActions`, off by default, + the `actions` instance): an IconButton, neutral outline
|
|
51
|
+
* md, with its Tooltip, such as a gear "Organizar categorias" or exporting. It sits outside the tools, always at the
|
|
52
|
+
* end of the FIRST line, on the right; the tools wrap, the action never goes down.
|
|
53
|
+
* Creating is NOT an action of the bar: creating is the FAB. The component does not enforce this; it documents it.
|
|
54
|
+
*/
|
|
36
55
|
actions?: ReactNode;
|
|
37
56
|
className?: string;
|
|
38
|
-
/**
|
|
57
|
+
/** In the compact arrangement (bar below 1024), moves the filters and the actions into a Drawer. The quick filters stay in view. */
|
|
39
58
|
mobileCollapse?: boolean;
|
|
40
59
|
};
|
|
41
|
-
/** One filter as a DropdownMenu of radio items (one filter
|
|
60
|
+
/** One filter as a DropdownMenu of radio items (one filter, expanded). */
|
|
42
61
|
declare function FilterDropdown({ f, placement }: {
|
|
43
62
|
f: DataTableFilterDef;
|
|
44
63
|
placement?: 'bottom-start' | 'bottom-end';
|
|
45
64
|
}): react.JSX.Element;
|
|
46
65
|
/**
|
|
47
|
-
* DataTableHeader — a composition of the Input (search), FilterChips, Buttons, the DropdownMenu, the Popover
|
|
48
|
-
* the Drawer: the bar above a table
|
|
49
|
-
*
|
|
50
|
-
*
|
|
66
|
+
* DataTableHeader — a composition of the Input (search), FilterChips, Chips, Buttons, the DropdownMenu, the Popover
|
|
67
|
+
* and the Drawer: the bar above a table (Figma [RDS] DataTableHeader, no variants). Two lines, 8 apart:
|
|
68
|
+
*
|
|
69
|
+
* - `row`, which never wraps: the tools (the search, the quick filters, the filter trigger, the view control and the
|
|
70
|
+
* count) wrap inside their own group, packed to the start; the action stays outside it, at the end of the first
|
|
71
|
+
* line, on the right. The search is always first and takes the free width, at least `--data-table-header-search-min`
|
|
72
|
+
* (320; 200 below 1024); what does not fit wraps.
|
|
73
|
+
* - `active`, only while a filter is on (one filter too): the active filters as removable Chips ("Status: Abertos"),
|
|
74
|
+
* wrapping, and "Limpar filtros" (a ghost sm Button, `onClear`) at the end, which gives the focus back to the search.
|
|
75
|
+
*
|
|
76
|
+
* Quick filters go in the `quickFilters` slot; 0 quick filters = do not pass the slot. One filter is a Button with a
|
|
77
|
+
* menu; two or more collapse into "Filtros" (a Popover), the count in its label ("Filtros · 2"). No Separator between
|
|
78
|
+
* the groups (it is left orphaned at the start of a wrapped line) and no Badge over the trigger.
|
|
79
|
+
*
|
|
80
|
+
* Two arrangements, by the screen width, as the Figma viewport mode (layout/compact below lg 1024; the SavingBar's cut):
|
|
81
|
+
* expanded from 1024, the trigger is a Button with its label; compact below it, an outline IconButton (sliders, 44)
|
|
82
|
+
* that, while a filter is on, becomes a fill Button with the number ("2"), named "Filtros, 2 ativos" or
|
|
83
|
+
* "Categoria, Pago"; one filter opens a Drawer (never a popover on a phone). There is no screen prop.
|
|
84
|
+
*
|
|
85
|
+
* Tab order is the visual order: search → quick filters → filter trigger → view → action → active Chips → Limpar
|
|
86
|
+
* filtros. Escape closes the menu, Popover or Drawer and gives the focus back to the trigger.
|
|
87
|
+
* Styles: data-table-header.css.
|
|
51
88
|
*/
|
|
52
|
-
declare function DataTableHeader({ search, filters,
|
|
89
|
+
declare function DataTableHeader({ search, filters, quickFilters, onClear, view, count, actions, className, mobileCollapse, }: DataTableHeaderProps): react.JSX.Element;
|
|
53
90
|
|
|
54
|
-
export { type DataTableFilterDef, type DataTableFilterOption, DataTableHeader, type DataTableHeaderProps, type DataTableHeaderSearch,
|
|
91
|
+
export { type DataTableFilterDef, type DataTableFilterOption, DataTableHeader, type DataTableHeaderProps, type DataTableHeaderSearch, FilterDropdown };
|