@godxjp/ui 30.4.2 → 30.5.3
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/agent/START-HERE.md +6 -6
- package/agent/components/Carousel.json +4 -1
- package/agent/components/RecordPicker.json +108 -0
- package/agent/components/ResponsiveGrid.json +3 -1
- package/agent/components/Reveal.json +6 -1
- package/agent/components/Table.json +6 -0
- package/agent/components/Text.json +8 -0
- package/agent/components-index.json +5 -0
- package/agent/components.json +135 -3
- package/agent/index.json +7 -7
- package/agent/llms.txt +7 -7
- package/agent/patterns/brand-theme-block.json +33 -0
- package/agent/patterns-index.json +32 -0
- package/agent/patterns.json +33 -0
- package/agent/tokens.json +12 -0
- package/dist/components/data-display/table.d.ts +30 -1
- package/dist/components/data-display/table.js +2 -1
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/data-entry/record-picker.d.ts +63 -0
- package/dist/components/data-entry/record-picker.js +359 -0
- package/dist/components/general/typography.d.ts +1 -0
- package/dist/components/general/typography.js +10 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +18 -0
- package/dist/i18n/messages/ja.json +18 -0
- package/dist/i18n/messages/vi.json +18 -0
- package/dist/props/components/data-entry.prop.d.ts +64 -0
- package/dist/props/components/general.prop.d.ts +15 -1
- package/dist/props/registry.d.ts +17 -0
- package/dist/props/registry.js +17 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +13 -0
- package/dist/styles/data-display-layout.css +6 -3
- package/dist/styles/data-entry-layout.css +82 -0
- package/dist/styles/dialog-layout.css +8 -0
- package/dist/styles/focus-ring.css +2 -0
- package/dist/styles/table-layout.css +13 -0
- package/dist/styles/text-layout.css +8 -0
- package/dist/tokens/components/data-display.css +2 -0
- package/dist/tokens/components/data-entry.css +3 -0
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/assets/tcgm/card-1.svg +1 -0
- package/docs/assets/tcgm/card-2.svg +1 -0
- package/docs/assets/tcgm/card-3.svg +1 -0
- package/docs/assets/tcgm/card-4.svg +1 -0
- package/docs/assets/tcgm/card-5.svg +1 -0
- package/docs/assets/tcgm/card-6.svg +1 -0
- package/docs/assets/tcgm/hero-prism.svg +1 -0
- package/docs/assets/tcgm/scene-1.svg +1 -0
- package/docs/assets/tcgm/scene-2.svg +1 -0
- package/docs/assets/tcgm/scene-3.svg +1 -0
- package/docs/assets/tcgm/scene-4.svg +1 -0
- package/docs/assets/tcgm/scene-5.svg +1 -0
- package/docs/assets/tcgm/tcgm-lockup-color.svg +1 -0
- package/docs/assets/tcgm/tcgm-symbol-color.svg +1 -0
- package/docs/data-entry/record-picker.tsx +208 -0
- package/docs/general/typography.tsx +28 -0
- package/docs/i18n/messages/en.json +185 -1
- package/docs/i18n/messages/ja.json +185 -1
- package/docs/i18n/messages/vi.json +185 -1
- package/docs/showcase/tcgm-website.tsx +1047 -0
- package/package.json +3 -3
- package/scripts/ui-audit.mjs +23 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Check, ChevronDown, X } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { normalizeSelectOptions } from "../../lib/select-options.js";
|
|
8
|
+
import { Badge } from "../data-display/badge.js";
|
|
9
|
+
import { EmptyState } from "../data-display/empty-state.js";
|
|
10
|
+
import { Button } from "../general/button.js";
|
|
11
|
+
import { Text } from "../general/typography.js";
|
|
12
|
+
import { Flex } from "../layout/flex.js";
|
|
13
|
+
import {
|
|
14
|
+
Dialog,
|
|
15
|
+
DialogBody,
|
|
16
|
+
DialogContent,
|
|
17
|
+
DialogFooter,
|
|
18
|
+
DialogHeader,
|
|
19
|
+
DialogTitle
|
|
20
|
+
} from "../feedback/dialog.js";
|
|
21
|
+
import { Command, CommandGroup } from "./command.js";
|
|
22
|
+
import { Input } from "./input.js";
|
|
23
|
+
import { Select } from "./select.js";
|
|
24
|
+
const RecordPicker = React.forwardRef(
|
|
25
|
+
function RecordPicker2({
|
|
26
|
+
mode = "single",
|
|
27
|
+
value,
|
|
28
|
+
defaultValue,
|
|
29
|
+
onValueChange,
|
|
30
|
+
options,
|
|
31
|
+
loadOptions,
|
|
32
|
+
count,
|
|
33
|
+
threshold = 10,
|
|
34
|
+
filters,
|
|
35
|
+
selectedOptions,
|
|
36
|
+
emptyOption,
|
|
37
|
+
placeholder,
|
|
38
|
+
dialogTitle,
|
|
39
|
+
disabled = false,
|
|
40
|
+
size,
|
|
41
|
+
className,
|
|
42
|
+
"data-field": fieldName,
|
|
43
|
+
...props
|
|
44
|
+
}, ref) {
|
|
45
|
+
const { t } = useTranslation();
|
|
46
|
+
const isMultiple = mode === "multiple";
|
|
47
|
+
const controlled = value !== void 0;
|
|
48
|
+
const [internal, setInternal] = React.useState(
|
|
49
|
+
() => toArray(defaultValue ?? (isMultiple ? [] : null))
|
|
50
|
+
);
|
|
51
|
+
const selected = controlled ? toArray(value) : internal;
|
|
52
|
+
const commit = React.useCallback(
|
|
53
|
+
(next) => {
|
|
54
|
+
if (!controlled) setInternal(next);
|
|
55
|
+
onValueChange?.(isMultiple ? next : next[0] ?? null);
|
|
56
|
+
},
|
|
57
|
+
[controlled, isMultiple, onValueChange]
|
|
58
|
+
);
|
|
59
|
+
const selectLoadOptions = React.useMemo(
|
|
60
|
+
() => loadOptions ? async ({ query, page }) => {
|
|
61
|
+
const r = await loadOptions({
|
|
62
|
+
query,
|
|
63
|
+
filters: {},
|
|
64
|
+
cursor: page > 1 ? String(page) : void 0
|
|
65
|
+
});
|
|
66
|
+
return { options: r.options, hasMore: r.nextCursor !== void 0 };
|
|
67
|
+
} : void 0,
|
|
68
|
+
[loadOptions]
|
|
69
|
+
);
|
|
70
|
+
const staticOptions = React.useMemo(
|
|
71
|
+
() => options ? normalizeSelectOptions(options) : [],
|
|
72
|
+
[options]
|
|
73
|
+
);
|
|
74
|
+
const total = count ?? (options ? staticOptions.length : void 0);
|
|
75
|
+
const asDialog = total === void 0 ? Boolean(loadOptions) : total > threshold;
|
|
76
|
+
if (!asDialog) {
|
|
77
|
+
return /* @__PURE__ */ jsx(
|
|
78
|
+
Select,
|
|
79
|
+
{
|
|
80
|
+
mode: isMultiple ? "multiple" : void 0,
|
|
81
|
+
loadOptions: selectLoadOptions,
|
|
82
|
+
id: props.id,
|
|
83
|
+
"data-field": fieldName,
|
|
84
|
+
"aria-describedby": props["aria-describedby"],
|
|
85
|
+
labelInValue: false,
|
|
86
|
+
showSearch: true,
|
|
87
|
+
options: withEmptyOption(options, emptyOption),
|
|
88
|
+
value: isMultiple ? selected : selected[0] ?? void 0,
|
|
89
|
+
onValueChange: ((next) => commit(toArray(next))),
|
|
90
|
+
placeholder: placeholder ?? t("dataEntry.recordPicker.placeholder"),
|
|
91
|
+
disabled,
|
|
92
|
+
size,
|
|
93
|
+
className
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return /* @__PURE__ */ jsx(
|
|
98
|
+
DialogPicker,
|
|
99
|
+
{
|
|
100
|
+
ref,
|
|
101
|
+
"data-field": fieldName,
|
|
102
|
+
isMultiple,
|
|
103
|
+
selected,
|
|
104
|
+
commit,
|
|
105
|
+
staticOptions,
|
|
106
|
+
loadOptions,
|
|
107
|
+
filters,
|
|
108
|
+
selectedOptions,
|
|
109
|
+
emptyOption,
|
|
110
|
+
placeholder,
|
|
111
|
+
dialogTitle,
|
|
112
|
+
disabled,
|
|
113
|
+
size,
|
|
114
|
+
className,
|
|
115
|
+
...props
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
function toArray(v) {
|
|
121
|
+
if (v === null || v === void 0) return [];
|
|
122
|
+
return Array.isArray(v) ? v : [v];
|
|
123
|
+
}
|
|
124
|
+
function withEmptyOption(options, emptyOption) {
|
|
125
|
+
if (!emptyOption) return options;
|
|
126
|
+
return [{ value: emptyOption.value, label: emptyOption.label }, ...options ?? []];
|
|
127
|
+
}
|
|
128
|
+
const DialogPicker = React.forwardRef(function DialogPicker2({
|
|
129
|
+
isMultiple,
|
|
130
|
+
selected,
|
|
131
|
+
commit,
|
|
132
|
+
staticOptions,
|
|
133
|
+
loadOptions,
|
|
134
|
+
filters,
|
|
135
|
+
selectedOptions,
|
|
136
|
+
emptyOption,
|
|
137
|
+
placeholder,
|
|
138
|
+
dialogTitle,
|
|
139
|
+
disabled,
|
|
140
|
+
size,
|
|
141
|
+
className,
|
|
142
|
+
...props
|
|
143
|
+
}, ref) {
|
|
144
|
+
const { t } = useTranslation();
|
|
145
|
+
const [open, setOpen] = React.useState(false);
|
|
146
|
+
const [query, setQuery] = React.useState("");
|
|
147
|
+
const [filterValues, setFilterValues] = React.useState({});
|
|
148
|
+
const [rows, setRows] = React.useState(staticOptions);
|
|
149
|
+
const [status, setStatus] = React.useState("idle");
|
|
150
|
+
const [cursor, setCursor] = React.useState(void 0);
|
|
151
|
+
const [draft, setDraft] = React.useState(selected);
|
|
152
|
+
React.useEffect(() => {
|
|
153
|
+
if (open) setDraft(selected);
|
|
154
|
+
}, [open, selected]);
|
|
155
|
+
const labelCache = React.useRef(/* @__PURE__ */ new Map());
|
|
156
|
+
for (const o of [...selectedOptions ?? [], ...staticOptions, ...rows]) {
|
|
157
|
+
labelCache.current.set(o.value, o);
|
|
158
|
+
}
|
|
159
|
+
if (emptyOption) {
|
|
160
|
+
labelCache.current.set(emptyOption.value, {
|
|
161
|
+
value: emptyOption.value,
|
|
162
|
+
label: emptyOption.label
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const labels = labelCache.current;
|
|
166
|
+
const load = React.useCallback(
|
|
167
|
+
async (q, f, more) => {
|
|
168
|
+
if (!loadOptions) return;
|
|
169
|
+
setStatus("loading");
|
|
170
|
+
try {
|
|
171
|
+
const result = await loadOptions({ query: q, filters: f, cursor: more });
|
|
172
|
+
setRows((prev) => more ? [...prev, ...result.options] : result.options);
|
|
173
|
+
setCursor(result.nextCursor);
|
|
174
|
+
setStatus("idle");
|
|
175
|
+
} catch {
|
|
176
|
+
setStatus("error");
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
[loadOptions]
|
|
180
|
+
);
|
|
181
|
+
React.useEffect(() => {
|
|
182
|
+
if (!open || !loadOptions) return;
|
|
183
|
+
const id = setTimeout(() => void load(query, filterValues), 250);
|
|
184
|
+
return () => clearTimeout(id);
|
|
185
|
+
}, [open, query, filterValues, load, loadOptions]);
|
|
186
|
+
const visible = React.useMemo(() => {
|
|
187
|
+
const base = loadOptions ? rows : staticOptions.filter((o) => o.label.toLowerCase().includes(query.trim().toLowerCase()));
|
|
188
|
+
return emptyOption && !query.trim() ? [{ value: emptyOption.value, label: emptyOption.label }, ...base] : base;
|
|
189
|
+
}, [loadOptions, rows, staticOptions, query, emptyOption]);
|
|
190
|
+
const groups = React.useMemo(() => {
|
|
191
|
+
const out = /* @__PURE__ */ new Map();
|
|
192
|
+
for (const o of visible) {
|
|
193
|
+
const key = o.group ?? "";
|
|
194
|
+
out.set(key, [...out.get(key) ?? [], o]);
|
|
195
|
+
}
|
|
196
|
+
return [...out.entries()];
|
|
197
|
+
}, [visible]);
|
|
198
|
+
const toggle = (optionValue) => {
|
|
199
|
+
if (!isMultiple) {
|
|
200
|
+
commit([optionValue]);
|
|
201
|
+
setOpen(false);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
setDraft(
|
|
205
|
+
(prev) => prev.includes(optionValue) ? prev.filter((v) => v !== optionValue) : [...prev, optionValue]
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
const chips = selected.map((v) => labels.get(v) ?? { value: v, label: v });
|
|
209
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
210
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "row", gap: "xs", align: "center", className: "ui-record-picker-row", children: [
|
|
211
|
+
/* @__PURE__ */ jsxs(
|
|
212
|
+
Button,
|
|
213
|
+
{
|
|
214
|
+
ref,
|
|
215
|
+
type: "button",
|
|
216
|
+
variant: "outline",
|
|
217
|
+
size,
|
|
218
|
+
disabled,
|
|
219
|
+
"aria-haspopup": "dialog",
|
|
220
|
+
onClick: () => setOpen(true),
|
|
221
|
+
className: cn("ui-record-picker-trigger", className),
|
|
222
|
+
...props,
|
|
223
|
+
children: [
|
|
224
|
+
/* @__PURE__ */ jsx("span", { className: "ui-record-picker-trigger-label", children: chips.length === 0 ? /* @__PURE__ */ jsx(Text, { as: "span", size: "sm", tone: "muted", children: placeholder ?? t("dataEntry.recordPicker.placeholder") }) : /* @__PURE__ */ jsx(Flex, { direction: "row", gap: "xs", wrap: true, align: "center", children: chips.map((c) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", as: "span", children: [
|
|
225
|
+
c.icon,
|
|
226
|
+
c.label
|
|
227
|
+
] }, c.value)) }) }),
|
|
228
|
+
/* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" })
|
|
229
|
+
]
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
!isMultiple && selected.length > 0 && !disabled ? /* @__PURE__ */ jsx(
|
|
233
|
+
Button,
|
|
234
|
+
{
|
|
235
|
+
variant: "ghost",
|
|
236
|
+
size: "icon-sm",
|
|
237
|
+
"aria-label": t("dataEntry.recordPicker.clear"),
|
|
238
|
+
onClick: () => commit([]),
|
|
239
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
240
|
+
}
|
|
241
|
+
) : null
|
|
242
|
+
] }),
|
|
243
|
+
/* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "ui-record-picker-dialog", children: [
|
|
244
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: dialogTitle ?? t("dataEntry.recordPicker.dialogTitle") }) }),
|
|
245
|
+
/* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsxs(Flex, { direction: "col", gap: "md", children: [
|
|
246
|
+
/* @__PURE__ */ jsx(
|
|
247
|
+
Input,
|
|
248
|
+
{
|
|
249
|
+
autoFocus: true,
|
|
250
|
+
type: "search",
|
|
251
|
+
value: query,
|
|
252
|
+
onChange: (e) => setQuery(e.target.value),
|
|
253
|
+
"aria-label": t("dataEntry.recordPicker.search"),
|
|
254
|
+
placeholder: t("dataEntry.recordPicker.searchPlaceholder")
|
|
255
|
+
}
|
|
256
|
+
),
|
|
257
|
+
filters?.length ? /* @__PURE__ */ jsx(
|
|
258
|
+
Flex,
|
|
259
|
+
{
|
|
260
|
+
direction: "row",
|
|
261
|
+
gap: "sm",
|
|
262
|
+
wrap: true,
|
|
263
|
+
role: "group",
|
|
264
|
+
"aria-label": t("dataEntry.recordPicker.filters"),
|
|
265
|
+
children: filters.map((f) => /* @__PURE__ */ jsx(
|
|
266
|
+
Select,
|
|
267
|
+
{
|
|
268
|
+
size: "sm",
|
|
269
|
+
"aria-label": f.label,
|
|
270
|
+
placeholder: f.label,
|
|
271
|
+
value: filterValues[f.name] ?? "",
|
|
272
|
+
onValueChange: (next) => setFilterValues((prev) => ({ ...prev, [f.name]: next })),
|
|
273
|
+
options: [
|
|
274
|
+
{ value: "", label: t("dataEntry.recordPicker.allFilter") },
|
|
275
|
+
...f.options
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
f.name
|
|
279
|
+
))
|
|
280
|
+
}
|
|
281
|
+
) : null,
|
|
282
|
+
/* @__PURE__ */ jsx(Command, { shouldFilter: false, split: isMultiple, className: "ui-record-picker-list", children: status === "error" ? /* @__PURE__ */ jsx(
|
|
283
|
+
EmptyState,
|
|
284
|
+
{
|
|
285
|
+
variant: "compact",
|
|
286
|
+
tone: "destructive",
|
|
287
|
+
title: t("dataEntry.recordPicker.error"),
|
|
288
|
+
action: /* @__PURE__ */ jsx(
|
|
289
|
+
Button,
|
|
290
|
+
{
|
|
291
|
+
variant: "outline",
|
|
292
|
+
size: "sm",
|
|
293
|
+
onClick: () => void load(query, filterValues),
|
|
294
|
+
children: t("dataEntry.recordPicker.more")
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
) : status === "loading" ? /* @__PURE__ */ jsx("div", { role: "status", className: "ui-record-picker-status", children: t("dataEntry.recordPicker.loading") }) : visible.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { variant: "compact", title: t("dataEntry.recordPicker.empty") }) : groups.map(([heading, items]) => {
|
|
299
|
+
const rendered = items.map((o) => {
|
|
300
|
+
const picked = (isMultiple ? draft : selected).includes(o.value);
|
|
301
|
+
return /* @__PURE__ */ jsxs(
|
|
302
|
+
"button",
|
|
303
|
+
{
|
|
304
|
+
type: "button",
|
|
305
|
+
role: "option",
|
|
306
|
+
"aria-selected": picked,
|
|
307
|
+
"data-picked": picked ? "" : void 0,
|
|
308
|
+
disabled: o.disabled,
|
|
309
|
+
className: "ui-record-picker-option",
|
|
310
|
+
onClick: () => toggle(o.value),
|
|
311
|
+
children: [
|
|
312
|
+
/* @__PURE__ */ jsx("span", { className: "ui-record-picker-tick", "aria-hidden": "true", children: picked ? /* @__PURE__ */ jsx(Check, {}) : null }),
|
|
313
|
+
o.icon,
|
|
314
|
+
/* @__PURE__ */ jsxs("span", { className: "ui-record-picker-option-label", children: [
|
|
315
|
+
o.label,
|
|
316
|
+
o.sublabel ? /* @__PURE__ */ jsx(Text, { as: "span", size: "2xs", tone: "muted", children: o.sublabel }) : null
|
|
317
|
+
] })
|
|
318
|
+
]
|
|
319
|
+
},
|
|
320
|
+
o.value
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
return heading ? /* @__PURE__ */ jsx(CommandGroup, { heading, children: rendered }, heading) : /* @__PURE__ */ jsx(React.Fragment, { children: rendered }, "__ungrouped");
|
|
324
|
+
}) }),
|
|
325
|
+
cursor !== void 0 && status !== "loading" ? /* @__PURE__ */ jsx(
|
|
326
|
+
Button,
|
|
327
|
+
{
|
|
328
|
+
variant: "outline",
|
|
329
|
+
size: "sm",
|
|
330
|
+
onClick: () => void load(query, filterValues, cursor),
|
|
331
|
+
children: t("dataEntry.recordPicker.more")
|
|
332
|
+
}
|
|
333
|
+
) : null
|
|
334
|
+
] }) }),
|
|
335
|
+
isMultiple ? /* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
336
|
+
/* @__PURE__ */ jsx(Text, { as: "span", size: "xs", tone: "muted", className: "me-auto", children: t("dataEntry.recordPicker.selected", { count: draft.length }) }),
|
|
337
|
+
/* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setDraft([]), children: [
|
|
338
|
+
/* @__PURE__ */ jsx(X, { "aria-hidden": "true" }),
|
|
339
|
+
t("dataEntry.recordPicker.clear")
|
|
340
|
+
] }),
|
|
341
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => setOpen(false), children: t("dataEntry.recordPicker.cancel") }),
|
|
342
|
+
/* @__PURE__ */ jsx(
|
|
343
|
+
Button,
|
|
344
|
+
{
|
|
345
|
+
size: "sm",
|
|
346
|
+
onClick: () => {
|
|
347
|
+
commit(draft);
|
|
348
|
+
setOpen(false);
|
|
349
|
+
},
|
|
350
|
+
children: t("dataEntry.recordPicker.confirm")
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
] }) : null
|
|
354
|
+
] }) })
|
|
355
|
+
] });
|
|
356
|
+
});
|
|
357
|
+
export {
|
|
358
|
+
RecordPicker
|
|
359
|
+
};
|
|
@@ -20,6 +20,7 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
|
|
|
20
20
|
clamp?: number;
|
|
21
21
|
ellipsis?: boolean | Omit<TypographyEllipsisConfigProp, "rows" | "expandable" | "onExpand">;
|
|
22
22
|
whitespace?: import("../../props/index.js").TextWhitespaceProp;
|
|
23
|
+
break?: import("../../props/index.js").TextBreakProp;
|
|
23
24
|
tabular?: boolean;
|
|
24
25
|
decoration?: "none" | "underline" | "line-through";
|
|
25
26
|
chip?: boolean;
|
|
@@ -380,6 +380,8 @@ const TextBase = React.forwardRef((props, ref) => {
|
|
|
380
380
|
truncate,
|
|
381
381
|
clamp,
|
|
382
382
|
whitespace,
|
|
383
|
+
// `break` is a reserved word, so it cannot be a binding name.
|
|
384
|
+
break: breakMode,
|
|
383
385
|
tabular,
|
|
384
386
|
decoration,
|
|
385
387
|
chip,
|
|
@@ -424,6 +426,11 @@ const TextBase = React.forwardRef((props, ref) => {
|
|
|
424
426
|
'Text: `truncate` and `whitespace="pre-wrap"` are mutually exclusive \u2014 `truncate` takes precedence (one line, one ellipsis); use `clamp` to keep preserved line breaks and still bound the height.'
|
|
425
427
|
);
|
|
426
428
|
}
|
|
429
|
+
if (breakMode === "anywhere" && truncating) {
|
|
430
|
+
console.warn(
|
|
431
|
+
'Text: `truncate` and `break="anywhere"` are mutually exclusive \u2014 `truncate` takes precedence (one line has nowhere to break to); use `clamp` to split the token and still bound the height.'
|
|
432
|
+
);
|
|
433
|
+
}
|
|
427
434
|
if (ellipsis && (truncate || clamp !== void 0)) {
|
|
428
435
|
console.warn(
|
|
429
436
|
"Text: `ellipsis` (antd) and `truncate`/`clamp` are the same axis \u2014 `ellipsis` takes precedence; drop the other."
|
|
@@ -452,6 +459,9 @@ const TextBase = React.forwardRef((props, ref) => {
|
|
|
452
459
|
// Inert default: `normal` is CSS's own behaviour, so it emits no attribute and there is no
|
|
453
460
|
// `[data-whitespace="normal"]` rule to lose a specificity argument with anything.
|
|
454
461
|
"data-whitespace": whitespace === "pre-wrap" && !truncating ? "pre-wrap" : void 0,
|
|
462
|
+
// Same shape and the same precedence as `whitespace`: `normal` is inert, and one line has
|
|
463
|
+
// nowhere to break to, so `truncate` simply does not emit it (gh#927).
|
|
464
|
+
"data-break": breakMode === "anywhere" && !truncating ? "anywhere" : void 0,
|
|
455
465
|
style: clampStyle,
|
|
456
466
|
"data-tabular": tabular ? "" : void 0,
|
|
457
467
|
"data-decoration": decoration,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "30.
|
|
3
|
+
"version": "30.5.3",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -189,6 +189,24 @@
|
|
|
189
189
|
"remove": "Remove {name}",
|
|
190
190
|
"uploading": "Uploading attachment",
|
|
191
191
|
"error": "Upload failed"
|
|
192
|
+
},
|
|
193
|
+
"recordPicker": {
|
|
194
|
+
"trigger": "Select",
|
|
195
|
+
"placeholder": "Select…",
|
|
196
|
+
"search": "Search",
|
|
197
|
+
"searchPlaceholder": "Search by keyword",
|
|
198
|
+
"dialogTitle": "Select",
|
|
199
|
+
"filters": "Filters",
|
|
200
|
+
"allFilter": "All",
|
|
201
|
+
"selected": "{count} selected",
|
|
202
|
+
"loading": "Loading",
|
|
203
|
+
"empty": "No matching items",
|
|
204
|
+
"error": "Could not load",
|
|
205
|
+
"confirm": "Confirm",
|
|
206
|
+
"cancel": "Cancel",
|
|
207
|
+
"clear": "Clear selection",
|
|
208
|
+
"more": "Load more",
|
|
209
|
+
"openDialog": "Choose from list"
|
|
192
210
|
}
|
|
193
211
|
},
|
|
194
212
|
"feedback": {
|
|
@@ -185,6 +185,24 @@
|
|
|
185
185
|
"remove": "{name} を削除",
|
|
186
186
|
"uploading": "添付をアップロード中",
|
|
187
187
|
"error": "アップロードに失敗しました"
|
|
188
|
+
},
|
|
189
|
+
"recordPicker": {
|
|
190
|
+
"trigger": "選択",
|
|
191
|
+
"placeholder": "選択してください",
|
|
192
|
+
"search": "検索",
|
|
193
|
+
"searchPlaceholder": "キーワードで検索",
|
|
194
|
+
"dialogTitle": "選択",
|
|
195
|
+
"filters": "絞り込み",
|
|
196
|
+
"allFilter": "すべて",
|
|
197
|
+
"selected": "選択中 {count} 件",
|
|
198
|
+
"loading": "読み込み中",
|
|
199
|
+
"empty": "該当する項目がありません",
|
|
200
|
+
"error": "読み込めませんでした",
|
|
201
|
+
"confirm": "決定",
|
|
202
|
+
"cancel": "キャンセル",
|
|
203
|
+
"clear": "選択を解除",
|
|
204
|
+
"more": "さらに読み込む",
|
|
205
|
+
"openDialog": "一覧から選択"
|
|
188
206
|
}
|
|
189
207
|
},
|
|
190
208
|
"feedback": {
|
|
@@ -186,6 +186,24 @@
|
|
|
186
186
|
"remove": "Xóa {name}",
|
|
187
187
|
"uploading": "Đang tải tệp đính kèm",
|
|
188
188
|
"error": "Tải lên thất bại"
|
|
189
|
+
},
|
|
190
|
+
"recordPicker": {
|
|
191
|
+
"trigger": "Chọn",
|
|
192
|
+
"placeholder": "Chọn…",
|
|
193
|
+
"search": "Tìm kiếm",
|
|
194
|
+
"searchPlaceholder": "Tìm theo từ khoá",
|
|
195
|
+
"dialogTitle": "Chọn",
|
|
196
|
+
"filters": "Bộ lọc",
|
|
197
|
+
"allFilter": "Tất cả",
|
|
198
|
+
"selected": "Đã chọn {count}",
|
|
199
|
+
"loading": "Đang tải",
|
|
200
|
+
"empty": "Không có mục nào khớp",
|
|
201
|
+
"error": "Không tải được",
|
|
202
|
+
"confirm": "Xác nhận",
|
|
203
|
+
"cancel": "Huỷ",
|
|
204
|
+
"clear": "Bỏ chọn",
|
|
205
|
+
"more": "Tải thêm",
|
|
206
|
+
"openDialog": "Chọn từ danh sách"
|
|
189
207
|
}
|
|
190
208
|
},
|
|
191
209
|
"feedback": {
|
|
@@ -1129,6 +1129,70 @@ export type SearchSelectOptionProp = {
|
|
|
1129
1129
|
group?: string;
|
|
1130
1130
|
disabled?: boolean;
|
|
1131
1131
|
};
|
|
1132
|
+
/**
|
|
1133
|
+
* One consumer-declared filter on a RecordPicker dialog (gh#932). The `name` is the key the
|
|
1134
|
+
* picker puts into `loadOptions({ filters })`, so the server reads its own vocabulary back.
|
|
1135
|
+
*/
|
|
1136
|
+
export type RecordPickerFilterProp = {
|
|
1137
|
+
name: string;
|
|
1138
|
+
label: string;
|
|
1139
|
+
options: {
|
|
1140
|
+
value: string;
|
|
1141
|
+
label: string;
|
|
1142
|
+
}[];
|
|
1143
|
+
};
|
|
1144
|
+
/**
|
|
1145
|
+
* RecordPicker — a picker whose SHAPE follows the size of the set behind it. Under `threshold`
|
|
1146
|
+
* it IS a `Select`; over it, a dialog with search and consumer-declared filters.
|
|
1147
|
+
*/
|
|
1148
|
+
export type RecordPickerProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "value" | "defaultValue" | "onChange"> & {
|
|
1149
|
+
/** `single` (default) or `multiple`. Decides the value shape AND whether the dialog confirms. */
|
|
1150
|
+
mode?: "single" | "multiple";
|
|
1151
|
+
value?: string | string[] | null;
|
|
1152
|
+
defaultValue?: string | string[] | null;
|
|
1153
|
+
/** Receives the shape you passed in: an array for `multiple`, a single value (or null) else. */
|
|
1154
|
+
onValueChange?: (value: string | string[] | null) => void;
|
|
1155
|
+
/** Static rows, client-filtered. Provide this OR `loadOptions`. */
|
|
1156
|
+
options?: (SearchSelectOptionProp | SelectOptionGroupProp)[];
|
|
1157
|
+
/** Server fetcher. `filters` carries the consumer's own filter vocabulary. */
|
|
1158
|
+
loadOptions?: (params: {
|
|
1159
|
+
query: string;
|
|
1160
|
+
filters: Record<string, string>;
|
|
1161
|
+
cursor?: string;
|
|
1162
|
+
}) => Promise<{
|
|
1163
|
+
options: SearchSelectOptionProp[];
|
|
1164
|
+
count?: number;
|
|
1165
|
+
nextCursor?: string;
|
|
1166
|
+
}>;
|
|
1167
|
+
/**
|
|
1168
|
+
* Size of the WHOLE set, which only a server knows — a page of results does not. Omitted with
|
|
1169
|
+
* `options`, it is their length; omitted with `loadOptions`, the dialog shape is assumed.
|
|
1170
|
+
*/
|
|
1171
|
+
count?: number;
|
|
1172
|
+
/** The dropdown/dialog switch. Default 10. */
|
|
1173
|
+
threshold?: number;
|
|
1174
|
+
/** Filters rendered above the dialog list; their values reach `loadOptions({ filters })`. */
|
|
1175
|
+
filters?: RecordPickerFilterProp[];
|
|
1176
|
+
/**
|
|
1177
|
+
* Labels for values the picker holds but has not loaded — on first render there IS no page. Kept
|
|
1178
|
+
* ahead of anything that loads later, so a chip never renders a raw id and never disappears.
|
|
1179
|
+
*/
|
|
1180
|
+
selectedOptions?: SearchSelectOptionProp[];
|
|
1181
|
+
/** A real row meaning "none" (an unassigned owner), pinned first — not a cleared field. */
|
|
1182
|
+
emptyOption?: {
|
|
1183
|
+
value: string;
|
|
1184
|
+
label: string;
|
|
1185
|
+
};
|
|
1186
|
+
placeholder?: string;
|
|
1187
|
+
dialogTitle?: string;
|
|
1188
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
1189
|
+
/**
|
|
1190
|
+
* Tên trường, do `FormField` truyền xuống. Khai tường minh vì CẢ HAI nhánh phải giữ nó: một
|
|
1191
|
+
* lỗi 422 của server bám theo `data-field`, và consumer đo được nhánh dropdown đánh rơi nó
|
|
1192
|
+
* trong khi nhánh Dialog thì giữ (gh#942).
|
|
1193
|
+
*/
|
|
1194
|
+
"data-field"?: string;
|
|
1195
|
+
};
|
|
1132
1196
|
export type SearchSelectLoadParamsProp = {
|
|
1133
1197
|
query: string;
|
|
1134
1198
|
/** 1-based page for infinite scroll. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Foundation component prop types — @see docs/COMPONENTS.md#foundation */
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DescriptionProp, DisabledProp, FontWeightProp, HeadingLevelProp, IconSizeProp, IdProp, InViewAmountProp, LabelProp, OnClickProp, OnOpenChangeProp, OpenProp, PendingProp, RevealDelayProp, RevealTriggerProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp, TitleLevelProp, TypographyActionsConfigProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyTypeProp } from "../vocabulary/index.js";
|
|
3
|
+
import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DescriptionProp, DisabledProp, FontWeightProp, HeadingLevelProp, IconSizeProp, IdProp, InViewAmountProp, LabelProp, OnClickProp, OnOpenChangeProp, OpenProp, PendingProp, RevealDelayProp, RevealTriggerProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp, TextBreakProp, TitleLevelProp, TypographyActionsConfigProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyTypeProp } from "../vocabulary/index.js";
|
|
4
4
|
/**
|
|
5
5
|
* @see Text — typographic primitive; replaces hand-rolled `<span className="text-[13px] …">`.
|
|
6
6
|
*
|
|
@@ -66,6 +66,20 @@ export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & Omit<T
|
|
|
66
66
|
* `clamp` composes with it — a clamped pre-wrap block shows its first N real lines.
|
|
67
67
|
*/
|
|
68
68
|
whitespace?: TextWhitespaceProp;
|
|
69
|
+
/**
|
|
70
|
+
* Where an over-long unbroken token may break. Default `normal` (CSS's own: it stays whole).
|
|
71
|
+
*
|
|
72
|
+
* `anywhere` is for a MACHINE identifier — an email address, a coupon code, a login id, a
|
|
73
|
+
* template key — in a narrow `DataTable` cell or `Descriptions` value: it may be split at any
|
|
74
|
+
* character to fit, so the column shrinks to the viewport instead of scrolling the page. It
|
|
75
|
+
* also releases a `nowrap` it inherited (a table cell's default) back to `normal` — newlines
|
|
76
|
+
* still collapse, because an identifier's whitespace is not content.
|
|
77
|
+
*
|
|
78
|
+
* Independent of `whitespace`: `whitespace="pre-wrap" break="anywhere"` keeps typed line breaks
|
|
79
|
+
* AND splits a long token. `truncate` WINS (one line has nowhere to break to), so the attribute
|
|
80
|
+
* is not emitted under it; `clamp` composes.
|
|
81
|
+
*/
|
|
82
|
+
break?: TextBreakProp;
|
|
69
83
|
/** Tabular figures for aligned numbers. */
|
|
70
84
|
tabular?: boolean;
|
|
71
85
|
decoration?: "none" | "underline" | "line-through";
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -464,6 +464,11 @@ export declare const VOCABULARY_REGISTRY: {
|
|
|
464
464
|
readonly category: "interaction";
|
|
465
465
|
readonly description: "Whitespace handling normal | pre-wrap: `pre-wrap` keeps the newlines and indentation a person typed (a plain-text note, a pasted log) and still wraps at the container edge; `truncate` outranks it";
|
|
466
466
|
};
|
|
467
|
+
readonly TextBreakProp: {
|
|
468
|
+
readonly file: "vocabulary/interaction.prop.ts";
|
|
469
|
+
readonly category: "interaction";
|
|
470
|
+
readonly description: "Where an over-long unbroken token may break normal | anywhere: `anywhere` (overflow-wrap: anywhere) lets a machine identifier (email, code, login id) split to fit a narrow table cell; independent of TextWhitespaceProp, and `truncate` outranks it";
|
|
471
|
+
};
|
|
467
472
|
readonly TypographyTypeProp: {
|
|
468
473
|
readonly file: "vocabulary/interaction.prop.ts";
|
|
469
474
|
readonly category: "interaction";
|
|
@@ -1802,6 +1807,18 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1802
1807
|
readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "PlaceholderProp", "EmptyMessageProp", "DisabledProp", "NameProp", "IdProp", "ClassNameProp", "OpenProp", "OnOpenChangeProp", "SizeProp", "DefaultOpenProp", "ControlStatusProp", "ControlVariantProp", "AllowClearProp", "NotFoundContentProp", "PopupMatchWidthProp", "PendingProp"];
|
|
1803
1808
|
readonly note: "Ant-style data-driven form of Select (options|loadOptions + showSearch). One Select for all single-selects.";
|
|
1804
1809
|
};
|
|
1810
|
+
readonly RecordPickerProp: {
|
|
1811
|
+
readonly group: "data-entry";
|
|
1812
|
+
readonly file: "components/data-entry.prop.ts";
|
|
1813
|
+
readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "SizeProp", "PlaceholderProp"];
|
|
1814
|
+
readonly note: "One picker whose SHAPE follows the size of the set: Select at or under `threshold`, a searchable Dialog with consumer-declared filters over it (gh#932).";
|
|
1815
|
+
};
|
|
1816
|
+
readonly RecordPickerFilterProp: {
|
|
1817
|
+
readonly group: "data-entry";
|
|
1818
|
+
readonly file: "components/data-entry.prop.ts";
|
|
1819
|
+
readonly vocabulary: readonly ["ValueProp", "LabelProp"];
|
|
1820
|
+
readonly note: "One filter on a RecordPicker dialog. `name` is the key that reaches loadOptions({ filters }), so the server reads its own vocabulary back.";
|
|
1821
|
+
};
|
|
1805
1822
|
readonly SearchSelectOptionProp: {
|
|
1806
1823
|
readonly group: "data-entry";
|
|
1807
1824
|
readonly file: "components/data-entry.prop.ts";
|
package/dist/props/registry.js
CHANGED
|
@@ -463,6 +463,11 @@ const VOCABULARY_REGISTRY = {
|
|
|
463
463
|
category: "interaction",
|
|
464
464
|
description: "Whitespace handling normal | pre-wrap: `pre-wrap` keeps the newlines and indentation a person typed (a plain-text note, a pasted log) and still wraps at the container edge; `truncate` outranks it"
|
|
465
465
|
},
|
|
466
|
+
TextBreakProp: {
|
|
467
|
+
file: "vocabulary/interaction.prop.ts",
|
|
468
|
+
category: "interaction",
|
|
469
|
+
description: "Where an over-long unbroken token may break normal | anywhere: `anywhere` (overflow-wrap: anywhere) lets a machine identifier (email, code, login id) split to fit a narrow table cell; independent of TextWhitespaceProp, and `truncate` outranks it"
|
|
470
|
+
},
|
|
466
471
|
TypographyTypeProp: {
|
|
467
472
|
file: "vocabulary/interaction.prop.ts",
|
|
468
473
|
category: "interaction",
|
|
@@ -2138,6 +2143,18 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
2138
2143
|
],
|
|
2139
2144
|
note: "Ant-style data-driven form of Select (options|loadOptions + showSearch). One Select for all single-selects."
|
|
2140
2145
|
},
|
|
2146
|
+
RecordPickerProp: {
|
|
2147
|
+
group: "data-entry",
|
|
2148
|
+
file: "components/data-entry.prop.ts",
|
|
2149
|
+
vocabulary: ["ValueProp", "OnValueChangeProp", "DisabledProp", "SizeProp", "PlaceholderProp"],
|
|
2150
|
+
note: "One picker whose SHAPE follows the size of the set: Select at or under `threshold`, a searchable Dialog with consumer-declared filters over it (gh#932)."
|
|
2151
|
+
},
|
|
2152
|
+
RecordPickerFilterProp: {
|
|
2153
|
+
group: "data-entry",
|
|
2154
|
+
file: "components/data-entry.prop.ts",
|
|
2155
|
+
vocabulary: ["ValueProp", "LabelProp"],
|
|
2156
|
+
note: "One filter on a RecordPicker dialog. `name` is the key that reaches loadOptions({ filters }), so the server reads its own vocabulary back."
|
|
2157
|
+
},
|
|
2141
2158
|
SearchSelectOptionProp: {
|
|
2142
2159
|
group: "data-entry",
|
|
2143
2160
|
file: "components/data-entry.prop.ts",
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
export type { ClassNameProp, ChildrenProp, IdProp, OpenProp, DefaultOpenProp, OnOpenChangeProp, HandlerProp, PendingProp, RequiredProp, DisabledProp, LabelProp, HelperProp, ErrorProp, ErrorBagProp, PlaceholderProp, NameProp, ValueProp, DefaultValueProp, OnValueChangeProp, OnChangeProp, OnClickProp, AsChildProp, FlushProp, WidthProp, ControlWidthProp, AllowClearProp, MaxTagCountProp, MaxTagPlaceholderProp, NotFoundContentProp, PopupMatchWidthProp, } from "./shared.prop.js";
|
|
3
3
|
export type { TitleProp, SubtitleProp, StatusProp, DescriptionProp, ExtraProp, FooterProp, ActionProp, IconProp, ConfirmLabelProp, CancelLabelProp, ActionsProp, EmptyMessageProp, } from "./content.prop.js";
|
|
4
4
|
export type { PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, MobileShellWidthProp, OrientationProp, TableDensityProp, DensityProp, GapNameProp, PadProp, PadRawProp, PadSides, GapProp, GapStepProp, } from "./layout.prop.js";
|
|
5
|
-
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, TextWhitespaceProp, TypographyTypeProp, TitleLevelProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyActionsConfigProp, SizeProp, ControlStatusProp, ControlVariantProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, CalloutKindProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, RevealTriggerProp, InViewAmountProp, ActivityVariantProp, ActivityAnnounceProp, IconSizeProp, } from "./interaction.prop.js";
|
|
5
|
+
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, TextWhitespaceProp, TextBreakProp, TypographyTypeProp, TitleLevelProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyActionsConfigProp, SizeProp, ControlStatusProp, ControlVariantProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, CalloutKindProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, RevealTriggerProp, InViewAmountProp, ActivityVariantProp, ActivityAnnounceProp, IconSizeProp, } from "./interaction.prop.js";
|
|
6
6
|
export type { BreadcrumbItemProp, BreadcrumbProp, BreadcrumbItemMenuProp, BreadcrumbItemMenuEntryProp, BreadcrumbSeparatorProp, BreadcrumbItemRenderProp, } from "./navigation.prop.js";
|
|
7
7
|
export type { GetRowIdProp, GetRowLabelProp, OnRowClickProp, ColumnDefProp, TablePresetProp, TableColumnPriorityProp, TableCellIndentProp, SelectedIdsProp, OnSelectChangeProp, OnTableDensityChangeProp, TableRowToneProp, RowToneProp, OnSortChangeProp, OnSearchChangeProp, OnClearFiltersProp, HasActiveFiltersProp, StickyProp, ColumnFixedProp, ColumnFilterValueProp, ColumnFilterItemProp, ColumnFilterStateProp, OnColumnFilterChangeProp, ColumnCompareProp, ColumnSorterProp, TableSelectionItemProp, TableRowSelectionProp, TableExpandableProp, TableSummaryProp, TableScrollProp, TableStickyProp, OnRowProp, TablePaginationProp, TablePaginationPositionProp, DescriptionsColumnProp, DescriptionsSpanProp, DescriptionsItemsProp, } from "./data.prop.js";
|