@crewlethq/ui 0.69.0 → 0.71.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.
Files changed (156) hide show
  1. package/README.md +25 -1
  2. package/dist/AgentHandoffPanel/index.js +4 -4
  3. package/dist/AppShell/index.js +3 -3
  4. package/dist/ArtifactBar/index.js +5 -5
  5. package/dist/AvatarPicker/index.js +8 -8
  6. package/dist/BriefCard/index.js +3 -3
  7. package/dist/Button/Button.d.ts +10 -0
  8. package/dist/Button/index.js +1 -1
  9. package/dist/{Button-VRRYSXFN.css → Button-GDEBGBX6.css} +30 -3
  10. package/dist/Canvas/index.js +2 -2
  11. package/dist/CanvasBoard/index.js +4 -4
  12. package/dist/CanvasToolbar/index.js +3 -3
  13. package/dist/CharacterPicker/index.js +2 -2
  14. package/dist/ChatThread/index.js +2 -2
  15. package/dist/CodeBlock/index.js +3 -3
  16. package/dist/ColorSwatch/index.js +3 -3
  17. package/dist/CommandPalette/index.js +4 -4
  18. package/dist/CommentThread/index.js +4 -4
  19. package/dist/Composer/index.js +2 -2
  20. package/dist/ConflictNote/index.js +2 -2
  21. package/dist/Copyable/index.js +2 -2
  22. package/dist/DataGrid/DataGrid.d.ts +50 -4
  23. package/dist/DataGrid/index.d.ts +2 -2
  24. package/dist/DataGrid/index.js +2 -2
  25. package/dist/{DataGrid-NHIN2I42.css → DataGrid-Q26F2V5Q.css} +145 -24
  26. package/dist/DataTable/index.js +4 -4
  27. package/dist/DataView/index.js +8 -7
  28. package/dist/{DataView-RH5UDA5F.css → DataView-L7HLNW7C.css} +1 -112
  29. package/dist/DatasetSource/index.js +1 -1
  30. package/dist/DateTimePicker/index.js +2 -2
  31. package/dist/DeepWorkCard/index.js +4 -4
  32. package/dist/DocTabsEditor/index.js +3 -3
  33. package/dist/DownloadButton/index.js +2 -2
  34. package/dist/EditingStatus/index.js +2 -2
  35. package/dist/{Editor-NZRUKWB4.js → Editor-NNQEALNT.js} +3 -3
  36. package/dist/EntityList/index.js +1 -1
  37. package/dist/ErrorBoundary/index.js +2 -2
  38. package/dist/FileDrop/index.js +2 -2
  39. package/dist/FilterPill/FilterPill.d.ts +63 -0
  40. package/dist/FilterPill/index.d.ts +3 -0
  41. package/dist/FilterPill/index.js +4 -0
  42. package/dist/FilterPill-4GMNFZND.css +134 -0
  43. package/dist/FollowBanner/index.js +2 -2
  44. package/dist/HuePicker/index.js +5 -5
  45. package/dist/InlineEditor/index.js +4 -4
  46. package/dist/LinkInterstitial/index.js +3 -3
  47. package/dist/ListInput/index.js +3 -3
  48. package/dist/LogoSlot/index.js +3 -3
  49. package/dist/MarkdownEditor/index.js +5 -5
  50. package/dist/Menu/Menu.d.ts +10 -1
  51. package/dist/Menu/index.js +2 -2
  52. package/dist/{Menu-OLUGHX56.css → Menu-I4SNXHOT.css} +12 -0
  53. package/dist/MergeConflicts/index.js +5 -5
  54. package/dist/Modal/index.js +2 -2
  55. package/dist/OpenInAppCard/index.js +4 -4
  56. package/dist/PeekRail/index.js +2 -2
  57. package/dist/PeopleRail/index.js +2 -2
  58. package/dist/PresenterView/index.js +3 -3
  59. package/dist/ProposalCard/index.js +4 -4
  60. package/dist/ReceiptStrip/index.js +2 -2
  61. package/dist/RefusalCard/index.js +1 -1
  62. package/dist/ResultTableCard/index.js +4 -4
  63. package/dist/RichEditor/index.js +2 -2
  64. package/dist/SandboxedFrame/index.js +2 -2
  65. package/dist/SegmentedControl/index.js +4 -4
  66. package/dist/SelectionBar/index.js +2 -2
  67. package/dist/ShareDialog/index.js +4 -4
  68. package/dist/SheetColumnEditor/index.js +8 -8
  69. package/dist/SheetGrid/index.js +5 -5
  70. package/dist/SlideCompare/index.js +2 -2
  71. package/dist/SlideFilmstrip/index.js +3 -3
  72. package/dist/StatusCard/index.js +1 -1
  73. package/dist/Switcher/index.js +3 -3
  74. package/dist/TableCells/index.js +2 -2
  75. package/dist/{TableCells-F6MUV572.css → TableCells-TKSNLRK3.css} +1 -0
  76. package/dist/Tabs/index.js +3 -3
  77. package/dist/ThemeSwitcher/index.js +5 -5
  78. package/dist/TimeRangePicker/index.js +6 -6
  79. package/dist/TimeWindowPicker/index.js +2 -2
  80. package/dist/Toaster/Toaster.d.ts +14 -2
  81. package/dist/Toaster/index.d.ts +1 -1
  82. package/dist/Toaster/index.js +1 -1
  83. package/dist/TreeCanvas/index.js +3 -3
  84. package/dist/VersionCompare/index.js +5 -5
  85. package/dist/VersionTimeline/index.js +2 -2
  86. package/dist/{chunk-HXJHRQDR.js → chunk-3EY5SEGH.js} +2 -2
  87. package/dist/{chunk-DS5NBENV.js → chunk-3LP3VPLT.js} +2 -2
  88. package/dist/{chunk-6MI2GMYG.js → chunk-3WN5HUAK.js} +2 -2
  89. package/dist/{chunk-4E3CE2UK.js → chunk-4DL2BQJE.js} +2 -2
  90. package/dist/{chunk-PQWNK3N7.js → chunk-4MVLED6E.js} +3 -3
  91. package/dist/{chunk-BXEKD5NU.js → chunk-6C6YK75K.js} +2 -2
  92. package/dist/{chunk-2A6DL3K5.js → chunk-6FBPFG3C.js} +1 -1
  93. package/dist/{chunk-L4UO57YP.js → chunk-73SAOOR5.js} +3 -3
  94. package/dist/{chunk-WXLQJUGO.js → chunk-ADSOY7UM.js} +1 -1
  95. package/dist/{chunk-GNDKUSCG.js → chunk-AGLONIVV.js} +1 -1
  96. package/dist/{chunk-2EA2GSA2.js → chunk-AQIFKLXY.js} +1 -1
  97. package/dist/{chunk-SUJO3AHN.js → chunk-B3PK2LND.js} +1 -1
  98. package/dist/{chunk-UYK3SGZI.js → chunk-BWFJB5JD.js} +3 -3
  99. package/dist/{chunk-I24FI46B.js → chunk-C667GCU7.js} +1 -1
  100. package/dist/{chunk-CWYU7DNT.js → chunk-CDNZTCP2.js} +1 -1
  101. package/dist/{chunk-NJYB4VJI.js → chunk-DB7UVFOY.js} +2 -2
  102. package/dist/{chunk-OJGI4XJH.js → chunk-DGSK4LLS.js} +1 -1
  103. package/dist/{chunk-7QTPJDRF.js → chunk-DGXZ635L.js} +7 -4
  104. package/dist/{chunk-2SU735S3.js → chunk-DV5L2GRY.js} +1 -1
  105. package/dist/{chunk-NSCYGUDG.js → chunk-EHFQMY3B.js} +1 -1
  106. package/dist/{chunk-S2UHV52X.js → chunk-EN4UJQ63.js} +3 -3
  107. package/dist/{chunk-6ID4DVML.js → chunk-EOXI3CRG.js} +1 -1
  108. package/dist/{chunk-VTGIDEI5.js → chunk-ERFXYGRF.js} +2 -2
  109. package/dist/{chunk-JEA5OX54.js → chunk-FQI62PIZ.js} +2 -2
  110. package/dist/{chunk-ELLRZ5XR.js → chunk-FURJVZCT.js} +72 -26
  111. package/dist/{chunk-5K7GGQNX.js → chunk-G4QZWVAB.js} +2 -2
  112. package/dist/{chunk-IABWA76I.js → chunk-H32JW6CZ.js} +2 -2
  113. package/dist/{chunk-PX54PALQ.js → chunk-HPI5J6AR.js} +1 -1
  114. package/dist/{chunk-ZEPUKRO7.js → chunk-IJ7KLXUZ.js} +1 -1
  115. package/dist/{chunk-PVZOP3QK.js → chunk-IPUEVTRJ.js} +1 -1
  116. package/dist/{chunk-RLBGU35B.js → chunk-J5WWMC35.js} +45 -46
  117. package/dist/{chunk-O3BNL4TV.js → chunk-JD7P2GJP.js} +1 -1
  118. package/dist/{chunk-SZFKGH2W.js → chunk-JIBWNHTC.js} +42 -9
  119. package/dist/{chunk-KIJJD4YD.js → chunk-JQEXAH7G.js} +1 -1
  120. package/dist/{chunk-K4IVKHKU.js → chunk-JT7WRPZ6.js} +1 -1
  121. package/dist/chunk-K4LZXSKZ.js +62 -0
  122. package/dist/{chunk-ZHVLDRAT.js → chunk-KAA3GFTP.js} +4 -4
  123. package/dist/{chunk-WDNURPXU.js → chunk-KL6A7JGH.js} +1 -1
  124. package/dist/{chunk-2JHGPXYG.js → chunk-KQWJWTED.js} +1 -1
  125. package/dist/{chunk-WU5JDEEY.js → chunk-L4HHWG4V.js} +1 -1
  126. package/dist/{chunk-GDDVI4US.js → chunk-LQWORB5B.js} +1 -1
  127. package/dist/{chunk-EHB4TSP2.js → chunk-NXNLAZPK.js} +2 -2
  128. package/dist/{chunk-WPMZKZUH.js → chunk-O3HCFM3D.js} +1 -1
  129. package/dist/{chunk-F32FFE6I.js → chunk-OBPINJNO.js} +1 -1
  130. package/dist/{chunk-T73DMDU4.js → chunk-OQG4P5KU.js} +17 -3
  131. package/dist/{chunk-UWOYDHVW.js → chunk-P64MIA7C.js} +1 -1
  132. package/dist/{chunk-DMK2A4IK.js → chunk-QSWQJX27.js} +1 -1
  133. package/dist/{chunk-D2ZXIQ23.js → chunk-R5OATXWU.js} +1 -1
  134. package/dist/{chunk-OFABBAUR.js → chunk-SMZPUHBL.js} +1 -1
  135. package/dist/{chunk-7QTJO3PV.js → chunk-SO5SXSTP.js} +1 -1
  136. package/dist/{chunk-IYG4ETAQ.js → chunk-T5GBTXNC.js} +1 -1
  137. package/dist/{chunk-DXVJSBEW.js → chunk-TKBFRGUV.js} +3 -3
  138. package/dist/{chunk-U7J52N67.js → chunk-TPCBPGSB.js} +1 -1
  139. package/dist/{chunk-W6UVBBNH.js → chunk-TYIHFDMP.js} +1 -1
  140. package/dist/{chunk-GJ7VIQWL.js → chunk-UY3FWQWG.js} +1 -1
  141. package/dist/{chunk-KHHDCNYM.js → chunk-V6X3DJ2G.js} +2 -2
  142. package/dist/{chunk-NTFVEOYY.js → chunk-VBA5FSWV.js} +1 -1
  143. package/dist/{chunk-7EOUVWGQ.js → chunk-VWMB3CJN.js} +1 -1
  144. package/dist/{chunk-CX6QT4CH.js → chunk-W5AXJWOW.js} +1 -1
  145. package/dist/{chunk-OWQATZGW.js → chunk-YGWIWDXE.js} +2 -2
  146. package/dist/{chunk-2T32N2WD.js → chunk-YUHKRRWO.js} +2 -2
  147. package/dist/{chunk-M25IV5MH.js → chunk-ZWCK4N4L.js} +1 -1
  148. package/dist/generated/index.d.ts +1 -0
  149. package/dist/generated/index.js +93 -92
  150. package/dist/index.js +93 -92
  151. package/dist/styles.css +333 -146
  152. package/package.json +3 -3
  153. package/dist/{chunk-XWOH3UPZ.js → chunk-5OFRDX66.js} +1 -1
  154. package/dist/{chunk-KBXSOBLD.js → chunk-ABZC3NLM.js} +0 -0
  155. package/dist/{chunk-VZICPYGR.js → chunk-SNQRGH4A.js} +1 -1
  156. package/dist/{chunk-AIMMHN5J.js → chunk-VLGGLLKH.js} +1 -1
@@ -1,15 +1,19 @@
1
1
  import { Checkbox } from './chunk-PBCNINMB.js';
2
2
  import { EmptyState } from './chunk-PPUR46MK.js';
3
3
  import { useMediaMatch } from './chunk-RTPQDNW3.js';
4
- import { Button } from './chunk-7QTPJDRF.js';
4
+ import { Button } from './chunk-DGXZ635L.js';
5
5
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
- import './DataGrid-NHIN2I42.css';
7
+ import './DataGrid-Q26F2V5Q.css';
8
8
  import { useId, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useSyncExternalStore, useEffect } from 'react';
9
9
  import { breakpoint } from '@crewlethq/tokens';
10
- import { ChevronDownGlyph, ChevronUpGlyph } from '@crewlethq/icons/glyphs';
10
+ import { ArrowDownGlyph, ArrowUpGlyph, ArrowUpDownGlyph } from '@crewlethq/icons/glyphs';
11
11
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
12
12
 
13
+ var DATA_GRID_ICON_TRACK = "calc(var(--size-target-min) + var(--spacing-3) * 2)";
14
+ function alignOf(column) {
15
+ return column.align ?? (column.icon ? "center" : "left");
16
+ }
13
17
  function columnChoicesOf(columns) {
14
18
  return columns.map((column) => ({
15
19
  key: column.key,
@@ -59,6 +63,15 @@ function parseGridSort(raw) {
59
63
  if (!raw) return null;
60
64
  return raw.startsWith("-") ? { key: raw.slice(1), desc: true } : { key: raw, desc: false };
61
65
  }
66
+ function nextGridSort(column, sort, defaultSort = "") {
67
+ const chosen = sort === defaultSort ? "" : sort;
68
+ const current2 = parseGridSort(chosen || defaultSort);
69
+ let next;
70
+ if (current2?.key !== column) next = column;
71
+ else if (!current2.desc) next = `-${column}`;
72
+ else next = chosen ? "" : column;
73
+ return next === defaultSort ? "" : next;
74
+ }
62
75
  function headerWord(column) {
63
76
  return typeof column.header === "string" ? column.header : "";
64
77
  }
@@ -120,7 +133,7 @@ function squeezed(wrap, visible, leading = 0) {
120
133
  let headCut = false;
121
134
  for (let i = 0; i < visible.length; i++) {
122
135
  const column = visible[i];
123
- if (!column.shrink || column.width) continue;
136
+ if (!column.shrink || column.width || column.icon) continue;
124
137
  const head = heads[i + leading];
125
138
  if (!head || head.getBoundingClientRect().width >= cap) continue;
126
139
  if (cutShort(head)) headCut = true;
@@ -156,6 +169,7 @@ function DataGrid({
156
169
  selection,
157
170
  isFailed,
158
171
  sort: sortRaw = "",
172
+ defaultSort = "",
159
173
  onSortChange,
160
174
  serverSorted = false,
161
175
  cols: colsRaw = "",
@@ -174,7 +188,7 @@ function DataGrid({
174
188
  className
175
189
  }) {
176
190
  const text = { ...LABELS, ...labels };
177
- const sort = parseGridSort(sortRaw);
191
+ const sort = parseGridSort(sortRaw || defaultSort);
178
192
  const body = useRef(null);
179
193
  const [cursor, setCursor] = useState(-1);
180
194
  const gridId = useId();
@@ -278,7 +292,7 @@ function DataGrid({
278
292
  ),
279
293
  action: true,
280
294
  phoneLead: true,
281
- width: "calc(var(--size-target-min) + var(--spacing-3) * 2)"
295
+ width: DATA_GRID_ICON_TRACK
282
296
  } : null;
283
297
  const drawnColumns = selectColumn ? [selectColumn, ...visibleColumns] : visibleColumns;
284
298
  const leading = drawnColumns.length - visibleColumns.length;
@@ -312,10 +326,31 @@ function DataGrid({
312
326
  body.current?.querySelector(`[data-row-index="${next}"]`)?.scrollIntoView({ block: "nearest" });
313
327
  return next;
314
328
  }),
329
+ // THE ROW'S OWN WAY IN, from the keyboard: its handler where it has
330
+ // one, else its link, followed as a click on it would be (with the
331
+ // keys held, so a modified Enter opens it elsewhere as a modified
332
+ // click does). A grid of links only had no Enter at all.
315
333
  activate: (event) => {
316
334
  const row = flat[cursor];
317
- if (row === void 0 || !onRowActivate) return false;
318
- onRowActivate(row, event);
335
+ if (row === void 0) return false;
336
+ if (onRowActivate) {
337
+ onRowActivate(row, event);
338
+ return true;
339
+ }
340
+ const link = body.current?.querySelector(
341
+ `[data-row-index="${cursor}"] > .crewlet-data-grid__cell > a.crewlet-data-grid__row-link`
342
+ );
343
+ if (!link) return false;
344
+ link.dispatchEvent(
345
+ new MouseEvent("click", {
346
+ bubbles: true,
347
+ cancelable: true,
348
+ metaKey: event.metaKey,
349
+ ctrlKey: event.ctrlKey,
350
+ shiftKey: event.shiftKey,
351
+ altKey: event.altKey
352
+ })
353
+ );
319
354
  return true;
320
355
  },
321
356
  rowCount: () => flat.length
@@ -324,11 +359,11 @@ function DataGrid({
324
359
  );
325
360
  function headerClick(column) {
326
361
  if (!column.sortValue || !onSortChange) return;
327
- if (sort?.key === column.key && !sort.desc) onSortChange(`-${column.key}`);
328
- else if (sort?.key === column.key && sort.desc) onSortChange("");
329
- else onSortChange(column.key);
362
+ onSortChange(nextGridSort(column.key, sortRaw, defaultSort));
330
363
  }
331
- const template = drawnColumns.map((c) => c.width ?? (c.shrink ? `fit-content(${SHRINK_CAP})` : `minmax(${c.floor ?? 0}, 1fr)`)).join(" ");
364
+ const template = drawnColumns.map(
365
+ (c) => c.width ?? (c.icon ? DATA_GRID_ICON_TRACK : c.shrink ? `fit-content(${SHRINK_CAP})` : `minmax(${c.floor ?? 0}, 1fr)`)
366
+ ).join(" ");
332
367
  if (flat.length === 0 && !bands?.length && empty) {
333
368
  return /* @__PURE__ */ jsx("div", { className: cx("crewlet-data-grid", className), "data-flush": flush || void 0, children: /* @__PURE__ */ jsx(
334
369
  EmptyState,
@@ -377,7 +412,8 @@ function DataGrid({
377
412
  role: "cell",
378
413
  className: cx(
379
414
  "crewlet-data-grid__cell",
380
- column.align === "right" && "crewlet-data-grid__cell--right",
415
+ alignOf(column) !== "left" && `crewlet-data-grid__cell--${alignOf(column)}`,
416
+ column.icon && "crewlet-data-grid__cell--icon",
381
417
  column.shrink && "crewlet-data-grid__cell--shrink"
382
418
  ),
383
419
  "data-lead": column.phoneLead || void 0,
@@ -444,36 +480,46 @@ function DataGrid({
444
480
  const sortable = Boolean(column.sortValue && onSortChange);
445
481
  const headClass = cx(
446
482
  "crewlet-data-grid__th",
447
- column.align === "right" && "crewlet-data-grid__th--right",
483
+ alignOf(column) !== "left" && `crewlet-data-grid__th--${alignOf(column)}`,
484
+ column.icon && "crewlet-data-grid__th--icon",
448
485
  column.shrink && "crewlet-data-grid__th--shrink",
449
486
  sorted && "crewlet-data-grid__th--sorted",
450
487
  !sortable && "crewlet-data-grid__th--plain"
451
488
  );
452
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
453
- /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__truncate", children: column.header }),
454
- sorted && (sort?.desc ? /* @__PURE__ */ jsx(ChevronDownGlyph, { size: "xs" }) : /* @__PURE__ */ jsx(ChevronUpGlyph, { size: "xs" }))
455
- ] });
489
+ const worded = column.header !== "" && column.header !== null && column.header !== void 0;
490
+ const label = worded ? /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__truncate", children: column.header }) : null;
491
+ const arrow = sorted ? sort?.desc ? /* @__PURE__ */ jsx(ArrowDownGlyph, { size: "xs" }) : /* @__PURE__ */ jsx(ArrowUpGlyph, { size: "xs" }) : sortable ? /* @__PURE__ */ jsx(ArrowUpDownGlyph, { size: "xs" }) : null;
492
+ const ariaSort = sorted ? sort?.desc ? "descending" : "ascending" : void 0;
493
+ const mark = arrow && /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__sort-mark", "aria-hidden": "true", children: arrow });
456
494
  if (!sortable) {
457
495
  const named = !headerWord(column) && !column.action ? column.label : void 0;
458
- return /* @__PURE__ */ jsxs("div", { className: headClass, role: "columnheader", title: named, children: [
459
- content,
460
- named && /* @__PURE__ */ jsx(VisuallyHidden, { children: named })
461
- ] }, column.key);
496
+ return (
497
+ // THE ORDER IN FORCE IS SAID on a head that cannot change it too:
498
+ // a grid sorted by its default, with nothing to press.
499
+ /* @__PURE__ */ jsxs("div", { className: headClass, role: "columnheader", title: named, "aria-sort": ariaSort, children: [
500
+ label,
501
+ mark,
502
+ named && /* @__PURE__ */ jsx(VisuallyHidden, { children: named })
503
+ ] }, column.key)
504
+ );
462
505
  }
463
506
  return /* @__PURE__ */ jsx(
464
507
  "div",
465
508
  {
466
509
  className: headClass,
467
510
  role: "columnheader",
468
- "aria-sort": sorted ? sort?.desc ? "descending" : "ascending" : void 0,
469
- children: /* @__PURE__ */ jsx(
511
+ "aria-sort": ariaSort,
512
+ children: /* @__PURE__ */ jsxs(
470
513
  "button",
471
514
  {
472
515
  type: "button",
473
516
  className: "crewlet-data-grid__sort",
474
517
  onClick: () => headerClick(column),
475
518
  "aria-label": headerWord(column) ? void 0 : column.label,
476
- children: content
519
+ children: [
520
+ label,
521
+ mark
522
+ ]
477
523
  }
478
524
  )
479
525
  },
@@ -544,4 +590,4 @@ function useAnyDataGridDriving() {
544
590
  return drivable.length > 0;
545
591
  }
546
592
 
547
- export { ChooserList, ColumnChooser, DataGrid, columnChoicesOf, countDataGridRows, fitGridColumns, parseGridSort, useAnyDataGridDriving, useDataGridDriving };
593
+ export { ChooserList, ColumnChooser, DATA_GRID_ICON_TRACK, DataGrid, columnChoicesOf, countDataGridRows, fitGridColumns, nextGridSort, parseGridSort, useAnyDataGridDriving, useDataGridDriving };
@@ -1,8 +1,8 @@
1
1
  import { safeHref } from './chunk-BAKPMH3S.js';
2
2
  import { IconTile } from './chunk-3LI4TRUR.js';
3
- import { ReceiptStrip } from './chunk-M25IV5MH.js';
3
+ import { ReceiptStrip } from './chunk-ZWCK4N4L.js';
4
4
  import { StatusCard } from './chunk-NTQPJJAN.js';
5
- import { ButtonLink, Button } from './chunk-7QTPJDRF.js';
5
+ import { ButtonLink, Button } from './chunk-DGXZ635L.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './OpenInAppCard-CKHCK7DO.css';
8
8
  import { CircleCheckGlyph } from '@crewlethq/icons/glyphs';
@@ -1,9 +1,9 @@
1
1
  import { useReorder } from './chunk-MPVMB2DV.js';
2
+ import { Kbd } from './chunk-ANTAQAR4.js';
2
3
  import { FormField, Textarea } from './chunk-ETSF7SU6.js';
3
4
  import { characterCountState, CharacterCount, countCharacters } from './chunk-PGCLHYVP.js';
4
- import { Kbd } from './chunk-ANTAQAR4.js';
5
5
  import { announce } from './chunk-2G355KDJ.js';
6
- import { Button } from './chunk-7QTPJDRF.js';
6
+ import { Button } from './chunk-DGXZ635L.js';
7
7
  import { isComposing } from './chunk-H5XTJ7GJ.js';
8
8
  import { IconButton } from './chunk-UAUP6XGK.js';
9
9
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
1
  import { today, CalendarGrid, shiftMonth, compareDays } from './chunk-EE3DJMSQ.js';
2
2
  import { Popover } from './chunk-KHJIEPZV.js';
3
- import { Button } from './chunk-7QTPJDRF.js';
3
+ import { Button } from './chunk-DGXZ635L.js';
4
4
  import { IconButton } from './chunk-UAUP6XGK.js';
5
5
  import { useFocusModality } from './chunk-NUZHC6MM.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- import { Button } from './chunk-7QTPJDRF.js';
1
+ import { Button } from './chunk-DGXZ635L.js';
2
2
  import './ErrorBoundary-U2PA3LY2.css';
3
3
  import { Component } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  import { useRoving, tabStop } from './chunk-EGMQURBR.js';
2
2
  import { StatusDot } from './chunk-WIATRXEJ.js';
3
3
  import { Count } from './chunk-MLDTLZAO.js';
4
- import { Menu } from './chunk-T73DMDU4.js';
4
+ import { Menu } from './chunk-OQG4P5KU.js';
5
5
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
6
6
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
7
7
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,19 +1,20 @@
1
1
  import { PageHeader } from './chunk-FPDIHEM4.js';
2
- import { DataTable } from './chunk-UYK3SGZI.js';
3
- import { DateTimePicker } from './chunk-PX54PALQ.js';
2
+ import { FilterPill } from './chunk-K4LZXSKZ.js';
3
+ import { DataTable } from './chunk-BWFJB5JD.js';
4
+ import { DateTimePicker } from './chunk-HPI5J6AR.js';
4
5
  import { useListbox, useOptionKeys } from './chunk-7KHM2FZH.js';
5
6
  import { Toolbar } from './chunk-NR4CPM4T.js';
6
7
  import { Popover } from './chunk-KHJIEPZV.js';
7
8
  import { RelativeTime } from './chunk-EJNJMHQG.js';
8
- import { Input } from './chunk-ETSF7SU6.js';
9
9
  import { Kbd } from './chunk-ANTAQAR4.js';
10
+ import { Input } from './chunk-ETSF7SU6.js';
10
11
  import { Count } from './chunk-MLDTLZAO.js';
11
- import { Menu } from './chunk-T73DMDU4.js';
12
- import { Button } from './chunk-7QTPJDRF.js';
12
+ import { Menu } from './chunk-OQG4P5KU.js';
13
+ import { Button } from './chunk-DGXZ635L.js';
13
14
  import { IconButton } from './chunk-UAUP6XGK.js';
14
15
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
15
16
  import { cx } from './chunk-ODEQTPFM.js';
16
- import './DataView-RH5UDA5F.css';
17
+ import './DataView-L7HLNW7C.css';
17
18
  import { useMemo, useState, useEffect, useCallback, useRef, useId } from 'react';
18
19
  import { SearchGlyph, ChevronDownGlyph, SlidersVerticalGlyph, ArrowUpGlyph, ArrowDownGlyph, XGlyph, ArrowUpDownGlyph, EyeGlyph, EyeOffGlyph, HashGlyph, ClockGlyph, ListGlyph, CheckGlyph } from '@crewlethq/icons/glyphs';
19
20
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -362,31 +363,34 @@ var isMultiple = (def) => def.kind === "select" && def.multiple === true;
362
363
  var chosenValues = (value) => Array.isArray(value) ? [...value] : [];
363
364
  var sameValue = (a, b) => String(a) === String(b);
364
365
  function formatFilterValue(def, value, labels) {
365
- const operator = operatorOf(def);
366
+ const { operator, answer } = filterAnswer(def, value, labels);
367
+ return operator ? `${operator} ${answer}` : answer;
368
+ }
369
+ function filterAnswer(def, value, labels) {
366
370
  const unusual = def.operator !== void 0 && def.operator !== defaultOperator(def);
367
- const prefix = unusual ? `${labels.operator[operator]} ` : "";
371
+ const compared = (answer) => unusual ? { operator: labels.operator[operatorOf(def)], answer } : { answer };
368
372
  if (isMultiple(def)) {
369
373
  const held = chosenValues(value);
370
- if (held.length === 0) return labels.any;
374
+ if (held.length === 0) return { answer: labels.any };
371
375
  if (held.length === 1) {
372
376
  const option = def.options?.find((candidate) => sameValue(candidate.value, held[0]));
373
- return `${prefix}${option ? option.label : String(held[0])}`;
377
+ return compared(option ? option.label : String(held[0]));
374
378
  }
375
- return labels.selected(held.length);
379
+ return { answer: labels.selected(held.length) };
376
380
  }
377
381
  if (value === void 0 || value === null || value === "") {
378
382
  const option = def.options?.find((candidate) => String(candidate.value) === "");
379
- return option ? option.label : labels.any;
383
+ return { answer: option ? option.label : labels.any };
380
384
  }
381
385
  if (def.kind === "select") {
382
386
  const option = def.options?.find((candidate) => sameValue(candidate.value, value));
383
- return `${prefix}${option ? option.label : String(value)}`;
387
+ return compared(option ? option.label : String(value));
384
388
  }
385
389
  if (def.kind === "datetime") {
386
390
  const at = new Date(String(value));
387
- if (!Number.isNaN(at.getTime())) return `${prefix}${at.toLocaleString()}`;
391
+ if (!Number.isNaN(at.getTime())) return compared(at.toLocaleString());
388
392
  }
389
- return `${prefix}${String(value)}`;
393
+ return compared(String(value));
390
394
  }
391
395
  function OptionListEditor({ def, value, labels, onCommit }) {
392
396
  const id = useId();
@@ -563,38 +567,33 @@ function FilterAxisChip({
563
567
  if (def.kind === "datetime") return /* @__PURE__ */ jsx(MomentEditor, { ...props });
564
568
  return /* @__PURE__ */ jsx(TextEditor, { ...props });
565
569
  };
566
- return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-filter-axis-chip", className), children: [
567
- /* @__PURE__ */ jsx(
568
- Popover,
569
- {
570
- align: "start",
571
- role: "dialog",
572
- label: labels.editor(def.label),
573
- defaultOpen: autoOpen,
574
- className: "crewlet-filter-axis__popover",
575
- trigger: (open, toggle) => /* @__PURE__ */ jsxs("button", { type: "button", className: cx("crewlet-filter-axis-chip__trigger", open && "is-open"), onClick: toggle, children: [
576
- /* @__PURE__ */ jsxs("span", { className: "crewlet-filter-axis-chip__label", children: [
577
- def.label,
578
- ":"
570
+ const { operator, answer } = filterAnswer(def, value, labels);
571
+ return /* @__PURE__ */ jsx(
572
+ FilterPill,
573
+ {
574
+ className: cx("crewlet-filter-axis-chip", className),
575
+ field: def.label,
576
+ operator,
577
+ value: answer,
578
+ onRemove,
579
+ removeLabel: labels.remove(def.label),
580
+ renderWords: (words, wordsClass) => /* @__PURE__ */ jsx(
581
+ Popover,
582
+ {
583
+ align: "start",
584
+ role: "dialog",
585
+ label: labels.editor(def.label),
586
+ defaultOpen: autoOpen,
587
+ className: "crewlet-filter-axis__popover",
588
+ trigger: (open, toggle) => /* @__PURE__ */ jsxs("button", { type: "button", className: cx(wordsClass, open && "is-open"), onClick: toggle, children: [
589
+ words,
590
+ /* @__PURE__ */ jsx(ChevronDownGlyph, { size: "xs" })
579
591
  ] }),
580
- /* @__PURE__ */ jsx("span", { className: "crewlet-filter-axis-chip__value", children: formatFilterValue(def, value, labels) }),
581
- /* @__PURE__ */ jsx(ChevronDownGlyph, { className: "crewlet-filter-axis-chip__chevron", size: "xs" })
582
- ] }),
583
- children: editor
584
- }
585
- ),
586
- onRemove ? /* @__PURE__ */ jsx(
587
- IconButton,
588
- {
589
- className: "crewlet-filter-axis-chip__remove",
590
- size: "sm",
591
- variant: "ghost",
592
- label: labels.remove(def.label),
593
- icon: /* @__PURE__ */ jsx(XGlyph, { size: "xs" }),
594
- onClick: onRemove
595
- }
596
- ) : null
597
- ] });
592
+ children: editor
593
+ }
594
+ )
595
+ }
596
+ );
598
597
  }
599
598
  function FilterAxisBar({
600
599
  filters,
@@ -1,4 +1,4 @@
1
- import { ConfirmModal } from './chunk-I24FI46B.js';
1
+ import { ConfirmModal } from './chunk-C667GCU7.js';
2
2
  import { InlineCode } from './chunk-PLL7ZJHY.js';
3
3
  import { Callout } from './chunk-BPCY7ZID.js';
4
4
  import './LinkInterstitial-ET4MSVSV.css';
@@ -30,18 +30,44 @@ var TITLES = {
30
30
  warning: "Heads up",
31
31
  danger: "Something went wrong"
32
32
  };
33
- var DURATIONS = {
34
- info: 4e3,
35
- success: 4e3,
36
- warning: 0,
37
- danger: 0
33
+ var GOES_BY_ITSELF = {
34
+ info: true,
35
+ success: true,
36
+ warning: false,
37
+ danger: false
38
38
  };
39
+ var READ_MS_PER_WORD = 300;
40
+ var READ_LEAD_MS = 2e3;
41
+ var READ_FLOOR_MS = 4e3;
42
+ var READ_CAP_MS = 15e3;
43
+ function readingDuration(text) {
44
+ const words = wordsIn(text);
45
+ return Math.min(READ_CAP_MS, Math.max(READ_FLOOR_MS, READ_LEAD_MS + words * READ_MS_PER_WORD));
46
+ }
47
+ var segmenter;
48
+ function wordsIn(text) {
49
+ if (segmenter === void 0) {
50
+ segmenter = typeof Intl !== "undefined" && typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "word" }) : null;
51
+ }
52
+ if (segmenter === null) return text.trim().split(/\s+/).filter(Boolean).length;
53
+ let words = 0;
54
+ for (const part of segmenter.segment(text)) {
55
+ if (part.isWordLike) words += 1;
56
+ }
57
+ return words;
58
+ }
39
59
  var KNOWN = /* @__PURE__ */ new Set(["info", "success", "warning", "danger"]);
40
60
  var isKnown = (variant) => KNOWN.has(variant);
41
61
  var durationOf = (toast) => {
62
+ const given = toast.duration ?? null;
63
+ if (given !== null) return timerSafe(given);
42
64
  const variant = toast.variant ?? "info";
43
- return toast.duration ?? (isKnown(variant) ? DURATIONS[variant] : 0);
65
+ if (!isKnown(variant) || !GOES_BY_ITSELF[variant]) return 0;
66
+ return readingDuration(readable(toast).join(" "));
44
67
  };
68
+ var MAX_TIMER_MS = 2 ** 31 - 1;
69
+ var timerSafe = (ms) => Number.isFinite(ms) ? Math.min(ms, MAX_TIMER_MS) : 0;
70
+ var readable = (toast) => [toast.title, toast.message].filter((part) => typeof part === "string");
45
71
  var isSticky = (toast) => durationOf(toast) <= 0;
46
72
  var politeness = (variant) => variant === "danger" || variant === "quota" ? "assertive" : "polite";
47
73
  var isToastAction = (value) => {
@@ -51,7 +77,7 @@ var isToastAction = (value) => {
51
77
  };
52
78
  var sentences = (parts) => parts.length < 2 ? parts[0] ?? "" : parts.map((part) => /[.!?]$/.test(part) ? part : `${part}.`).join(" ");
53
79
  function spoken(toast, titles) {
54
- const parts = [toast.title, toast.message].filter((part) => typeof part === "string");
80
+ const parts = readable(toast);
55
81
  if (parts.length > 0) return parts.join(". ");
56
82
  const variant = toast.variant ?? "info";
57
83
  return isKnown(variant) ? titles[variant] ?? "Notification" : "Notification";
@@ -70,8 +96,15 @@ function ToastItem({
70
96
  const dismiss = useCallback(() => onDismiss(id), [onDismiss, id]);
71
97
  const [paused, setPaused] = useState(false);
72
98
  const remaining = useRef(duration);
99
+ const counting = useRef({ version, duration });
73
100
  useEffect(() => {
74
- remaining.current = duration;
101
+ const was = counting.current;
102
+ if (was.version !== version) {
103
+ remaining.current = duration;
104
+ } else if (was.duration !== duration) {
105
+ remaining.current = Math.max(0, remaining.current + duration - was.duration);
106
+ }
107
+ counting.current = { version, duration };
75
108
  }, [duration, version]);
76
109
  useEffect(() => {
77
110
  if (duration <= 0 || paused) return;
@@ -273,4 +306,4 @@ function ToastProvider({ children, position = "bottom-right", inset, renderActio
273
306
  ] });
274
307
  }
275
308
 
276
- export { ToastProvider, Toaster, toasterInsetStyle, useToast };
309
+ export { ToastProvider, Toaster, readingDuration, toasterInsetStyle, useToast };
@@ -1,5 +1,5 @@
1
1
  import { useTreeState, useMeasuredSizes, layoutForest, treeAncestors, useLayoutAnchor, treeExpandable, layoutConnectors, treeItemAction, treeStep, treePosInSet, treeSetSize, treeLevel, placeGroups } from './chunk-MY374UUD.js';
2
- import { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, Canvas } from './chunk-F32FFE6I.js';
2
+ import { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, Canvas } from './chunk-OBPINJNO.js';
3
3
  import { focusables } from './chunk-H5XTJ7GJ.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import './TreeCanvas-5FPK4CII.css';
@@ -1,5 +1,5 @@
1
1
  import { Callout } from './chunk-BPCY7ZID.js';
2
- import { Button } from './chunk-7QTPJDRF.js';
2
+ import { Button } from './chunk-DGXZ635L.js';
3
3
  import { isComposing } from './chunk-H5XTJ7GJ.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import { useEffect } from 'react';
@@ -0,0 +1,62 @@
1
+ import { IconButton } from './chunk-UAUP6XGK.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './FilterPill-4GMNFZND.css';
4
+ import { XGlyph } from '@crewlethq/icons/glyphs';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+
7
+ var FILTER_PILL_LABELS = {
8
+ remove: (sentence) => `Remove the ${sentence} filter`,
9
+ removeUnnamed: "Remove this filter",
10
+ fieldEnd: ":"
11
+ };
12
+ var FILTER_PILL_WORDS_CLASS = "crewlet-filter-pill__words";
13
+ function filterPillSentence(field, operator, value) {
14
+ const parts = [field, operator, value].filter((part) => part !== void 0 && part !== null && part !== "");
15
+ if (!parts.every((part) => typeof part === "string" || typeof part === "number")) return void 0;
16
+ return parts.join(" ");
17
+ }
18
+ function FilterPill({
19
+ field,
20
+ operator,
21
+ value,
22
+ onRemove,
23
+ removeLabel,
24
+ renderWords,
25
+ labels,
26
+ className
27
+ }) {
28
+ const text = { ...FILTER_PILL_LABELS, ...labels };
29
+ const hasValue = value !== void 0 && value !== null && value !== "";
30
+ const hasOperator = operator !== void 0 && operator !== null && operator !== "";
31
+ const words = /* @__PURE__ */ jsxs(Fragment, { children: [
32
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-filter-pill__field", children: [
33
+ field,
34
+ hasValue && !hasOperator ? text.fieldEnd : null
35
+ ] }),
36
+ hasOperator ? /* @__PURE__ */ jsxs(Fragment, { children: [
37
+ " ",
38
+ /* @__PURE__ */ jsx("span", { className: "crewlet-filter-pill__operator", children: operator })
39
+ ] }) : null,
40
+ hasValue ? /* @__PURE__ */ jsxs(Fragment, { children: [
41
+ " ",
42
+ /* @__PURE__ */ jsx("span", { className: "crewlet-filter-pill__value", children: value })
43
+ ] }) : null
44
+ ] });
45
+ const sentence = filterPillSentence(field, hasOperator ? operator : void 0, hasValue ? value : void 0);
46
+ return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-filter-pill", className), children: [
47
+ renderWords ? renderWords(words, FILTER_PILL_WORDS_CLASS) : /* @__PURE__ */ jsx("span", { className: FILTER_PILL_WORDS_CLASS, children: words }),
48
+ onRemove ? /* @__PURE__ */ jsx(
49
+ IconButton,
50
+ {
51
+ className: "crewlet-filter-pill__remove",
52
+ size: "sm",
53
+ variant: "ghost",
54
+ label: removeLabel ?? (sentence ? text.remove(sentence) : text.removeUnnamed),
55
+ icon: /* @__PURE__ */ jsx(XGlyph, { size: "xs" }),
56
+ onClick: onRemove
57
+ }
58
+ ) : null
59
+ ] });
60
+ }
61
+
62
+ export { FILTER_PILL_LABELS, FILTER_PILL_WORDS_CLASS, FilterPill, filterPillSentence };
@@ -1,12 +1,12 @@
1
1
  import { Select } from './chunk-VK45YJLH.js';
2
2
  import { SHEET_LABELS, SHEET_COLUMN_TYPES, optionHue, retypeColumn } from './chunk-LFSIKGRQ.js';
3
- import { HueSwatch } from './chunk-2EA2GSA2.js';
3
+ import { HueSwatch } from './chunk-AQIFKLXY.js';
4
4
  import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
5
5
  import { Checkbox } from './chunk-PBCNINMB.js';
6
- import { FormField, Input } from './chunk-ETSF7SU6.js';
7
6
  import { Kbd } from './chunk-ANTAQAR4.js';
8
- import { Menu } from './chunk-T73DMDU4.js';
9
- import { Button } from './chunk-7QTPJDRF.js';
7
+ import { FormField, Input } from './chunk-ETSF7SU6.js';
8
+ import { Menu } from './chunk-OQG4P5KU.js';
9
+ import { Button } from './chunk-DGXZ635L.js';
10
10
  import { IconButton } from './chunk-UAUP6XGK.js';
11
11
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
12
12
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
1
  import { Toolbar } from './chunk-NR4CPM4T.js';
2
- import { ShortcutTip } from './chunk-F32FFE6I.js';
2
+ import { ShortcutTip } from './chunk-OBPINJNO.js';
3
3
  import { IconButton } from './chunk-UAUP6XGK.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import './CanvasToolbar-EM5EVZED.css';
@@ -1,4 +1,4 @@
1
- import { Button } from './chunk-7QTPJDRF.js';
1
+ import { Button } from './chunk-DGXZ635L.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './FileDrop-WE7BNZGV.css';
4
4
  import { forwardRef, useRef, useState } from 'react';
@@ -1,6 +1,6 @@
1
1
  import { Toolbar } from './chunk-NR4CPM4T.js';
2
2
  import { announce } from './chunk-2G355KDJ.js';
3
- import { Button } from './chunk-7QTPJDRF.js';
3
+ import { Button } from './chunk-DGXZ635L.js';
4
4
  import { returnFocus } from './chunk-NUZHC6MM.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './SelectionBar-SCAU6EBY.css';
@@ -1,4 +1,4 @@
1
- import { Modal } from './chunk-I24FI46B.js';
1
+ import { Modal } from './chunk-C667GCU7.js';
2
2
  import { useListbox, useOptionKeys } from './chunk-7KHM2FZH.js';
3
3
  import { Popover } from './chunk-KHJIEPZV.js';
4
4
  import { KeyChip, highlightMatch } from './chunk-HBDA76EZ.js';
@@ -1,7 +1,7 @@
1
- import { Modal } from './chunk-I24FI46B.js';
1
+ import { Modal } from './chunk-C667GCU7.js';
2
2
  import { useListbox, useHighlightRest } from './chunk-7KHM2FZH.js';
3
- import { Input } from './chunk-ETSF7SU6.js';
4
3
  import { Kbd } from './chunk-ANTAQAR4.js';
4
+ import { Input } from './chunk-ETSF7SU6.js';
5
5
  import { Count } from './chunk-MLDTLZAO.js';
6
6
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
7
7
  import { isComposing } from './chunk-H5XTJ7GJ.js';
@@ -1,7 +1,7 @@
1
1
  import { PrincipalAvatar } from './chunk-CI3VPIJN.js';
2
2
  import { RelativeTime } from './chunk-EJNJMHQG.js';
3
3
  import { Timeline } from './chunk-4MJN2KN6.js';
4
- import { Button } from './chunk-7QTPJDRF.js';
4
+ import { Button } from './chunk-DGXZ635L.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './VersionTimeline-DEAQ7CJG.css';
7
7
  import { RotateCcwClockGlyph, PencilGlyph, ShieldGlyph, DatabaseGlyph, UploadGlyph } from '@crewlethq/icons/glyphs';
@@ -1,7 +1,7 @@
1
1
  import { LayerNodeBridge } from './chunk-LM3ISVJA.js';
2
2
  import { Tooltip } from './chunk-I33UIUZD.js';
3
3
  import { Kbd } from './chunk-ANTAQAR4.js';
4
- import { Button } from './chunk-7QTPJDRF.js';
4
+ import { Button } from './chunk-DGXZ635L.js';
5
5
  import { LAYER_REPOSITION_EVENT, LayerHost } from './chunk-OMV5W53A.js';
6
6
  import { IconButton } from './chunk-UAUP6XGK.js';
7
7
  import { returnFocus } from './chunk-NUZHC6MM.js';