prime-ui-kit 0.12.0 → 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 +3 -1
- package/dist/chunks/{chunk-VOZ7J72X.js → chunk-E6SQBSDF.js} +133 -28
- package/dist/chunks/{chunk-YJO3NJIJ.js → chunk-Z3WKKAS6.js} +6662 -5282
- package/dist/chunks/{chunk-OTOIOHVE.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 +10 -8
- package/dist/components/kanban/Kanban.d.ts +17 -2
- package/dist/components/list/List.d.ts +18 -3
- 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.js +6 -2
- 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/cheatsheet.md +12 -0
- package/dist/skill/choosing.md +5 -2
- package/dist/skill/components.md +5 -4
- package/dist/skill/composition.md +1 -1
- package/dist/skill/layouts.md +2 -0
- package/dist/skill/patterns/chat.module.css +0 -9
- package/dist/skill/patterns/chat.tsx +71 -25
- package/dist/skill/patterns/kanban-board.tsx +2 -8
- package/dist/skill/patterns/schedule.tsx +15 -3
- 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 +9 -7
- 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 +19 -4
- package/dist/skill/reference/components/list/examples/reorder.tsx +48 -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/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/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 +9 -7
- 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 +19 -4
- package/src/components/list/examples/reorder.tsx +48 -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/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/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
|
|
|
@@ -337,6 +338,7 @@ accessibility, examples and common mistakes.
|
|
|
337
338
|
| `getPasswordStrength(value)` | The kit's 0–4 password estimate behind `Input.Root strength`; replace it with `getStrength`. |
|
|
338
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. |
|
|
339
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». |
|
|
340
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. |
|
|
341
343
|
| `moveBefore(items, id, beforeId, getId)` | Applies a `Dnd` or DataTable `onReorder` to your array. |
|
|
342
344
|
| `matchesSmartFilter`, `resolveSmartFilterValues` | Apply a SmartFilter value to your rows. |
|
|
@@ -1095,6 +1095,8 @@ var iconRegistry = {
|
|
|
1095
1095
|
"format.link": Link2,
|
|
1096
1096
|
"format.list": List,
|
|
1097
1097
|
"format.quote": TextQuote,
|
|
1098
|
+
/** Hidden text (a spoiler) in text formatting; `field.password.hide` masks a password. */
|
|
1099
|
+
"format.spoiler": EyeOff,
|
|
1098
1100
|
"format.strikethrough": Strikethrough,
|
|
1099
1101
|
"format.underline": Underline,
|
|
1100
1102
|
"object.activity": Activity,
|
|
@@ -5939,6 +5941,7 @@ var Select_default = {
|
|
|
5939
5941
|
search: "Select_search",
|
|
5940
5942
|
group: "Select_group",
|
|
5941
5943
|
separator: "Select_separator",
|
|
5944
|
+
actions: "Select_actions",
|
|
5942
5945
|
item: "Select_item",
|
|
5943
5946
|
itemText: "Select_itemText",
|
|
5944
5947
|
itemTitle: "Select_itemTitle",
|
|
@@ -6174,6 +6177,59 @@ function SelectItem({
|
|
|
6174
6177
|
);
|
|
6175
6178
|
}
|
|
6176
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";
|
|
6177
6233
|
|
|
6178
6234
|
// src/components/select/Select.tsx
|
|
6179
6235
|
import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
@@ -6184,7 +6240,8 @@ var SELECT_LABELS = {
|
|
|
6184
6240
|
loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
|
|
6185
6241
|
retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
|
|
6186
6242
|
clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
|
|
6187
|
-
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"
|
|
6188
6245
|
};
|
|
6189
6246
|
function SelectRoot(props) {
|
|
6190
6247
|
const {
|
|
@@ -6227,11 +6284,30 @@ function SelectRoot(props) {
|
|
|
6227
6284
|
const disabled = useInheritedDisabled(disabledProp);
|
|
6228
6285
|
const labels = React51.useMemo(() => ({ ...SELECT_LABELS, ...labelsProp }), [labelsProp]);
|
|
6229
6286
|
const ids = useFieldFrame(id, { hint, error, invalid });
|
|
6230
|
-
const [
|
|
6287
|
+
const [stored, setStored] = useControllableState({
|
|
6231
6288
|
value: props.value,
|
|
6232
|
-
defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
|
|
6233
|
-
onChange: props.onValueChange
|
|
6289
|
+
defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
|
|
6234
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;
|
|
6235
6311
|
const selected = React51.useMemo(
|
|
6236
6312
|
() => Array.isArray(value) ? value : value ? [value] : [],
|
|
6237
6313
|
[value]
|
|
@@ -6257,18 +6333,18 @@ function SelectRoot(props) {
|
|
|
6257
6333
|
const pick = React51.useCallback(
|
|
6258
6334
|
(optionValue) => {
|
|
6259
6335
|
if (multiple) {
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6336
|
+
const list = Array.isArray(value) ? value : [];
|
|
6337
|
+
commitRef.current(
|
|
6338
|
+
list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
|
|
6339
|
+
);
|
|
6264
6340
|
return;
|
|
6265
6341
|
}
|
|
6266
|
-
|
|
6342
|
+
commitRef.current(optionValue);
|
|
6267
6343
|
setOpen(false);
|
|
6268
6344
|
},
|
|
6269
|
-
[multiple,
|
|
6345
|
+
[multiple, value, setOpen]
|
|
6270
6346
|
);
|
|
6271
|
-
const clear = React51.useCallback(() =>
|
|
6347
|
+
const clear = React51.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
|
|
6272
6348
|
const context = React51.useMemo(
|
|
6273
6349
|
() => ({
|
|
6274
6350
|
size,
|
|
@@ -6284,6 +6360,7 @@ function SelectRoot(props) {
|
|
|
6284
6360
|
clear,
|
|
6285
6361
|
clearable,
|
|
6286
6362
|
loading,
|
|
6363
|
+
saving,
|
|
6287
6364
|
loadingMore,
|
|
6288
6365
|
hasMore,
|
|
6289
6366
|
onLoadMore,
|
|
@@ -6317,6 +6394,7 @@ function SelectRoot(props) {
|
|
|
6317
6394
|
clear,
|
|
6318
6395
|
clearable,
|
|
6319
6396
|
loading,
|
|
6397
|
+
saving,
|
|
6320
6398
|
loadingMore,
|
|
6321
6399
|
hasMore,
|
|
6322
6400
|
onLoadMore,
|
|
@@ -6347,12 +6425,14 @@ function SelectRoot(props) {
|
|
|
6347
6425
|
className,
|
|
6348
6426
|
children: [
|
|
6349
6427
|
/* @__PURE__ */ jsx39(SelectProvider, { value: context, children: /* @__PURE__ */ jsx39(ControlSizeProvider, { value: size, children }) }),
|
|
6350
|
-
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 })
|
|
6351
6430
|
]
|
|
6352
6431
|
}
|
|
6353
6432
|
);
|
|
6354
6433
|
}
|
|
6355
6434
|
SelectRoot.displayName = "Select.Root";
|
|
6435
|
+
var takeNext = (_current, next) => next;
|
|
6356
6436
|
function SelectTrigger({
|
|
6357
6437
|
className,
|
|
6358
6438
|
children,
|
|
@@ -6375,13 +6455,15 @@ function SelectTrigger({
|
|
|
6375
6455
|
describedBy,
|
|
6376
6456
|
triggerRef,
|
|
6377
6457
|
loading,
|
|
6458
|
+
saving,
|
|
6378
6459
|
clearable,
|
|
6379
6460
|
selected,
|
|
6380
6461
|
clear,
|
|
6381
6462
|
labels
|
|
6382
6463
|
} = useSelectContext();
|
|
6383
6464
|
const mergedRef = useMergedRefs(triggerRef, ref);
|
|
6384
|
-
const
|
|
6465
|
+
const busy = loading || saving;
|
|
6466
|
+
const showClear = clearable && selected.length > 0 && !disabled && !busy;
|
|
6385
6467
|
return /* @__PURE__ */ jsxs26(
|
|
6386
6468
|
"button",
|
|
6387
6469
|
{
|
|
@@ -6396,7 +6478,7 @@ function SelectTrigger({
|
|
|
6396
6478
|
"aria-invalid": invalid || void 0,
|
|
6397
6479
|
"aria-required": required || void 0,
|
|
6398
6480
|
"aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
|
|
6399
|
-
"aria-busy":
|
|
6481
|
+
"aria-busy": busy || void 0,
|
|
6400
6482
|
disabled,
|
|
6401
6483
|
className: cx(fieldTriggerClass, Select_default.trigger, className),
|
|
6402
6484
|
onClick: (event) => {
|
|
@@ -6418,7 +6500,7 @@ function SelectTrigger({
|
|
|
6418
6500
|
state: isOpen ? "open" : "closed",
|
|
6419
6501
|
size,
|
|
6420
6502
|
invalid: invalid || void 0,
|
|
6421
|
-
loading:
|
|
6503
|
+
loading: busy || void 0,
|
|
6422
6504
|
disabled: disabled || void 0,
|
|
6423
6505
|
"focus-ring": focusRing ? void 0 : false
|
|
6424
6506
|
}),
|
|
@@ -6443,7 +6525,7 @@ function SelectTrigger({
|
|
|
6443
6525
|
}
|
|
6444
6526
|
)
|
|
6445
6527
|
) : null,
|
|
6446
|
-
/* @__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" }) })
|
|
6447
6529
|
]
|
|
6448
6530
|
}
|
|
6449
6531
|
);
|
|
@@ -6516,6 +6598,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6516
6598
|
query,
|
|
6517
6599
|
setQuery,
|
|
6518
6600
|
loading,
|
|
6601
|
+
saving,
|
|
6519
6602
|
loadingMore,
|
|
6520
6603
|
hasMore,
|
|
6521
6604
|
onLoadMore,
|
|
@@ -6526,6 +6609,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6526
6609
|
registry
|
|
6527
6610
|
} = useSelectContext();
|
|
6528
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`;
|
|
6529
6618
|
const floating = useFloatingLayer({
|
|
6530
6619
|
open: isOpen,
|
|
6531
6620
|
onOpenChange: setOpen,
|
|
@@ -6567,20 +6656,27 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6567
6656
|
}
|
|
6568
6657
|
const inSearch = event.target instanceof HTMLInputElement;
|
|
6569
6658
|
if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
|
|
6570
|
-
const
|
|
6659
|
+
const stops = enabledOptions(panelRef.current);
|
|
6571
6660
|
const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
6572
6661
|
if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
|
|
6573
6662
|
event.preventDefault();
|
|
6574
|
-
const match = typeahead.find(event.key,
|
|
6663
|
+
const match = typeahead.find(event.key, stops, highlight.get());
|
|
6575
6664
|
if (match) {
|
|
6576
6665
|
highlight.set(match.dataset.value);
|
|
6577
6666
|
match.scrollIntoView?.({ block: "nearest" });
|
|
6578
6667
|
}
|
|
6579
6668
|
return;
|
|
6580
6669
|
}
|
|
6581
|
-
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
|
+
});
|
|
6582
6678
|
};
|
|
6583
|
-
if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children });
|
|
6679
|
+
if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children: items });
|
|
6584
6680
|
const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
|
|
6585
6681
|
return /* @__PURE__ */ jsxs26(
|
|
6586
6682
|
FloatingPanel,
|
|
@@ -6624,13 +6720,14 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6624
6720
|
"aria-multiselectable": multiple || void 0,
|
|
6625
6721
|
"aria-labelledby": triggerId,
|
|
6626
6722
|
"aria-activedescendant": searchable ? void 0 : activeDescendant,
|
|
6627
|
-
"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,
|
|
6628
6725
|
tabIndex: -1,
|
|
6629
6726
|
hidden: region === "error" ? true : void 0,
|
|
6630
6727
|
"data-autofocus": searchable || region === "error" ? void 0 : "",
|
|
6631
6728
|
className: cx(Select_default.listbox, swapClass),
|
|
6632
6729
|
children: [
|
|
6633
|
-
|
|
6730
|
+
items,
|
|
6634
6731
|
region === "loading" ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_ROWS2 }) : null,
|
|
6635
6732
|
region === "ready" && hasMore ? /* @__PURE__ */ jsx39("div", { ref: sentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
|
|
6636
6733
|
region === "ready" && loadingMore ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
|
|
@@ -6642,6 +6739,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6642
6739
|
/* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: labels.empty }),
|
|
6643
6740
|
query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx39(EmptyPage.Description, { children: labels.emptyHint }) : null
|
|
6644
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,
|
|
6645
6748
|
region === "error" ? /* @__PURE__ */ jsxs26(EmptyPage.Root, { layout: "compact", size, role: "alert", className: swapClass, children: [
|
|
6646
6749
|
/* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: loadError }),
|
|
6647
6750
|
onRetry ? /* @__PURE__ */ jsx39(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs26(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
|
|
@@ -6650,7 +6753,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6650
6753
|
] }) }) : null
|
|
6651
6754
|
] }) : null,
|
|
6652
6755
|
/* @__PURE__ */ jsx39(VisuallyHidden, { "aria-live": "polite", children: loading || loadingMore ? labels.loading : "" }),
|
|
6653
|
-
/* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, highlight })
|
|
6756
|
+
/* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, panelRef, highlight })
|
|
6654
6757
|
]
|
|
6655
6758
|
}
|
|
6656
6759
|
);
|
|
@@ -6658,6 +6761,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
|
|
|
6658
6761
|
SelectContent.displayName = "Select.Content";
|
|
6659
6762
|
function HighlightOnOpen({
|
|
6660
6763
|
listboxRef,
|
|
6764
|
+
panelRef,
|
|
6661
6765
|
highlight
|
|
6662
6766
|
}) {
|
|
6663
6767
|
const { isOpen, query, selected, registry } = useSelectContext();
|
|
@@ -6673,15 +6777,15 @@ function HighlightOnOpen({
|
|
|
6673
6777
|
return () => highlight.set(void 0);
|
|
6674
6778
|
}, [isOpen, listboxRef, highlight]);
|
|
6675
6779
|
React51.useLayoutEffect(() => {
|
|
6676
|
-
if (query !== "") highlight.set(enabledOptions(
|
|
6677
|
-
}, [query,
|
|
6780
|
+
if (query !== "") highlight.set(enabledOptions(panelRef.current)[0]?.dataset.value);
|
|
6781
|
+
}, [query, panelRef, highlight]);
|
|
6678
6782
|
React51.useLayoutEffect(() => {
|
|
6679
6783
|
if (query === "") return;
|
|
6680
6784
|
const options = enabledOptions(listboxRef.current);
|
|
6681
6785
|
if (!options.some((item) => item.dataset.value === highlight.get())) {
|
|
6682
|
-
highlight.set(options[0]?.dataset.value);
|
|
6786
|
+
highlight.set((options[0] ?? enabledOptions(panelRef.current)[0])?.dataset.value);
|
|
6683
6787
|
}
|
|
6684
|
-
}, [version, query, listboxRef, highlight]);
|
|
6788
|
+
}, [version, query, listboxRef, panelRef, highlight]);
|
|
6685
6789
|
return null;
|
|
6686
6790
|
}
|
|
6687
6791
|
function SelectGroup({ className, ...rest }) {
|
|
@@ -6704,7 +6808,8 @@ var Select = {
|
|
|
6704
6808
|
ItemDescription: SelectItemDescription,
|
|
6705
6809
|
ItemMeta: SelectItemMeta,
|
|
6706
6810
|
Group: SelectGroup,
|
|
6707
|
-
Separator: SelectSeparator
|
|
6811
|
+
Separator: SelectSeparator,
|
|
6812
|
+
Action: SelectAction
|
|
6708
6813
|
};
|
|
6709
6814
|
|
|
6710
6815
|
export {
|