@tensor_1/react 2.47.0 → 2.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +540 -2
- package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
- package/dist/announce.d.ts +10 -0
- package/dist/announce.js +30 -0
- package/dist/chart-analytic.cjs +33 -25
- package/dist/chart-preset.cjs +23 -15
- package/dist/chart.cjs +23 -15
- package/dist/combobox-model.d.ts +10 -1
- package/dist/combobox-model.js +15 -0
- package/dist/command-palette-model.d.ts +44 -0
- package/dist/command-palette-model.js +36 -0
- package/dist/components/AccountMenu.d.ts +44 -0
- package/dist/components/AccountMenu.js +43 -0
- package/dist/components/AppShell.d.ts +45 -2
- package/dist/components/AppShell.js +116 -5
- package/dist/components/AuditLog.d.ts +128 -0
- package/dist/components/AuditLog.js +196 -0
- package/dist/components/BrandProfiles.js +4 -3
- package/dist/components/Breadcrumbs.d.ts +9 -2
- package/dist/components/Breadcrumbs.js +3 -2
- package/dist/components/Button.d.ts +12 -5
- package/dist/components/Button.js +7 -3
- package/dist/components/Card.d.ts +18 -1
- package/dist/components/Card.js +5 -1
- package/dist/components/ChangeHighlight.d.ts +30 -0
- package/dist/components/ChangeHighlight.js +21 -0
- package/dist/components/ChartCore.js +2 -1
- package/dist/components/Checkbox.d.ts +27 -1
- package/dist/components/Checkbox.js +31 -2
- package/dist/components/Chip.d.ts +7 -3
- package/dist/components/Chip.js +2 -2
- package/dist/components/CodeDisplay.d.ts +65 -0
- package/dist/components/CodeDisplay.js +124 -0
- package/dist/components/Combobox.d.ts +27 -6
- package/dist/components/Combobox.js +195 -58
- package/dist/components/CommandPalette.d.ts +36 -1
- package/dist/components/CommandPalette.js +254 -2
- package/dist/components/ContactCard.d.ts +66 -0
- package/dist/components/ContactCard.js +74 -0
- package/dist/components/Count.d.ts +24 -0
- package/dist/components/Count.js +32 -0
- package/dist/components/DashboardCanvas.js +14 -0
- package/dist/components/DataWorkspace.d.ts +167 -0
- package/dist/components/DataWorkspace.js +380 -0
- package/dist/components/DateFieldParts.d.ts +2 -1
- package/dist/components/DateFieldParts.js +7 -0
- package/dist/components/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker.js +67 -28
- package/dist/components/DateRangePicker.d.ts +12 -2
- package/dist/components/DateRangePicker.js +13 -12
- package/dist/components/DetailPage.d.ts +7 -1
- package/dist/components/DetailPage.js +2 -1
- package/dist/components/Dialogs.d.ts +71 -10
- package/dist/components/Dialogs.js +130 -30
- package/dist/components/DiffViewer.d.ts +23 -3
- package/dist/components/DiffViewer.js +26 -12
- package/dist/components/DiscardPrompt.js +16 -0
- package/dist/components/DisplayPreferences.d.ts +83 -0
- package/dist/components/DisplayPreferences.js +185 -0
- package/dist/components/EditorialHome.d.ts +23 -3
- package/dist/components/EditorialHome.js +16 -11
- package/dist/components/EntityPicker.d.ts +20 -3
- package/dist/components/EntityPicker.js +32 -13
- package/dist/components/FilterEditor.d.ts +18 -4
- package/dist/components/FilterEditor.js +141 -19
- package/dist/components/FocusOnMount.d.ts +282 -0
- package/dist/components/FocusOnMount.js +12 -0
- package/dist/components/InfoTip.js +11 -12
- package/dist/components/InlineEdit.d.ts +87 -20
- package/dist/components/InlineEdit.js +197 -54
- package/dist/components/Input.d.ts +12 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Kanban.d.ts +14 -3
- package/dist/components/Kanban.js +9 -4
- package/dist/components/Kbd.d.ts +6 -1
- package/dist/components/Kbd.js +6 -6
- package/dist/components/Lightbox.d.ts +41 -5
- package/dist/components/Lightbox.js +95 -9
- package/dist/components/MatchReview.d.ts +40 -1
- package/dist/components/MatchReview.js +130 -4
- package/dist/components/MetricInput.js +3 -2
- package/dist/components/Modal.d.ts +2 -1
- package/dist/components/Modal.js +13 -4
- package/dist/components/MotionList.d.ts +303 -0
- package/dist/components/MotionList.js +175 -0
- package/dist/components/NavFavourites.d.ts +5 -0
- package/dist/components/NavFavourites.js +7 -7
- package/dist/components/OtpInput.d.ts +33 -0
- package/dist/components/OtpInput.js +123 -0
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Pagination.js +6 -5
- package/dist/components/PasswordInput.d.ts +34 -0
- package/dist/components/PasswordInput.js +101 -0
- package/dist/components/Peek.js +3 -3
- package/dist/components/Popover.js +11 -0
- package/dist/components/PrintLayout.d.ts +63 -0
- package/dist/components/PrintLayout.js +114 -0
- package/dist/components/QrCode.d.ts +47 -0
- package/dist/components/QrCode.js +55 -0
- package/dist/components/QrScanner.d.ts +95 -0
- package/dist/components/QrScanner.js +266 -0
- package/dist/components/RelationshipGraph.d.ts +32 -1
- package/dist/components/RelationshipGraph.js +22 -6
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +268 -118
- package/dist/components/RelationshipGraphList.js +33 -6
- package/dist/components/RuleBuilder.js +39 -7
- package/dist/components/SchedulingAgenda.d.ts +3 -1
- package/dist/components/SchedulingCalendar.d.ts +3 -1
- package/dist/components/SchedulingCalendar.js +43 -4
- package/dist/components/SchedulingResourceDay.d.ts +57 -0
- package/dist/components/SchedulingResourceDay.js +287 -0
- package/dist/components/SchedulingTimeGrid.d.ts +3 -1
- package/dist/components/SchedulingTimeline.d.ts +3 -1
- package/dist/components/SearchSuggest.d.ts +23 -3
- package/dist/components/SearchSuggest.js +56 -18
- package/dist/components/Segmented.d.ts +39 -4
- package/dist/components/Segmented.js +39 -5
- package/dist/components/Select.d.ts +3 -2
- package/dist/components/Select.js +7 -1
- package/dist/components/ShortcutHint.d.ts +11 -10
- package/dist/components/ShortcutHint.js +44 -38
- package/dist/components/Sidebar.d.ts +36 -4
- package/dist/components/Sidebar.js +37 -12
- package/dist/components/SortableList.d.ts +45 -0
- package/dist/components/SortableList.js +147 -0
- package/dist/components/Stat.d.ts +28 -3
- package/dist/components/Stat.js +13 -3
- package/dist/components/States.d.ts +33 -1
- package/dist/components/States.js +43 -1
- package/dist/components/StatusPill.d.ts +14 -3
- package/dist/components/StatusPill.js +11 -3
- package/dist/components/Steps.js +2 -1
- package/dist/components/Table.d.ts +9 -2
- package/dist/components/Table.js +4 -2
- package/dist/components/TableControls.js +18 -58
- package/dist/components/TableOverflowProbe.d.ts +12 -0
- package/dist/components/TableOverflowProbe.js +27 -0
- package/dist/components/Tabs.d.ts +2 -1
- package/dist/components/Tabs.js +10 -2
- package/dist/components/TagInput.d.ts +67 -0
- package/dist/components/TagInput.js +342 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.js +2 -2
- package/dist/components/TimePicker.d.ts +80 -0
- package/dist/components/TimePicker.js +347 -0
- package/dist/components/Toast.d.ts +1 -1
- package/dist/components/Toast.js +109 -4
- package/dist/components/Tooltip.d.ts +8 -4
- package/dist/components/Tooltip.js +86 -28
- package/dist/components/Tree.d.ts +8 -0
- package/dist/components/Tree.js +11 -5
- package/dist/display-preferences-model.d.ts +53 -0
- package/dist/display-preferences-model.js +64 -0
- package/dist/emoji.cjs +143 -49
- package/dist/filter-model.d.ts +59 -3
- package/dist/filter-model.js +67 -2
- package/dist/hooks/useAnchoredPosition.js +14 -2
- package/dist/hooks/useChangeHighlight.d.ts +33 -0
- package/dist/hooks/useChangeHighlight.js +44 -0
- package/dist/hooks/useDeferredReorder.d.ts +32 -0
- package/dist/hooks/useDeferredReorder.js +47 -0
- package/dist/hooks/useDialog.d.ts +5 -0
- package/dist/hooks/useDialog.js +17 -3
- package/dist/hooks/useKeyboardGrab.d.ts +58 -0
- package/dist/hooks/useKeyboardGrab.js +118 -0
- package/dist/hooks/useOptimisticValue.d.ts +51 -0
- package/dist/hooks/useOptimisticValue.js +61 -0
- package/dist/hooks/useReducedMotion.d.ts +4 -1
- package/dist/hooks/useReducedMotion.js +7 -1
- package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
- package/dist/hooks/useResolvedFilterLabels.js +34 -0
- package/dist/hooks/useSlidingIndicator.d.ts +18 -0
- package/dist/hooks/useSlidingIndicator.js +80 -0
- package/dist/hooks/useVirtualRows.d.ts +21 -2
- package/dist/hooks/useVirtualRows.js +30 -3
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/index.cjs +19687 -13423
- package/dist/index.d.cts +3419 -651
- package/dist/index.d.ts +48 -18
- package/dist/index.js +153 -9
- package/dist/labels-context.d.ts +93 -3
- package/dist/motion.d.ts +11 -0
- package/dist/motion.js +35 -0
- package/dist/overlay-stack.d.ts +6 -0
- package/dist/overlay-stack.js +13 -0
- package/dist/qr-model.d.ts +65 -0
- package/dist/qr-model.js +323 -0
- package/dist/relationship-graph-model.d.ts +92 -3
- package/dist/relationship-graph-model.js +134 -15
- package/dist/reorder.d.ts +30 -0
- package/dist/reorder.js +74 -0
- package/dist/rich-text.cjs +46 -4
- package/dist/scheduling-resource-model.d.ts +76 -0
- package/dist/scheduling-resource-model.js +74 -0
- package/dist/search-suggest-model.js +3 -1
- package/dist/shell-context.d.ts +11 -0
- package/dist/shell-context.js +7 -0
- package/dist/time-field-model.d.ts +46 -0
- package/dist/time-field-model.js +152 -0
- package/dist/toast-store.d.ts +22 -3
- package/dist/toast-store.js +26 -9
- package/package.json +2 -1
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useId, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
|
+
import { placeId, sameOrder, useRowDrag } from "../reorder.js";
|
|
5
6
|
import { Button } from "./Button.js";
|
|
6
7
|
import { Checkbox } from "./Checkbox.js";
|
|
8
|
+
import { DatePicker } from "./DatePicker.js";
|
|
7
9
|
import { EditorIcon } from "./EditorIcons.js";
|
|
10
|
+
import { StarIcon } from "../icons/components.js";
|
|
8
11
|
import { Input } from "./Input.js";
|
|
9
12
|
import { Popover } from "./Popover.js";
|
|
10
13
|
import { Segmented, SegmentedOption } from "./Segmented.js";
|
|
14
|
+
import { Select } from "./Select.js";
|
|
11
15
|
import { Switch } from "./Switch.js";
|
|
12
16
|
const VIEW_MENU_COLUMN_LABELS = {
|
|
13
17
|
rowActions: "Column actions: {label}",
|
|
@@ -170,7 +174,7 @@ function ViewMenu({
|
|
|
170
174
|
if (el && document.activeElement !== el) el.focus();
|
|
171
175
|
});
|
|
172
176
|
const commit = (next, id) => {
|
|
173
|
-
setDraft(
|
|
177
|
+
setDraft(null);
|
|
174
178
|
onReorder?.([...next]);
|
|
175
179
|
const column = byId.get(id);
|
|
176
180
|
if (column) setAnnouncement(fill(labels.moved, { label: columnText(column), position: next.indexOf(id) + 1, count: next.length }));
|
|
@@ -190,6 +194,11 @@ function ViewMenu({
|
|
|
190
194
|
const start = dragStart.current;
|
|
191
195
|
dragStart.current = null;
|
|
192
196
|
if (start && !sameOrder(start, order)) commit(order, id);
|
|
197
|
+
else setDraft(null);
|
|
198
|
+
},
|
|
199
|
+
cancel: () => {
|
|
200
|
+
dragStart.current = null;
|
|
201
|
+
setDraft(null);
|
|
193
202
|
}
|
|
194
203
|
});
|
|
195
204
|
const rowActions = (column, index) => [
|
|
@@ -288,7 +297,7 @@ function FilterPopover({ label, type = "text", value, onValueChange, options, ap
|
|
|
288
297
|
return /* @__PURE__ */ jsxs("div", { className: "uix-filter-popover", children: [
|
|
289
298
|
/* @__PURE__ */ jsxs("div", { className: "uix-field", children: [
|
|
290
299
|
/* @__PURE__ */ jsx("label", { className: "uix-field__label", htmlFor: controlId, children: label }),
|
|
291
|
-
type === "select" || type === "enum" || type === "boolean" ? /* @__PURE__ */ jsx(
|
|
300
|
+
type === "select" || type === "enum" || type === "boolean" ? /* @__PURE__ */ jsx(Select, { id: controlId, value, options: options ?? [], onValueChange: (next) => onValueChange(next) }) : type === "date" ? /* @__PURE__ */ jsx(DatePicker, { id: controlId, value: value || null, placeholder, onValueChange: (next) => onValueChange(next ?? "") }) : /* @__PURE__ */ jsx(Input, { id: controlId, type, value, placeholder, onChange: (event) => onValueChange(event.currentTarget.value) })
|
|
292
301
|
] }),
|
|
293
302
|
/* @__PURE__ */ jsxs("div", { className: "uix-filter-popover__actions", children: [
|
|
294
303
|
/* @__PURE__ */ jsx(Button, { type: "button", onClick: onClear, children: clearLabel }),
|
|
@@ -296,60 +305,6 @@ function FilterPopover({ label, type = "text", value, onValueChange, options, ap
|
|
|
296
305
|
] })
|
|
297
306
|
] });
|
|
298
307
|
}
|
|
299
|
-
const sameOrder = (a, b) => a.length === b.length && a.every((id, i) => id === b[i]);
|
|
300
|
-
function dropIndex(rows, dragged, clientY) {
|
|
301
|
-
let index = 0;
|
|
302
|
-
for (const row of rows) {
|
|
303
|
-
if (row === dragged) continue;
|
|
304
|
-
const box = row.getBoundingClientRect();
|
|
305
|
-
if (clientY > box.top + box.height / 2) index++;
|
|
306
|
-
}
|
|
307
|
-
return index;
|
|
308
|
-
}
|
|
309
|
-
function useRowDrag(rowSelector, handlers) {
|
|
310
|
-
const [dragging, setDragging] = useState(null);
|
|
311
|
-
const drag = useRef(null);
|
|
312
|
-
const latest = useRef(handlers);
|
|
313
|
-
latest.current = handlers;
|
|
314
|
-
useEffect(() => {
|
|
315
|
-
if (!dragging) return;
|
|
316
|
-
const move = (event) => {
|
|
317
|
-
const current = drag.current;
|
|
318
|
-
if (!current) return;
|
|
319
|
-
latest.current.over(current.id, dropIndex(Array.from(current.list.querySelectorAll(`:scope > ${rowSelector}`)), current.row, event.clientY));
|
|
320
|
-
};
|
|
321
|
-
const end = () => {
|
|
322
|
-
const current = drag.current;
|
|
323
|
-
drag.current = null;
|
|
324
|
-
setDragging(null);
|
|
325
|
-
if (current) latest.current.drop(current.id);
|
|
326
|
-
};
|
|
327
|
-
window.addEventListener("pointermove", move);
|
|
328
|
-
window.addEventListener("pointerup", end);
|
|
329
|
-
window.addEventListener("pointercancel", end);
|
|
330
|
-
return () => {
|
|
331
|
-
window.removeEventListener("pointermove", move);
|
|
332
|
-
window.removeEventListener("pointerup", end);
|
|
333
|
-
window.removeEventListener("pointercancel", end);
|
|
334
|
-
};
|
|
335
|
-
}, [dragging, rowSelector]);
|
|
336
|
-
const start = (event, id) => {
|
|
337
|
-
const row = event.currentTarget.closest("li");
|
|
338
|
-
if (!row?.parentElement) return;
|
|
339
|
-
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
340
|
-
drag.current = { id, list: row.parentElement, row };
|
|
341
|
-
setDragging(id);
|
|
342
|
-
};
|
|
343
|
-
return { dragging, start };
|
|
344
|
-
}
|
|
345
|
-
function placeId(ids, id, index) {
|
|
346
|
-
const from = ids.indexOf(id);
|
|
347
|
-
const to = Math.max(0, Math.min(index, ids.length - 1));
|
|
348
|
-
if (from < 0 || from === to) return ids;
|
|
349
|
-
const next = ids.filter((other) => other !== id);
|
|
350
|
-
next.splice(to, 0, id);
|
|
351
|
-
return next;
|
|
352
|
-
}
|
|
353
308
|
function SavedViewMenu({ items, sections, onSelect, onPinChange, pinLabel, unpinLabel, onReorder, reorderLabel, emptyLabel, actions, footer }) {
|
|
354
309
|
const baseId = useId();
|
|
355
310
|
const groups = sections ?? [{ id: void 0, items: items ?? [] }];
|
|
@@ -363,7 +318,7 @@ function SavedViewMenu({ items, sections, onSelect, onPinChange, pinLabel, unpin
|
|
|
363
318
|
const current = orderOf(group);
|
|
364
319
|
const next = placeId(current, id, current.indexOf(id) + delta);
|
|
365
320
|
if (next === current) return;
|
|
366
|
-
setDraft(
|
|
321
|
+
setDraft(null);
|
|
367
322
|
onReorder?.([...next], group.id);
|
|
368
323
|
};
|
|
369
324
|
const { dragging, start: startDrag } = useRowDrag(".uix-saved-views__row", {
|
|
@@ -380,7 +335,12 @@ function SavedViewMenu({ items, sections, onSelect, onPinChange, pinLabel, unpin
|
|
|
380
335
|
dragStart.current = null;
|
|
381
336
|
if (!group) return;
|
|
382
337
|
const end = orderOf(group);
|
|
338
|
+
setDraft(null);
|
|
383
339
|
if (start && !sameOrder(start, end)) onReorder?.([...end], group.id);
|
|
340
|
+
},
|
|
341
|
+
cancel: () => {
|
|
342
|
+
dragStart.current = null;
|
|
343
|
+
setDraft(null);
|
|
384
344
|
}
|
|
385
345
|
});
|
|
386
346
|
const visible = groups.filter((group) => group.items.length > 0);
|
|
@@ -415,7 +375,7 @@ function SavedViewMenu({ items, sections, onSelect, onPinChange, pinLabel, unpin
|
|
|
415
375
|
}
|
|
416
376
|
),
|
|
417
377
|
/* @__PURE__ */ jsx("button", { type: "button", id: nameId, className: "uix-menu__item", "data-active": item.active || void 0, "aria-current": item.active || void 0, title: typeof item.label === "string" ? item.label : void 0, onClick: () => onSelect(item.id), children: /* @__PURE__ */ jsx("span", { className: "uix-saved-views__name", children: item.label }) }),
|
|
418
|
-
onPinChange && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-saved-views__pin", "aria-label": item.pinned ? unpinLabel : pinLabel, "data-on": item.pinned || void 0, onClick: () => onPinChange(item.id, !item.pinned), children:
|
|
378
|
+
onPinChange && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-saved-views__pin", "aria-label": item.pinned ? unpinLabel : pinLabel, "data-on": item.pinned || void 0, onClick: () => onPinChange(item.id, !item.pinned), children: /* @__PURE__ */ jsx(StarIcon, {}) }),
|
|
419
379
|
extra != null && extra !== false && /* @__PURE__ */ jsx("span", { className: "uix-saved-views__actions", children: extra })
|
|
420
380
|
] }, item.id);
|
|
421
381
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Measures whether a `TableWrap`'s table is wider than the wrap and writes it to the wrap as
|
|
5
|
+
* `data-overflow="true" | "false"`, so frozen columns draw their dividers only where rows can
|
|
6
|
+
* scroll under them (PR #168 review). A hidden child, like BusyBar, so `TableWrap` itself stays a
|
|
7
|
+
* server component. Without ResizeObserver (or before it runs) there is no attribute and the
|
|
8
|
+
* dividers stay, as in plain HTML.
|
|
9
|
+
*/
|
|
10
|
+
declare function TableOverflowProbe(): react.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { TableOverflowProbe };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useLayoutEffect, useRef } from "react";
|
|
4
|
+
function TableOverflowProbe() {
|
|
5
|
+
const ref = useRef(null);
|
|
6
|
+
useLayoutEffect(() => {
|
|
7
|
+
const wrap = ref.current?.parentElement;
|
|
8
|
+
if (!wrap || typeof ResizeObserver === "undefined") return void 0;
|
|
9
|
+
const measure = () => {
|
|
10
|
+
const next = String(wrap.scrollWidth > wrap.clientWidth + 1);
|
|
11
|
+
if (wrap.getAttribute("data-overflow") !== next) wrap.setAttribute("data-overflow", next);
|
|
12
|
+
};
|
|
13
|
+
measure();
|
|
14
|
+
const observer = new ResizeObserver(measure);
|
|
15
|
+
observer.observe(wrap);
|
|
16
|
+
const table = wrap.querySelector("table");
|
|
17
|
+
if (table) observer.observe(table);
|
|
18
|
+
return () => {
|
|
19
|
+
observer.disconnect();
|
|
20
|
+
wrap.removeAttribute("data-overflow");
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
return /* @__PURE__ */ jsx("span", { ref, hidden: true });
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
TableOverflowProbe
|
|
27
|
+
};
|
|
@@ -13,7 +13,8 @@ interface TabsProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'r
|
|
|
13
13
|
children?: ReactNode;
|
|
14
14
|
className?: string;
|
|
15
15
|
/**
|
|
16
|
-
* What happens when the tabs don't fit. `'wrap'` (default)
|
|
16
|
+
* What happens when the tabs don't fit. `'wrap'` (default): the tab row wraps onto more rows,
|
|
17
|
+
* and no tab is wider than its row, so one long label wraps inside its tab (HAR-1754).
|
|
17
18
|
* `'scroll'` keeps one row that scrolls sideways, with pointer-only edge buttons
|
|
18
19
|
* shown on the side that has hidden tabs. The selected tab is always scrolled into view.
|
|
19
20
|
*/
|
package/dist/components/Tabs.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Children, createContext, isValidElement, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
|
+
import { useSlidingIndicator } from "../hooks/useSlidingIndicator.js";
|
|
5
6
|
const TabsCtx = createContext({});
|
|
6
7
|
const Chevron = ({ d }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d }) });
|
|
7
8
|
const inlineOffset = (el, rtl) => rtl ? -el.scrollLeft : el.scrollLeft;
|
|
@@ -18,6 +19,9 @@ function Tabs({
|
|
|
18
19
|
}) {
|
|
19
20
|
const baseId = useId();
|
|
20
21
|
const listRef = useRef(null);
|
|
22
|
+
const indicatorRef = useRef(null);
|
|
23
|
+
const sliding = variant !== "enclosed";
|
|
24
|
+
useSlidingIndicator(listRef, indicatorRef, sliding ? '[role="tab"][aria-selected="true"]' : ":not(*)");
|
|
21
25
|
const contextValue = useMemo(() => ({ value, onChange, baseId }), [value, onChange, baseId]);
|
|
22
26
|
const scroll = overflow === "scroll";
|
|
23
27
|
const [hidden, setHidden] = useState({ start: false, end: false });
|
|
@@ -101,7 +105,7 @@ function Tabs({
|
|
|
101
105
|
target.focus();
|
|
102
106
|
if (activation === "automatic") target.click();
|
|
103
107
|
};
|
|
104
|
-
const list = /* @__PURE__ */
|
|
108
|
+
const list = /* @__PURE__ */ jsxs(
|
|
105
109
|
"div",
|
|
106
110
|
{
|
|
107
111
|
...listProps,
|
|
@@ -109,7 +113,10 @@ function Tabs({
|
|
|
109
113
|
role: "tablist",
|
|
110
114
|
className: cx("uix-tabs", `uix-tabs--${variant}`, scroll && "uix-tabs--scroll", className),
|
|
111
115
|
onKeyDown,
|
|
112
|
-
children:
|
|
116
|
+
children: [
|
|
117
|
+
tabs,
|
|
118
|
+
sliding && /* @__PURE__ */ jsx("span", { ref: indicatorRef, className: "uix-tabs__indicator", "aria-hidden": "true", hidden: true })
|
|
119
|
+
]
|
|
113
120
|
}
|
|
114
121
|
);
|
|
115
122
|
return /* @__PURE__ */ jsxs(TabsCtx.Provider, { value: contextValue, children: [
|
|
@@ -151,6 +158,7 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
|
151
158
|
return /* @__PURE__ */ jsx(
|
|
152
159
|
"button",
|
|
153
160
|
{
|
|
161
|
+
type: "button",
|
|
154
162
|
role: "tab",
|
|
155
163
|
id: ctx.baseId ? `${ctx.baseId}-tab-${value}` : void 0,
|
|
156
164
|
"aria-controls": ctx.baseId ? `${ctx.baseId}-panel-${value}` : void 0,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { AriaAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Every word `TagInput` renders or announces. */
|
|
5
|
+
interface TagInputLabels {
|
|
6
|
+
/** Name of a chip's × button; `{tag}`. */
|
|
7
|
+
remove: string;
|
|
8
|
+
/** Announced after a tag was added; `{tag}`. */
|
|
9
|
+
added: string;
|
|
10
|
+
/** Announced after a tag was removed; `{tag}`. */
|
|
11
|
+
removed: string;
|
|
12
|
+
/** Shown when the tag is already there; `{tag}`. */
|
|
13
|
+
duplicate: string;
|
|
14
|
+
/** Shown when `maxTags` are there; `{max}`. */
|
|
15
|
+
max: string;
|
|
16
|
+
/** Name of the suggestion list. */
|
|
17
|
+
suggestions: string;
|
|
18
|
+
/** Name of the list of chips. */
|
|
19
|
+
list: string;
|
|
20
|
+
/** Part of the field's description: how many tags there are; `{count}`. */
|
|
21
|
+
count: string;
|
|
22
|
+
}
|
|
23
|
+
declare const DEFAULT_TAG_INPUT_LABELS: TagInputLabels;
|
|
24
|
+
interface TagInputProps {
|
|
25
|
+
/** The tags, in order. */
|
|
26
|
+
value: readonly string[];
|
|
27
|
+
onValueChange: (value: string[]) => void;
|
|
28
|
+
/** Offered while typing (those already added are left out); ArrowDown reaches them. */
|
|
29
|
+
suggestions?: readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Check a tag before it is added: return a message to refuse it (shown under the field), or
|
|
32
|
+
* `null` to accept it. Runs after the duplicate and `maxTags` checks.
|
|
33
|
+
*/
|
|
34
|
+
validate?: (tag: string, value: readonly string[]) => string | null | undefined;
|
|
35
|
+
/** The most tags; past it, adding is refused with the `max` message. */
|
|
36
|
+
maxTags?: number;
|
|
37
|
+
/** Keys that add the typed text. Default Enter and comma. */
|
|
38
|
+
separators?: readonly string[];
|
|
39
|
+
/** Submits each tag as its own value under this name (hidden inputs). */
|
|
40
|
+
name?: string;
|
|
41
|
+
/** Lands on the text input, so a `<label htmlFor>` or `<Field>` names it. */
|
|
42
|
+
id?: string;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
invalid?: boolean;
|
|
46
|
+
'aria-label'?: string;
|
|
47
|
+
'aria-labelledby'?: string;
|
|
48
|
+
'aria-describedby'?: string;
|
|
49
|
+
'aria-invalid'?: AriaAttributes['aria-invalid'];
|
|
50
|
+
'aria-required'?: AriaAttributes['aria-required'];
|
|
51
|
+
/** Translatable words; English defaults in {@link DEFAULT_TAG_INPUT_LABELS}. */
|
|
52
|
+
labels?: Partial<TagInputLabels>;
|
|
53
|
+
className?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Several short tags in one field (HAR-1377): type and press Enter (or a comma) to add a chip;
|
|
57
|
+
* pasting "a, b, c" adds three. A duplicate (ignoring case and accents), a refusal from `validate`
|
|
58
|
+
* or one past `maxTags` keeps the text and says why. Suggestions open under the field as a
|
|
59
|
+
* top-layer list once the person types (or presses ArrowDown): ArrowDown / ArrowUp move, Enter adds
|
|
60
|
+
* the active one, Escape closes it. Backspace in the empty field
|
|
61
|
+
* goes to the last chip; ArrowLeft / ArrowRight move between chips and back to the field;
|
|
62
|
+
* Backspace or Delete on a chip removes it. Each change is announced politely. Works in `Field`
|
|
63
|
+
* (the text input gets the label, hint and error) and submits each tag under `name`.
|
|
64
|
+
*/
|
|
65
|
+
declare function TagInput({ value, onValueChange, suggestions, validate, maxTags, separators, name, id: idProp, placeholder, disabled, invalid, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, 'aria-required': ariaRequired, labels: labelOverrides, className, }: TagInputProps): react.JSX.Element;
|
|
66
|
+
|
|
67
|
+
export { DEFAULT_TAG_INPUT_LABELS, TagInput, type TagInputLabels, type TagInputProps };
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "../cx.js";
|
|
5
|
+
import { fillLabel } from "../fill-label.js";
|
|
6
|
+
import { useAnchoredPosition, zoomOf } from "../hooks/useAnchoredPosition.js";
|
|
7
|
+
import { XIcon } from "../icons/components.js";
|
|
8
|
+
import { useUixLabels } from "../labels-context.js";
|
|
9
|
+
import { foldForSearch } from "../search-suggest-model.js";
|
|
10
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
11
|
+
const DEFAULT_TAG_INPUT_LABELS = {
|
|
12
|
+
remove: "Remove {tag}",
|
|
13
|
+
added: "{tag} added.",
|
|
14
|
+
removed: "{tag} removed.",
|
|
15
|
+
duplicate: "{tag} is already added.",
|
|
16
|
+
max: "You can add up to {max}.",
|
|
17
|
+
suggestions: "Suggestions",
|
|
18
|
+
list: "Tags",
|
|
19
|
+
count: "{count} added"
|
|
20
|
+
};
|
|
21
|
+
const same = (a, b) => foldForSearch(a).text === foldForSearch(b).text;
|
|
22
|
+
function TagInput({
|
|
23
|
+
value,
|
|
24
|
+
onValueChange,
|
|
25
|
+
suggestions,
|
|
26
|
+
validate,
|
|
27
|
+
maxTags,
|
|
28
|
+
separators = ["Enter", ","],
|
|
29
|
+
name,
|
|
30
|
+
id: idProp,
|
|
31
|
+
placeholder,
|
|
32
|
+
disabled,
|
|
33
|
+
invalid,
|
|
34
|
+
"aria-label": ariaLabel,
|
|
35
|
+
"aria-labelledby": ariaLabelledBy,
|
|
36
|
+
"aria-describedby": ariaDescribedBy,
|
|
37
|
+
"aria-invalid": ariaInvalid,
|
|
38
|
+
"aria-required": ariaRequired,
|
|
39
|
+
labels: labelOverrides,
|
|
40
|
+
className
|
|
41
|
+
}) {
|
|
42
|
+
const labels = { ...DEFAULT_TAG_INPUT_LABELS, ...useUixLabels().tagInput, ...labelOverrides };
|
|
43
|
+
const uid = useId();
|
|
44
|
+
const id = idProp ?? `${uid}-input`;
|
|
45
|
+
const listId = `${uid}-suggestions`;
|
|
46
|
+
const messageId = `${uid}-message`;
|
|
47
|
+
const optionId = (index) => `${listId}-${index}`;
|
|
48
|
+
const boxRef = useRef(null);
|
|
49
|
+
const inputRef = useRef(null);
|
|
50
|
+
const popupRef = useRef(null);
|
|
51
|
+
const chipRefs = useRef([]);
|
|
52
|
+
const [text, setText] = useState("");
|
|
53
|
+
const [message, setMessage] = useState(null);
|
|
54
|
+
const [announcement, setAnnouncement] = useState("");
|
|
55
|
+
const [focusChip, setFocusChip] = useState(null);
|
|
56
|
+
const [open, setOpen] = useState(false);
|
|
57
|
+
const [active, setActive] = useState(-1);
|
|
58
|
+
const matches = useMemo(() => {
|
|
59
|
+
if (!suggestions?.length) return [];
|
|
60
|
+
const needle = foldForSearch(text.trim()).text;
|
|
61
|
+
return suggestions.filter((s) => !value.some((v) => same(v, s)) && (!needle || foldForSearch(s).text.includes(needle))).slice(0, 50);
|
|
62
|
+
}, [suggestions, text, value]);
|
|
63
|
+
const showing = open && matches.length > 0 && !disabled;
|
|
64
|
+
const refuse = (reason) => {
|
|
65
|
+
setMessage(reason);
|
|
66
|
+
setAnnouncement(reason);
|
|
67
|
+
};
|
|
68
|
+
const add = (raw) => {
|
|
69
|
+
let next = [...value];
|
|
70
|
+
const added = [];
|
|
71
|
+
let refusedAt = -1;
|
|
72
|
+
let reason = "";
|
|
73
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
74
|
+
const tag = raw[i].trim();
|
|
75
|
+
if (!tag) continue;
|
|
76
|
+
if (next.some((v) => same(v, tag))) reason = fillLabel(labels.duplicate, { tag });
|
|
77
|
+
else if (maxTags != null && next.length >= maxTags) reason = fillLabel(labels.max, { max: maxTags });
|
|
78
|
+
else reason = validate?.(tag, next) || "";
|
|
79
|
+
if (reason) {
|
|
80
|
+
refusedAt = i;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
next = [...next, tag];
|
|
84
|
+
added.push(tag);
|
|
85
|
+
}
|
|
86
|
+
if (added.length) {
|
|
87
|
+
setOpen(false);
|
|
88
|
+
setAnnouncement(fillLabel(labels.added, { tag: added.join(", ") }));
|
|
89
|
+
onValueChange(next);
|
|
90
|
+
}
|
|
91
|
+
if (refusedAt < 0) {
|
|
92
|
+
setMessage(null);
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
refuse(reason);
|
|
96
|
+
const joiner = separators.includes(",") ? ", " : " ";
|
|
97
|
+
return raw.slice(refusedAt).map((piece) => piece.trim()).filter(Boolean).join(joiner);
|
|
98
|
+
};
|
|
99
|
+
const remove = (index) => {
|
|
100
|
+
const tag = value[index];
|
|
101
|
+
if (tag == null || disabled) return;
|
|
102
|
+
onValueChange(value.filter((_, i) => i !== index));
|
|
103
|
+
setMessage(null);
|
|
104
|
+
setAnnouncement(fillLabel(labels.removed, { tag }));
|
|
105
|
+
setFocusChip(index > 0 ? index - 1 : null);
|
|
106
|
+
if (index === 0) inputRef.current?.focus();
|
|
107
|
+
};
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (focusChip == null) return;
|
|
110
|
+
const chip = chipRefs.current[focusChip];
|
|
111
|
+
if (chip) chip.focus();
|
|
112
|
+
else inputRef.current?.focus();
|
|
113
|
+
setFocusChip(null);
|
|
114
|
+
}, [focusChip, value]);
|
|
115
|
+
const commitText = (extra = []) => {
|
|
116
|
+
setText(add([text, ...extra]));
|
|
117
|
+
setActive(-1);
|
|
118
|
+
};
|
|
119
|
+
const onInputKeyDown = (event) => {
|
|
120
|
+
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
121
|
+
const { key } = event;
|
|
122
|
+
if (key === "ArrowDown" || key === "ArrowUp") {
|
|
123
|
+
if (!matches.length) return;
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
if (!showing) {
|
|
126
|
+
setOpen(true);
|
|
127
|
+
setActive(key === "ArrowDown" ? 0 : matches.length - 1);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
setActive((i) => i < 0 ? key === "ArrowDown" ? 0 : matches.length - 1 : Math.max(0, Math.min(matches.length - 1, i + (key === "ArrowDown" ? 1 : -1))));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (key === "Escape" && showing) {
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
event.stopPropagation();
|
|
136
|
+
setOpen(false);
|
|
137
|
+
setActive(-1);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (separators.includes(key)) {
|
|
141
|
+
if (key === "Enter" && showing && active >= 0) {
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
if (!add([matches[active]])) {
|
|
144
|
+
setText("");
|
|
145
|
+
setActive(-1);
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (key === "Enter" && !text.trim()) return;
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
commitText();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const caretAtStart = event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === 0;
|
|
155
|
+
if (key === "Backspace" && !text || key === "ArrowLeft" && caretAtStart) {
|
|
156
|
+
if (!value.length) return;
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
setOpen(false);
|
|
159
|
+
chipRefs.current[value.length - 1]?.focus();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const onChipKeyDown = (event, index) => {
|
|
163
|
+
const { key } = event;
|
|
164
|
+
if (key === "Backspace" || key === "Delete") {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
remove(index);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (key === "ArrowLeft") {
|
|
170
|
+
event.preventDefault();
|
|
171
|
+
chipRefs.current[Math.max(0, index - 1)]?.focus();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (key === "ArrowRight") {
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
if (index < value.length - 1) chipRefs.current[index + 1]?.focus();
|
|
177
|
+
else inputRef.current?.focus();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (key === "Escape") {
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
inputRef.current?.focus();
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const onPaste = (event) => {
|
|
186
|
+
const pasted = event.clipboardData?.getData("text") ?? "";
|
|
187
|
+
const chars = separators.filter((s) => s.length === 1).map((s) => s.replace(/[\\^\]-]/g, "\\$&")).join("");
|
|
188
|
+
const split = new RegExp(`[\\n\\r${chars}]+`);
|
|
189
|
+
if (!split.test(pasted)) return;
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
const pieces = pasted.split(split);
|
|
192
|
+
setText(add([`${text}${pieces[0] ?? ""}`, ...pieces.slice(1)]));
|
|
193
|
+
};
|
|
194
|
+
useIsomorphicLayoutEffect(() => {
|
|
195
|
+
const popup = popupRef.current;
|
|
196
|
+
const box = boxRef.current;
|
|
197
|
+
if (!popup || !box) return;
|
|
198
|
+
const isOpen = () => {
|
|
199
|
+
try {
|
|
200
|
+
return popup.matches(":popover-open");
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
if (showing) {
|
|
206
|
+
const zoom = zoomOf(box);
|
|
207
|
+
popup.style.minWidth = `${Math.round(box.getBoundingClientRect().width / zoom)}px`;
|
|
208
|
+
try {
|
|
209
|
+
if (!isOpen()) popup.showPopover();
|
|
210
|
+
} catch {
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
try {
|
|
214
|
+
if (isOpen()) popup.hidePopover();
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}, [showing]);
|
|
219
|
+
useAnchoredPosition(boxRef, popupRef, { open: showing, placement: "bottom-start", offset: 4, padding: 8 });
|
|
220
|
+
useIsomorphicLayoutEffect(() => {
|
|
221
|
+
if (!showing || active < 0) return;
|
|
222
|
+
popupRef.current?.ownerDocument.getElementById(optionId(active))?.scrollIntoView?.({ block: "nearest" });
|
|
223
|
+
}, [showing, active]);
|
|
224
|
+
const isInvalid = !!invalid || ariaInvalid === true || ariaInvalid === "true";
|
|
225
|
+
const countId = `${uid}-count`;
|
|
226
|
+
const describedBy = [ariaDescribedBy, message ? messageId : void 0, value.length ? countId : void 0].filter(Boolean).join(" ") || void 0;
|
|
227
|
+
const popoverAttr = { popover: "manual" };
|
|
228
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-taginput-field", className), children: [
|
|
229
|
+
/* @__PURE__ */ jsxs(
|
|
230
|
+
"div",
|
|
231
|
+
{
|
|
232
|
+
ref: boxRef,
|
|
233
|
+
className: "uix-taginput",
|
|
234
|
+
"data-invalid": isInvalid || void 0,
|
|
235
|
+
"data-disabled": disabled || void 0,
|
|
236
|
+
onMouseDown: (event) => {
|
|
237
|
+
if (event.target === event.currentTarget) {
|
|
238
|
+
event.preventDefault();
|
|
239
|
+
inputRef.current?.focus();
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
onBlur: (event) => {
|
|
243
|
+
if (!boxRef.current?.contains(event.relatedTarget)) {
|
|
244
|
+
setOpen(false);
|
|
245
|
+
setActive(-1);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
children: [
|
|
249
|
+
value.length > 0 && /* @__PURE__ */ jsx("span", { role: "list", "aria-label": labels.list, className: "uix-taginput__tags", children: value.map((tag, index) => /* @__PURE__ */ jsxs("span", { className: "uix-tag", role: "listitem", children: [
|
|
250
|
+
tag,
|
|
251
|
+
!disabled && /* @__PURE__ */ jsx(
|
|
252
|
+
"button",
|
|
253
|
+
{
|
|
254
|
+
ref: (el) => {
|
|
255
|
+
chipRefs.current[index] = el;
|
|
256
|
+
},
|
|
257
|
+
type: "button",
|
|
258
|
+
className: "uix-tag__remove",
|
|
259
|
+
tabIndex: -1,
|
|
260
|
+
"aria-label": fillLabel(labels.remove, { tag }),
|
|
261
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
262
|
+
onClick: () => remove(index),
|
|
263
|
+
onKeyDown: (event) => onChipKeyDown(event, index),
|
|
264
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
] }, `${tag}-${index}`)) }),
|
|
268
|
+
/* @__PURE__ */ jsx(
|
|
269
|
+
"input",
|
|
270
|
+
{
|
|
271
|
+
ref: inputRef,
|
|
272
|
+
id,
|
|
273
|
+
className: "uix-taginput__field",
|
|
274
|
+
type: "text",
|
|
275
|
+
role: suggestions ? "combobox" : void 0,
|
|
276
|
+
"aria-autocomplete": suggestions ? "list" : void 0,
|
|
277
|
+
"aria-expanded": suggestions ? showing : void 0,
|
|
278
|
+
"aria-controls": suggestions ? listId : void 0,
|
|
279
|
+
"aria-activedescendant": showing && active >= 0 ? optionId(active) : void 0,
|
|
280
|
+
"aria-label": ariaLabel,
|
|
281
|
+
"aria-labelledby": ariaLabelledBy,
|
|
282
|
+
"aria-describedby": describedBy,
|
|
283
|
+
"aria-invalid": isInvalid || !!message || void 0,
|
|
284
|
+
"aria-required": ariaRequired,
|
|
285
|
+
autoComplete: "off",
|
|
286
|
+
spellCheck: false,
|
|
287
|
+
enterKeyHint: "enter",
|
|
288
|
+
placeholder,
|
|
289
|
+
disabled,
|
|
290
|
+
value: text,
|
|
291
|
+
onChange: (event) => {
|
|
292
|
+
const next = event.target.value;
|
|
293
|
+
if (separators.includes(",") && next.includes(",")) {
|
|
294
|
+
const pieces = next.split(",");
|
|
295
|
+
if (!add([pieces[0]])) setText(pieces.slice(1).join(",").trimStart());
|
|
296
|
+
else setText(next.replace(/,/g, ""));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
setText(next);
|
|
300
|
+
if (message) setMessage(null);
|
|
301
|
+
setOpen(next.trim().length > 0);
|
|
302
|
+
setActive(-1);
|
|
303
|
+
},
|
|
304
|
+
onKeyDown: onInputKeyDown,
|
|
305
|
+
onPaste
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
),
|
|
311
|
+
name && value.map((tag, index) => /* @__PURE__ */ jsx("input", { type: "hidden", name, value: tag, disabled }, `${tag}-${index}`)),
|
|
312
|
+
message && /* @__PURE__ */ jsx("span", { id: messageId, className: "uix-field__warning uix-taginput__message", children: message }),
|
|
313
|
+
value.length > 0 && /* @__PURE__ */ jsx("span", { id: countId, className: "uix-visually-hidden", children: fillLabel(labels.count, { count: value.length }) }),
|
|
314
|
+
/* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", role: "status", "aria-live": "polite", children: announcement }),
|
|
315
|
+
suggestions && /* @__PURE__ */ jsx("div", { ref: popupRef, className: "uix-select__popup uix-taginput__popup", hidden: !showing, ...popoverAttr, onMouseDown: (event) => event.preventDefault(), children: /* @__PURE__ */ jsx("div", { id: listId, role: "listbox", "aria-label": labels.suggestions, className: "uix-listbox uix-select__listbox", children: matches.map((suggestion, index) => /* @__PURE__ */ jsx(
|
|
316
|
+
"div",
|
|
317
|
+
{
|
|
318
|
+
id: optionId(index),
|
|
319
|
+
role: "option",
|
|
320
|
+
"aria-selected": index === active,
|
|
321
|
+
className: "uix-listbox__option",
|
|
322
|
+
"data-active": index === active || void 0,
|
|
323
|
+
onPointerMove: () => {
|
|
324
|
+
if (index !== active) setActive(index);
|
|
325
|
+
},
|
|
326
|
+
onClick: () => {
|
|
327
|
+
if (!add([suggestion])) {
|
|
328
|
+
setText("");
|
|
329
|
+
setActive(-1);
|
|
330
|
+
}
|
|
331
|
+
inputRef.current?.focus();
|
|
332
|
+
},
|
|
333
|
+
children: /* @__PURE__ */ jsx("span", { className: "uix-listbox__label", children: suggestion })
|
|
334
|
+
},
|
|
335
|
+
suggestion
|
|
336
|
+
)) }) })
|
|
337
|
+
] });
|
|
338
|
+
}
|
|
339
|
+
export {
|
|
340
|
+
DEFAULT_TAG_INPUT_LABELS,
|
|
341
|
+
TagInput
|
|
342
|
+
};
|
|
@@ -3,6 +3,11 @@ import { TextareaHTMLAttributes } from 'react';
|
|
|
3
3
|
|
|
4
4
|
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
5
5
|
invalid?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* `lg`: the public-page size beside `Input size="lg"` and `Button size="lg"` (HAR-1812): larger
|
|
8
|
+
* text and padding, never shorter than 44 px. It still grows with `rows` and the resize handle.
|
|
9
|
+
*/
|
|
10
|
+
size?: 'md' | 'lg';
|
|
6
11
|
}
|
|
7
12
|
declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
8
13
|
|
|
@@ -2,11 +2,11 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
4
|
const Textarea = forwardRef(
|
|
5
|
-
({ invalid, className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5
|
+
({ invalid, size = "md", className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
6
6
|
"textarea",
|
|
7
7
|
{
|
|
8
8
|
ref,
|
|
9
|
-
className: cx("uix-textarea", className),
|
|
9
|
+
className: cx("uix-textarea", size === "lg" && "uix-textarea--lg", className),
|
|
10
10
|
"aria-invalid": invalid || void 0,
|
|
11
11
|
...props
|
|
12
12
|
}
|