prime-ui-kit 0.12.0 → 0.13.1

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.
Files changed (138) hide show
  1. package/README.md +3 -1
  2. package/dist/chunks/{chunk-YJO3NJIJ.js → chunk-JV2KB5JZ.js} +6662 -5282
  3. package/dist/chunks/{chunk-VOZ7J72X.js → chunk-PK2GC77E.js} +169 -51
  4. package/dist/chunks/{chunk-OTOIOHVE.js → chunk-XNOJEX55.js} +14 -5
  5. package/dist/color-picker.js +2 -2
  6. package/dist/components/chat/Chat.d.ts +11 -12
  7. package/dist/components/chat/chatContext.d.ts +2 -0
  8. package/dist/components/chat-list/ChatList.d.ts +191 -0
  9. package/dist/components/chat-list/formatChatTime.d.ts +6 -0
  10. package/dist/components/command-menu/CommandMenu.d.ts +10 -5
  11. package/dist/components/composer/Composer.d.ts +3 -10
  12. package/dist/components/data-table/DataTable.d.ts +16 -2
  13. package/dist/components/data-table/Row.d.ts +23 -7
  14. package/dist/components/data-table/StateRows.d.ts +5 -1
  15. package/dist/components/data-table/reorder.d.ts +3 -1
  16. package/dist/components/data-table/rows.d.ts +20 -4
  17. package/dist/components/file-upload/FileUpload.d.ts +7 -0
  18. package/dist/components/gantt/Gantt.d.ts +19 -1
  19. package/dist/components/gantt/GanttBar.d.ts +4 -1
  20. package/dist/components/gantt/GanttRow.d.ts +8 -1
  21. package/dist/components/index.d.ts +10 -8
  22. package/dist/components/kanban/Kanban.d.ts +17 -2
  23. package/dist/components/list/List.d.ts +18 -3
  24. package/dist/components/message/Message.d.ts +13 -0
  25. package/dist/components/message/MessageParts.d.ts +2 -0
  26. package/dist/components/modal/DialogParts.d.ts +5 -1
  27. package/dist/components/select/Select.d.ts +11 -5
  28. package/dist/components/select/SelectItem.d.ts +19 -0
  29. package/dist/components/select/selectContext.d.ts +4 -0
  30. package/dist/components/sparkline/Sparkline.d.ts +14 -3
  31. package/dist/components/textarea/Textarea.d.ts +11 -3
  32. package/dist/hooks/useUploadQueue.d.ts +5 -1
  33. package/dist/icons/registry.d.ts +2 -0
  34. package/dist/index.css +1 -1
  35. package/dist/index.js +6 -2
  36. package/dist/internal/attachmentTile.d.ts +5 -1
  37. package/dist/internal/richText.d.ts +7 -2
  38. package/dist/internal/textFormatting.d.ts +52 -0
  39. package/dist/internal/textFormattingToolbar.d.ts +26 -0
  40. package/dist/skill/cheatsheet.md +12 -0
  41. package/dist/skill/choosing.md +5 -2
  42. package/dist/skill/components.md +5 -4
  43. package/dist/skill/composition.md +1 -1
  44. package/dist/skill/layouts.md +2 -0
  45. package/dist/skill/patterns/chat.module.css +0 -9
  46. package/dist/skill/patterns/chat.tsx +71 -25
  47. package/dist/skill/patterns/kanban-board.tsx +2 -8
  48. package/dist/skill/patterns/schedule.tsx +15 -3
  49. package/dist/skill/reference/components/chat/COMPONENT.md +13 -4
  50. package/dist/skill/reference/components/chat/examples/states.tsx +100 -0
  51. package/dist/skill/reference/components/chat-list/COMPONENT.md +256 -0
  52. package/dist/skill/reference/components/chat-list/examples/controlled.tsx +103 -0
  53. package/dist/skill/reference/components/chat-list/examples/examples.module.css +66 -0
  54. package/dist/skill/reference/components/chat-list/examples/live.tsx +133 -0
  55. package/dist/skill/reference/components/chat-list/examples/long-list.tsx +87 -0
  56. package/dist/skill/reference/components/chat-list/examples/narrow.tsx +88 -0
  57. package/dist/skill/reference/components/chat-list/examples/overview.tsx +194 -0
  58. package/dist/skill/reference/components/chat-list/examples/search.tsx +71 -0
  59. package/dist/skill/reference/components/chat-list/examples/sizes.tsx +61 -0
  60. package/dist/skill/reference/components/chat-list/examples/states.tsx +107 -0
  61. package/dist/skill/reference/components/chat-list/examples/structure.tsx +135 -0
  62. package/dist/skill/reference/components/command-menu/COMPONENT.md +15 -11
  63. package/dist/skill/reference/components/command-menu/examples/server-search.tsx +11 -9
  64. package/dist/skill/reference/components/composer/COMPONENT.md +8 -7
  65. package/dist/skill/reference/components/composer/examples/formatting.tsx +1 -1
  66. package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -0
  67. package/dist/skill/reference/components/data-table/COMPONENT.md +21 -6
  68. package/dist/skill/reference/components/data-table/examples/groups.tsx +2 -1
  69. package/dist/skill/reference/components/data-table/examples/trend.tsx +85 -0
  70. package/dist/skill/reference/components/drawer/COMPONENT.md +7 -6
  71. package/dist/skill/reference/components/drawer/examples/client-card.tsx +50 -0
  72. package/dist/skill/reference/components/fieldset/COMPONENT.md +1 -0
  73. package/dist/skill/reference/components/file-upload/COMPONENT.md +9 -7
  74. package/dist/skill/reference/components/file-upload/examples/overview.tsx +14 -3
  75. package/dist/skill/reference/components/gantt/COMPONENT.md +15 -5
  76. package/dist/skill/reference/components/gantt/examples/row-link.tsx +96 -0
  77. package/dist/skill/reference/components/kanban/COMPONENT.md +12 -4
  78. package/dist/skill/reference/components/kanban/examples/item-link.tsx +92 -0
  79. package/dist/skill/reference/components/list/COMPONENT.md +19 -4
  80. package/dist/skill/reference/components/list/examples/reorder.tsx +48 -0
  81. package/dist/skill/reference/components/message/COMPONENT.md +18 -2
  82. package/dist/skill/reference/components/message/examples/bot-actions.tsx +51 -0
  83. package/dist/skill/reference/components/modal/COMPONENT.md +6 -4
  84. package/dist/skill/reference/components/select/COMPONENT.md +38 -7
  85. package/dist/skill/reference/components/select/examples/create-action.tsx +107 -0
  86. package/dist/skill/reference/components/select/examples/saving.tsx +47 -0
  87. package/dist/skill/reference/components/sheet/COMPONENT.md +4 -4
  88. package/dist/skill/reference/components/sparkline/COMPONENT.md +16 -2
  89. package/dist/skill/reference/components/sparkline/examples/compact.tsx +41 -0
  90. package/dist/skill/reference/components/sparkline/examples/examples.module.css +12 -0
  91. package/dist/skill/reference/components/textarea/COMPONENT.md +22 -2
  92. package/dist/skill/reference/components/textarea/examples/formatting.tsx +20 -0
  93. package/package.json +2 -2
  94. package/src/components/chat/COMPONENT.md +13 -4
  95. package/src/components/chat/examples/states.tsx +100 -0
  96. package/src/components/chat-list/COMPONENT.md +256 -0
  97. package/src/components/chat-list/examples/controlled.tsx +103 -0
  98. package/src/components/chat-list/examples/examples.module.css +66 -0
  99. package/src/components/chat-list/examples/live.tsx +133 -0
  100. package/src/components/chat-list/examples/long-list.tsx +87 -0
  101. package/src/components/chat-list/examples/narrow.tsx +88 -0
  102. package/src/components/chat-list/examples/overview.tsx +194 -0
  103. package/src/components/chat-list/examples/search.tsx +71 -0
  104. package/src/components/chat-list/examples/sizes.tsx +61 -0
  105. package/src/components/chat-list/examples/states.tsx +107 -0
  106. package/src/components/chat-list/examples/structure.tsx +135 -0
  107. package/src/components/command-menu/COMPONENT.md +15 -11
  108. package/src/components/command-menu/examples/server-search.tsx +11 -9
  109. package/src/components/composer/COMPONENT.md +8 -7
  110. package/src/components/composer/examples/formatting.tsx +1 -1
  111. package/src/components/confirm-dialog/COMPONENT.md +1 -0
  112. package/src/components/data-table/COMPONENT.md +21 -6
  113. package/src/components/data-table/examples/groups.tsx +2 -1
  114. package/src/components/data-table/examples/trend.tsx +85 -0
  115. package/src/components/drawer/COMPONENT.md +7 -6
  116. package/src/components/drawer/examples/client-card.tsx +50 -0
  117. package/src/components/fieldset/COMPONENT.md +1 -0
  118. package/src/components/file-upload/COMPONENT.md +9 -7
  119. package/src/components/file-upload/examples/overview.tsx +14 -3
  120. package/src/components/gantt/COMPONENT.md +15 -5
  121. package/src/components/gantt/examples/row-link.tsx +96 -0
  122. package/src/components/kanban/COMPONENT.md +12 -4
  123. package/src/components/kanban/examples/item-link.tsx +92 -0
  124. package/src/components/list/COMPONENT.md +19 -4
  125. package/src/components/list/examples/reorder.tsx +48 -0
  126. package/src/components/message/COMPONENT.md +18 -2
  127. package/src/components/message/examples/bot-actions.tsx +51 -0
  128. package/src/components/modal/COMPONENT.md +6 -4
  129. package/src/components/select/COMPONENT.md +38 -7
  130. package/src/components/select/examples/create-action.tsx +107 -0
  131. package/src/components/select/examples/saving.tsx +47 -0
  132. package/src/components/sheet/COMPONENT.md +4 -4
  133. package/src/components/sparkline/COMPONENT.md +16 -2
  134. package/src/components/sparkline/examples/compact.tsx +41 -0
  135. package/src/components/sparkline/examples/examples.module.css +12 -0
  136. package/src/components/textarea/COMPONENT.md +22 -2
  137. package/src/components/textarea/examples/formatting.tsx +20 -0
  138. package/dist/components/composer/format.d.ts +0 -39
@@ -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,
@@ -1364,36 +1366,43 @@ function usePosition(enabled, anchorRef, layerRef, {
1364
1366
  };
1365
1367
  }
1366
1368
  const { offset, pad, arrow } = metricsRef.current;
1367
- const rect = anchor.getBoundingClientRect();
1368
- const pos = computeFloatingPosition(
1369
- resolveAnchorRect ? resolveAnchorRect(anchor, rect) : rect,
1370
- layer.offsetWidth,
1371
- layer.offsetHeight,
1372
- window.innerWidth,
1373
- window.innerHeight,
1374
- {
1375
- side: preferredSide,
1376
- align,
1377
- offset,
1378
- viewportPad: pad,
1379
- flip: true,
1380
- matchAnchorWidth,
1381
- arrowInset: arrow,
1382
- boundary: resolveBoundary?.(anchor) ?? void 0
1383
- }
1384
- );
1385
- setResolvedSide(pos.side);
1369
+ const rawRect = anchor.getBoundingClientRect();
1370
+ const rect = resolveAnchorRect ? resolveAnchorRect(anchor, rawRect) : rawRect;
1371
+ const boundary = resolveBoundary?.(anchor) ?? void 0;
1372
+ const compute = (width2, height2) => computeFloatingPosition(rect, width2, height2, window.innerWidth, window.innerHeight, {
1373
+ side: preferredSide,
1374
+ align,
1375
+ offset,
1376
+ viewportPad: pad,
1377
+ flip: true,
1378
+ matchAnchorWidth,
1379
+ arrowInset: arrow,
1380
+ boundary
1381
+ });
1386
1382
  const set = (name, value) => {
1387
1383
  if (layer.style.getPropertyValue(name) !== value) layer.style.setProperty(name, value);
1388
1384
  };
1389
1385
  const px = (n) => n === void 0 ? "" : `${n}px`;
1390
1386
  set("position", "fixed");
1387
+ let width = layer.offsetWidth;
1388
+ let height = layer.offsetHeight;
1389
+ let pos = compute(width, height);
1390
+ for (let pass = 0; pass < 3; pass++) {
1391
+ set(FLOAT_MIN_WIDTH_VAR, px(pos.minWidth));
1392
+ set(FLOAT_MAX_WIDTH_VAR, px(pos.maxWidth));
1393
+ set(FLOAT_MAX_HEIGHT_VAR, px(pos.maxHeight));
1394
+ const nextWidth = layer.offsetWidth;
1395
+ const nextHeight = layer.offsetHeight;
1396
+ if (nextWidth === width && nextHeight === height) break;
1397
+ width = nextWidth;
1398
+ height = nextHeight;
1399
+ pos = compute(width, height);
1400
+ }
1401
+ setResolvedSide(pos.side);
1391
1402
  set("top", px(pos.top));
1392
1403
  set("left", px(pos.left));
1393
- set(FLOAT_MIN_WIDTH_VAR, px(pos.minWidth));
1394
- set(FLOAT_MAX_WIDTH_VAR, px(pos.maxWidth));
1395
- set(FLOAT_MAX_HEIGHT_VAR, px(pos.maxHeight));
1396
1404
  set(FLOAT_ARROW_VAR, px(pos.arrow));
1405
+ delete layer.dataset.floatPending;
1397
1406
  },
1398
1407
  [
1399
1408
  anchorRef,
@@ -1409,9 +1418,12 @@ function usePosition(enabled, anchorRef, layerRef, {
1409
1418
  );
1410
1419
  const updateRef = React12.useRef(update);
1411
1420
  updateRef.current = update;
1421
+ const enabledRef = React12.useRef(enabled);
1422
+ enabledRef.current = enabled;
1412
1423
  const attachLayer = React12.useCallback(
1413
1424
  (node) => {
1414
1425
  layerRef.current = node;
1426
+ if (node && enabledRef.current) node.dataset.floatPending = "";
1415
1427
  setAttached(node !== null);
1416
1428
  },
1417
1429
  [layerRef]
@@ -1440,7 +1452,10 @@ function usePosition(enabled, anchorRef, layerRef, {
1440
1452
  target.addEventListener("scroll", follow, { passive: true });
1441
1453
  }
1442
1454
  window.visualViewport?.addEventListener("resize", resize);
1443
- const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(follow);
1455
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => {
1456
+ cancelAnimationFrame(frame2);
1457
+ updateRef.current(false);
1458
+ });
1444
1459
  if (layerRef.current) observer?.observe(layerRef.current);
1445
1460
  if (anchorRef.current) observer?.observe(anchorRef.current);
1446
1461
  return () => {
@@ -5939,6 +5954,7 @@ var Select_default = {
5939
5954
  search: "Select_search",
5940
5955
  group: "Select_group",
5941
5956
  separator: "Select_separator",
5957
+ actions: "Select_actions",
5942
5958
  item: "Select_item",
5943
5959
  itemText: "Select_itemText",
5944
5960
  itemTitle: "Select_itemTitle",
@@ -6174,6 +6190,59 @@ function SelectItem({
6174
6190
  );
6175
6191
  }
6176
6192
  SelectItem.displayName = "Select.Item";
6193
+ var ACTION_PREFIX = "__prime_select_action";
6194
+ var isActionValue = (value) => value.startsWith(ACTION_PREFIX);
6195
+ function SelectAction({
6196
+ onSelect,
6197
+ disabled = false,
6198
+ className,
6199
+ children,
6200
+ onClick: onClick2,
6201
+ onMouseMove,
6202
+ ref,
6203
+ ...rest
6204
+ }) {
6205
+ const { highlight, listboxId, setOpen, size } = useSelectContext();
6206
+ const value = `${ACTION_PREFIX}${React50.useId()}`;
6207
+ const isHighlighted = useStoreSlice(highlight, (current) => current === value);
6208
+ const parts = splitItemChildren(children);
6209
+ return (
6210
+ // biome-ignore lint/a11y/useFocusableInteractive: focus stays on the listbox / search (aria-activedescendant)
6211
+ // biome-ignore lint/a11y/useKeyWithClickEvents: the keyboard is handled on the listbox
6212
+ /* @__PURE__ */ jsxs25(
6213
+ "div",
6214
+ {
6215
+ ...rest,
6216
+ ref,
6217
+ id: optionDomId(listboxId, value),
6218
+ role: "option",
6219
+ "aria-disabled": disabled || void 0,
6220
+ className: cx(menu_default.item, className),
6221
+ onClick: (event) => {
6222
+ onClick2?.(event);
6223
+ if (event.defaultPrevented || disabled) return;
6224
+ onSelect();
6225
+ setOpen(false);
6226
+ },
6227
+ onMouseMove: (event) => {
6228
+ onMouseMove?.(event);
6229
+ if (!disabled && !isHighlighted) highlight.set(value);
6230
+ },
6231
+ ...toDataAttributes({
6232
+ value,
6233
+ action: true,
6234
+ highlighted: isHighlighted,
6235
+ disabled
6236
+ }),
6237
+ children: [
6238
+ sizeMedia(parts.leading, size),
6239
+ /* @__PURE__ */ jsx38("span", { className: Select_default.itemText, children: parts.body })
6240
+ ]
6241
+ }
6242
+ )
6243
+ );
6244
+ }
6245
+ SelectAction.displayName = "Select.Action";
6177
6246
 
6178
6247
  // src/components/select/Select.tsx
6179
6248
  import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
@@ -6184,7 +6253,8 @@ var SELECT_LABELS = {
6184
6253
  loading: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
6185
6254
  retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
6186
6255
  clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
6187
- optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E"
6256
+ optional: "\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
6257
+ 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
6258
  };
6189
6259
  function SelectRoot(props) {
6190
6260
  const {
@@ -6227,11 +6297,30 @@ function SelectRoot(props) {
6227
6297
  const disabled = useInheritedDisabled(disabledProp);
6228
6298
  const labels = React51.useMemo(() => ({ ...SELECT_LABELS, ...labelsProp }), [labelsProp]);
6229
6299
  const ids = useFieldFrame(id, { hint, error, invalid });
6230
- const [value, setValue] = useControllableState({
6300
+ const [stored, setStored] = useControllableState({
6231
6301
  value: props.value,
6232
- defaultValue: props.defaultValue ?? (multiple ? [] : void 0),
6233
- onChange: props.onValueChange
6302
+ defaultValue: props.defaultValue ?? (multiple ? [] : void 0)
6234
6303
  });
6304
+ const changes = usePendingChanges(stored, takeNext);
6305
+ const value = changes.shown;
6306
+ const saving = changes.pending.length > 0;
6307
+ const [announcement, setAnnouncement] = React51.useState("");
6308
+ const onValueChange = props.onValueChange;
6309
+ const commit = (next) => {
6310
+ if (saving || Object.is(next, value)) return;
6311
+ const outcome = onValueChange?.(next);
6312
+ if (!isPromiseLike(outcome)) {
6313
+ setStored(next);
6314
+ return;
6315
+ }
6316
+ setAnnouncement("");
6317
+ changes.track(next, outcome, {
6318
+ onResolve: () => setStored(next),
6319
+ onReject: () => setAnnouncement(labels.changeFailed)
6320
+ });
6321
+ };
6322
+ const commitRef = React51.useRef(commit);
6323
+ commitRef.current = commit;
6235
6324
  const selected = React51.useMemo(
6236
6325
  () => Array.isArray(value) ? value : value ? [value] : [],
6237
6326
  [value]
@@ -6257,18 +6346,18 @@ function SelectRoot(props) {
6257
6346
  const pick = React51.useCallback(
6258
6347
  (optionValue) => {
6259
6348
  if (multiple) {
6260
- setValue((prev) => {
6261
- const list = Array.isArray(prev) ? prev : [];
6262
- return list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue];
6263
- });
6349
+ const list = Array.isArray(value) ? value : [];
6350
+ commitRef.current(
6351
+ list.includes(optionValue) ? list.filter((item) => item !== optionValue) : [...list, optionValue]
6352
+ );
6264
6353
  return;
6265
6354
  }
6266
- setValue(optionValue);
6355
+ commitRef.current(optionValue);
6267
6356
  setOpen(false);
6268
6357
  },
6269
- [multiple, setValue, setOpen]
6358
+ [multiple, value, setOpen]
6270
6359
  );
6271
- const clear = React51.useCallback(() => setValue(multiple ? [] : ""), [multiple, setValue]);
6360
+ const clear = React51.useCallback(() => commitRef.current(multiple ? [] : ""), [multiple]);
6272
6361
  const context = React51.useMemo(
6273
6362
  () => ({
6274
6363
  size,
@@ -6284,6 +6373,7 @@ function SelectRoot(props) {
6284
6373
  clear,
6285
6374
  clearable,
6286
6375
  loading,
6376
+ saving,
6287
6377
  loadingMore,
6288
6378
  hasMore,
6289
6379
  onLoadMore,
@@ -6317,6 +6407,7 @@ function SelectRoot(props) {
6317
6407
  clear,
6318
6408
  clearable,
6319
6409
  loading,
6410
+ saving,
6320
6411
  loadingMore,
6321
6412
  hasMore,
6322
6413
  onLoadMore,
@@ -6347,12 +6438,14 @@ function SelectRoot(props) {
6347
6438
  className,
6348
6439
  children: [
6349
6440
  /* @__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
6441
+ name ? (selected.length > 0 || multiple ? selected : [""]).map((item) => /* @__PURE__ */ jsx39("input", { type: "hidden", name, value: item, disabled }, item)) : null,
6442
+ /* @__PURE__ */ jsx39(VisuallyHidden, { role: "status", "aria-live": "polite", children: announcement })
6351
6443
  ]
6352
6444
  }
6353
6445
  );
6354
6446
  }
6355
6447
  SelectRoot.displayName = "Select.Root";
6448
+ var takeNext = (_current, next) => next;
6356
6449
  function SelectTrigger({
6357
6450
  className,
6358
6451
  children,
@@ -6375,13 +6468,15 @@ function SelectTrigger({
6375
6468
  describedBy,
6376
6469
  triggerRef,
6377
6470
  loading,
6471
+ saving,
6378
6472
  clearable,
6379
6473
  selected,
6380
6474
  clear,
6381
6475
  labels
6382
6476
  } = useSelectContext();
6383
6477
  const mergedRef = useMergedRefs(triggerRef, ref);
6384
- const showClear = clearable && selected.length > 0 && !disabled && !loading;
6478
+ const busy = loading || saving;
6479
+ const showClear = clearable && selected.length > 0 && !disabled && !busy;
6385
6480
  return /* @__PURE__ */ jsxs26(
6386
6481
  "button",
6387
6482
  {
@@ -6396,7 +6491,7 @@ function SelectTrigger({
6396
6491
  "aria-invalid": invalid || void 0,
6397
6492
  "aria-required": required || void 0,
6398
6493
  "aria-describedby": [ariaDescribedBy, describedBy].filter(Boolean).join(" ") || void 0,
6399
- "aria-busy": loading || void 0,
6494
+ "aria-busy": busy || void 0,
6400
6495
  disabled,
6401
6496
  className: cx(fieldTriggerClass, Select_default.trigger, className),
6402
6497
  onClick: (event) => {
@@ -6418,7 +6513,7 @@ function SelectTrigger({
6418
6513
  state: isOpen ? "open" : "closed",
6419
6514
  size,
6420
6515
  invalid: invalid || void 0,
6421
- loading: loading || void 0,
6516
+ loading: busy || void 0,
6422
6517
  disabled: disabled || void 0,
6423
6518
  "focus-ring": focusRing ? void 0 : false
6424
6519
  }),
@@ -6443,7 +6538,7 @@ function SelectTrigger({
6443
6538
  }
6444
6539
  )
6445
6540
  ) : null,
6446
- /* @__PURE__ */ jsx39("span", { className: Select_default.chevron, "aria-hidden": "true", children: loading ? /* @__PURE__ */ jsx39(Spinner, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx39(Icon, { name: "nav.chevronDown" }) })
6541
+ /* @__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
6542
  ]
6448
6543
  }
6449
6544
  );
@@ -6516,6 +6611,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6516
6611
  query,
6517
6612
  setQuery,
6518
6613
  loading,
6614
+ saving,
6519
6615
  loadingMore,
6520
6616
  hasMore,
6521
6617
  onLoadMore,
@@ -6526,6 +6622,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6526
6622
  registry
6527
6623
  } = useSelectContext();
6528
6624
  const listboxRef = React51.useRef(null);
6625
+ const items = [];
6626
+ const actions = [];
6627
+ for (const child of React51.Children.toArray(children)) {
6628
+ (React51.isValidElement(child) && child.type === SelectAction ? actions : items).push(child);
6629
+ }
6630
+ const actionsId = `${listboxId}-actions`;
6529
6631
  const floating = useFloatingLayer({
6530
6632
  open: isOpen,
6531
6633
  onOpenChange: setOpen,
@@ -6567,20 +6669,27 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6567
6669
  }
6568
6670
  const inSearch = event.target instanceof HTMLInputElement;
6569
6671
  if (inSearch && [" ", "Home", "End"].includes(event.key)) return;
6570
- const items = enabledOptions(listboxRef.current);
6672
+ const stops = enabledOptions(panelRef.current);
6571
6673
  const printable = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
6572
6674
  if (printable && !inSearch && (event.key !== " " || typeahead.isTyping())) {
6573
6675
  event.preventDefault();
6574
- const match = typeahead.find(event.key, items, highlight.get());
6676
+ const match = typeahead.find(event.key, stops, highlight.get());
6575
6677
  if (match) {
6576
6678
  highlight.set(match.dataset.value);
6577
6679
  match.scrollIntoView?.({ block: "nearest" });
6578
6680
  }
6579
6681
  return;
6580
6682
  }
6581
- handleListboxKeyDown(event, { items, highlight, onSelect: pick });
6683
+ handleListboxKeyDown(event, {
6684
+ items: stops,
6685
+ highlight,
6686
+ onSelect: (value) => {
6687
+ if (isActionValue(value)) document.getElementById(optionDomId(listboxId, value))?.click();
6688
+ else pick(value);
6689
+ }
6690
+ });
6582
6691
  };
6583
- if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children });
6692
+ if (!floating.mounted) return /* @__PURE__ */ jsx39("div", { hidden: true, children: items });
6584
6693
  const activeDescendant = isOpen && highlighted !== void 0 ? optionDomId(listboxId, highlighted) : void 0;
6585
6694
  return /* @__PURE__ */ jsxs26(
6586
6695
  FloatingPanel,
@@ -6624,13 +6733,14 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6624
6733
  "aria-multiselectable": multiple || void 0,
6625
6734
  "aria-labelledby": triggerId,
6626
6735
  "aria-activedescendant": searchable ? void 0 : activeDescendant,
6627
- "aria-busy": loading || loadingMore || void 0,
6736
+ "aria-busy": loading || loadingMore || saving || void 0,
6737
+ "aria-owns": actions.length > 0 && region !== "error" ? actionsId : void 0,
6628
6738
  tabIndex: -1,
6629
6739
  hidden: region === "error" ? true : void 0,
6630
6740
  "data-autofocus": searchable || region === "error" ? void 0 : "",
6631
6741
  className: cx(Select_default.listbox, swapClass),
6632
6742
  children: [
6633
- children,
6743
+ items,
6634
6744
  region === "loading" ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_ROWS2 }) : null,
6635
6745
  region === "ready" && hasMore ? /* @__PURE__ */ jsx39("div", { ref: sentinelRef, "aria-hidden": "true", className: menu_default.loadSentinel }) : null,
6636
6746
  region === "ready" && loadingMore ? /* @__PURE__ */ jsx39(SkeletonRows, { count: LOADING_MORE_ROWS }) : null
@@ -6642,6 +6752,12 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6642
6752
  /* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: labels.empty }),
6643
6753
  query !== "" && labels.emptyHint ? /* @__PURE__ */ jsx39(EmptyPage.Description, { children: labels.emptyHint }) : null
6644
6754
  ] }) : null,
6755
+ actions.length > 0 && region !== "error" ? (
6756
+ // Owned by the listbox (`aria-owns`): its options for assistive tech, pinned under the
6757
+ // scroller and the empty state for the eye.
6758
+ // biome-ignore lint/a11y/useSemanticElements: a group of options inside a listbox, not a form fieldset
6759
+ /* @__PURE__ */ jsx39("div", { id: actionsId, role: "group", className: Select_default.actions, children: actions })
6760
+ ) : null,
6645
6761
  region === "error" ? /* @__PURE__ */ jsxs26(EmptyPage.Root, { layout: "compact", size, role: "alert", className: swapClass, children: [
6646
6762
  /* @__PURE__ */ jsx39(EmptyPage.Title, { as: "p", children: loadError }),
6647
6763
  onRetry ? /* @__PURE__ */ jsx39(EmptyPage.Actions, { children: /* @__PURE__ */ jsxs26(Button.Root, { variant: "soft", tone: "neutral", onClick: onRetry, children: [
@@ -6650,7 +6766,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6650
6766
  ] }) }) : null
6651
6767
  ] }) : null,
6652
6768
  /* @__PURE__ */ jsx39(VisuallyHidden, { "aria-live": "polite", children: loading || loadingMore ? labels.loading : "" }),
6653
- /* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, highlight })
6769
+ /* @__PURE__ */ jsx39(HighlightOnOpen, { listboxRef, panelRef, highlight })
6654
6770
  ]
6655
6771
  }
6656
6772
  );
@@ -6658,6 +6774,7 @@ function SelectContent({ searchable = false, className, children, ...rest }) {
6658
6774
  SelectContent.displayName = "Select.Content";
6659
6775
  function HighlightOnOpen({
6660
6776
  listboxRef,
6777
+ panelRef,
6661
6778
  highlight
6662
6779
  }) {
6663
6780
  const { isOpen, query, selected, registry } = useSelectContext();
@@ -6673,15 +6790,15 @@ function HighlightOnOpen({
6673
6790
  return () => highlight.set(void 0);
6674
6791
  }, [isOpen, listboxRef, highlight]);
6675
6792
  React51.useLayoutEffect(() => {
6676
- if (query !== "") highlight.set(enabledOptions(listboxRef.current)[0]?.dataset.value);
6677
- }, [query, listboxRef, highlight]);
6793
+ if (query !== "") highlight.set(enabledOptions(panelRef.current)[0]?.dataset.value);
6794
+ }, [query, panelRef, highlight]);
6678
6795
  React51.useLayoutEffect(() => {
6679
6796
  if (query === "") return;
6680
6797
  const options = enabledOptions(listboxRef.current);
6681
6798
  if (!options.some((item) => item.dataset.value === highlight.get())) {
6682
- highlight.set(options[0]?.dataset.value);
6799
+ highlight.set((options[0] ?? enabledOptions(panelRef.current)[0])?.dataset.value);
6683
6800
  }
6684
- }, [version, query, listboxRef, highlight]);
6801
+ }, [version, query, listboxRef, panelRef, highlight]);
6685
6802
  return null;
6686
6803
  }
6687
6804
  function SelectGroup({ className, ...rest }) {
@@ -6704,7 +6821,8 @@ var Select = {
6704
6821
  ItemDescription: SelectItemDescription,
6705
6822
  ItemMeta: SelectItemMeta,
6706
6823
  Group: SelectGroup,
6707
- Separator: SelectSeparator
6824
+ Separator: SelectSeparator,
6825
+ Action: SelectAction
6708
6826
  };
6709
6827
 
6710
6828
  export {
@@ -17,7 +17,7 @@ import {
17
17
  useControllableState,
18
18
  useFieldFrame,
19
19
  useInheritedDisabled
20
- } from "./chunk-VOZ7J72X.js";
20
+ } from "./chunk-PK2GC77E.js";
21
21
  import {
22
22
  cx
23
23
  } from "./chunk-Q3BFRQHZ.js";
@@ -121,10 +121,19 @@ var FORMAT_LABELS = { hsl: "HSL", rgb: "RGB", hex: "Hex" };
121
121
  var isFormat = (value) => value in FORMAT_LABELS;
122
122
  function FormatSelect({ className, ...rest }) {
123
123
  const { format, setFormat, labels } = useColorPickerContext();
124
- return /* @__PURE__ */ jsx("div", { ...rest, className: cx(ColorPicker_default.formatSelectWrap, className), children: /* @__PURE__ */ jsxs(Select.Root, { value: format, onValueChange: (value) => isFormat(value) && setFormat(value), children: [
125
- /* @__PURE__ */ jsx(Select.Trigger, { "aria-label": labels.format, children: /* @__PURE__ */ jsx(Select.Value, {}) }),
126
- /* @__PURE__ */ jsx(Select.Content, { children: Object.entries(FORMAT_LABELS).map(([value, label]) => /* @__PURE__ */ jsx(Select.Item, { label, value, children: label }, value)) })
127
- ] }) });
124
+ return /* @__PURE__ */ jsx("div", { ...rest, className: cx(ColorPicker_default.formatSelectWrap, className), children: /* @__PURE__ */ jsxs(
125
+ Select.Root,
126
+ {
127
+ value: format,
128
+ onValueChange: (value) => {
129
+ if (isFormat(value)) setFormat(value);
130
+ },
131
+ children: [
132
+ /* @__PURE__ */ jsx(Select.Trigger, { "aria-label": labels.format, children: /* @__PURE__ */ jsx(Select.Value, {}) }),
133
+ /* @__PURE__ */ jsx(Select.Content, { children: Object.entries(FORMAT_LABELS).map(([value, label]) => /* @__PURE__ */ jsx(Select.Item, { label, value, children: label }, value)) })
134
+ ]
135
+ }
136
+ ) });
128
137
  }
129
138
  function displayChannelValue(color, channel, space) {
130
139
  const raw = color.toFormat(space).getChannelValue(channel);
@@ -4,8 +4,8 @@ import {
4
4
  ColorField,
5
5
  ColorPicker,
6
6
  parseColor
7
- } from "./chunks/chunk-OTOIOHVE.js";
8
- import "./chunks/chunk-VOZ7J72X.js";
7
+ } from "./chunks/chunk-XNOJEX55.js";
8
+ import "./chunks/chunk-PK2GC77E.js";
9
9
  import "./chunks/chunk-Q3BFRQHZ.js";
10
10
  export {
11
11
  ColorField,
@@ -50,10 +50,12 @@ export type ChatHeaderProps = React.HTMLAttributes<HTMLDivElement> & {
50
50
  ref?: React.Ref<HTMLDivElement>;
51
51
  };
52
52
  /**
53
- * The top of the chat: who it is with. A row of the leading element (an `Avatar`), the title over
54
- * the description, and the actions at the end.
53
+ * The top of the chat: who it is with. A row of the leading elements (a back button, an `Avatar`),
54
+ * the title over the description, and the actions at the end. Children are sorted by type:
55
+ * `Chat.Title`, `Chat.Description` and `Chat.Actions` take their places, everything else leads
56
+ * the row side by side, in the order written.
55
57
  */
56
- declare function ChatHeader({ className, ...rest }: ChatHeaderProps): import("react/jsx-runtime").JSX.Element;
58
+ declare function ChatHeader({ className, children, ...rest }: ChatHeaderProps): import("react/jsx-runtime").JSX.Element;
57
59
  declare namespace ChatHeader {
58
60
  var displayName: string;
59
61
  }
@@ -123,6 +125,11 @@ export type ChatMessagesProps<T = unknown> = Omit<MessageListProps, "group" | "s
123
125
  * incoming messages keep the avatar's gutter. Default `direct`.
124
126
  */
125
127
  type?: "direct" | "group";
128
+ /**
129
+ * The first load of the conversation: bubble-shaped placeholders stand in the list's place
130
+ * (`aria-busy`, `labels.loading` announced), then cross-fade into the messages.
131
+ */
132
+ loading?: boolean;
126
133
  /** Older history exists: a placeholder stands above the first message and `onLoadOlder` runs at the top. */
127
134
  hasOlder?: boolean;
128
135
  /** The reader reached the top while `hasOlder`: load older messages and prepend them. */
@@ -152,15 +159,7 @@ export type ChatMessagesProps<T = unknown> = Omit<MessageListProps, "group" | "s
152
159
  /** The label of a date. Default «Сегодня», «Вчера», «12 марта». */
153
160
  formatDate?: (date: Date, now: Date) => string;
154
161
  };
155
- /**
156
- * The conversation: the one message list of the kit, in its own scroller. A `role="log"` of rows
157
- * (new messages are announced politely) with one tab stop — arrows, Home and End move between
158
- * messages. Rows come from `items` (dates, runs and the unread band added for you) or from
159
- * children (`Message.Root`, `Chat.Separator`, `Chat.Service`, `Chat.Unread`; `Chat.SelectionBar`
160
- * and `Message.Typing` close the list). Only the rows around the view render; the list opens at
161
- * the end and keeps the reader's place.
162
- */
163
- declare function ChatMessages<T>({ type, hasOlder, onLoadOlder, items, getKey, getAuthor, getDate, isService, renderMessage, unread, groupWindow, now, formatDate, children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }: ChatMessagesProps<T>): import("react/jsx-runtime").JSX.Element;
162
+ declare function ChatMessages<T>({ type, loading, hasOlder, onLoadOlder, items, getKey, getAuthor, getDate, isService, renderMessage, unread, groupWindow, now, formatDate, children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }: ChatMessagesProps<T>): import("react/jsx-runtime").JSX.Element;
164
163
  declare namespace ChatMessages {
165
164
  var displayName: string;
166
165
  }
@@ -20,6 +20,8 @@ export type ChatLabels = MessageListLabels & {
20
20
  messages: string;
21
21
  /** The band above the first unread message of `items` (`Chat.Messages unread`). */
22
22
  unread: string;
23
+ /** Announced while the conversation loads for the first time (`Chat.Messages loading`). */
24
+ loading: string;
23
25
  };
24
26
  /** What the parts of a chat share; `Chat.Root` owns it. */
25
27
  export type ChatContextValue = {