@rojaostudio/ds 2.0.0-next.3 → 2.0.0-next.31
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 +45 -15
- package/dist/components/form-actions.js +33 -12
- 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 +33 -0
- package/dist/components/internal/bottom-bar.js +64 -0
- package/dist/components/internal/button.d.ts +1 -1
- package/dist/components/internal/icons.d.ts +11 -1
- package/dist/components/internal/icons.js +23 -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 +38 -10
- package/dist/components/saving-bar.js +30 -7
- 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 +21 -8
- 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 +799 -266
- package/styles/rds/components.css +57 -31
- package/styles/rds/foundation.css +1 -1
- package/styles/rds/theme.css +40 -29
- package/styles/rds.css +1 -1
|
@@ -5,8 +5,7 @@ import {
|
|
|
5
5
|
__spreadValues
|
|
6
6
|
} from "../chunk-ORMEWXMH.js";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { useState } from "react";
|
|
9
|
-
import { Badge } from "./badge.js";
|
|
8
|
+
import { useRef, useState } from "react";
|
|
10
9
|
import { Button } from "./button.js";
|
|
11
10
|
import { Chip } from "./chip.js";
|
|
12
11
|
import { Drawer } from "./drawer.js";
|
|
@@ -14,49 +13,57 @@ import { DropdownMenu, DropdownMenuRadioGroup, DropdownMenuRadioItem } from "./d
|
|
|
14
13
|
import { FilterChip, FilterChipGroup } from "./filter-chip.js";
|
|
15
14
|
import { IconButton } from "./icon-button.js";
|
|
16
15
|
import { Input } from "./input.js";
|
|
17
|
-
import {
|
|
16
|
+
import { SearchIcon, SlidersIcon } from "./internal/icons.js";
|
|
18
17
|
import { Popover } from "./popover.js";
|
|
19
|
-
import { Separator } from "./separator.js";
|
|
20
18
|
import { Tooltip } from "./tooltip.js";
|
|
21
19
|
function optionLabel(filter) {
|
|
22
20
|
var _a, _b;
|
|
23
21
|
if (filter.value === "") return filter.label;
|
|
24
22
|
return (_b = (_a = filter.options.find((o) => o.value === filter.value)) == null ? void 0 : _a.label) != null ? _b : filter.label;
|
|
25
23
|
}
|
|
24
|
+
function chipLabel(filter) {
|
|
25
|
+
return `${filter.label}: ${optionLabel(filter)}`;
|
|
26
|
+
}
|
|
26
27
|
function FilterTrigger(_a) {
|
|
27
28
|
var _b = _a, { filter } = _b, rest = __objRest(_b, ["filter"]);
|
|
28
|
-
|
|
29
|
+
const on = filter.value !== "";
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
Button,
|
|
32
|
+
__spreadProps(__spreadValues({}, rest), {
|
|
33
|
+
tone: "neutral",
|
|
34
|
+
variant: on ? "fill" : "outline",
|
|
35
|
+
icon: /* @__PURE__ */ jsx(SlidersIcon, {}),
|
|
36
|
+
iconPosition: "start",
|
|
37
|
+
"aria-label": on ? `${filter.label}, ${optionLabel(filter)}` : void 0,
|
|
38
|
+
"data-filter-toggle": "",
|
|
39
|
+
children: filter.label
|
|
40
|
+
})
|
|
41
|
+
);
|
|
29
42
|
}
|
|
30
43
|
function FilterDropdown({ f, placement = "bottom-start" }) {
|
|
31
44
|
return /* @__PURE__ */ jsx(DropdownMenu, { align: placement === "bottom-end" ? "end" : "start", "aria-label": f.label, trigger: /* @__PURE__ */ jsx(FilterTrigger, { filter: f }), children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, { value: f.value, onValueChange: f.onChange, children: f.options.map((opt) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, { value: opt.value, textValue: opt.label, children: opt.count != null ? `${opt.label} \xB7 ${opt.count}` : opt.label }, opt.value)) }) });
|
|
32
45
|
}
|
|
33
46
|
function FiltersButton(_c) {
|
|
34
47
|
var _d = _c, { count } = _d, rest = __objRest(_d, ["count"]);
|
|
35
|
-
return /* @__PURE__ */
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
48
|
+
return /* @__PURE__ */ jsx(
|
|
49
|
+
Button,
|
|
50
|
+
__spreadProps(__spreadValues({}, rest), {
|
|
51
|
+
tone: "neutral",
|
|
52
|
+
variant: count > 0 ? "fill" : "outline",
|
|
53
|
+
icon: /* @__PURE__ */ jsx(SlidersIcon, {}),
|
|
54
|
+
iconPosition: "start",
|
|
55
|
+
"data-filter-toggle": "",
|
|
56
|
+
children: count > 0 ? `Filtros \xB7 ${count}` : "Filtros"
|
|
57
|
+
})
|
|
58
|
+
);
|
|
39
59
|
}
|
|
40
|
-
function FilterGroups({
|
|
41
|
-
filters,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}) {
|
|
46
|
-
return /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__groups", children: [
|
|
47
|
-
filters.map((f) => /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__group", children: [
|
|
48
|
-
/* @__PURE__ */ jsx("p", { className: "rds-data-table-header__group-label", "aria-hidden": "true", children: f.label }),
|
|
49
|
-
/* @__PURE__ */ jsx(FilterChipGroup, { "aria-label": f.label, children: f.options.map((opt) => /* @__PURE__ */ jsx(FilterChip, { active: f.value === opt.value, count: opt.count, onClick: () => onPick(f, opt.value), children: opt.label }, opt.value)) })
|
|
50
|
-
] }, f.key)),
|
|
51
|
-
onClear && showClear && /* @__PURE__ */ jsx(Button, { tone: "neutral", variant: "ghost", onClick: onClear, children: "Limpar filtros" })
|
|
52
|
-
] });
|
|
60
|
+
function FilterGroups({ filters, onPick }) {
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__groups", children: filters.map((f) => /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__group", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("p", { className: "rds-data-table-header__group-label", "aria-hidden": "true", children: f.label }),
|
|
63
|
+
/* @__PURE__ */ jsx(FilterChipGroup, { "aria-label": f.label, children: f.options.map((opt) => /* @__PURE__ */ jsx(FilterChip, { pressed: f.value === opt.value, count: opt.count, onClick: () => onPick(f, opt.value), children: opt.label }, opt.value)) })
|
|
64
|
+
] }, f.key)) });
|
|
53
65
|
}
|
|
54
|
-
function FiltersPopover({
|
|
55
|
-
filters,
|
|
56
|
-
onClear,
|
|
57
|
-
showClear,
|
|
58
|
-
trigger
|
|
59
|
-
}) {
|
|
66
|
+
function FiltersPopover({ filters, trigger }) {
|
|
60
67
|
const [open, setOpen] = useState(false);
|
|
61
68
|
return /* @__PURE__ */ jsx(Popover, { trigger, "aria-label": "Filtros", side: "bottom", align: "end", open, onOpenChange: setOpen, children: /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__scroll", children: /* @__PURE__ */ jsx(
|
|
62
69
|
FilterGroups,
|
|
@@ -65,19 +72,50 @@ function FiltersPopover({
|
|
|
65
72
|
onPick: (f, v) => {
|
|
66
73
|
f.onChange(v);
|
|
67
74
|
setOpen(false);
|
|
68
|
-
}
|
|
69
|
-
onClear: onClear ? () => {
|
|
70
|
-
onClear();
|
|
71
|
-
setOpen(false);
|
|
72
|
-
} : void 0,
|
|
73
|
-
showClear
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
77
|
) }) });
|
|
76
78
|
}
|
|
79
|
+
function CompactFilterTrigger(_e) {
|
|
80
|
+
var _f = _e, {
|
|
81
|
+
label,
|
|
82
|
+
state,
|
|
83
|
+
active
|
|
84
|
+
} = _f, rest = __objRest(_f, [
|
|
85
|
+
"label",
|
|
86
|
+
"state",
|
|
87
|
+
"active"
|
|
88
|
+
]);
|
|
89
|
+
const name = state ? `${label}, ${state}` : label;
|
|
90
|
+
return /* @__PURE__ */ jsx(Tooltip, { text: label, children: active > 0 ? /* @__PURE__ */ jsx(Button, __spreadProps(__spreadValues({}, rest), { tone: "neutral", variant: "fill", icon: /* @__PURE__ */ jsx(SlidersIcon, {}), iconPosition: "start", "aria-label": name, "data-filter-toggle": "", children: String(active) })) : /* @__PURE__ */ jsx(IconButton, __spreadProps(__spreadValues({}, rest), { icon: /* @__PURE__ */ jsx(SlidersIcon, {}), label: name, variant: "outline", tone: "neutral", size: "md", "data-filter-toggle": "" })) });
|
|
91
|
+
}
|
|
92
|
+
function activeState(count) {
|
|
93
|
+
if (count === 0) return void 0;
|
|
94
|
+
return count === 1 ? "1 ativo" : `${count} ativos`;
|
|
95
|
+
}
|
|
96
|
+
function useDrawer() {
|
|
97
|
+
const [open, setOpenState] = useState(false);
|
|
98
|
+
const triggerRef = useRef(null);
|
|
99
|
+
const setOpen = (next) => {
|
|
100
|
+
setOpenState(next);
|
|
101
|
+
if (!next) requestAnimationFrame(() => {
|
|
102
|
+
var _a;
|
|
103
|
+
return (_a = triggerRef.current) == null ? void 0 : _a.focus();
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
const triggerProps = {
|
|
107
|
+
ref: triggerRef,
|
|
108
|
+
"aria-haspopup": "dialog",
|
|
109
|
+
"aria-expanded": open,
|
|
110
|
+
onClick: () => setOpen(true)
|
|
111
|
+
};
|
|
112
|
+
return { open, setOpen, triggerProps };
|
|
113
|
+
}
|
|
77
114
|
function MobileSingleFilter({ f }) {
|
|
78
|
-
const
|
|
115
|
+
const { open, setOpen, triggerProps } = useDrawer();
|
|
116
|
+
const on = f.value !== "";
|
|
79
117
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
80
|
-
/* @__PURE__ */ jsx(
|
|
118
|
+
/* @__PURE__ */ jsx(CompactFilterTrigger, __spreadProps(__spreadValues({}, triggerProps), { label: f.label, state: on ? optionLabel(f) : void 0, active: on ? 1 : 0 })),
|
|
81
119
|
/* @__PURE__ */ jsx(Drawer, { open, onOpenChange: setOpen, title: f.label, children: /* @__PURE__ */ jsx(
|
|
82
120
|
FilterGroups,
|
|
83
121
|
{
|
|
@@ -85,92 +123,101 @@ function MobileSingleFilter({ f }) {
|
|
|
85
123
|
onPick: (_, v) => {
|
|
86
124
|
f.onChange(v);
|
|
87
125
|
setOpen(false);
|
|
88
|
-
}
|
|
89
|
-
showClear: false
|
|
126
|
+
}
|
|
90
127
|
}
|
|
91
128
|
) })
|
|
92
129
|
] });
|
|
93
130
|
}
|
|
131
|
+
function MobileCollapsedFilters({
|
|
132
|
+
filters,
|
|
133
|
+
actions,
|
|
134
|
+
activeCount
|
|
135
|
+
}) {
|
|
136
|
+
const { open, setOpen, triggerProps } = useDrawer();
|
|
137
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
|
+
/* @__PURE__ */ jsx(CompactFilterTrigger, __spreadProps(__spreadValues({}, triggerProps), { label: "Filtros", state: activeState(activeCount), active: activeCount })),
|
|
139
|
+
/* @__PURE__ */ jsx(Drawer, { open, onOpenChange: setOpen, title: "Filtros", children: /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__groups", children: [
|
|
140
|
+
/* @__PURE__ */ jsx(
|
|
141
|
+
FilterGroups,
|
|
142
|
+
{
|
|
143
|
+
filters,
|
|
144
|
+
onPick: (f, v) => {
|
|
145
|
+
f.onChange(v);
|
|
146
|
+
setOpen(false);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
actions && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__drawer-actions", children: actions })
|
|
151
|
+
] }) })
|
|
152
|
+
] });
|
|
153
|
+
}
|
|
94
154
|
function DataTableHeader({
|
|
95
155
|
search,
|
|
96
156
|
filters = [],
|
|
97
|
-
|
|
157
|
+
quickFilters,
|
|
98
158
|
onClear,
|
|
159
|
+
view,
|
|
160
|
+
count,
|
|
99
161
|
actions,
|
|
100
162
|
className,
|
|
101
163
|
mobileCollapse = false
|
|
102
164
|
}) {
|
|
103
|
-
var _a, _b;
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const collapseDesktop = filters.length >= 2;
|
|
165
|
+
var _a, _b, _c;
|
|
166
|
+
const searchRef = useRef(null);
|
|
167
|
+
const rootRef = useRef(null);
|
|
107
168
|
const activeFilters = filters.filter((f) => f.value !== "");
|
|
169
|
+
const activeFilterCount = activeFilters.length;
|
|
170
|
+
const collapseDesktop = filters.length >= 2;
|
|
108
171
|
const singleFilter = filters.length === 1 ? filters[0] : null;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"aria-label": (_a = search.placeholder) != null ? _a : "Buscar\u2026",
|
|
117
|
-
placeholder: (_b = search.placeholder) != null ? _b : "Buscar\u2026",
|
|
118
|
-
leadingIcon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
119
|
-
clearable: true,
|
|
120
|
-
clearLabel: "Limpar busca",
|
|
121
|
-
value: search.value,
|
|
122
|
-
onChange: (e) => search.onChange(e.target.value)
|
|
172
|
+
const clear = () => {
|
|
173
|
+
onClear == null ? void 0 : onClear();
|
|
174
|
+
requestAnimationFrame(() => {
|
|
175
|
+
var _a2, _b2, _c2;
|
|
176
|
+
if (searchRef.current) {
|
|
177
|
+
searchRef.current.focus();
|
|
178
|
+
return;
|
|
123
179
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
180
|
+
const toggles = (_b2 = (_a2 = rootRef.current) == null ? void 0 : _a2.querySelectorAll("[data-filter-toggle]")) != null ? _b2 : [];
|
|
181
|
+
(_c2 = [...toggles].find((t) => t.offsetParent !== null)) == null ? void 0 : _c2.focus();
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: ["rds-data-table-header", className].filter(Boolean).join(" "), children: [
|
|
185
|
+
/* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__row", children: [
|
|
186
|
+
/* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__tools", children: [
|
|
187
|
+
search && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__search", role: "search", "aria-label": (_a = search.label) != null ? _a : "Buscar", children: /* @__PURE__ */ jsx(
|
|
188
|
+
Input,
|
|
132
189
|
{
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
190
|
+
ref: searchRef,
|
|
191
|
+
type: "search",
|
|
192
|
+
"aria-label": (_b = search.label) != null ? _b : "Buscar",
|
|
193
|
+
placeholder: (_c = search.placeholder) != null ? _c : "Buscar\u2026",
|
|
194
|
+
leadingIcon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
195
|
+
clearable: true,
|
|
196
|
+
clearLabel: "Limpar busca",
|
|
197
|
+
value: search.value,
|
|
198
|
+
onChange: (e) => search.onChange(e.target.value)
|
|
137
199
|
}
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
FiltersPopover,
|
|
145
|
-
{
|
|
146
|
-
filters,
|
|
147
|
-
onClear,
|
|
148
|
-
showClear: activeFilterCount > 0,
|
|
149
|
-
trigger: /* @__PURE__ */ jsx(FiltersButton, { count: activeFilterCount })
|
|
150
|
-
}
|
|
151
|
-
) }),
|
|
152
|
-
mobileCollapse && (filters.length >= 2 || actions) && /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__narrow", children: [
|
|
153
|
-
/* @__PURE__ */ jsx(FiltersButton, { count: activeFilterCount, onClick: () => setSheetOpen(true) }),
|
|
154
|
-
/* @__PURE__ */ jsx(Drawer, { open: sheetOpen, onOpenChange: setSheetOpen, title: "Filtros", children: /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__groups", children: [
|
|
155
|
-
/* @__PURE__ */ jsx(
|
|
156
|
-
FilterGroups,
|
|
200
|
+
) }),
|
|
201
|
+
quickFilters && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__quick", role: "group", "aria-label": "Filtros r\xE1pidos", children: quickFilters }),
|
|
202
|
+
filters.length > 0 && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__wide", children: collapseDesktop ? /* @__PURE__ */ jsx(FiltersPopover, { filters, trigger: /* @__PURE__ */ jsx(FiltersButton, { count: activeFilterCount }) }) : filters.map((f) => /* @__PURE__ */ jsx(FilterDropdown, { f }, f.key)) }),
|
|
203
|
+
singleFilter && !(mobileCollapse && actions) && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__narrow", children: /* @__PURE__ */ jsx(MobileSingleFilter, { f: singleFilter }) }),
|
|
204
|
+
!mobileCollapse && filters.length >= 2 && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__narrow", children: /* @__PURE__ */ jsx(
|
|
205
|
+
FiltersPopover,
|
|
157
206
|
{
|
|
158
207
|
filters,
|
|
159
|
-
|
|
160
|
-
f.onChange(v);
|
|
161
|
-
setSheetOpen(false);
|
|
162
|
-
},
|
|
163
|
-
onClear: onClear ? () => {
|
|
164
|
-
onClear();
|
|
165
|
-
setSheetOpen(false);
|
|
166
|
-
} : void 0,
|
|
167
|
-
showClear: activeFilterCount > 0
|
|
208
|
+
trigger: /* @__PURE__ */ jsx(CompactFilterTrigger, { label: "Filtros", state: activeState(activeFilterCount), active: activeFilterCount })
|
|
168
209
|
}
|
|
169
|
-
),
|
|
170
|
-
actions && /* @__PURE__ */ jsx("div", { className: "rds-data-table-
|
|
171
|
-
|
|
210
|
+
) }),
|
|
211
|
+
mobileCollapse && (filters.length >= 2 || actions) && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__narrow", children: /* @__PURE__ */ jsx(MobileCollapsedFilters, { filters, actions, activeCount: activeFilterCount }) }),
|
|
212
|
+
view && /* @__PURE__ */ jsx("div", { className: "rds-data-table-header__view", children: view }),
|
|
213
|
+
count != null && count !== false && /* @__PURE__ */ jsx("span", { className: "rds-data-table-header__count", "aria-live": "polite", children: count })
|
|
214
|
+
] }),
|
|
215
|
+
actions && /* @__PURE__ */ jsx("div", { className: ["rds-data-table-header__actions", mobileCollapse && "rds-data-table-header__wide"].filter(Boolean).join(" "), children: actions })
|
|
172
216
|
] }),
|
|
173
|
-
|
|
217
|
+
activeFilters.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rds-data-table-header__active", children: [
|
|
218
|
+
/* @__PURE__ */ jsx("div", { className: "rds-data-table-header__chips", children: activeFilters.map((f) => /* @__PURE__ */ jsx(Chip, { onRemove: () => f.onChange(""), removeLabel: `Remover filtro ${chipLabel(f)}`, children: chipLabel(f) }, f.key)) }),
|
|
219
|
+
onClear && /* @__PURE__ */ jsx(Button, { tone: "neutral", variant: "ghost", size: "sm", onClick: clear, children: "Limpar filtros" })
|
|
220
|
+
] })
|
|
174
221
|
] });
|
|
175
222
|
}
|
|
176
223
|
export {
|
|
@@ -30,7 +30,7 @@ interface DatePickerProps extends FieldTextProps {
|
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* DatePicker — Figma [RDS] Forms/DatePicker. A date field that takes typing (dd/mm/aaaa, the slashes come by
|
|
33
|
-
* themselves) and, from the calendar button, opens the Calendar in a popover (Figma: `
|
|
33
|
+
* themselves) and, from the calendar button, opens the Calendar in a popover (Figma: `open`). Choosing a day
|
|
34
34
|
* closes it and gives the focus back to the field; Escape closes without choosing. For a date near today, where
|
|
35
35
|
* seeing the month helps: a birth date is an Input. Styles: date-picker.css, internal/field.css, calendar.css.
|
|
36
36
|
*/
|
|
@@ -2,10 +2,13 @@ import * as _radix_ui_react_dialog from '@radix-ui/react-dialog';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ModalProps } from './internal/modal.js';
|
|
4
4
|
|
|
5
|
-
type DialogSize = 'sm' | '
|
|
5
|
+
type DialogSize = 'sm' | 'md' | 'lg';
|
|
6
6
|
interface DialogProps extends ModalProps {
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* sm 400 (a question with one field), md 560 (a short form, the default), lg 720 (a table or a preview) (Figma:
|
|
9
|
+
* `size`). `'default'` is deprecated (2.0.0-next): it is `'md'`.
|
|
10
|
+
*/
|
|
11
|
+
size?: DialogSize | 'default';
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
14
|
* Dialog — Figma [RDS] Overlays/Dialog. A window over the screen for a short task: create, edit (Radix Dialog).
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { ModalClose, ModalShell } from "./internal/modal.js";
|
|
8
8
|
function Dialog(_a) {
|
|
9
|
-
var _b = _a, { size = "
|
|
10
|
-
return /* @__PURE__ */ jsx(ModalShell, __spreadValues({ prefix: "rds-dialog", modifiers: [`rds-dialog--${size}`] }, props));
|
|
9
|
+
var _b = _a, { size = "md" } = _b, props = __objRest(_b, ["size"]);
|
|
10
|
+
return /* @__PURE__ */ jsx(ModalShell, __spreadValues({ prefix: "rds-dialog", modifiers: [`rds-dialog--${size === "default" ? "md" : size}`] }, props));
|
|
11
11
|
}
|
|
12
12
|
const DialogClose = ModalClose;
|
|
13
13
|
export {
|
|
@@ -30,8 +30,11 @@ declare function DropdownMenu({ trigger, children, align, side, open, defaultOpe
|
|
|
30
30
|
interface DropdownMenuItemProps extends MenuItemContentProps {
|
|
31
31
|
/** Runs when the item is chosen (click, Enter or Space); the menu then closes. A destructive action asks first (AlertDialog). */
|
|
32
32
|
onSelect?: () => void;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* neutral (default), or danger for what destroys: last, after a separator (Figma: `tone`). `'default'` is
|
|
35
|
+
* deprecated (2.0.0-next): it is `'neutral'`.
|
|
36
|
+
*/
|
|
37
|
+
tone?: DropdownMenuItemTone | 'default';
|
|
35
38
|
/** Stays in the list, can't be chosen, and the arrows skip it. */
|
|
36
39
|
disabled?: boolean;
|
|
37
40
|
/** The text typing jumps by, when the label is not plain text. */
|
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @deprecated Use `<FileInput
|
|
5
|
+
* @deprecated Use `<FileInput layout="dropzone">` (Figma [RDS] Forms/FileInput), which has the label, the hint, the
|
|
6
6
|
* error and the chosen file's row. Kept as a thin wrapper so 1.x code keeps compiling.
|
|
7
7
|
*/
|
|
8
8
|
interface DropzoneProps {
|
|
@@ -17,7 +17,7 @@ interface DropzoneProps {
|
|
|
17
17
|
'aria-label'?: string;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* @deprecated Use `<FileInput
|
|
20
|
+
* @deprecated Use `<FileInput layout="dropzone">`. A drop target only: it hands the files over and stays empty,
|
|
21
21
|
* ready for the next ones, as the 1.x Dropzone did.
|
|
22
22
|
*/
|
|
23
23
|
declare function Dropzone({ onFiles, accept, multiple, disabled, className, children, 'aria-label': ariaLabel, }: DropzoneProps): react.JSX.Element;
|
|
@@ -2,14 +2,19 @@ import * as react from 'react';
|
|
|
2
2
|
import { ComponentPropsWithRef, ReactNode } from 'react';
|
|
3
3
|
import { FieldTextProps } from './internal/field.js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** The field's arrangement (Figma: `layout`). */
|
|
6
|
+
type FileInputLayout = 'field' | 'dropzone' | 'tile';
|
|
7
|
+
/** @deprecated Use FileInputLayout (2.0.0-next: `variant` is `layout`). */
|
|
8
|
+
type FileInputVariant = FileInputLayout;
|
|
6
9
|
interface FileInputProps extends Omit<FieldTextProps, 'labelPosition'>, Omit<ComponentPropsWithRef<'input'>, 'type' | 'children' | 'prefix' | 'value' | 'defaultValue' | 'size'> {
|
|
7
10
|
/**
|
|
8
|
-
* The
|
|
9
|
-
* the file on, when the file is what the screen is about (a receipt, a spreadsheet). tile: a 112 square with
|
|
10
|
-
* preview, for a photo or a logo.
|
|
11
|
+
* The arrangement (Figma: `layout`). field (default): the Input's box, for a dense form. dropzone: a dashed area to
|
|
12
|
+
* drop the file on, when the file is what the screen is about (a receipt, a spreadsheet). tile: a 112 square with
|
|
13
|
+
* the image's preview, for a photo or a logo.
|
|
11
14
|
*/
|
|
12
|
-
|
|
15
|
+
layout?: FileInputLayout;
|
|
16
|
+
/** @deprecated Use `layout` (2.0.0-next): the same three values. */
|
|
17
|
+
variant?: FileInputLayout;
|
|
13
18
|
/** Controlled: the name shown (Figma: `fileName`). By default, the chosen file's name. */
|
|
14
19
|
fileName?: string;
|
|
15
20
|
/** Controlled: the size beside the name in the dropzone (Figma: `fileSize`). By default, the chosen file's, as "1,2 MB". */
|
|
@@ -43,7 +48,7 @@ interface FileInputProps extends Omit<FieldTextProps, 'labelPosition'>, Omit<Com
|
|
|
43
48
|
/** "1,2 MB", "830 KB", "512 B": the size the way a person reads it. */
|
|
44
49
|
declare function formatFileSize(bytes: number): string;
|
|
45
50
|
/**
|
|
46
|
-
* FileInput — Figma [RDS] Forms/FileInput. A file field in three
|
|
51
|
+
* FileInput — Figma [RDS] Forms/FileInput. A file field in three layouts (`layout`): field, the Input's box with the
|
|
47
52
|
* clip, "Escolher arquivo" and the name; dropzone, a dashed area that takes a dragged file; tile, a square with the
|
|
48
53
|
* image's preview and the buttons to swap or remove it. In every shape the native <input type="file"> does the work:
|
|
49
54
|
* it lies transparent over the box, so a click, Enter or Space open the system's chooser, the label names it,
|
|
@@ -51,6 +56,6 @@ declare function formatFileSize(bytes: number): string;
|
|
|
51
56
|
* size in the hint and check them in code (a failure is the errorMessage). Styles: file-input.css and
|
|
52
57
|
* internal/field.css.
|
|
53
58
|
*/
|
|
54
|
-
declare function FileInput({ variant, label, hint, error, errorMessage, required, fileName, fileSize, preview, previewAlt, dropTitle, tileText, clearable, onClear, onFiles, clearLabel, replaceLabel, chooseLabel, emptyLabel, id, disabled, className, style, onChange, ref, ...input }: FileInputProps): react.JSX.Element;
|
|
59
|
+
declare function FileInput({ layout: layoutProp, variant, label, hint, error, errorMessage, required, fileName, fileSize, preview, previewAlt, dropTitle, tileText, clearable, onClear, onFiles, clearLabel, replaceLabel, chooseLabel, emptyLabel, id, disabled, className, style, onChange, ref, ...input }: FileInputProps): react.JSX.Element;
|
|
55
60
|
|
|
56
|
-
export { FileInput, type FileInputProps, type FileInputVariant, formatFileSize };
|
|
61
|
+
export { FileInput, type FileInputLayout, type FileInputProps, type FileInputVariant, formatFileSize };
|
|
@@ -25,7 +25,8 @@ function formatFileSize(bytes) {
|
|
|
25
25
|
}
|
|
26
26
|
function FileInput(_a) {
|
|
27
27
|
var _b = _a, {
|
|
28
|
-
|
|
28
|
+
layout: layoutProp,
|
|
29
|
+
variant,
|
|
29
30
|
label,
|
|
30
31
|
hint,
|
|
31
32
|
error,
|
|
@@ -51,6 +52,7 @@ function FileInput(_a) {
|
|
|
51
52
|
onChange,
|
|
52
53
|
ref
|
|
53
54
|
} = _b, input = __objRest(_b, [
|
|
55
|
+
"layout",
|
|
54
56
|
"variant",
|
|
55
57
|
"label",
|
|
56
58
|
"hint",
|
|
@@ -77,23 +79,24 @@ function FileInput(_a) {
|
|
|
77
79
|
"onChange",
|
|
78
80
|
"ref"
|
|
79
81
|
]);
|
|
80
|
-
var _a2, _b2, _c;
|
|
82
|
+
var _a2, _b2, _c, _d;
|
|
83
|
+
const layout = (_a2 = layoutProp != null ? layoutProp : variant) != null ? _a2 : "field";
|
|
81
84
|
warnIfUnlabelled("FileInput", label, input["aria-label"], input["aria-labelledby"]);
|
|
82
|
-
const inside =
|
|
85
|
+
const inside = layout === "dropzone";
|
|
83
86
|
const ids = useFieldIds(id, inside ? void 0 : hint, error, errorMessage);
|
|
84
87
|
const { controlId, errorId, invalid } = ids;
|
|
85
88
|
const own = useRef(null);
|
|
86
89
|
const [chosen, setChosen] = useState(null);
|
|
87
90
|
const [dragging, setDragging] = useState(false);
|
|
88
91
|
useEffect(() => () => revoke(chosen), [chosen]);
|
|
89
|
-
const shownName = (
|
|
92
|
+
const shownName = (_b2 = fileName != null ? fileName : chosen == null ? void 0 : chosen.name) != null ? _b2 : "";
|
|
90
93
|
const shownSize = fileSize != null ? fileSize : fileName === void 0 && chosen ? formatFileSize(chosen.size) : void 0;
|
|
91
|
-
const shownPreview = (
|
|
92
|
-
const filled =
|
|
94
|
+
const shownPreview = (_c = preview != null ? preview : chosen == null ? void 0 : chosen.url) != null ? _c : "";
|
|
95
|
+
const filled = layout === "tile" ? Boolean(shownPreview) : Boolean(shownName);
|
|
93
96
|
const showClear = clearable && filled && !disabled;
|
|
94
97
|
const insideHintId = inside && hasContent(hint) && !filled ? `${controlId}-hint` : void 0;
|
|
95
98
|
const describedBy = [inside ? insideHintId : ids.hintId, errorId, input["aria-describedby"]].filter(Boolean).join(" ") || void 0;
|
|
96
|
-
const removeName = clearLabel != null ? clearLabel :
|
|
99
|
+
const removeName = clearLabel != null ? clearLabel : layout === "tile" ? "Remover imagem" : "Remover arquivo";
|
|
97
100
|
function change(event) {
|
|
98
101
|
const files = event.target.files;
|
|
99
102
|
if (!(files == null ? void 0 : files.length)) {
|
|
@@ -101,7 +104,7 @@ function FileInput(_a) {
|
|
|
101
104
|
} else {
|
|
102
105
|
const size = Array.from(files).reduce((sum, file) => sum + file.size, 0);
|
|
103
106
|
const first = files[0];
|
|
104
|
-
const url =
|
|
107
|
+
const url = layout === "tile" && first.type.startsWith("image/") && typeof URL.createObjectURL === "function" ? URL.createObjectURL(first) : void 0;
|
|
105
108
|
setChosen({ name: files.length === 1 ? first.name : `${files.length} arquivos`, size, url });
|
|
106
109
|
}
|
|
107
110
|
onChange == null ? void 0 : onChange(event);
|
|
@@ -149,14 +152,14 @@ function FileInput(_a) {
|
|
|
149
152
|
},
|
|
150
153
|
onDrop: drop
|
|
151
154
|
};
|
|
152
|
-
const covered = !(
|
|
155
|
+
const covered = !(layout === "tile" && filled);
|
|
153
156
|
const control = /* @__PURE__ */ jsx(
|
|
154
157
|
"input",
|
|
155
158
|
__spreadProps(__spreadValues({}, input), {
|
|
156
159
|
ref: setRef,
|
|
157
160
|
id: controlId,
|
|
158
161
|
type: "file",
|
|
159
|
-
accept: (
|
|
162
|
+
accept: (_d = input.accept) != null ? _d : layout === "tile" ? "image/*" : void 0,
|
|
160
163
|
className: ["rds-field__control", "rds-file-input__control", !covered && "rds-file-input__control--off"].filter(Boolean).join(" "),
|
|
161
164
|
tabIndex: covered ? input.tabIndex : -1,
|
|
162
165
|
required,
|
|
@@ -168,7 +171,7 @@ function FileInput(_a) {
|
|
|
168
171
|
);
|
|
169
172
|
const clearButton = showClear && /* @__PURE__ */ jsx(FieldAction, { label: removeName, icon: /* @__PURE__ */ jsx(CloseIcon, {}), onClick: clear });
|
|
170
173
|
let face;
|
|
171
|
-
if (
|
|
174
|
+
if (layout === "dropzone") {
|
|
172
175
|
face = filled ? /* @__PURE__ */ jsxs("span", { className: "rds-file-input__file", children: [
|
|
173
176
|
/* @__PURE__ */ jsx("span", { className: "rds-file-input__circle", "aria-hidden": "true", children: /* @__PURE__ */ jsx(PaperclipIcon, {}) }),
|
|
174
177
|
/* @__PURE__ */ jsxs("span", { className: "rds-file-input__file-texts", "aria-hidden": "true", children: [
|
|
@@ -183,7 +186,7 @@ function FileInput(_a) {
|
|
|
183
186
|
hasContent(hint) && /* @__PURE__ */ jsx("span", { id: insideHintId, className: "rds-file-input__caption", children: hint })
|
|
184
187
|
] })
|
|
185
188
|
] });
|
|
186
|
-
} else if (
|
|
189
|
+
} else if (layout === "tile") {
|
|
187
190
|
face = filled ? /* @__PURE__ */ jsx("img", { className: "rds-file-input__preview", src: shownPreview, alt: previewAlt != null ? previewAlt : typeof label === "string" ? `Pr\xE9via de ${label}` : "Pr\xE9via" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
188
191
|
/* @__PURE__ */ jsx("span", { className: "rds-file-input__tile-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ImagePlusIcon, {}) }),
|
|
189
192
|
/* @__PURE__ */ jsx("span", { className: "rds-file-input__tile-text", "aria-hidden": "true", children: tileText })
|
|
@@ -198,16 +201,16 @@ function FileInput(_a) {
|
|
|
198
201
|
] });
|
|
199
202
|
}
|
|
200
203
|
const boxClassName = [
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
layout === "field" && showClear && "rds-field__box--action",
|
|
205
|
+
layout === "dropzone" && "rds-file-input__area",
|
|
206
|
+
layout === "tile" && "rds-file-input__area rds-file-input__tile",
|
|
207
|
+
layout !== "field" && filled && "rds-file-input__area--filled",
|
|
208
|
+
layout !== "field" && dragging && "rds-file-input__area--dragging"
|
|
206
209
|
].filter(Boolean).join(" ");
|
|
207
210
|
return /* @__PURE__ */ jsxs(
|
|
208
211
|
FieldShell,
|
|
209
212
|
{
|
|
210
|
-
kind: `rds-file-input rds-file-input--${
|
|
213
|
+
kind: `rds-file-input rds-file-input--${layout}`,
|
|
211
214
|
controlId,
|
|
212
215
|
hintId: inside ? void 0 : ids.hintId,
|
|
213
216
|
errorId,
|
|
@@ -218,19 +221,19 @@ function FileInput(_a) {
|
|
|
218
221
|
required,
|
|
219
222
|
disabled,
|
|
220
223
|
boxClassName: boxClassName || void 0,
|
|
221
|
-
boxProps:
|
|
224
|
+
boxProps: layout === "field" ? void 0 : boxProps,
|
|
222
225
|
className,
|
|
223
226
|
style,
|
|
224
227
|
children: [
|
|
225
228
|
face,
|
|
226
229
|
control,
|
|
227
|
-
|
|
230
|
+
layout === "tile" ? filled && !disabled && /* @__PURE__ */ jsxs("span", { className: "rds-file-input__actions", children: [
|
|
228
231
|
/* @__PURE__ */ jsx(FieldAction, { label: replaceLabel, icon: /* @__PURE__ */ jsx(UploadIcon, {}), onClick: () => {
|
|
229
232
|
var _a3;
|
|
230
233
|
return (_a3 = own.current) == null ? void 0 : _a3.click();
|
|
231
234
|
} }),
|
|
232
235
|
clearButton
|
|
233
|
-
] }) :
|
|
236
|
+
] }) : layout === "field" && clearButton
|
|
234
237
|
]
|
|
235
238
|
}
|
|
236
239
|
);
|
|
@@ -8,17 +8,23 @@ interface FilterChipProps extends Omit<ComponentPropsWithRef<'button'>, 'childre
|
|
|
8
8
|
count?: ReactNode;
|
|
9
9
|
/** An icon before the label, in the label's colour (Figma: `showIcon` + `icon`). Decorative. */
|
|
10
10
|
icon?: ReactNode;
|
|
11
|
-
/** Controlled: the filter is on (Figma:
|
|
12
|
-
|
|
11
|
+
/** Controlled: the filter is on (Figma: `pressed`), as the Toggle. */
|
|
12
|
+
pressed?: boolean;
|
|
13
13
|
/** Uncontrolled: on at first. */
|
|
14
|
-
|
|
14
|
+
defaultPressed?: boolean;
|
|
15
15
|
/** Called with the new state when the chip is pressed (a button, not a link). */
|
|
16
|
+
onPressedChange?: (pressed: boolean) => void;
|
|
17
|
+
/** @deprecated Use `pressed` (2.0.0-next). */
|
|
18
|
+
active?: boolean;
|
|
19
|
+
/** @deprecated Use `defaultPressed` (2.0.0-next). */
|
|
20
|
+
defaultActive?: boolean;
|
|
21
|
+
/** @deprecated Use `onPressedChange` (2.0.0-next). */
|
|
16
22
|
onActiveChange?: (active: boolean) => void;
|
|
17
23
|
/** Rendered as aria-disabled="true": stays in the tab order and takes focus, but does not turn on or navigate. */
|
|
18
24
|
disabled?: boolean;
|
|
19
25
|
/**
|
|
20
26
|
* Render the single child element (an `<a>`, a framework `Link`) with the chip's classes, for a filter that
|
|
21
|
-
* lives in the URL and should survive back/forward. The link gets aria-current when
|
|
27
|
+
* lives in the URL and should survive back/forward. The link gets aria-current when pressed.
|
|
22
28
|
*/
|
|
23
29
|
asChild?: boolean;
|
|
24
30
|
}
|
|
@@ -28,7 +34,7 @@ interface FilterChipProps extends Omit<ComponentPropsWithRef<'button'>, 'childre
|
|
|
28
34
|
* brand tint, brand border and label. Up to 5 in a FilterChipGroup; more than that, the Select. A value that can
|
|
29
35
|
* be removed is the Chip. Styles: filter-chip.css.
|
|
30
36
|
*/
|
|
31
|
-
declare function FilterChip({ children, count, icon, active, defaultActive, onActiveChange, disabled, asChild, type, className, onClick, ...rest }: FilterChipProps): react.JSX.Element;
|
|
37
|
+
declare function FilterChip({ children, count, icon, pressed: pressedProp, defaultPressed, onPressedChange, active, defaultActive, onActiveChange, disabled, asChild, type, className, onClick, ...rest }: FilterChipProps): react.JSX.Element;
|
|
32
38
|
interface FilterChipGroupProps extends HTMLAttributes<HTMLDivElement> {
|
|
33
39
|
/** Required: what the filters cut, such as "Filtrar por tipo". Several groups on a page must be told apart. */
|
|
34
40
|
'aria-label': string;
|