@crewlethq/ui 0.84.2 → 0.86.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 (103) hide show
  1. package/README.md +53 -5
  2. package/dist/Accordion/index.js +1 -1
  3. package/dist/AgentHandoffPanel/index.js +2 -2
  4. package/dist/ArtifactBar/index.js +1 -1
  5. package/dist/AttentionList/AttentionList.d.ts +82 -0
  6. package/dist/AttentionList/index.d.ts +3 -0
  7. package/dist/AttentionList/index.js +9 -0
  8. package/dist/AttentionList-LVX7KRET.css +212 -0
  9. package/dist/AvatarPicker/index.js +2 -2
  10. package/dist/ChangeList/index.js +2 -2
  11. package/dist/ChoiceCards/ChoiceCards.d.ts +35 -6
  12. package/dist/ChoiceCards/index.d.ts +1 -1
  13. package/dist/ChoiceCards/index.js +1 -1
  14. package/dist/{ChoiceCards-TVMBO3HZ.css → ChoiceCards-KHJW2FKO.css} +49 -0
  15. package/dist/ChoiceList/ChoiceList.d.ts +2 -2
  16. package/dist/ChoiceList/index.js +1 -1
  17. package/dist/{ChoiceList-JN4PPNFW.css → ChoiceList-ZQMZTEZX.css} +33 -17
  18. package/dist/CodeBlock/index.js +2 -2
  19. package/dist/ColorSwatch/index.js +2 -2
  20. package/dist/ContrastBadge/index.js +2 -2
  21. package/dist/ContrastHelp/index.js +3 -3
  22. package/dist/Copyable/index.js +1 -1
  23. package/dist/{Copyable-IS3MHMPL.css → Copyable-P5AMRHFX.css} +18 -4
  24. package/dist/DataGrid/index.js +1 -1
  25. package/dist/{DataGrid-Q26F2V5Q.css → DataGrid-SAHEL4SN.css} +57 -0
  26. package/dist/DataView/index.js +2 -2
  27. package/dist/DeepWorkCard/index.js +3 -3
  28. package/dist/Disclosure/Disclosure.d.ts +10 -1
  29. package/dist/Disclosure/index.js +1 -1
  30. package/dist/{Disclosure-D727FN5X.css → Disclosure-RJSKKO7Z.css} +20 -0
  31. package/dist/KeyValueRows/KeyValueRows.d.ts +125 -0
  32. package/dist/KeyValueRows/index.d.ts +3 -0
  33. package/dist/KeyValueRows/index.js +12 -0
  34. package/dist/KeyValueRows-US5KW7JK.css +44 -0
  35. package/dist/LogoSlot/index.js +3 -3
  36. package/dist/MarkdownEditor/index.js +1 -1
  37. package/dist/MemberPicker/MemberPicker.d.ts +86 -0
  38. package/dist/MemberPicker/index.d.ts +3 -0
  39. package/dist/MemberPicker/index.js +11 -0
  40. package/dist/MemberPicker-ZD35VEK6.css +162 -0
  41. package/dist/MergeConflicts/index.js +1 -1
  42. package/dist/PresenterView/index.js +2 -2
  43. package/dist/ProposalCard/index.js +3 -3
  44. package/dist/RailList/RailList.d.ts +74 -0
  45. package/dist/RailList/index.d.ts +3 -0
  46. package/dist/RailList/index.js +17 -0
  47. package/dist/RailList-N2ZBPRM2.css +97 -0
  48. package/dist/RelatedRow/index.js +2 -2
  49. package/dist/RichEditor/index.js +1 -1
  50. package/dist/RunChip/index.js +3 -3
  51. package/dist/SegmentedControl/index.js +1 -1
  52. package/dist/{SegmentedControl-B7XCUOML.css → SegmentedControl-7GY2KM44.css} +11 -0
  53. package/dist/SetupWizard/index.js +3 -3
  54. package/dist/ShareDialog/index.js +3 -3
  55. package/dist/{StepList-A4YVU4JI.css → StepList-OAJ45IBX.css} +12 -1
  56. package/dist/Stepper/StepList.d.ts +7 -4
  57. package/dist/Stepper/index.js +1 -1
  58. package/dist/TableCells/TableCells.d.ts +60 -0
  59. package/dist/TableCells/index.d.ts +2 -2
  60. package/dist/TableCells/index.js +2 -1
  61. package/dist/{TableCells-TKSNLRK3.css → TableCells-ZALZLLEF.css} +28 -0
  62. package/dist/Text/Text.d.ts +25 -3
  63. package/dist/Text/index.js +1 -1
  64. package/dist/ThemeSwitcher/index.js +1 -1
  65. package/dist/TimeRangePicker/index.js +1 -1
  66. package/dist/VersionCompare/index.js +1 -1
  67. package/dist/{chunk-CV2LU2T2.js → chunk-35CKF77R.js} +2 -2
  68. package/dist/{chunk-AUSFKGKL.js → chunk-3AMWXJQX.js} +1 -1
  69. package/dist/{chunk-AFLS26AC.js → chunk-3CALM534.js} +36 -2
  70. package/dist/{chunk-AOJ6ZA77.js → chunk-3MFRTZH6.js} +1 -1
  71. package/dist/{chunk-QSWQJX27.js → chunk-4ME4J3YY.js} +1 -1
  72. package/dist/{chunk-6FBPFG3C.js → chunk-6EZX26BD.js} +1 -1
  73. package/dist/chunk-AELKT34H.js +121 -0
  74. package/dist/{chunk-X7VZQKIW.js → chunk-AQ7ZV3CH.js} +1 -1
  75. package/dist/{chunk-EAHEJNVJ.js → chunk-CL3FWLDO.js} +1 -1
  76. package/dist/{chunk-XNC3M4IN.js → chunk-E2QPZGLG.js} +1 -1
  77. package/dist/{chunk-T5GBTXNC.js → chunk-ETNQYT5O.js} +1 -1
  78. package/dist/{chunk-36WK24AI.js → chunk-EVM6GYZ2.js} +1 -1
  79. package/dist/{chunk-B7NX425Z.js → chunk-JDMJVVVQ.js} +12 -4
  80. package/dist/chunk-KA4RBKQV.js +148 -0
  81. package/dist/{chunk-ABRWL5FJ.js → chunk-L2QRKIL4.js} +3 -2
  82. package/dist/{chunk-P7HMY3BQ.js → chunk-M33DABTW.js} +2 -2
  83. package/dist/{chunk-LVJGN5II.js → chunk-NAHA62WD.js} +3 -1
  84. package/dist/{chunk-QP2P6GDQ.js → chunk-O5CEG7TQ.js} +14 -0
  85. package/dist/{chunk-6SFDL4QH.js → chunk-P3LNA6G4.js} +1 -1
  86. package/dist/chunk-REWKR3S4.js +73 -0
  87. package/dist/{chunk-WMO722J2.js → chunk-TBQFZV4H.js} +1 -1
  88. package/dist/{chunk-RJWO2PC5.js → chunk-TMML7BHT.js} +14 -5
  89. package/dist/chunk-TRZS7DLB.js +159 -0
  90. package/dist/{chunk-K6RWEQ6P.js → chunk-WRZPO4YL.js} +2 -2
  91. package/dist/{chunk-DD7RBNT4.js → chunk-XH55NRHO.js} +1 -1
  92. package/dist/{chunk-6RW2MUTY.js → chunk-XU7RQNT6.js} +1 -1
  93. package/dist/{chunk-AQNP3KQU.js → chunk-Y7PPKQFQ.js} +1 -1
  94. package/dist/generated/index.d.ts +4 -0
  95. package/dist/generated/index.js +92 -88
  96. package/dist/index.js +92 -88
  97. package/dist/styles.css +763 -30
  98. package/package.json +3 -3
  99. package/dist/{Editor-5D5Z3LBQ.js → Editor-VGNB35NJ.js} +1 -1
  100. package/dist/{chunk-22CU7V4J.js → chunk-K2HEYQJL.js} +1 -1
  101. package/dist/{chunk-REEZQCML.js → chunk-PAGITACP.js} +0 -0
  102. package/dist/{chunk-LMEMH6DO.js → chunk-WCJTOKTY.js} +1 -1
  103. package/dist/{chunk-2ZSCHQOA.js → chunk-WMSXPF7T.js} +1 -1
@@ -57,10 +57,22 @@ export interface TextProps extends HTMLAttributes<HTMLElement> {
57
57
  * it on every push, because the proportional digits have different widths.
58
58
  */
59
59
  numeric?: boolean | undefined;
60
- /** One line, cut with an ellipsis. */
60
+ /**
61
+ * One line, cut with an ellipsis: a name in a narrow column, a caption
62
+ * under it. While the words are cut, the pointer's title carries them whole
63
+ * (see `titleWhenCut`).
64
+ */
61
65
  truncate?: boolean | undefined;
62
- /** Two or three lines, then an ellipsis. */
66
+ /** Two or three lines, then an ellipsis, with the whole words on the title while they are cut. */
63
67
  clamp?: 2 | 3 | undefined;
68
+ /**
69
+ * Whether words cut by `truncate` or `clamp` carry their whole text as the
70
+ * element's title while they are cut. On by default. Turn it off where
71
+ * something else already shows the whole words, a `Tooltip` around the
72
+ * text or a title on the element around it, so the reader is not shown
73
+ * them twice. A `title` the caller passes always wins.
74
+ */
75
+ titleWhenCut?: boolean | undefined;
64
76
  /** Bounds the line length, for anything a reader reads rather than scans. */
65
77
  measure?: TextMeasure | undefined;
66
78
  }
@@ -77,5 +89,15 @@ export interface TextProps extends HTMLAttributes<HTMLElement> {
77
89
  * `variant` sets the size, the weight, the tracking and the ink together,
78
90
  * because those four move as one. `tone` overrides only the ink, for the case
79
91
  * where the same register carries a quieter fact.
92
+ *
93
+ * CUT WORDS ARE STILL READABLE WHOLE. A line cut with an ellipsis hid the
94
+ * end of a name from a sighted reader, who had no way to read it short of
95
+ * widening the window, while a screen reader read it whole (the cut is
96
+ * paint, not content). So a cut Text puts its whole words on its title. It
97
+ * is MEASURED AT THE MOMENT THE POINTER ARRIVES, which is the only moment a
98
+ * title is read: the words and the column are what they are then, so a title
99
+ * never goes stale after a resize or a new value, and a table of a thousand
100
+ * cut cells costs nothing until one is hovered. Words that fit carry no
101
+ * title, since a tooltip that repeats what is on the screen is noise.
80
102
  */
81
- export declare function Text({ as: Tag, variant, tone, mono, numeric, truncate, clamp, measure, className, children, ...rest }: TextProps): import("react").JSX.Element;
103
+ export declare function Text({ as: Tag, variant, tone, mono, numeric, truncate, clamp, measure, titleWhenCut, className, children, ...rest }: TextProps): import("react").JSX.Element;
@@ -1,2 +1,2 @@
1
- export { Text } from '../chunk-QP2P6GDQ.js';
1
+ export { Text } from '../chunk-O5CEG7TQ.js';
2
2
  import '../chunk-ODEQTPFM.js';
@@ -1,7 +1,7 @@
1
1
  export { DensitySwitcher, ThemeSwitcher } from '../chunk-5V6GW6HK.js';
2
2
  export { applyStoredPreferences, resolveTheme, useDensityPreference, useSystemTheme, useThemePreference } from '../chunk-Z24ZUSTX.js';
3
3
  export { DENSITY_PREFERENCES, PALETTE_ID, THEME_PREFERENCES, applyDensity, applyPalette, applyTheme, isDensityPreference, isPaletteId, isThemePreference } from '../chunk-ZXXDZJQN.js';
4
- import '../chunk-36WK24AI.js';
4
+ import '../chunk-EVM6GYZ2.js';
5
5
  import '../chunk-AZYE7NR4.js';
6
6
  import '../chunk-MVKUE4FI.js';
7
7
  import '../chunk-EGMQURBR.js';
@@ -1,7 +1,7 @@
1
1
  export { TIME_RANGE_CUSTOM, TIME_RANGE_PICKER_LABELS, TimeRangePicker, timeRangeFieldKey, timeRangeProblem } from '../chunk-ZJVLGYE3.js';
2
2
  import '../chunk-ZXXZESCD.js';
3
3
  import '../chunk-BPCY7ZID.js';
4
- import '../chunk-36WK24AI.js';
4
+ import '../chunk-EVM6GYZ2.js';
5
5
  import '../chunk-AZYE7NR4.js';
6
6
  import '../chunk-MVKUE4FI.js';
7
7
  import '../chunk-EGMQURBR.js';
@@ -1,6 +1,6 @@
1
1
  export { VERSION_COMPARE_LABELS, VERSION_COMPARE_LENSES, VersionCompare } from '../chunk-RBQRTGXX.js';
2
2
  import '../chunk-AOFVXE6V.js';
3
- import '../chunk-36WK24AI.js';
3
+ import '../chunk-EVM6GYZ2.js';
4
4
  import '../chunk-AZYE7NR4.js';
5
5
  import '../chunk-MVKUE4FI.js';
6
6
  import '../chunk-EGMQURBR.js';
@@ -1,8 +1,8 @@
1
- import { StepList } from './chunk-RJWO2PC5.js';
1
+ import { StepList } from './chunk-TMML7BHT.js';
2
2
  import { ReceiptStrip } from './chunk-ZWCK4N4L.js';
3
3
  import { Meter } from './chunk-RQFRRPV6.js';
4
4
  import { StatusCard } from './chunk-FLW5U7YS.js';
5
- import { Disclosure } from './chunk-LVJGN5II.js';
5
+ import { Disclosure } from './chunk-NAHA62WD.js';
6
6
  import { Spinner } from './chunk-XSPCITPN.js';
7
7
  import { cx } from './chunk-ODEQTPFM.js';
8
8
  import './DeepWorkCard-CMRRNISU.css';
@@ -9,7 +9,7 @@ import { jsx } from 'react/jsx-runtime';
9
9
  var engine = null;
10
10
  var loading = null;
11
11
  function loadEngine() {
12
- loading ??= import('./Editor-5D5Z3LBQ.js').then(
12
+ loading ??= import('./Editor-VGNB35NJ.js').then(
13
13
  (module) => {
14
14
  engine = module.Editor;
15
15
  return engine;
@@ -1,3 +1,4 @@
1
+ import { Text } from './chunk-O5CEG7TQ.js';
1
2
  import { Link } from './chunk-QF5UNP4T.js';
2
3
  import { Tag } from './chunk-LBGKLYBY.js';
3
4
  import { RelativeTime } from './chunk-EJNJMHQG.js';
@@ -5,7 +6,7 @@ import { EmptyValue } from './chunk-RE3FBGQQ.js';
5
6
  import { Avatar } from './chunk-XZY6S3UC.js';
6
7
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
7
8
  import { cx } from './chunk-ODEQTPFM.js';
8
- import './TableCells-TKSNLRK3.css';
9
+ import './TableCells-ZALZLLEF.css';
9
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
11
 
11
12
  function TableKeyCell({ value, text, href, emptyLabel = "Not set" }) {
@@ -84,5 +85,38 @@ function TableTextCell({ children, icon, mark }) {
84
85
  /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__truncate", children })
85
86
  ] });
86
87
  }
88
+ function TableTwoLineCell({
89
+ value,
90
+ detail,
91
+ mono,
92
+ title,
93
+ titleWhenCut = true,
94
+ icon,
95
+ mark
96
+ }) {
97
+ const ownTitles = titleWhenCut && title === void 0;
98
+ const hasDetail = detail !== void 0 && detail !== null && detail !== false && detail !== "";
99
+ const leading = mark ?? (icon !== void 0 && icon !== null ? /* @__PURE__ */ jsx("span", { className: "crewlet-table-cell__icon", "aria-hidden": "true", children: icon }) : null);
100
+ const leads = leading !== null && leading !== void 0 && leading !== false;
101
+ const lines = /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__lines", title: leads ? void 0 : title, children: [
102
+ /* @__PURE__ */ jsx(Text, { variant: "inherit", truncate: true, mono: mono === "value" || mono === "both", titleWhenCut: ownTitles, children: value }),
103
+ hasDetail ? /* @__PURE__ */ jsx(
104
+ Text,
105
+ {
106
+ variant: "caption",
107
+ tone: "secondary",
108
+ truncate: true,
109
+ mono: mono === "detail" || mono === "both",
110
+ titleWhenCut: ownTitles,
111
+ children: detail
112
+ }
113
+ ) : null
114
+ ] });
115
+ if (!leads) return lines;
116
+ return /* @__PURE__ */ jsxs("span", { className: "crewlet-table-cell__two-line", title, children: [
117
+ leading,
118
+ lines
119
+ ] });
120
+ }
87
121
 
88
- export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell };
122
+ export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell, TableTwoLineCell };
@@ -1,6 +1,6 @@
1
1
  import { DiffList } from './chunk-LR4IWUWQ.js';
2
2
  import { Tag } from './chunk-LBGKLYBY.js';
3
- import { Disclosure } from './chunk-LVJGN5II.js';
3
+ import { Disclosure } from './chunk-NAHA62WD.js';
4
4
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './ChangeList-ITJMTVDF.css';
@@ -1,4 +1,4 @@
1
- import { CopyButton } from './chunk-T5GBTXNC.js';
1
+ import { CopyButton } from './chunk-ETNQYT5O.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './CodeBlock-T47UA5GM.css';
4
4
  import { forwardRef, useRef, useState, useLayoutEffect } from 'react';
@@ -1,4 +1,4 @@
1
- import { Copyable } from './chunk-T5GBTXNC.js';
1
+ import { Copyable } from './chunk-ETNQYT5O.js';
2
2
  import { normalizeHex } from './chunk-7W3LYIOC.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './ColorSwatch-V4DA4TK5.css';
@@ -0,0 +1,121 @@
1
+ import { Card } from './chunk-U2IQNDDR.js';
2
+ import { Button } from './chunk-DGXZ635L.js';
3
+ import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
4
+ import { VisuallyHidden } from './chunk-UT6CW3C7.js';
5
+ import { cx } from './chunk-ODEQTPFM.js';
6
+ import './AttentionList-LVX7KRET.css';
7
+ import { useId, useState } from 'react';
8
+ import { BellGlyph, ChevronDownGlyph, CircleAlertGlyph, TriangleAlertGlyph, InfoGlyph } from '@crewlethq/icons/glyphs';
9
+ import { jsxs, jsx } from 'react/jsx-runtime';
10
+
11
+ var plural = (n, one, many) => `${n} ${n === 1 ? one : many}`;
12
+ var ATTENTION_LIST_LABELS = {
13
+ title: "Needs attention",
14
+ tones: { danger: "Problem", warning: "Warning", info: "Note" },
15
+ details: "Details",
16
+ more: (hidden) => `Show ${hidden} more`,
17
+ less: "Show fewer",
18
+ summary: (c) => [
19
+ c.danger ? plural(c.danger, "problem", "problems") : "",
20
+ c.warning ? plural(c.warning, "warning", "warnings") : "",
21
+ c.info ? plural(c.info, "note", "notes") : ""
22
+ ].filter(Boolean).join(", ")
23
+ };
24
+ var ORDER = { danger: 0, warning: 1, info: 2 };
25
+ var TONES = ["danger", "warning", "info"];
26
+ function ToneGlyph({ tone, size }) {
27
+ if (tone === "danger") return /* @__PURE__ */ jsx(CircleAlertGlyph, { size });
28
+ if (tone === "warning") return /* @__PURE__ */ jsx(TriangleAlertGlyph, { size });
29
+ return /* @__PURE__ */ jsx(InfoGlyph, { size });
30
+ }
31
+ function AttentionList({ items, collapseAfter = 3, labels: overrides, headingLevel, className }) {
32
+ const contextLevel = useHeadingLevel();
33
+ const Heading = headingTag(headingLevel ?? contextLevel);
34
+ const words = {
35
+ ...ATTENTION_LIST_LABELS,
36
+ ...overrides,
37
+ tones: { ...ATTENTION_LIST_LABELS.tones, ...overrides?.tones }
38
+ };
39
+ const id = useId();
40
+ const [expanded, setExpanded] = useState(false);
41
+ const [opened, setOpened] = useState(/* @__PURE__ */ new Set());
42
+ if (items.length === 0) return null;
43
+ const ordered = [...items].sort((a, b) => ORDER[a.tone] - ORDER[b.tone]);
44
+ const counts = { danger: 0, warning: 0, info: 0 };
45
+ for (const i of items) counts[i.tone] += 1;
46
+ const folds = ordered.length > collapseAfter + 1;
47
+ const shown = folds && !expanded ? ordered.slice(0, collapseAfter) : ordered;
48
+ const media = ordered.some((item) => item.media != null);
49
+ return /* @__PURE__ */ jsxs(Card, { as: "section", padding: "none", className: cx("crewlet-attention-list", className), children: [
50
+ /* @__PURE__ */ jsx(
51
+ Card.Header,
52
+ {
53
+ icon: /* @__PURE__ */ jsx(BellGlyph, { size: "sm" }),
54
+ actions: /* @__PURE__ */ jsxs("span", { className: "crewlet-attention-list__counts", children: [
55
+ TONES.filter((tone) => counts[tone] > 0).map((tone) => /* @__PURE__ */ jsxs("span", { className: cx("crewlet-attention-list__count", `is-${tone}`), "aria-hidden": true, children: [
56
+ /* @__PURE__ */ jsx(ToneGlyph, { tone, size: "xs" }),
57
+ counts[tone]
58
+ ] }, tone)),
59
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: words.summary(counts) })
60
+ ] }),
61
+ children: /* @__PURE__ */ jsx(Card.Title, { as: Heading, children: words.title })
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsxs(Card.Body, { padding: "none", children: [
65
+ /* @__PURE__ */ jsx("ul", { className: cx("crewlet-attention-list__rows", media && "crewlet-attention-list__rows--media"), children: shown.map((item, index) => {
66
+ const open = opened.has(item.key);
67
+ const panel = `${id}-${index}`;
68
+ return /* @__PURE__ */ jsxs("li", { className: "crewlet-attention-list__item", children: [
69
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-attention-list__row", children: [
70
+ /* @__PURE__ */ jsx("span", { className: cx("crewlet-attention-list__glyph", `is-${item.tone}`), "aria-hidden": true, children: /* @__PURE__ */ jsx(ToneGlyph, { tone: item.tone, size: "sm" }) }),
71
+ item.media != null ? /* @__PURE__ */ jsx("span", { className: "crewlet-attention-list__media", "aria-hidden": true, children: item.media }) : null,
72
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-attention-list__text", children: [
73
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-attention-list__line", children: [
74
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: `${words.tones[item.tone]}: ` }),
75
+ item.title
76
+ ] }),
77
+ item.meta ? /* @__PURE__ */ jsx("span", { className: "crewlet-attention-list__meta", children: item.meta }) : null
78
+ ] }),
79
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-attention-list__end", children: [
80
+ item.details ? /* @__PURE__ */ jsx(
81
+ Button,
82
+ {
83
+ variant: "ghost",
84
+ size: "small",
85
+ flush: true,
86
+ className: "crewlet-attention-list__details",
87
+ "aria-expanded": open,
88
+ "aria-controls": open ? panel : void 0,
89
+ trailingIcon: /* @__PURE__ */ jsx(ChevronDownGlyph, { size: "xs" }),
90
+ onClick: () => setOpened((was) => {
91
+ const next = new Set(was);
92
+ if (next.has(item.key)) next.delete(item.key);
93
+ else next.add(item.key);
94
+ return next;
95
+ }),
96
+ children: words.details
97
+ }
98
+ ) : null,
99
+ item.action != null ? /* @__PURE__ */ jsx("span", { className: "crewlet-attention-list__action", children: item.action }) : null
100
+ ] })
101
+ ] }),
102
+ item.details && open ? /* @__PURE__ */ jsx("div", { id: panel, className: "crewlet-attention-list__body", children: item.details }) : null
103
+ ] }, item.key);
104
+ }) }),
105
+ folds ? /* @__PURE__ */ jsx("div", { className: "crewlet-attention-list__foot", children: /* @__PURE__ */ jsx(
106
+ Button,
107
+ {
108
+ variant: "ghost",
109
+ size: "small",
110
+ flush: true,
111
+ className: "crewlet-attention-list__more",
112
+ "aria-expanded": expanded,
113
+ onClick: () => setExpanded((e) => !e),
114
+ children: expanded ? words.less : words.more(ordered.length - collapseAfter)
115
+ }
116
+ ) }) : null
117
+ ] })
118
+ ] });
119
+ }
120
+
121
+ export { ATTENTION_LIST_LABELS, AttentionList };
@@ -1,4 +1,4 @@
1
- import { StepStateMark } from './chunk-RJWO2PC5.js';
1
+ import { StepStateMark } from './chunk-TMML7BHT.js';
2
2
  import { DisclosureAnatomy } from './chunk-ULYHDP7U.js';
3
3
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- import { Text } from './chunk-QP2P6GDQ.js';
1
+ import { Text } from './chunk-O5CEG7TQ.js';
2
2
  import { Inline, Stack, Spacer } from './chunk-ZAC7SKUN.js';
3
3
  import { Card } from './chunk-U2IQNDDR.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,7 +1,7 @@
1
1
  import { DisclosureAnatomy } from './chunk-ULYHDP7U.js';
2
2
  import { useHeadingLevel } from './chunk-PQADV6P6.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
- import './Disclosure-D727FN5X.css';
4
+ import './Disclosure-RJSKKO7Z.css';
5
5
  import './Accordion-V7YNDK7Y.css';
6
6
  import { createContext, useState, useCallback, useMemo, useContext, useId } from 'react';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -3,7 +3,7 @@ import { Button } from './chunk-DGXZ635L.js';
3
3
  import { IconButton } from './chunk-UAUP6XGK.js';
4
4
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
- import './Copyable-IS3MHMPL.css';
6
+ import './Copyable-P5AMRHFX.css';
7
7
  import { useCallback } from 'react';
8
8
  import { CheckGlyph, CircleAlertGlyph, CopyGlyph } from '@crewlethq/icons/glyphs';
9
9
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,3 +1,3 @@
1
1
  import './HitArea-QUOS6ZDJ.css';
2
2
  import './Tabs-M2ELSU3V.css';
3
- import './SegmentedControl-B7XCUOML.css';
3
+ import './SegmentedControl-7GY2KM44.css';
@@ -1,7 +1,7 @@
1
1
  import { StatusDot } from './chunk-CYQBDZ6M.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
- import './ChoiceCards-TVMBO3HZ.css';
4
- import { useId } from 'react';
3
+ import './ChoiceCards-KHJW2FKO.css';
4
+ import { useId, Fragment } from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
7
7
  function ChoiceCards({
@@ -19,6 +19,8 @@ function ChoiceCards({
19
19
  const inFact = (o) => o.disabledReasonAt !== void 0 && o.disabledReasonAt >= 0 && o.disabledReasonAt < (o.facts?.length ?? 0);
20
20
  const reasons = options.some((o) => o.disabled && o.disabledReason && !inFact(o)) ? 1 : 0;
21
21
  const rows = { "--crewlet-choice-cards-rows": 1 + (described ? 1 : 0) + facts + reasons };
22
+ const chosen = options.find((o) => o.value === value && o.detail != null && !o.disabled) ?? null;
23
+ const detailId = `${name}-detail`;
22
24
  return /* @__PURE__ */ jsx(
23
25
  "div",
24
26
  {
@@ -43,7 +45,7 @@ function ChoiceCards({
43
45
  ...(option.facts ?? []).map((_, at) => at === reasonAt ? reason : part(`fact-${at}`)),
44
46
  reasonAt < 0 ? reason : null
45
47
  ].filter(Boolean).join(" ");
46
- return /* @__PURE__ */ jsxs(
48
+ const card = /* @__PURE__ */ jsxs(
47
49
  "label",
48
50
  {
49
51
  htmlFor: id,
@@ -60,6 +62,7 @@ function ChoiceCards({
60
62
  disabled: option.disabled,
61
63
  "aria-labelledby": labelledBy,
62
64
  "aria-describedby": describedBy || void 0,
65
+ "aria-controls": option === chosen ? detailId : void 0,
63
66
  onChange: () => onChange(option.value),
64
67
  className: "crewlet-choice-cards__radio"
65
68
  }
@@ -67,7 +70,7 @@ function ChoiceCards({
67
70
  /* @__PURE__ */ jsxs("span", { className: "crewlet-choice-cards__title", children: [
68
71
  option.media != null ? /* @__PURE__ */ jsx("span", { className: "crewlet-choice-cards__media", "aria-hidden": true, children: option.media }) : null,
69
72
  /* @__PURE__ */ jsx("span", { id: part("label"), className: "crewlet-choice-cards__label", children: option.label }),
70
- option.tag ? /* @__PURE__ */ jsx("span", { id: part("tag"), className: "crewlet-choice-cards__tag", children: option.tag }) : null
73
+ option.tag ? /* @__PURE__ */ jsx("span", { id: part("tag"), className: cx("crewlet-choice-cards__tag", option.tagTone && `is-${option.tagTone}`), children: option.tag }) : null
71
74
  ] }),
72
75
  option.description ? /* @__PURE__ */ jsx("span", { id: part("description"), className: "crewlet-choice-cards__description", children: option.description }) : described ? /* @__PURE__ */ jsx("span", { className: "crewlet-choice-cards__description", "aria-hidden": true }) : null,
73
76
  option.facts && option.facts.length > 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-choice-cards__facts", children: option.facts.map((fact, at) => /* @__PURE__ */ jsxs(
@@ -88,6 +91,11 @@ function ChoiceCards({
88
91
  },
89
92
  option.value
90
93
  );
94
+ if (option !== chosen) return card;
95
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ card,
97
+ /* @__PURE__ */ jsx("div", { id: detailId, role: "group", "aria-labelledby": part("label"), className: "crewlet-choice-cards__detail", children: option.detail })
98
+ ] }, option.value);
91
99
  })
92
100
  }
93
101
  );
@@ -0,0 +1,148 @@
1
+ import { Checkbox } from './chunk-YQ7Q52XU.js';
2
+ import { IconButton } from './chunk-UAUP6XGK.js';
3
+ import { cx } from './chunk-ODEQTPFM.js';
4
+ import './MemberPicker-ZD35VEK6.css';
5
+ import { useId, useState } from 'react';
6
+ import { ChevronRightGlyph } from '@crewlethq/icons/glyphs';
7
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
+
9
+ var MEMBER_PICKER_LABELS = {
10
+ later: "Includes agents who join later",
11
+ through: (group) => `Through ${group}`,
12
+ leftOut: "Left out",
13
+ summary: (chosen, total) => `${chosen} of ${total} ${total === 1 ? "agent" : "agents"}`,
14
+ count: (n) => `${n} ${n === 1 ? "agent" : "agents"}`,
15
+ expand: (group) => `Show the agents in ${group}`
16
+ };
17
+ var without = (list, drop) => list.filter((k) => !drop.includes(k));
18
+ var plus = (list, add) => [.../* @__PURE__ */ new Set([...list, ...add])];
19
+ function chosenMembers(groups, ungrouped, value) {
20
+ const out = /* @__PURE__ */ new Set();
21
+ for (const g of groups) {
22
+ for (const m of g.members) {
23
+ if (value.groups.includes(g.key) && !value.except.includes(m.key) || value.members.includes(m.key)) out.add(m.key);
24
+ }
25
+ }
26
+ for (const m of ungrouped) if (value.members.includes(m.key)) out.add(m.key);
27
+ return out;
28
+ }
29
+ function MemberPicker({
30
+ label,
31
+ groups,
32
+ ungrouped = [],
33
+ value,
34
+ onChange,
35
+ defaultOpen = [],
36
+ labels: overrides,
37
+ className
38
+ }) {
39
+ const words = { ...MEMBER_PICKER_LABELS, ...overrides };
40
+ const id = useId();
41
+ const [open, setOpen] = useState(
42
+ () => /* @__PURE__ */ new Set([
43
+ ...defaultOpen,
44
+ ...groups.filter((g) => g.members.some((m) => value.except.includes(m.key) || value.members.includes(m.key))).map((g) => g.key)
45
+ ])
46
+ );
47
+ const total = (/* @__PURE__ */ new Set([...groups.flatMap((g) => g.members.map((m) => m.key)), ...ungrouped.map((m) => m.key)])).size;
48
+ const chosen = chosenMembers(groups, ungrouped, value);
49
+ const toggleGroup = (g, on) => {
50
+ const keys = g.members.map((m) => m.key);
51
+ onChange({
52
+ groups: on ? plus(value.groups, [g.key]) : without(value.groups, [g.key]),
53
+ // THE GROUP'S OWN OVERRIDES GO EITHER WAY: chosen whole, nobody is left
54
+ // out or chosen twice; unchosen, nobody stays chosen behind its back.
55
+ members: without(value.members, keys),
56
+ except: without(value.except, keys)
57
+ });
58
+ };
59
+ const toggleMember = (m, on) => {
60
+ const reached = groups.some((g) => value.groups.includes(g.key) && g.members.some((x) => x.key === m.key));
61
+ onChange({
62
+ ...value,
63
+ members: on && !reached ? plus(value.members, [m.key]) : without(value.members, [m.key]),
64
+ except: !on && reached ? plus(value.except, [m.key]) : without(value.except, [m.key])
65
+ });
66
+ };
67
+ const memberRow = (m, group, at) => {
68
+ const viaGroup = !!group && value.groups.includes(group.key);
69
+ const leftOut = viaGroup && value.except.includes(m.key);
70
+ const mark = viaGroup ? leftOut ? words.leftOut : words.through(group.label) : null;
71
+ const detailId = m.detail ? `${id}-${at}-detail` : null;
72
+ const markId = mark ? `${id}-${at}-mark` : null;
73
+ const describedBy = cx(detailId, markId);
74
+ const boxId = `${id}-${at}-box`;
75
+ return /* @__PURE__ */ jsxs("li", { className: cx("crewlet-member-picker__member", leftOut && "is-left-out"), children: [
76
+ /* @__PURE__ */ jsx(
77
+ Checkbox,
78
+ {
79
+ id: boxId,
80
+ label: m.name,
81
+ hideLabel: true,
82
+ size: "sm",
83
+ checked: chosen.has(m.key),
84
+ onCheckedChange: (on) => toggleMember(m, on),
85
+ ...describedBy ? { "aria-describedby": describedBy } : {}
86
+ }
87
+ ),
88
+ m.avatar != null ? /* @__PURE__ */ jsx("span", { className: "crewlet-member-picker__avatar", "aria-hidden": true, children: m.avatar }) : null,
89
+ /* @__PURE__ */ jsxs("label", { htmlFor: boxId, className: "crewlet-member-picker__text", children: [
90
+ /* @__PURE__ */ jsx("span", { className: "crewlet-member-picker__name", children: m.name }),
91
+ detailId ? /* @__PURE__ */ jsx("span", { id: detailId, className: "crewlet-member-picker__detail", children: m.detail }) : null
92
+ ] }),
93
+ markId ? /* @__PURE__ */ jsx("span", { id: markId, className: cx("crewlet-member-picker__mark", leftOut && "is-left-out"), children: mark }) : null
94
+ ] }, m.key);
95
+ };
96
+ return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-member-picker", className), role: "group", "aria-label": label, children: [
97
+ /* @__PURE__ */ jsx("p", { className: "crewlet-member-picker__summary", "aria-live": "polite", children: words.summary(chosen.size, total) }),
98
+ /* @__PURE__ */ jsxs("ul", { className: "crewlet-member-picker__list", children: [
99
+ groups.map((g, gi) => {
100
+ const whole = value.groups.includes(g.key);
101
+ const reached = g.members.filter((m) => chosen.has(m.key)).length;
102
+ const all = g.members.length > 0 && reached === g.members.length;
103
+ const ticked = whole && (all || g.members.length === 0);
104
+ const mixed = !ticked && reached + (whole ? 1 : 0) > 0;
105
+ const isOpen = open.has(g.key);
106
+ const panel = `${id}-g${gi}`;
107
+ return /* @__PURE__ */ jsxs("li", { className: cx("crewlet-member-picker__group", isOpen && "is-open"), children: [
108
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-member-picker__group-row", children: [
109
+ /* @__PURE__ */ jsx(
110
+ IconButton,
111
+ {
112
+ size: "sm",
113
+ variant: "ghost",
114
+ className: "crewlet-member-picker__toggle",
115
+ label: words.expand(g.label),
116
+ icon: /* @__PURE__ */ jsx(ChevronRightGlyph, { size: "sm" }),
117
+ "aria-expanded": isOpen,
118
+ "aria-controls": isOpen ? panel : void 0,
119
+ onClick: () => setOpen((was) => {
120
+ const next = new Set(was);
121
+ if (next.has(g.key)) next.delete(g.key);
122
+ else next.add(g.key);
123
+ return next;
124
+ })
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx(
128
+ Checkbox,
129
+ {
130
+ label: g.label,
131
+ size: "sm",
132
+ checked: ticked,
133
+ indeterminate: mixed,
134
+ description: whole ? words.later : void 0,
135
+ onCheckedChange: () => toggleGroup(g, !ticked)
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx("span", { className: "crewlet-member-picker__count", children: words.count(g.members.length) })
139
+ ] }),
140
+ isOpen ? /* @__PURE__ */ jsx("ul", { id: panel, className: "crewlet-member-picker__members", children: g.members.map((m, mi) => memberRow(m, g, `g${gi}-m${mi}`)) }) : null
141
+ ] }, g.key);
142
+ }),
143
+ ungrouped.length > 0 ? /* @__PURE__ */ jsx("li", { className: "crewlet-member-picker__group", children: /* @__PURE__ */ jsx("ul", { className: "crewlet-member-picker__members is-ungrouped", children: ungrouped.map((m, mi) => memberRow(m, null, `u-m${mi}`)) }) }) : null
144
+ ] })
145
+ ] });
146
+ }
147
+
148
+ export { MEMBER_PICKER_LABELS, MemberPicker, chosenMembers };
@@ -4,7 +4,7 @@ import { EmptyState } from './chunk-PPUR46MK.js';
4
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-Q26F2V5Q.css';
7
+ import './DataGrid-SAHEL4SN.css';
8
8
  import { useId, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useSyncExternalStore, useEffect } from 'react';
9
9
  import { breakpoint } from '@crewlethq/tokens';
10
10
  import { ArrowDownGlyph, ArrowUpGlyph, ArrowUpDownGlyph } from '@crewlethq/icons/glyphs';
@@ -414,7 +414,8 @@ function DataGrid({
414
414
  "crewlet-data-grid__cell",
415
415
  alignOf(column) !== "left" && `crewlet-data-grid__cell--${alignOf(column)}`,
416
416
  column.icon && "crewlet-data-grid__cell--icon",
417
- column.shrink && "crewlet-data-grid__cell--shrink"
417
+ column.shrink && "crewlet-data-grid__cell--shrink",
418
+ column.action && "crewlet-data-grid__cell--action"
418
419
  ),
419
420
  "data-lead": column.phoneLead || void 0,
420
421
  "data-phone-omit": column.phoneOmit || void 0,
@@ -1,8 +1,8 @@
1
1
  import { RefusalStrip, ReceiptStrip } from './chunk-ZWCK4N4L.js';
2
- import { ChangeList } from './chunk-AOJ6ZA77.js';
2
+ import { ChangeList } from './chunk-3MFRTZH6.js';
3
3
  import { StatusCard } from './chunk-FLW5U7YS.js';
4
4
  import { Checkbox } from './chunk-YQ7Q52XU.js';
5
- import { Disclosure } from './chunk-LVJGN5II.js';
5
+ import { Disclosure } from './chunk-NAHA62WD.js';
6
6
  import { Button } from './chunk-DGXZ635L.js';
7
7
  import { Spinner } from './chunk-XSPCITPN.js';
8
8
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,7 +1,7 @@
1
1
  import { DisclosureAnatomy } from './chunk-ULYHDP7U.js';
2
2
  import { useHeadingLevel } from './chunk-PQADV6P6.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
- import './Disclosure-D727FN5X.css';
4
+ import './Disclosure-RJSKKO7Z.css';
5
5
  import { useState, useId, useCallback } from 'react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
 
@@ -17,6 +17,7 @@ function Disclosure({
17
17
  lazy = false,
18
18
  variant = "default",
19
19
  size = "default",
20
+ flush = false,
20
21
  headingLevel,
21
22
  className,
22
23
  children,
@@ -39,6 +40,7 @@ function Disclosure({
39
40
  "crewlet-disclosure",
40
41
  `crewlet-disclosure--${variant}`,
41
42
  size === "compact" && "crewlet-disclosure--compact",
43
+ flush && "crewlet-disclosure--flush",
42
44
  className
43
45
  ),
44
46
  "data-state": open ? "open" : "closed",
@@ -11,14 +11,22 @@ function Text({
11
11
  truncate = false,
12
12
  clamp,
13
13
  measure,
14
+ titleWhenCut = true,
14
15
  className,
15
16
  children,
16
17
  ...rest
17
18
  }) {
19
+ const cuts = truncate || clamp !== void 0;
20
+ const measures = cuts && titleWhenCut && rest.title === void 0;
21
+ const { onMouseEnter } = rest;
18
22
  return /* @__PURE__ */ jsx(
19
23
  Tag,
20
24
  {
21
25
  ...rest,
26
+ onMouseEnter: measures ? (event) => {
27
+ titleIfCut(event.currentTarget, truncate ? "inline" : "block");
28
+ onMouseEnter?.(event);
29
+ } : onMouseEnter,
22
30
  className: cx(
23
31
  "crewlet-text",
24
32
  `crewlet-text--${variant}`,
@@ -34,5 +42,11 @@ function Text({
34
42
  }
35
43
  );
36
44
  }
45
+ function titleIfCut(element, axis) {
46
+ const cut = axis === "inline" ? element.scrollWidth > element.clientWidth : element.scrollHeight > element.clientHeight;
47
+ const words = (element.textContent ?? "").replace(/\s+/g, " ").trim();
48
+ if (cut && words !== "") element.setAttribute("title", words);
49
+ else element.removeAttribute("title");
50
+ }
37
51
 
38
52
  export { Text };
@@ -1,5 +1,5 @@
1
1
  import { FileDrop, FilePickButton } from './chunk-KQWJWTED.js';
2
- import { contrastRatio } from './chunk-2ZSCHQOA.js';
2
+ import { contrastRatio } from './chunk-WMSXPF7T.js';
3
3
  import { normalizeHex } from './chunk-7W3LYIOC.js';
4
4
  import { Button } from './chunk-DGXZ635L.js';
5
5
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';