@antadesign/anta 0.3.2 → 0.3.4
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/dist/anta_helpers.d.ts +97 -0
- package/dist/anta_helpers.js +70 -0
- package/dist/calendar-core.d.ts +126 -0
- package/dist/calendar-core.js +289 -0
- package/dist/components/Button.d.ts +9 -1
- package/dist/components/Button.js +5 -2
- package/dist/components/Calendar.d.ts +85 -0
- package/dist/components/Calendar.js +226 -0
- package/dist/components/Checkbox.d.ts +16 -11
- package/dist/components/Checkbox.js +13 -7
- package/dist/components/Expander.d.ts +7 -1
- package/dist/components/Expander.js +4 -2
- package/dist/components/Input.d.ts +13 -5
- package/dist/components/Input.js +14 -6
- package/dist/components/InputDate.d.ts +89 -0
- package/dist/components/InputDate.js +273 -0
- package/dist/components/InputDate.module.css +1 -0
- package/dist/components/Menu.d.ts +14 -1
- package/dist/components/Menu.js +6 -2
- package/dist/components/MenuItem.d.ts +48 -7
- package/dist/components/MenuItem.js +72 -14
- package/dist/components/MenuSeparator.d.ts +13 -2
- package/dist/components/MenuSeparator.js +12 -2
- package/dist/components/Progress.d.ts +4 -1
- package/dist/components/Progress.js +4 -3
- package/dist/components/RadioGroup.d.ts +12 -10
- package/dist/components/RadioGroup.js +5 -5
- package/dist/components/Select.d.ts +319 -0
- package/dist/components/Select.js +341 -0
- package/dist/components/Select.module.css +1 -0
- package/dist/components/Tab.d.ts +3 -0
- package/dist/components/Tab.js +2 -1
- package/dist/components/TabPanel.d.ts +21 -13
- package/dist/components/TabPanel.js +13 -1
- package/dist/components/Tabs.d.ts +75 -40
- package/dist/components/Tabs.js +20 -88
- package/dist/components/Tag.d.ts +10 -9
- package/dist/components/Tag.js +2 -2
- package/dist/components/Text.d.ts +6 -5
- package/dist/components/Title.d.ts +4 -2
- package/dist/components/Tooltip.d.ts +4 -1
- package/dist/components/Tooltip.js +5 -0
- package/dist/elements/a-button.css +1 -1
- package/dist/elements/a-calendar.css +1 -0
- package/dist/elements/a-calendar.d.ts +76 -0
- package/dist/elements/a-calendar.js +190 -0
- package/dist/elements/a-checkbox.css +1 -1
- package/dist/elements/a-checkbox.d.ts +1 -2
- package/dist/elements/a-checkbox.js +5 -5
- package/dist/elements/a-expander.css +1 -1
- package/dist/elements/a-expander.d.ts +16 -5
- package/dist/elements/a-expander.js +59 -8
- package/dist/elements/a-icon.shapes.css +1 -1
- package/dist/elements/a-icon.shapes.d.ts +6 -1
- package/dist/elements/a-icon.shapes.js +9 -0
- package/dist/elements/a-input.css +1 -1
- package/dist/elements/a-input.d.ts +6 -0
- package/dist/elements/a-input.js +28 -8
- package/dist/elements/a-menu-group.css +1 -1
- package/dist/elements/a-menu-item.css +1 -1
- package/dist/elements/a-menu-item.d.ts +22 -10
- package/dist/elements/a-menu-item.js +17 -0
- package/dist/elements/a-menu-separator.css +1 -1
- package/dist/elements/a-menu.css +1 -1
- package/dist/elements/a-menu.d.ts +61 -20
- package/dist/elements/a-menu.js +337 -58
- package/dist/elements/a-progress.css +1 -1
- package/dist/elements/a-radio-group.d.ts +1 -3
- package/dist/elements/a-radio-group.js +13 -13
- package/dist/elements/a-radio.css +1 -1
- package/dist/elements/a-radio.d.ts +3 -11
- package/dist/elements/a-radio.js +3 -34
- package/dist/elements/a-tab.css +1 -1
- package/dist/elements/a-tab.d.ts +3 -11
- package/dist/elements/a-tab.js +3 -34
- package/dist/elements/a-tabpanel.css +1 -1
- package/dist/elements/a-tabpanel.d.ts +17 -0
- package/dist/elements/a-tabpanel.js +66 -0
- package/dist/elements/a-tabs.css +1 -1
- package/dist/elements/a-tabs.d.ts +1 -4
- package/dist/elements/a-tabs.js +14 -14
- package/dist/elements/a-tag.css +1 -1
- package/dist/elements/a-text.d.ts +14 -13
- package/dist/elements/a-text.js +53 -23
- package/dist/elements/a-tooltip.css +1 -1
- package/dist/elements/a-tooltip.d.ts +1 -11
- package/dist/elements/a-tooltip.js +20 -19
- package/dist/elements/index.d.ts +2 -1
- package/dist/elements/index.js +6 -1
- package/dist/general_types.d.ts +158 -42
- package/dist/index.d.ts +10 -4
- package/dist/index.js +38 -3
- package/dist/jsx-runtime.d.ts +16 -7
- package/dist/jsx-runtime.js +6 -0
- package/dist/reset.css +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
|
|
2
|
+
import { useState, useId } from "../jsx-runtime";
|
|
3
|
+
import { Input } from "./Input";
|
|
4
|
+
import { Icon } from "./Icon";
|
|
5
|
+
import { Menu } from "./Menu";
|
|
6
|
+
import { MenuItem } from "./MenuItem";
|
|
7
|
+
import { MenuGroup } from "./MenuGroup";
|
|
8
|
+
import { MenuSeparator } from "./MenuSeparator";
|
|
9
|
+
import { Tooltip } from "./Tooltip";
|
|
10
|
+
import styles from "./Select.module.css";
|
|
11
|
+
const IS_MAC = typeof navigator !== "undefined" && /Mac|iPhone|iPad/i.test(navigator.userAgent || "");
|
|
12
|
+
const normalize = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
13
|
+
function optionsWithSelection(options, values) {
|
|
14
|
+
const set = new Set(values == null ? [] : Array.isArray(values) ? values : [values]);
|
|
15
|
+
const state = (on, total) => on === 0 ? "none" : on === total ? "all" : "some";
|
|
16
|
+
const walk = (items) => items.map((raw) => {
|
|
17
|
+
if (typeof raw !== "string" && Array.isArray(raw.submenu)) {
|
|
18
|
+
const sm = raw;
|
|
19
|
+
const children = walk(sm.submenu);
|
|
20
|
+
const on = children.reduce((n, c) => n + c.on, 0);
|
|
21
|
+
const total = children.reduce((n, c) => n + c.total, 0);
|
|
22
|
+
return { node: { ...sm, submenu: children.map((c) => c.node), selectionState: state(on, total) }, on, total };
|
|
23
|
+
}
|
|
24
|
+
if (typeof raw !== "string" && Array.isArray(raw.options)) {
|
|
25
|
+
const g = raw;
|
|
26
|
+
const children = walk(g.options);
|
|
27
|
+
const on = children.reduce((n, c) => n + c.on, 0);
|
|
28
|
+
const total = children.reduce((n, c) => n + c.total, 0);
|
|
29
|
+
return { node: { ...g, options: children.map((c) => c.node), selectionState: state(on, total) }, on, total };
|
|
30
|
+
}
|
|
31
|
+
const o = normalize(raw);
|
|
32
|
+
const selected = set.has(o.value);
|
|
33
|
+
return { node: { ...o, selected }, on: selected ? 1 : 0, total: 1 };
|
|
34
|
+
});
|
|
35
|
+
return walk(options).map((c) => c.node);
|
|
36
|
+
}
|
|
37
|
+
const Select = (props) => {
|
|
38
|
+
const {
|
|
39
|
+
options,
|
|
40
|
+
selection,
|
|
41
|
+
indicator,
|
|
42
|
+
value,
|
|
43
|
+
defaultValue,
|
|
44
|
+
onValueChange,
|
|
45
|
+
placeholder,
|
|
46
|
+
icon,
|
|
47
|
+
label,
|
|
48
|
+
hint,
|
|
49
|
+
size,
|
|
50
|
+
status,
|
|
51
|
+
statusIcon,
|
|
52
|
+
round,
|
|
53
|
+
disabled,
|
|
54
|
+
toneSelected,
|
|
55
|
+
filter,
|
|
56
|
+
selectAll,
|
|
57
|
+
selectAllLabel = "Select all",
|
|
58
|
+
renderOption,
|
|
59
|
+
renderIndicator,
|
|
60
|
+
renderTrigger,
|
|
61
|
+
renderEmpty,
|
|
62
|
+
className,
|
|
63
|
+
style,
|
|
64
|
+
...rest
|
|
65
|
+
} = props;
|
|
66
|
+
const multiple = selection === "multiple";
|
|
67
|
+
const statusColor = status && status !== "neutral" ? `var(--text-2-${status})` : void 0;
|
|
68
|
+
const mark = multiple ? "checkbox" : indicator ?? "none";
|
|
69
|
+
const menuItemIndicator = mark === "none" ? void 0 : mark;
|
|
70
|
+
const emit = onValueChange;
|
|
71
|
+
const controlled = value !== void 0;
|
|
72
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
73
|
+
const currentRaw = controlled ? value : internal;
|
|
74
|
+
const [open, setOpen] = useState(false);
|
|
75
|
+
const [query, setQuery] = useState("");
|
|
76
|
+
const [activeId, setActiveId] = useState(null);
|
|
77
|
+
const uid = useId();
|
|
78
|
+
const isSubmenu = (it) => typeof it === "object" && Array.isArray(it.submenu);
|
|
79
|
+
const isGroup = (it) => typeof it === "object" && Array.isArray(it.options);
|
|
80
|
+
const collectLeaves = (items, group, disabled2, out) => {
|
|
81
|
+
for (const raw of items) {
|
|
82
|
+
if (typeof raw !== "string" && isSubmenu(raw)) collectLeaves(raw.submenu, raw.label, disabled2 || !!raw.disabled, out);
|
|
83
|
+
else if (typeof raw !== "string" && isGroup(raw)) collectLeaves(raw.options, raw.label, disabled2 || !!raw.disabled, out);
|
|
84
|
+
else {
|
|
85
|
+
const o = normalize(raw);
|
|
86
|
+
out.push({ opt: o, disabled: disabled2 || !!o.disabled, group });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const allLeaves = [];
|
|
91
|
+
collectLeaves(options, void 0, false, allLeaves);
|
|
92
|
+
const seenValues = /* @__PURE__ */ new Set();
|
|
93
|
+
for (const l of allLeaves) {
|
|
94
|
+
if (seenValues.has(l.opt.value))
|
|
95
|
+
console.warn(`[anta] <Select> duplicate option value=${JSON.stringify(l.opt.value)} \u2014 values must be unique.`);
|
|
96
|
+
seenValues.add(l.opt.value);
|
|
97
|
+
}
|
|
98
|
+
const byValue = new Map(allLeaves.map((l) => [l.opt.value, l.opt]));
|
|
99
|
+
const filtering = filter !== void 0 && filter !== false;
|
|
100
|
+
const q = query.trim();
|
|
101
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
102
|
+
const queryRe = filtering && typeof filter !== "function" && q ? new RegExp(q.split(/\s+/).map(escapeRe).join("\\s+"), "i") : null;
|
|
103
|
+
const matches = (o) => typeof filter === "function" ? filter(o, q) : !queryRe || [o.value, o.label ?? "", o.hint ?? ""].some((s) => queryRe.test(s));
|
|
104
|
+
const prune = typeof filter === "function" || filtering && !!q;
|
|
105
|
+
const visibleLeaves = prune ? allLeaves.filter((l) => matches(l.opt)) : allLeaves;
|
|
106
|
+
const flattening = filtering && !!q;
|
|
107
|
+
const highlight = (text) => {
|
|
108
|
+
if (!queryRe) return text;
|
|
109
|
+
const re = new RegExp(queryRe.source, "gi");
|
|
110
|
+
const out = [];
|
|
111
|
+
let last = 0;
|
|
112
|
+
let m;
|
|
113
|
+
while ((m = re.exec(text)) !== null) {
|
|
114
|
+
if (m.index > last) out.push(text.slice(last, m.index));
|
|
115
|
+
out.push(/* @__PURE__ */ jsx("b", { children: m[0] }, out.length));
|
|
116
|
+
last = m.index + m[0].length;
|
|
117
|
+
if (m[0].length === 0) re.lastIndex++;
|
|
118
|
+
}
|
|
119
|
+
if (out.length === 0) return text;
|
|
120
|
+
if (last < text.length) out.push(text.slice(last));
|
|
121
|
+
return out;
|
|
122
|
+
};
|
|
123
|
+
const selectedValues = Array.isArray(currentRaw) ? currentRaw : currentRaw != null ? [currentRaw] : [];
|
|
124
|
+
const isSelected = (v) => selectedValues.includes(v);
|
|
125
|
+
const selectedOptions = selectedValues.map((v) => byValue.get(v)).filter(Boolean);
|
|
126
|
+
let display = "";
|
|
127
|
+
if (multiple) {
|
|
128
|
+
if (selectedOptions.length === 1) display = selectedOptions[0].label ?? selectedOptions[0].value;
|
|
129
|
+
else if (selectedOptions.length > 1) display = `${selectedOptions.length} selected`;
|
|
130
|
+
} else if (currentRaw != null) {
|
|
131
|
+
const o = byValue.get(currentRaw);
|
|
132
|
+
display = o ? o.label ?? o.value : "";
|
|
133
|
+
}
|
|
134
|
+
const choose = (o, e) => {
|
|
135
|
+
if (multiple) {
|
|
136
|
+
if (selectAll && e?.altKey) {
|
|
137
|
+
const next2 = [o.value];
|
|
138
|
+
if (!controlled) setInternal(next2);
|
|
139
|
+
emit?.(next2, { value: o.value, option: o, selected: true });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const has = selectedValues.includes(o.value);
|
|
143
|
+
const next = has ? selectedValues.filter((v) => v !== o.value) : [...selectedValues, o.value];
|
|
144
|
+
if (!controlled) setInternal(next);
|
|
145
|
+
emit?.(next, { value: o.value, option: o, selected: !has });
|
|
146
|
+
} else {
|
|
147
|
+
if (!controlled) setInternal(o.value);
|
|
148
|
+
emit?.(o.value, { value: o.value, option: o });
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const enabledValues = multiple ? visibleLeaves.filter((l) => !l.disabled).map((l) => l.opt.value) : [];
|
|
152
|
+
const enabledSelected = enabledValues.filter((v) => selectedValues.includes(v));
|
|
153
|
+
const allSelected = enabledValues.length > 0 && enabledSelected.length === enabledValues.length;
|
|
154
|
+
const someSelected = enabledSelected.length > 0 && !allSelected;
|
|
155
|
+
const toggleAll = () => {
|
|
156
|
+
const keep = selectedValues.filter((v) => !enabledValues.includes(v));
|
|
157
|
+
const next = allSelected ? keep : [...keep, ...enabledValues];
|
|
158
|
+
if (!controlled) setInternal(next);
|
|
159
|
+
emit?.(next, { all: true, selected: !allSelected });
|
|
160
|
+
};
|
|
161
|
+
const renderOptionRow = (o, disabled2) => {
|
|
162
|
+
const optState = { value: o.value, selected: isSelected(o.value), disabled: disabled2 };
|
|
163
|
+
const custom = renderOption?.(o, optState);
|
|
164
|
+
const customMark = renderIndicator?.(optState);
|
|
165
|
+
const ariaSelectable = !multiple && mark === "none" ? { role: "menuitemradio", "aria-checked": isSelected(o.value) ? "true" : "false" } : void 0;
|
|
166
|
+
const isolateHint = multiple && selectAll && !disabled2 ? IS_MAC ? "\u2325+Click to select only this" : "Alt+Click to select only this" : void 0;
|
|
167
|
+
const tip = o.tooltip ?? isolateHint;
|
|
168
|
+
const hintOnly = o.tooltip == null && isolateHint != null;
|
|
169
|
+
return /* @__PURE__ */ jsxs(
|
|
170
|
+
MenuItem,
|
|
171
|
+
{
|
|
172
|
+
id: `${uid}-opt-${o.value}`,
|
|
173
|
+
selectionIndicator: menuItemIndicator,
|
|
174
|
+
...ariaSelectable,
|
|
175
|
+
indicator: customMark ?? void 0,
|
|
176
|
+
label: custom ? void 0 : queryRe ? highlight(o.label ?? o.value) : o.label ?? o.value,
|
|
177
|
+
hint: custom ? void 0 : queryRe && o.hint ? highlight(o.hint) : o.hint,
|
|
178
|
+
icon: custom ? void 0 : o.icon,
|
|
179
|
+
tone: o.tone,
|
|
180
|
+
toneSelected,
|
|
181
|
+
selected: isSelected(o.value),
|
|
182
|
+
disabled: disabled2 || void 0,
|
|
183
|
+
"data-menu-open": multiple ? "" : void 0,
|
|
184
|
+
onSelect: (e) => choose(o, e),
|
|
185
|
+
children: [
|
|
186
|
+
custom,
|
|
187
|
+
tip && /* @__PURE__ */ jsx(Tooltip, { ...hintOnly ? { follow: true, delay: 700 } : {}, children: tip })
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
o.value
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
const renderTree = (items, disabled2) => {
|
|
194
|
+
const out = [];
|
|
195
|
+
items.forEach((raw, i) => {
|
|
196
|
+
if (typeof raw !== "string" && isSubmenu(raw)) {
|
|
197
|
+
const dis = disabled2 || !!raw.disabled;
|
|
198
|
+
const inner = renderTree(raw.submenu, dis);
|
|
199
|
+
if (inner.length)
|
|
200
|
+
out.push(
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
MenuItem,
|
|
203
|
+
{
|
|
204
|
+
submenu: true,
|
|
205
|
+
label: raw.label,
|
|
206
|
+
icon: raw.icon,
|
|
207
|
+
disabled: dis || void 0,
|
|
208
|
+
"data-menu-open": multiple ? "" : void 0,
|
|
209
|
+
children: /* @__PURE__ */ jsx(Menu, { children: inner })
|
|
210
|
+
},
|
|
211
|
+
`sub-${i}-${raw.label}`
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (typeof raw !== "string" && isGroup(raw)) {
|
|
217
|
+
const dis = disabled2 || !!raw.disabled;
|
|
218
|
+
const inner = renderTree(raw.options, dis);
|
|
219
|
+
if (inner.length) out.push(/* @__PURE__ */ jsx(MenuGroup, { label: raw.label, children: inner }, `grp-${i}-${raw.label}`));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const o = normalize(raw);
|
|
223
|
+
if (typeof filter === "function" && !matches(o)) return;
|
|
224
|
+
out.push(renderOptionRow(o, disabled2 || !!o.disabled));
|
|
225
|
+
});
|
|
226
|
+
return out;
|
|
227
|
+
};
|
|
228
|
+
const renderFlat = () => {
|
|
229
|
+
const shown = allLeaves.filter((l) => matches(l.opt));
|
|
230
|
+
const out = [];
|
|
231
|
+
for (let i = 0; i < shown.length; ) {
|
|
232
|
+
const label2 = shown[i].group;
|
|
233
|
+
if (label2 === void 0) {
|
|
234
|
+
out.push(renderOptionRow(shown[i].opt, shown[i].disabled));
|
|
235
|
+
i++;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const rows = [];
|
|
239
|
+
const start = i;
|
|
240
|
+
while (i < shown.length && shown[i].group === label2) {
|
|
241
|
+
rows.push(renderOptionRow(shown[i].opt, shown[i].disabled));
|
|
242
|
+
i++;
|
|
243
|
+
}
|
|
244
|
+
out.push(/* @__PURE__ */ jsx(MenuGroup, { label: label2, children: rows }, `flat-${start}-${label2}`));
|
|
245
|
+
}
|
|
246
|
+
return out;
|
|
247
|
+
};
|
|
248
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
249
|
+
renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsx(
|
|
250
|
+
Input,
|
|
251
|
+
{
|
|
252
|
+
label,
|
|
253
|
+
hint,
|
|
254
|
+
placeholder,
|
|
255
|
+
value: display,
|
|
256
|
+
readOnly: true,
|
|
257
|
+
dimActions: true,
|
|
258
|
+
disabled,
|
|
259
|
+
leading: icon ? /* @__PURE__ */ jsx(Icon, { shape: icon }) : void 0,
|
|
260
|
+
size,
|
|
261
|
+
status,
|
|
262
|
+
statusIcon,
|
|
263
|
+
round,
|
|
264
|
+
"aria-haspopup": "menu",
|
|
265
|
+
"aria-expanded": open ? "true" : "false",
|
|
266
|
+
onKeyDown: (e) => {
|
|
267
|
+
if (!open && (e.key === "Enter" || e.key === " " || e.key === "ArrowDown")) {
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
e.currentTarget.click();
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
trailing: (
|
|
273
|
+
// Chevron rotates down → up when open (spacing + rotation in the CSS
|
|
274
|
+
// module, matching the Input "Select dropdown" example).
|
|
275
|
+
/* @__PURE__ */ jsx(
|
|
276
|
+
Icon,
|
|
277
|
+
{
|
|
278
|
+
shape: "chevron-down",
|
|
279
|
+
className: open ? `${styles.chevron} ${styles.open}` : styles.chevron,
|
|
280
|
+
style: statusColor ? { color: statusColor } : void 0
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
),
|
|
284
|
+
className,
|
|
285
|
+
style,
|
|
286
|
+
...rest
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsxs(
|
|
290
|
+
Menu,
|
|
291
|
+
{
|
|
292
|
+
onStateChange: (_e, { next }) => {
|
|
293
|
+
setOpen(next);
|
|
294
|
+
if (!next) {
|
|
295
|
+
setQuery("");
|
|
296
|
+
setActiveId(null);
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
onactivedescendant: (e) => setActiveId((e.nativeEvent ?? e).detail?.id ?? null),
|
|
300
|
+
children: [
|
|
301
|
+
filtering && // `slot="header"` pins the field in the Menu's fixed header region (above
|
|
302
|
+
// the scrolling options); `data-menu-search` puts the menu in combobox
|
|
303
|
+
// mode — it focuses this field on open and drives an active-option cursor.
|
|
304
|
+
/* @__PURE__ */ jsx("div", { className: styles.filter, slot: "header", "data-menu-open": "", children: /* @__PURE__ */ jsx(
|
|
305
|
+
Input,
|
|
306
|
+
{
|
|
307
|
+
"data-menu-search": "",
|
|
308
|
+
size: "small",
|
|
309
|
+
value: query,
|
|
310
|
+
placeholder: "Filter\u2026",
|
|
311
|
+
"aria-label": "Filter options",
|
|
312
|
+
"aria-autocomplete": "list",
|
|
313
|
+
"aria-activedescendant": open && activeId ? activeId : void 0,
|
|
314
|
+
onInput: (e) => setQuery(e.currentTarget.value)
|
|
315
|
+
}
|
|
316
|
+
) }),
|
|
317
|
+
multiple && selectAll && visibleLeaves.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
318
|
+
/* @__PURE__ */ jsx(
|
|
319
|
+
MenuItem,
|
|
320
|
+
{
|
|
321
|
+
selectionIndicator: "checkbox",
|
|
322
|
+
selected: allSelected,
|
|
323
|
+
indeterminate: someSelected,
|
|
324
|
+
label: selectAllLabel,
|
|
325
|
+
"data-menu-open": "",
|
|
326
|
+
"data-menu-skip-active": "",
|
|
327
|
+
onSelect: toggleAll
|
|
328
|
+
}
|
|
329
|
+
),
|
|
330
|
+
/* @__PURE__ */ jsx(MenuSeparator, {})
|
|
331
|
+
] }),
|
|
332
|
+
visibleLeaves.length === 0 ? renderEmpty?.({ query: q }) : flattening ? renderFlat() : renderTree(options, false)
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
] });
|
|
337
|
+
};
|
|
338
|
+
export {
|
|
339
|
+
Select,
|
|
340
|
+
optionsWithSelection
|
|
341
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.chevron{margin-inline-end:7px;transition:transform .15s ease}.chevron.open{transform:rotate(180deg)}.filter{padding:4px 4px 0}
|
package/dist/components/Tab.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ export interface TabProps {
|
|
|
14
14
|
icon?: IconShape;
|
|
15
15
|
/** Trailing icon shape, rendered after the label. */
|
|
16
16
|
iconTrailing?: IconShape;
|
|
17
|
+
/** Fully-round just this tab's box. `<Tabs round>` rounds the whole strip
|
|
18
|
+
* (tabs + sliding indicator) instead. */
|
|
19
|
+
round?: boolean;
|
|
17
20
|
/** Per-tab tone override, same vocabulary as `<Tabs tone>` — colours this one tab's
|
|
18
21
|
* label + icons (all priorities/modes, named or custom colour) and, when it's the
|
|
19
22
|
* active tab, its indicator. For a **custom literal colour** the sliding indicator can't
|
package/dist/components/Tab.js
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
*
|
|
1
|
+
/**
|
|
2
|
+
* A tab panel inside `<Tabs>`. Renders a self-managing `<a-tabpanel>` — the element
|
|
3
|
+
* finds its `<a-tabs>` (its flat sibling under the same parent — `Tabs` renders the
|
|
4
|
+
* strip and panels with no wrapper), matches by `value`, and shows/hides itself
|
|
5
|
+
* off-DOM. This wrapper is a pure projection: it sets the static ARIA (`role`,
|
|
6
|
+
* `tabindex`, `value`) and passes `children` straight through; `Tabs` never reads
|
|
7
|
+
* or toggles it.
|
|
8
|
+
*
|
|
9
|
+
* Use it as a direct child of `<Tabs>`, paired to an `options` entry by `value`.
|
|
10
|
+
* For a strip and panels in different layout regions (no shared parent), or to
|
|
11
|
+
* unmount an inactive panel (the old `mounting="active" | "lazy"`), drive selection
|
|
12
|
+
* with a controlled `value` and render the content yourself — see the Tabs docs.
|
|
13
|
+
*/
|
|
5
14
|
export interface TabPanelProps {
|
|
6
|
-
/** Pairs this panel with the
|
|
15
|
+
/** Pairs this panel with the tab (`options` entry) of the same `value`. */
|
|
7
16
|
value: string;
|
|
8
17
|
/** Panel content — arbitrary React/Preact. */
|
|
9
18
|
children?: React.ReactNode;
|
|
10
|
-
/**
|
|
11
|
-
|
|
19
|
+
/** How this panel hides while inactive: `display` (default — removed from layout
|
|
20
|
+
* and the a11y tree) or `visibility` (keeps its layout box, to measure it or
|
|
21
|
+
* avoid reflow). Both stay mounted; to *not render* an inactive panel, render it
|
|
22
|
+
* conditionally off a controlled `value` (see the Tabs docs).
|
|
23
|
+
* @defaultValue display */
|
|
24
|
+
hideMode?: "display" | "visibility";
|
|
12
25
|
/** CSS class on the rendered `<a-tabpanel>`. */
|
|
13
26
|
className?: string;
|
|
14
27
|
/** Inline style on the rendered `<a-tabpanel>`. */
|
|
15
28
|
style?: React.CSSProperties;
|
|
16
29
|
}
|
|
17
|
-
|
|
18
|
-
* A tab panel inside `<Tabs>`. Configuration only — `Tabs` reads its props and renders
|
|
19
|
-
* the real `<a-tabpanel>`, so this component itself produces no DOM. Use it as a direct
|
|
20
|
-
* child of `<Tabs>`; rendering it elsewhere does nothing.
|
|
21
|
-
*/
|
|
22
|
-
export declare const TabPanel: (_props: TabPanelProps) => null;
|
|
30
|
+
export declare const TabPanel: ({ value, children, hideMode, className, style }: TabPanelProps) => any;
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { jsx } from "@antadesign/anta/jsx-runtime";
|
|
2
|
+
const TabPanel = ({ value, children, hideMode, className, style }) => /* @__PURE__ */ jsx(
|
|
3
|
+
"a-tabpanel",
|
|
4
|
+
{
|
|
5
|
+
value,
|
|
6
|
+
role: "tabpanel",
|
|
7
|
+
tabIndex: 0,
|
|
8
|
+
"hide-mode": hideMode === "visibility" ? "visibility" : void 0,
|
|
9
|
+
class: className,
|
|
10
|
+
style,
|
|
11
|
+
children
|
|
12
|
+
}
|
|
13
|
+
);
|
|
2
14
|
export {
|
|
3
15
|
TabPanel
|
|
4
16
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BaseProps } from "../general_types";
|
|
2
|
+
import type { IconShape } from "../elements/a-icon.shapes";
|
|
2
3
|
/** The element's `statechange` payload — `next`/`prev` are tab values (`null` = none). */
|
|
3
4
|
type StateDetail = {
|
|
4
5
|
next: string | null;
|
|
@@ -9,33 +10,58 @@ type StateChangeEvent = CustomEvent<StateDetail>;
|
|
|
9
10
|
export interface TabsChangeAttrs {
|
|
10
11
|
value: string | null;
|
|
11
12
|
}
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
* - `
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
|
|
13
|
+
/** One tab as a plain data object for the `options` array — the single source `Tabs`
|
|
14
|
+
* renders its strip from (like `RadioGroup`'s `options`). `Tabs` reads these fields to
|
|
15
|
+
* render the underlying `<a-tab>` (`tabindex`, `role`, and selection are all `Tabs`'
|
|
16
|
+
* job, published off-DOM by the element). */
|
|
17
|
+
export interface TabOption {
|
|
18
|
+
/** This tab's identity — pairs it with the `<TabPanel value="…">` of the same
|
|
19
|
+
* value, and the value reported by `onStateChange` / `onChange`. Unique per strip. */
|
|
20
|
+
value: string;
|
|
21
|
+
/** Visible label. The string shorthand for the tab's content; for richer content
|
|
22
|
+
* pass `children` instead (`label` wins when both are set). */
|
|
23
|
+
label?: React.ReactNode;
|
|
24
|
+
/** Tab content when you need more than a string — used if `label` is omitted. */
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
/** Leading icon shape, rendered before the label. */
|
|
27
|
+
icon?: IconShape;
|
|
28
|
+
/** Trailing icon shape, rendered after the label. */
|
|
29
|
+
iconTrailing?: IconShape;
|
|
30
|
+
/** Fully-round just this tab's box. `<Tabs round>` rounds the whole strip
|
|
31
|
+
* (tabs + sliding indicator) instead. */
|
|
32
|
+
round?: boolean;
|
|
33
|
+
/** Per-tab tone override, same vocabulary as `<Tabs tone>` — colours this one tab's
|
|
34
|
+
* label + icons (all priorities/modes, named or custom colour) and, when it's the
|
|
35
|
+
* active tab, its indicator. For a **custom literal colour** the sliding indicator can't
|
|
36
|
+
* adopt it (the shared moving element can't read a descendant's colour), so a custom tone
|
|
37
|
+
* colours the label everywhere and the indicator only in `noslide`; the six **named**
|
|
38
|
+
* tones colour both in every mode. Overrides the strip's `tone` for this tab.
|
|
39
|
+
* @defaultValue inherits the strip's `tone` */
|
|
40
|
+
tone?: "neutral" | "brand" | "info" | "success" | "warning" | "critical" | (string & {});
|
|
41
|
+
/** Disable just this tab — skipped by keyboard nav and dropped from the tab order
|
|
42
|
+
* (a disabled-but-selected tab stays reachable, per the ARIA pattern). */
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
}
|
|
23
45
|
/** Public props for `<Tabs>`. */
|
|
24
46
|
export interface TabsProps extends Omit<BaseProps, "onChange"> {
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
47
|
+
/** Optional `<TabPanel value="…">` panels, one per tab value. Each is a
|
|
48
|
+
* self-managing `<a-tabpanel>` that shows itself when its `value` is the active
|
|
49
|
+
* tab. Omit them to use `Tabs` as a bare selectable strip. To place panels in a
|
|
50
|
+
* different layout region, or to unmount an inactive panel, drive selection with
|
|
51
|
+
* a controlled `value` and render the content yourself (see the docs). */
|
|
30
52
|
children?: React.ReactNode;
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
/** The tabs, as a data array (the strip's single source). Each entry is a
|
|
54
|
+
* `TabOption` (`value`, `label` or `children`, `icon`, `iconTrailing`, `tone`,
|
|
55
|
+
* `disabled`, `round`). */
|
|
56
|
+
options?: TabOption[];
|
|
57
|
+
/** Controlled active value — the tab `value` to mark selected (and, when a
|
|
58
|
+
* `<TabPanel value="…">` shares it, the panel to reveal). When set, you own
|
|
59
|
+
* selection: the strip renders exactly what this says, and a user pick only
|
|
60
|
+
* *requests* a change via `onStateChange` — apply it by updating this prop.
|
|
61
|
+
* Leave undefined (and use `defaultValue`) for uncontrolled. */
|
|
36
62
|
value?: string;
|
|
37
|
-
/** Initial active value for the uncontrolled case
|
|
38
|
-
*
|
|
63
|
+
/** Initial active value for the uncontrolled case. After first render `Tabs`
|
|
64
|
+
* owns selection itself. */
|
|
39
65
|
defaultValue?: string;
|
|
40
66
|
/** Fired whenever the active tab changes — event-first. `detail` is
|
|
41
67
|
* `{ next, prev }` (values; `null` = none). Cancelable: `event.preventDefault()`
|
|
@@ -71,42 +97,51 @@ export interface TabsProps extends Omit<BaseProps, "onChange"> {
|
|
|
71
97
|
* is opt-in via CSS); vertical stacks them.
|
|
72
98
|
* @defaultValue 'horizontal' */
|
|
73
99
|
orientation?: "horizontal" | "vertical";
|
|
74
|
-
/** How inactive panels are mounted/hidden. Per-panel `<TabPanel mounting>` overrides.
|
|
75
|
-
* @defaultValue 'display' */
|
|
76
|
-
mounting?: TabsMounting;
|
|
77
100
|
/** Disable the sliding indicator. By default the selected-tab indicator animates
|
|
78
101
|
* between tabs (a single rectangle, via CSS anchor positioning); `noslide` paints it
|
|
79
102
|
* per tab so it snaps with no movement. (Browsers without anchor positioning get that
|
|
80
103
|
* per-tab paint automatically — `noslide` is the explicit opt-out.) */
|
|
81
104
|
noslide?: boolean;
|
|
105
|
+
/** Fully-round the tabs and the sliding indicator (and the primary track
|
|
106
|
+
* well). Applies strip-wide; a single tab's `round` rounds just that tab. A
|
|
107
|
+
* `number` (px) or CSS length string sets a custom radius on the top-level
|
|
108
|
+
* track well only — the tab pills + indicator stay fully round. */
|
|
109
|
+
round?: boolean | number | string;
|
|
82
110
|
/** Disable the whole strip. */
|
|
83
111
|
disabled?: boolean;
|
|
84
112
|
}
|
|
85
113
|
/**
|
|
86
|
-
* `<Tabs>` — a tablist with optional panels
|
|
87
|
-
* children.
|
|
114
|
+
* `<Tabs>` — a tablist with optional panels. The strip renders from the `options`
|
|
115
|
+
* array; panels are `<TabPanel>` children that manage their own visibility.
|
|
88
116
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* reflects the current value into panel visibility on re-render.
|
|
117
|
+
* The strip (`<a-tabs>`) and the panels render as flat siblings — there is no wrapper
|
|
118
|
+
* element, so `className` / `id` / `style` / `...rest` land on the strip. Laying the
|
|
119
|
+
* strip out relative to its panels is the consumer's job: a horizontal strip stacks
|
|
120
|
+
* above the panels in normal flow; for a vertical strip beside them, wrap `<Tabs>` in
|
|
121
|
+
* your own flex container. Any non-`TabPanel` children render verbatim as siblings too.
|
|
95
122
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
123
|
+
* `<a-tabs>` owns selection off-DOM (it sets each tab's `selected` property and the
|
|
124
|
+
* roving `aria-activedescendant` via `ElementInternals`, writing no attribute to any
|
|
125
|
+
* tab); this wrapper mirrors the value only to render the strip's roving `tabindex`,
|
|
126
|
+
* and the panels read it straight from `<a-tabs>`. Controlled (`value` + `onStateChange`)
|
|
127
|
+
* or uncontrolled (`defaultValue`).
|
|
98
128
|
*
|
|
99
129
|
* Requires `@antadesign/anta/elements` (client-side only).
|
|
100
130
|
*
|
|
101
131
|
* @example
|
|
102
132
|
* ```tsx
|
|
103
|
-
* <Tabs
|
|
104
|
-
*
|
|
105
|
-
*
|
|
133
|
+
* <Tabs
|
|
134
|
+
* defaultValue="account"
|
|
135
|
+
* label="Settings"
|
|
136
|
+
* options={[
|
|
137
|
+
* { value: "account", label: "Account", icon: "user" },
|
|
138
|
+
* { value: "security", label: "Security" },
|
|
139
|
+
* ]}
|
|
140
|
+
* >
|
|
106
141
|
* <TabPanel value="account"><AccountForm /></TabPanel>
|
|
107
142
|
* <TabPanel value="security"><SecurityForm /></TabPanel>
|
|
108
143
|
* </Tabs>
|
|
109
144
|
* ```
|
|
110
145
|
*/
|
|
111
|
-
export declare const Tabs: ({ children, value, defaultValue, onStateChange, onChange, onValueChange, onFocus, onBlur, label, priority, tone, size, orientation,
|
|
146
|
+
export declare const Tabs: ({ children, options, value, defaultValue, onStateChange, onChange, onValueChange, onFocus, onBlur, label, priority, tone, size, orientation, noslide, round, disabled, className, style, id, ...rest }: TabsProps) => any;
|
|
112
147
|
export {};
|