prime-ui-kit 0.11.1 → 0.13.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 +4 -1
- package/dist/chunks/{chunk-WDTSHOTD.js → chunk-E6SQBSDF.js} +140 -30
- package/dist/chunks/{chunk-CUH6DJ57.js → chunk-Z3WKKAS6.js} +6572 -5024
- package/dist/chunks/{chunk-GKX3QAUC.js → chunk-ZSJMNA46.js} +14 -5
- package/dist/color-picker.js +2 -2
- package/dist/components/chat/Chat.d.ts +11 -12
- package/dist/components/chat/chatContext.d.ts +2 -0
- package/dist/components/chat-list/ChatList.d.ts +191 -0
- package/dist/components/chat-list/formatChatTime.d.ts +6 -0
- package/dist/components/command-menu/CommandMenu.d.ts +10 -5
- package/dist/components/composer/Composer.d.ts +3 -10
- package/dist/components/data-table/DataTable.d.ts +16 -2
- package/dist/components/data-table/Row.d.ts +23 -7
- package/dist/components/data-table/StateRows.d.ts +5 -1
- package/dist/components/data-table/reorder.d.ts +3 -1
- package/dist/components/data-table/rows.d.ts +20 -4
- package/dist/components/file-upload/FileUpload.d.ts +7 -0
- package/dist/components/gantt/Gantt.d.ts +19 -1
- package/dist/components/gantt/GanttBar.d.ts +4 -1
- package/dist/components/gantt/GanttRow.d.ts +8 -1
- package/dist/components/index.d.ts +11 -7
- package/dist/components/kanban/Kanban.d.ts +17 -2
- package/dist/components/list/List.d.ts +120 -0
- package/dist/components/message/Message.d.ts +13 -0
- package/dist/components/message/MessageParts.d.ts +2 -0
- package/dist/components/modal/DialogParts.d.ts +5 -1
- package/dist/components/select/Select.d.ts +11 -5
- package/dist/components/select/SelectItem.d.ts +19 -0
- package/dist/components/select/selectContext.d.ts +4 -0
- package/dist/components/sparkline/Sparkline.d.ts +14 -3
- package/dist/components/textarea/Textarea.d.ts +11 -3
- package/dist/hooks/useUploadQueue.d.ts +5 -1
- package/dist/icons/registry.d.ts +2 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -2
- package/dist/internal/VisuallyHidden.d.ts +6 -1
- package/dist/internal/attachmentTile.d.ts +5 -1
- package/dist/internal/richText.d.ts +7 -2
- package/dist/internal/textFormatting.d.ts +52 -0
- package/dist/internal/textFormattingToolbar.d.ts +26 -0
- package/dist/skill/api-contract.md +1 -1
- package/dist/skill/cheatsheet.md +13 -1
- package/dist/skill/choosing.md +9 -4
- package/dist/skill/components.md +7 -5
- package/dist/skill/composition.md +9 -1
- package/dist/skill/layouts.md +4 -1
- package/dist/skill/patterns/app-shell.module.css +18 -0
- package/dist/skill/patterns/app-shell.tsx +301 -0
- package/dist/skill/patterns/chat.module.css +0 -25
- package/dist/skill/patterns/chat.tsx +72 -29
- package/dist/skill/patterns/kanban-board.module.css +28 -0
- package/dist/skill/patterns/kanban-board.tsx +612 -0
- package/dist/skill/patterns/media-library.module.css +66 -0
- package/dist/skill/patterns/media-library.tsx +638 -0
- package/dist/skill/patterns/schedule.module.css +22 -0
- package/dist/skill/patterns/schedule.tsx +722 -0
- package/dist/skill/reference/components/chat/COMPONENT.md +13 -4
- package/dist/skill/reference/components/chat/examples/states.tsx +100 -0
- package/dist/skill/reference/components/chat-list/COMPONENT.md +256 -0
- package/dist/skill/reference/components/chat-list/examples/controlled.tsx +103 -0
- package/dist/skill/reference/components/chat-list/examples/examples.module.css +66 -0
- package/dist/skill/reference/components/chat-list/examples/live.tsx +133 -0
- package/dist/skill/reference/components/chat-list/examples/long-list.tsx +87 -0
- package/dist/skill/reference/components/chat-list/examples/narrow.tsx +88 -0
- package/dist/skill/reference/components/chat-list/examples/overview.tsx +194 -0
- package/dist/skill/reference/components/chat-list/examples/search.tsx +71 -0
- package/dist/skill/reference/components/chat-list/examples/sizes.tsx +61 -0
- package/dist/skill/reference/components/chat-list/examples/states.tsx +107 -0
- package/dist/skill/reference/components/chat-list/examples/structure.tsx +135 -0
- package/dist/skill/reference/components/command-menu/COMPONENT.md +15 -11
- package/dist/skill/reference/components/command-menu/examples/server-search.tsx +11 -9
- package/dist/skill/reference/components/composer/COMPONENT.md +8 -7
- package/dist/skill/reference/components/composer/examples/formatting.tsx +1 -1
- package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -0
- package/dist/skill/reference/components/data-table/COMPONENT.md +21 -6
- package/dist/skill/reference/components/data-table/examples/groups.tsx +2 -1
- package/dist/skill/reference/components/data-table/examples/trend.tsx +85 -0
- package/dist/skill/reference/components/drawer/COMPONENT.md +7 -6
- package/dist/skill/reference/components/drawer/examples/client-card.tsx +50 -0
- package/dist/skill/reference/components/fieldset/COMPONENT.md +1 -0
- package/dist/skill/reference/components/file-upload/COMPONENT.md +12 -8
- package/dist/skill/reference/components/file-upload/examples/overview.tsx +14 -3
- package/dist/skill/reference/components/gantt/COMPONENT.md +15 -5
- package/dist/skill/reference/components/gantt/examples/row-link.tsx +96 -0
- package/dist/skill/reference/components/kanban/COMPONENT.md +12 -4
- package/dist/skill/reference/components/kanban/examples/item-link.tsx +92 -0
- package/dist/skill/reference/components/list/COMPONENT.md +195 -0
- package/dist/skill/reference/components/list/examples/as-link.tsx +37 -0
- package/dist/skill/reference/components/list/examples/examples.module.css +18 -0
- package/dist/skill/reference/components/list/examples/overflow.tsx +46 -0
- package/dist/skill/reference/components/list/examples/overview.tsx +63 -0
- package/dist/skill/reference/components/list/examples/reorder.tsx +48 -0
- package/dist/skill/reference/components/list/examples/sizes.tsx +35 -0
- package/dist/skill/reference/components/list/examples/states.tsx +27 -0
- package/dist/skill/reference/components/list/examples/with-icon.tsx +60 -0
- package/dist/skill/reference/components/message/COMPONENT.md +18 -2
- package/dist/skill/reference/components/message/examples/bot-actions.tsx +51 -0
- package/dist/skill/reference/components/modal/COMPONENT.md +6 -4
- package/dist/skill/reference/components/page-content/COMPONENT.md +2 -2
- package/dist/skill/reference/components/page-content/examples/examples.module.css +5 -12
- package/dist/skill/reference/components/page-content/examples/list-detail.tsx +13 -18
- package/dist/skill/reference/components/select/COMPONENT.md +38 -7
- package/dist/skill/reference/components/select/examples/create-action.tsx +107 -0
- package/dist/skill/reference/components/select/examples/saving.tsx +47 -0
- package/dist/skill/reference/components/sheet/COMPONENT.md +4 -4
- package/dist/skill/reference/components/sparkline/COMPONENT.md +16 -2
- package/dist/skill/reference/components/sparkline/examples/compact.tsx +41 -0
- package/dist/skill/reference/components/sparkline/examples/examples.module.css +12 -0
- package/dist/skill/reference/components/textarea/COMPONENT.md +22 -2
- package/dist/skill/reference/components/textarea/examples/formatting.tsx +20 -0
- package/dist/skill/reference/components/visually-hidden/COMPONENT.md +6 -3
- package/dist/skill/reference/components/visually-hidden/examples/overview.tsx +2 -2
- package/package.json +2 -2
- package/src/components/chat/COMPONENT.md +13 -4
- package/src/components/chat/examples/states.tsx +100 -0
- package/src/components/chat-list/COMPONENT.md +256 -0
- package/src/components/chat-list/examples/controlled.tsx +103 -0
- package/src/components/chat-list/examples/examples.module.css +66 -0
- package/src/components/chat-list/examples/live.tsx +133 -0
- package/src/components/chat-list/examples/long-list.tsx +87 -0
- package/src/components/chat-list/examples/narrow.tsx +88 -0
- package/src/components/chat-list/examples/overview.tsx +194 -0
- package/src/components/chat-list/examples/search.tsx +71 -0
- package/src/components/chat-list/examples/sizes.tsx +61 -0
- package/src/components/chat-list/examples/states.tsx +107 -0
- package/src/components/chat-list/examples/structure.tsx +135 -0
- package/src/components/command-menu/COMPONENT.md +15 -11
- package/src/components/command-menu/examples/server-search.tsx +11 -9
- package/src/components/composer/COMPONENT.md +8 -7
- package/src/components/composer/examples/formatting.tsx +1 -1
- package/src/components/confirm-dialog/COMPONENT.md +1 -0
- package/src/components/data-table/COMPONENT.md +21 -6
- package/src/components/data-table/examples/groups.tsx +2 -1
- package/src/components/data-table/examples/trend.tsx +85 -0
- package/src/components/drawer/COMPONENT.md +7 -6
- package/src/components/drawer/examples/client-card.tsx +50 -0
- package/src/components/fieldset/COMPONENT.md +1 -0
- package/src/components/file-upload/COMPONENT.md +12 -8
- package/src/components/file-upload/examples/overview.tsx +14 -3
- package/src/components/gantt/COMPONENT.md +15 -5
- package/src/components/gantt/examples/row-link.tsx +96 -0
- package/src/components/kanban/COMPONENT.md +12 -4
- package/src/components/kanban/examples/item-link.tsx +92 -0
- package/src/components/list/COMPONENT.md +195 -0
- package/src/components/list/examples/as-link.tsx +37 -0
- package/src/components/list/examples/examples.module.css +18 -0
- package/src/components/list/examples/overflow.tsx +46 -0
- package/src/components/list/examples/overview.tsx +63 -0
- package/src/components/list/examples/reorder.tsx +48 -0
- package/src/components/list/examples/sizes.tsx +35 -0
- package/src/components/list/examples/states.tsx +27 -0
- package/src/components/list/examples/with-icon.tsx +60 -0
- package/src/components/message/COMPONENT.md +18 -2
- package/src/components/message/examples/bot-actions.tsx +51 -0
- package/src/components/modal/COMPONENT.md +6 -4
- package/src/components/page-content/COMPONENT.md +2 -2
- package/src/components/page-content/examples/examples.module.css +5 -12
- package/src/components/page-content/examples/list-detail.tsx +13 -18
- package/src/components/select/COMPONENT.md +38 -7
- package/src/components/select/examples/create-action.tsx +107 -0
- package/src/components/select/examples/saving.tsx +47 -0
- package/src/components/sheet/COMPONENT.md +4 -4
- package/src/components/sparkline/COMPONENT.md +16 -2
- package/src/components/sparkline/examples/compact.tsx +41 -0
- package/src/components/sparkline/examples/examples.module.css +12 -0
- package/src/components/textarea/COMPONENT.md +22 -2
- package/src/components/textarea/examples/formatting.tsx +20 -0
- package/src/components/visually-hidden/COMPONENT.md +6 -3
- package/src/components/visually-hidden/examples/overview.tsx +2 -2
- package/dist/components/composer/format.d.ts +0 -39
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
|
|
8
8
|
**A calm, precise React 19 UI kit for product interfaces** — admin panels, dashboards, settings, forms
|
|
9
|
-
and data tables.
|
|
9
|
+
and data tables. 79 components on one design contract, one API vocabulary and one set of tokens, so
|
|
10
10
|
every screen you build looks like it was drawn by the same hand.
|
|
11
11
|
|
|
12
12
|
- **Graphite design language.** Depth from fill, not lines — a surface ladder where every nested
|
|
@@ -249,6 +249,7 @@ accessibility, examples and common mistakes.
|
|
|
249
249
|
| [**VoicePlayer**](https://github.com/esurkov1/prime-ui/blob/main/src/components/voice-player/COMPONENT.md) | A voice message player: a round play disk, a waveform that is the seek slider, and the time with the playback speed; one sound at a time, `getWaveform` for audio without levels. |
|
|
250
250
|
| [**VideoNote**](https://github.com/esurkov1/prime-ui/blob/main/src/components/video-note/COMPONENT.md) | A round video message: a still first frame with the play disk, played with sound on a press; the same player API as VoicePlayer — transcript, transfer either way, one sound at a time. |
|
|
251
251
|
| [**Composer**](https://github.com/esurkov1/prime-ui/blob/main/src/components/composer/COMPONENT.md) | The message input of a chat: a growing field, Enter to send, attachments, reply / edit bar, Markdown formatting, voice and video messages with pause, the typing signal. |
|
|
252
|
+
| [**ChatList**](https://github.com/esurkov1/prime-ui/blob/main/src/components/chat-list/COMPONENT.md) | The conversation list of a messenger: avatars with presence, names, times, the last message with its author or media word, unread / muted / mention counts, typing and drafts, a row menu, search, rows that glide to a new order, long lists rendered around the view. |
|
|
252
253
|
|
|
253
254
|
### Status and loading (`status`)
|
|
254
255
|
|
|
@@ -271,6 +272,7 @@ accessibility, examples and common mistakes.
|
|
|
271
272
|
| [**Tabs**](https://github.com/esurkov1/prime-ui/blob/main/src/components/tabs/COMPONENT.md) | Tabs for navigating between content panels of one screen. |
|
|
272
273
|
| [**Breadcrumb**](https://github.com/esurkov1/prime-ui/blob/main/src/components/breadcrumb/COMPONENT.md) | Breadcrumbs: the path to the current page. |
|
|
273
274
|
| [**Pagination**](https://github.com/esurkov1/prime-ui/blob/main/src/components/pagination/COMPONENT.md) | Page-by-page navigation: arrows, page numbers with ellipsis and a compact «3 / 12» view. |
|
|
275
|
+
| [**List**](https://github.com/esurkov1/prime-ui/blob/main/src/components/list/COMPONENT.md) | A selectable list of rows — the list half of a list + detail screen: conversations, tickets, mail, records. |
|
|
274
276
|
| [**Stepper**](https://github.com/esurkov1/prime-ui/blob/main/src/components/stepper/COMPONENT.md) | Steps of a multi-step process with pending, active, completed and danger statuses. |
|
|
275
277
|
| [**Sidebar**](https://github.com/esurkov1/prime-ui/blob/main/src/layout/sidebar/COMPONENT.md) | App side navigation in three modes — expanded, compact, hidden — and an off-canvas panel on narrow screens. |
|
|
276
278
|
| [**BottomNav**](https://github.com/esurkov1/prime-ui/blob/main/src/layout/bottom-nav/COMPONENT.md) | Phone navigation bar: 2–6 sections, flat or a floating glass capsule, with an optional round action. |
|
|
@@ -336,6 +338,7 @@ accessibility, examples and common mistakes.
|
|
|
336
338
|
| `getPasswordStrength(value)` | The kit's 0–4 password estimate behind `Input.Root strength`; replace it with `getStrength`. |
|
|
337
339
|
| `useUploadQueue({ upload, concurrency })` | The upload queue behind FileUpload `queue`: your `upload(file, { signal, onProgress })` runs a few at a time, with progress, abort on remove and retry. |
|
|
338
340
|
| `groupMessages`, `formatMessageDate`, `formatMessageTime`, `hueOf` | Chat data → dated runs of one author (`Chat.Messages items` runs it for you), the date and time labels, and a palette hue stable per person. |
|
|
341
|
+
| `formatChatTime(date, now)` | The time of a dialog's last message as `ChatList` shows it: «14:32» today, «пн» this week, «12 мар», «12.03.2025». |
|
|
339
342
|
| `getWaveform` | The 0…1 levels of a recorded voice message (a `Blob` or a URL) for `VoicePlayer waveform`, decoded with the Web Audio API. |
|
|
340
343
|
| `moveBefore(items, id, beforeId, getId)` | Applies a `Dnd` or DataTable `onReorder` to your array. |
|
|
341
344
|
| `matchesSmartFilter`, `resolveSmartFilterValues` | Apply a SmartFilter value to your rows. |
|
|
@@ -134,8 +134,13 @@ var VisuallyHidden_default = {
|
|
|
134
134
|
// src/internal/VisuallyHidden.tsx
|
|
135
135
|
import { jsx } from "react/jsx-runtime";
|
|
136
136
|
var visuallyHiddenClass = VisuallyHidden_default.root;
|
|
137
|
-
function VisuallyHidden({ className, ...rest }) {
|
|
138
|
-
|
|
137
|
+
function VisuallyHidden({ className, live, ...rest }) {
|
|
138
|
+
const region = live ? {
|
|
139
|
+
role: live === "assertive" ? "alert" : "status",
|
|
140
|
+
"aria-live": live,
|
|
141
|
+
"aria-atomic": true
|
|
142
|
+
} : null;
|
|
143
|
+
return /* @__PURE__ */ jsx("span", { className: cx(VisuallyHidden_default.root, className), ...region, ...rest });
|
|
139
144
|
}
|
|
140
145
|
VisuallyHidden.displayName = "VisuallyHidden";
|
|
141
146
|
|
|
@@ -1090,6 +1095,8 @@ var iconRegistry = {
|
|
|
1090
1095
|
"format.link": Link2,
|
|
1091
1096
|
"format.list": List,
|
|
1092
1097
|
"format.quote": TextQuote,
|
|
1098
|
+
/** Hidden text (a spoiler) in text formatting; `field.password.hide` masks a password. */
|
|
1099
|
+
"format.spoiler": EyeOff,
|
|
1093
1100
|
"format.strikethrough": Strikethrough,
|
|
1094
1101
|
"format.underline": Underline,
|
|
1095
1102
|
"object.activity": Activity,
|
|
@@ -5934,6 +5941,7 @@ var Select_default = {
|
|
|
5934
5941
|
search: "Select_search",
|
|
5935
5942
|
group: "Select_group",
|
|
5936
5943
|
separator: "Select_separator",
|
|
5944
|
+
actions: "Select_actions",
|
|
5937
5945
|
item: "Select_item",
|
|
5938
5946
|
itemText: "Select_itemText",
|
|
5939
5947
|
itemTitle: "Select_itemTitle",
|
|
@@ -6169,6 +6177,59 @@ function SelectItem({
|
|
|
6169
6177
|
);
|
|
6170
6178
|
}
|
|
6171
6179
|
SelectItem.displayName = "Select.Item";
|
|
6180
|
+
var ACTION_PREFIX = "__prime_select_action";
|
|
6181
|
+
var isActionValue = (value) => value.startsWith(ACTION_PREFIX);
|
|
6182
|
+
function SelectAction({
|
|
6183
|
+
onSelect,
|
|
6184
|
+
disabled = false,
|
|
6185
|
+
className,
|
|
6186
|
+
children,
|
|
6187
|
+
onClick: onClick2,
|
|
6188
|
+
onMouseMove,
|
|
6189
|
+
ref,
|
|
6190
|
+
...rest
|
|
6191
|
+
}) {
|
|
6192
|
+
const { highlight, listboxId, setOpen, size } = useSelectContext();
|
|
6193
|
+
const value = `${ACTION_PREFIX}${React50.useId()}`;
|
|
6194
|
+
const isHighlighted = useStoreSlice(highlight, (current) => current === value);
|
|
6195
|
+
const parts = splitItemChildren(children);
|
|
6196
|
+
return (
|
|
6197
|
+
// biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
|
|
6198
|
+
// biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
|
|
6199
|
+
/* @__PURE__ */ jsxs25(
|
|
6200
|
+
"div",
|
|
6201
|
+
{
|
|
6202
|
+
...rest,
|
|
6203
|
+
ref,
|
|
6204
|
+
id: optionDomId(listboxId, value),
|
|
6205
|
+
role: "option",
|
|
6206
|
+
"aria-disabled": disabled || void 0,
|
|
6207
|
+
className: cx(menu_default.item, className),
|
|
6208
|
+
onClick: (event) => {
|
|
6209
|
+
onClick2?.(event);
|
|
6210
|
+
if (event.defaultPrevented || disabled) return;
|
|
6211
|
+
onSelect();
|
|
6212
|
+
setOpen(false);
|
|
6213
|
+
},
|
|
6214
|
+
onMouseMove: (event) => {
|
|
6215
|
+
onMouseMove?.(event);
|
|
6216
|
+
if (!disabled && !isHighlighted) highlight.set(value);
|
|
6217
|
+
},
|
|
6218
|
+
...toDataAttributes({
|
|
6219
|
+
value,
|
|
6220
|
+
action: true,
|
|
6221
|
+
highlighted: isHighlighted,
|
|
6222
|
+
disabled
|
|
6223
|
+
}),
|
|
6224
|
+
children: [
|
|
6225
|
+
sizeMedia(parts.leading, size),
|
|
6226
|
+
/* @__PURE__ */ jsx38("span", { className: Select_default.itemText, children: parts.body })
|
|
6227
|
+
]
|
|
6228
|
+
}
|
|
6229
|
+
)
|
|
6230
|
+
);
|
|
6231
|
+
}
|
|
6232
|
+
SelectAction.displayName = "Select.Action";
|
|
6172
6233
|
|
|
6173
6234
|
// src/components/select/Select.tsx
|
|
6174
6235
|
import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
@@ -6179,7 +6240,8 @@ var SELECT_LABELS = {
|
|
|
6179
6240
|
loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
|
|
6180
6241
|
retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
|
|
6181
6242
|
clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
|
|
6182
|
-
optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E"
|
|
6243
|
+
optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
|
|
6244
|
+
changeFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440"
|
|
6183
6245
|
};
|
|
6184
6246
|
function SelectRoot(props) {
|
|
6185
6247
|
const {
|
|
@@ -6222,11 +6284,30 @@ function SelectRoot(props) {
|
|
|
6222
6284
|
const disabled = useInheritedDisabled(disabledProp);
|
|
6223
6285
|
const labels = React51.useMemo(() => ({ ...SELECT_LABELS, ...labelsProp }), [labelsProp]);
|
|
6224
6286
|
const ids = useFieldFrame(id, { hint, error, invalid });
|
|
6225
|
-
const [
|
|
6287
|
+
const [stored, setStored] = useControllableState({
|
|
6226
6288
|
value: props.value,
|
|
6227
|
-
defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
|
|
6228
|
-
onChange: props.onValueChange
|
|
6289
|
+
defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
|
|
6229
6290
|
});
|
|
6291
|
+
const changes = usePendingChanges(stored, takeNext);
|
|
6292
|
+
const value = changes.shown;
|
|
6293
|
+
const saving = changes.pending.length > 0;
|
|
6294
|
+
const [announcement, setAnnouncement] = React51.useState("");
|
|
6295
|
+
const onValueChange = props.onValueChange;
|
|
6296
|
+
const commit = (next) => {
|
|
6297
|
+
if (saving || Object.is(next, value)) return;
|
|
6298
|
+
const outcome = onValueChange?.(next);
|
|
6299
|
+
if (!isPromiseLike(outcome)) {
|
|
6300
|
+
setStored(next);
|
|
6301
|
+
return;
|
|
6302
|
+
}
|
|
6303
|
+
setAnnouncement("");
|
|
6304
|
+
changes.track(next, outcome, {
|
|
6305
|
+
onResolve: () => setStored(next),
|
|
6306
|
+
onReject: () => setAnnouncement(labels.changeFailed)
|
|
6307
|
+
});
|
|
6308
|
+
};
|
|
6309
|
+
const commitRef = React51.useRef(commit);
|
|
6310
|
+
commitRef.current = commit;
|
|
6230
6311
|
const selected = React51.useMemo(
|
|
6231
6312
|
() => Array.isArray(value) ? value : value ? [value] : [],
|
|
6232
6313
|
[value]
|
|
@@ -6252,18 +6333,18 @@ function SelectRoot(props) {
|
|
|
6252
6333
|
const pick = React51.useCallback(
|
|
6253
6334
|
(optionValue) => {
|
|
6254
6335
|
if (multiple) {
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6336
|
+
const list = Array.isArray(value) ? value : [];
|
|
6337
|
+
commitRef.current(
|
|
6338
|
+
list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
|
|
6339
|
+
);
|
|
6259
6340
|
return;
|
|
6260
6341
|
}
|
|
6261
|
-
|
|
6342
|
+
commitRef.current(optionValue);
|
|
6262
6343
|
setOpen(false);
|
|
6263
6344
|
},
|
|
6264
|
-
[multiple,
|
|
6345
|
+
[multiple, value, setOpen]
|
|
6265
6346
|
);
|
|
6266
|
-
const clear = React51.useCallback(() =>
|
|
6347
|
+
const clear = React51.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
|
|
6267
6348
|
const context = React51.useMemo(
|
|
6268
6349
|
() => ({
|
|
6269
6350
|
size,
|
|
@@ -6279,6 +6360,7 @@ function SelectRoot(props) {
|
|
|
6279
6360
|
clear,
|
|
6280
6361
|
clearable,
|
|
6281
6362
|
loading,
|
|
6363
|
+
saving,
|
|
6282
6364
|
loadingMore,
|
|
6283
6365
|
hasMore,
|
|
6284
6366
|
onLoadMore,
|
|
@@ -6312,6 +6394,7 @@ function SelectRoot(props) {
|
|
|
6312
6394
|
clear,
|
|
6313
6395
|
clearable,
|
|
6314
6396
|
loading,
|
|
6397
|
+
saving,
|
|
6315
6398
|
loadingMore,
|
|
6316
6399
|
hasMore,
|
|
6317
6400
|
onLoadMore,
|
|
@@ -6342,12 +6425,14 @@ function SelectRoot(props) {
|
|
|
6342
6425
|
className,
|
|
6343
6426
|
children: [
|
|
6344
6427
|
/* @__PURE__ */ jsx39(SelectProvider, { value: context, children: /* @__PURE__ */ jsx39(ControlSizeProvider, { value: size, children }) }),
|
|
6345
|
-
name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx39("input", { type: "hidden", name, value: item, disabled }, item)) : null
|
|
6428
|
+
name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx39("input", { type: "hidden", name, value: item, disabled }, item)) : null,
|
|
6429
|
+
/* @__PURE__ */ jsx39(VisuallyHidden, { role: "status", "aria-live": "polite", children: announcement })
|
|
6346
6430
|
]
|
|
6347
6431
|
}
|
|
6348
6432
|
);
|
|
6349
6433
|
}
|
|
6350
6434
|
SelectRoot.displayName = "Select.Root";
|
|
6435
|
+
var takeNext = (_current, next) => next;
|
|
6351
6436
|
function SelectTrigger({
|
|
6352
6437
|
className,
|
|
6353
6438
|
children,
|
|
@@ -6370,13 +6455,15 @@ function SelectTrigger({
|
|
|
6370
6455
|
describedBy,
|
|
6371
6456
|
triggerRef,
|
|
6372
6457
|
loading,
|
|
6458
|
+
saving,
|
|
6373
6459
|
clearable,
|
|
6374
6460
|
selected,
|
|
6375
6461
|
clear,
|
|
6376
6462
|
labels
|
|
6377
6463
|
} = useSelectContext();
|
|
6378
6464
|
const mergedRef = useMergedRefs(triggerRef, ref);
|
|
6379
|
-
const
|
|
6465
|
+
const busy = loading || saving;
|
|
6466
|
+
const showClear = clearable && selected.length > 0 && !disabled && !busy;
|
|
6380
6467
|
return /* @__PURE__ */ jsxs26(
|
|
6381
6468
|
"button",
|
|
6382
6469
|
{
|
|
@@ -6391,7 +6478,7 @@ function SelectTrigger({
|
|
|
6391
6478
|
"aria-invalid": invalid || void 0,
|
|
6392
6479
|
"aria-required": required || void 0,
|
|
6393
6480
|
"aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
|
|
6394
|
-
"aria-busy":
|
|
6481
|
+
"aria-busy": busy || void 0,
|
|
6395
6482
|
disabled,
|
|
6396
6483
|
className: cx(fieldTriggerClass, Select_default.trigger, className),
|
|
6397
6484
|
onClick: (event) => {
|
|
@@ -6413,7 +6500,7 @@ function SelectTrigger({
|
|
|
6413
6500
|
state: isOpen ? "open" : "closed",
|
|
6414
6501
|
size,
|
|
6415
6502
|
invalid: invalid || void 0,
|
|
6416
|
-
loading:
|
|
6503
|
+
loading: busy || void 0,
|
|
6417
6504
|
disabled: disabled || void 0,
|
|
6418
6505
|
"focus-ring": focusRing ? void 0 : false
|
|
6419
6506
|
}),
|
|
@@ -6438,7 +6525,7 @@ function SelectTrigger({
|
|
|
6438
6525
|
}
|
|
6439
6526
|
)
|
|
6440
6527
|
) : null,
|
|
6441
|
-
/* @__PURE__ */ jsx39("span", { className: Select_default.chevron, "aria-hidden": "true", children:
|
|
6528
|
+
/* @__PURE__ */ jsx39("span", { className: Select_default.chevron, "aria-hidden": "true", children: busy ? /* @__PURE__ */ jsx39(Spinner, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx39(Icon, { name: "nav.chevronDown" }) })
|
|
6442
6529
|
]
|
|
6443
6530
|
}
|
|
6444
6531
|
);
|
|
@@ -6511,6 +6598,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6511
6598
|
query,
|
|
6512
6599
|
setQuery,
|
|
6513
6600
|
loading,
|
|
6601
|
+
saving,
|
|
6514
6602
|
loadingMore,
|
|
6515
6603
|
hasMore,
|
|
6516
6604
|
onLoadMore,
|
|
@@ -6521,6 +6609,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6521
6609
|
registry
|
|
6522
6610
|
} = useSelectContext();
|
|
6523
6611
|
const listboxRef = React51.useRef(null);
|
|
6612
|
+
const items = [];
|
|
6613
|
+
const actions = [];
|
|
6614
|
+
for (const child of React51.Children.toArray(children)) {
|
|
6615
|
+
(React51.isValidElement(child) && child.type === SelectAction ? actions : items).push(child);
|
|
6616
|
+
}
|
|
6617
|
+
const actionsId = `${listboxId}-actions`;
|
|
6524
6618
|
const floating = useFloatingLayer({
|
|
6525
6619
|
open: isOpen,
|
|
6526
6620
|
onOpenChange: setOpen,
|
|
@@ -6562,20 +6656,27 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6562
6656
|
}
|
|
6563
6657
|
const inSearch = event.target instanceof HTMLInputElement;
|
|
6564
6658
|
if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
|
|
6565
|
-
const
|
|
6659
|
+
const stops = enabledOptions(panelRef.current);
|
|
6566
6660
|
const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
6567
6661
|
if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
|
|
6568
6662
|
event.preventDefault();
|
|
6569
|
-
const match = typeahead.find(event.key,
|
|
6663
|
+
const match = typeahead.find(event.key, stops, highlight.get());
|
|
6570
6664
|
if (match) {
|
|
6571
6665
|
highlight.set(match.dataset.value);
|
|
6572
6666
|
match.scrollIntoView?.({ block: "nearest" });
|
|
6573
6667
|
}
|
|
6574
6668
|
return;
|
|
6575
6669
|
}
|
|
6576
|
-
handleListboxKeyDown(event, {
|
|
6670
|
+
handleListboxKeyDown(event, {
|
|
6671
|
+
items: stops,
|
|
6672
|
+
highlight,
|
|
6673
|
+
onSelect: (value) => {
|
|
6674
|
+
if (isActionValue(value)) document.getElementById(optionDomId(listboxId, value))?.click();
|
|
6675
|
+
else pick(value);
|
|
6676
|
+
}
|
|
6677
|
+
});
|
|
6577
6678
|
};
|
|
6578
|
-
if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children });
|
|
6679
|
+
if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children: items });
|
|
6579
6680
|
const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
|
|
6580
6681
|
return /* @__PURE__ */ jsxs26(
|
|
6581
6682
|
FloatingPanel,
|
|
@@ -6619,13 +6720,14 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6619
6720
|
"aria-multiselectable": multiple || void 0,
|
|
6620
6721
|
"aria-labelledby": triggerId,
|
|
6621
6722
|
"aria-activedescendant": searchable ? void 0 : activeDescendant,
|
|
6622
|
-
"aria-busy": loading || loadingMore || void 0,
|
|
6723
|
+
"aria-busy": loading || loadingMore || saving || void 0,
|
|
6724
|
+
"aria-owns": actions.length > 0 && region !== "error" ? actionsId : void 0,
|
|
6623
6725
|
tabIndex: -1,
|
|
6624
6726
|
hidden: region === "error" ? true : void 0,
|
|
6625
6727
|
"data-autofocus": searchable || region === "error" ? void 0 : "",
|
|
6626
6728
|
className: cx(Select_default.listbox, swapClass),
|
|
6627
6729
|
children: [
|
|
6628
|
-
|
|
6730
|
+
items,
|
|
6629
6731
|
region === "loading" ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_ROWS2 }) : null,
|
|
6630
6732
|
region === "ready" && hasMore ? /* @__PURE__ */ jsx39("div", { ref: sentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
|
|
6631
6733
|
region === "ready" && loadingMore ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
|
|
@@ -6637,6 +6739,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6637
6739
|
/* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: labels.empty }),
|
|
6638
6740
|
query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx39(EmptyPage.Description, { children: labels.emptyHint }) : null
|
|
6639
6741
|
] }) : null,
|
|
6742
|
+
actions.length > 0 && region !== "error" ? (
|
|
6743
|
+
// Owned by the listbox (`aria-owns`): its options for assistive tech, pinned under the
|
|
6744
|
+
// scroller and the empty state for the eye.
|
|
6745
|
+
// biome-ignore lint/a11y/useSemanticElements: a group of options inside a listbox, not a form fieldset
|
|
6746
|
+
/* @__PURE__ */ jsx39("div", { id: actionsId, role: "group", className: Select_default.actions, children: actions })
|
|
6747
|
+
) : null,
|
|
6640
6748
|
region === "error" ? /* @__PURE__ */ jsxs26(EmptyPage.Root, { layout: "compact", size, role: "alert", className: swapClass, children: [
|
|
6641
6749
|
/* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: loadError }),
|
|
6642
6750
|
onRetry ? /* @__PURE__ */ jsx39(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs26(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
|
|
@@ -6645,7 +6753,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6645
6753
|
] }) }) : null
|
|
6646
6754
|
] }) : null,
|
|
6647
6755
|
/* @__PURE__ */ jsx39(VisuallyHidden, { "aria-live": "polite", children: loading || loadingMore ? labels.loading : "" }),
|
|
6648
|
-
/* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, highlight })
|
|
6756
|
+
/* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, panelRef, highlight })
|
|
6649
6757
|
]
|
|
6650
6758
|
}
|
|
6651
6759
|
);
|
|
@@ -6653,6 +6761,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6653
6761
|
SelectContent.displayName = "Select.Content";
|
|
6654
6762
|
function HighlightOnOpen({
|
|
6655
6763
|
listboxRef,
|
|
6764
|
+
panelRef,
|
|
6656
6765
|
highlight
|
|
6657
6766
|
}) {
|
|
6658
6767
|
const { isOpen, query, selected, registry } = useSelectContext();
|
|
@@ -6668,15 +6777,15 @@ function HighlightOnOpen({
|
|
|
6668
6777
|
return () => highlight.set(void 0);
|
|
6669
6778
|
}, [isOpen, listboxRef, highlight]);
|
|
6670
6779
|
React51.useLayoutEffect(() => {
|
|
6671
|
-
if (query !== "") highlight.set(enabledOptions(
|
|
6672
|
-
}, [query,
|
|
6780
|
+
if (query !== "") highlight.set(enabledOptions(panelRef.current)[0]?.dataset.value);
|
|
6781
|
+
}, [query, panelRef, highlight]);
|
|
6673
6782
|
React51.useLayoutEffect(() => {
|
|
6674
6783
|
if (query === "") return;
|
|
6675
6784
|
const options = enabledOptions(listboxRef.current);
|
|
6676
6785
|
if (!options.some((item) => item.dataset.value === highlight.get())) {
|
|
6677
|
-
highlight.set(options[0]?.dataset.value);
|
|
6786
|
+
highlight.set((options[0] ?? enabledOptions(panelRef.current)[0])?.dataset.value);
|
|
6678
6787
|
}
|
|
6679
|
-
}, [version, query, listboxRef, highlight]);
|
|
6788
|
+
}, [version, query, listboxRef, panelRef, highlight]);
|
|
6680
6789
|
return null;
|
|
6681
6790
|
}
|
|
6682
6791
|
function SelectGroup({ className, ...rest }) {
|
|
@@ -6699,7 +6808,8 @@ var Select = {
|
|
|
6699
6808
|
ItemDescription: SelectItemDescription,
|
|
6700
6809
|
ItemMeta: SelectItemMeta,
|
|
6701
6810
|
Group: SelectGroup,
|
|
6702
|
-
Separator: SelectSeparator
|
|
6811
|
+
Separator: SelectSeparator,
|
|
6812
|
+
Action: SelectAction
|
|
6703
6813
|
};
|
|
6704
6814
|
|
|
6705
6815
|
export {
|