@crewlethq/ui 0.45.0 → 0.47.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 (123) hide show
  1. package/README.md +28 -0
  2. package/dist/AgentHandoffPanel/index.js +6 -3
  3. package/dist/AppShell/index.js +3 -3
  4. package/dist/ArrangeList/index.js +5 -3
  5. package/dist/ArtifactBar/index.js +5 -5
  6. package/dist/AvatarPicker/index.js +6 -6
  7. package/dist/Canvas/index.js +1 -1
  8. package/dist/CanvasBoard/index.js +1 -1
  9. package/dist/CanvasToolbar/index.js +1 -1
  10. package/dist/CatalogTile/index.js +1 -1
  11. package/dist/{CatalogTile-VPSLCKJE.css → CatalogTile-26XN7L2A.css} +13 -7
  12. package/dist/CharacterCount/CharacterCount.d.ts +63 -0
  13. package/dist/CharacterCount/index.d.ts +3 -0
  14. package/dist/CharacterCount/index.js +4 -0
  15. package/dist/CharacterCount-S735DICR.css +29 -0
  16. package/dist/Checkbox/index.js +5 -2
  17. package/dist/Combobox/index.js +5 -3
  18. package/dist/CommandPalette/index.js +6 -4
  19. package/dist/CommentThread/index.js +6 -3
  20. package/dist/Composer/index.js +5 -2
  21. package/dist/ConfirmField/index.js +5 -2
  22. package/dist/DataTable/index.js +8 -6
  23. package/dist/DataView/index.js +9 -7
  24. package/dist/DateTimePicker/index.js +1 -1
  25. package/dist/DocTabsEditor/index.js +5 -4
  26. package/dist/EditingStatus/index.js +2 -1
  27. package/dist/{Editor-AMO2B54T.js → Editor-MLGK3KOG.js} +6 -4
  28. package/dist/FollowBanner/index.js +2 -2
  29. package/dist/HuePicker/index.js +5 -5
  30. package/dist/InlineEditor/InlineEditor.d.ts +86 -0
  31. package/dist/InlineEditor/index.d.ts +3 -0
  32. package/dist/InlineEditor/index.js +9 -0
  33. package/dist/InlineEditor-W55DDKML.css +72 -0
  34. package/dist/Input/FormField.d.ts +27 -1
  35. package/dist/Input/Textarea.d.ts +16 -0
  36. package/dist/Input/index.d.ts +3 -2
  37. package/dist/Input/index.js +4 -1
  38. package/dist/{Input-OQZBCRX5.css → Input-VDSV7VWJ.css} +19 -0
  39. package/dist/LinkInterstitial/index.js +3 -3
  40. package/dist/List/List.d.ts +16 -1
  41. package/dist/List/index.js +1 -1
  42. package/dist/{List-YHLIZFK4.css → List-XY445TKY.css} +31 -0
  43. package/dist/ListInput/ListInput.d.ts +87 -2
  44. package/dist/ListInput/index.d.ts +2 -2
  45. package/dist/ListInput/index.js +5 -2
  46. package/dist/{ListInput-O7LJKOIG.css → ListInput-WUP2YITQ.css} +147 -2
  47. package/dist/MarkdownEditor/index.js +5 -5
  48. package/dist/Menu/index.js +2 -2
  49. package/dist/MergeConflicts/index.js +5 -5
  50. package/dist/Modal/index.js +2 -2
  51. package/dist/PresenterView/index.js +3 -3
  52. package/dist/PrincipalPicker/index.js +6 -4
  53. package/dist/RelatedRow/index.js +2 -2
  54. package/dist/RichEditor/index.js +1 -1
  55. package/dist/SegmentedControl/index.js +4 -4
  56. package/dist/Select/index.js +1 -1
  57. package/dist/ShareDialog/index.js +3 -3
  58. package/dist/SheetColumnEditor/index.js +10 -8
  59. package/dist/SheetGrid/index.js +3 -3
  60. package/dist/SlideCompare/index.js +1 -1
  61. package/dist/SlideFilmstrip/index.js +3 -3
  62. package/dist/Switcher/index.js +5 -4
  63. package/dist/Tabs/index.js +3 -3
  64. package/dist/Text/Text.d.ts +8 -0
  65. package/dist/Text/index.js +1 -1
  66. package/dist/{Text-S3Q4O3IG.css → Text-XOCOU34C.css} +9 -0
  67. package/dist/ThemeSwitcher/index.js +5 -5
  68. package/dist/TileGrid/index.js +1 -1
  69. package/dist/{TileGrid-I6LNYD2H.css → TileGrid-UYMVVVJK.css} +30 -0
  70. package/dist/TimeWindowPicker/index.js +5 -3
  71. package/dist/TreeCanvas/index.js +1 -1
  72. package/dist/VersionCompare/index.js +5 -5
  73. package/dist/{chunk-5AHDGYKN.js → chunk-2KQR6JKE.js} +2 -2
  74. package/dist/{chunk-4DIKLY53.js → chunk-32TGEMQQ.js} +1 -1
  75. package/dist/{chunk-QOP7QYUW.js → chunk-34RMTXDZ.js} +1 -1
  76. package/dist/{chunk-Q7HLZH32.js → chunk-3QSKDZR5.js} +1 -1
  77. package/dist/{chunk-BVFMLSE3.js → chunk-5EBDOE3C.js} +1 -1
  78. package/dist/{chunk-W53CWWX3.js → chunk-627KFRON.js} +2 -2
  79. package/dist/{chunk-AGNZIT3Z.js → chunk-6EBGPCAW.js} +1 -1
  80. package/dist/{chunk-BF5WV7NM.js → chunk-6FVGSWLS.js} +1 -1
  81. package/dist/{chunk-7CXGSS7D.js → chunk-6R5BSA36.js} +1 -1
  82. package/dist/{chunk-NF6SWHQI.js → chunk-7JED2NYP.js} +2 -2
  83. package/dist/chunk-7P336RA5.js +147 -0
  84. package/dist/{chunk-GI3S6RMM.js → chunk-AS2BMY3E.js} +3 -3
  85. package/dist/{chunk-N3SHQ3VU.js → chunk-CWKWMIIJ.js} +1 -1
  86. package/dist/{chunk-KKUJSMLF.js → chunk-DY4DQ7EB.js} +1 -1
  87. package/dist/{chunk-ZI5G5RS7.js → chunk-EXRRTKWT.js} +59 -9
  88. package/dist/{chunk-EY7LACIR.js → chunk-F57N6ZJG.js} +1 -1
  89. package/dist/chunk-ICVS3U4S.js +436 -0
  90. package/dist/{chunk-KA75QPFM.js → chunk-ILFEWRLG.js} +1 -1
  91. package/dist/{chunk-JF3TJUBU.js → chunk-JWNYI7UD.js} +1 -1
  92. package/dist/{chunk-GPIRKHGS.js → chunk-LIJQT74Y.js} +1 -1
  93. package/dist/{chunk-TC7DJTXI.js → chunk-MULOZYHL.js} +2 -0
  94. package/dist/{chunk-FV6H7H5I.js → chunk-MUQJCH2Y.js} +4 -4
  95. package/dist/{chunk-ZUTUI27P.js → chunk-N4GBDK4L.js} +1 -1
  96. package/dist/{chunk-Y4GXCKOC.js → chunk-OHJ2R2X4.js} +3 -3
  97. package/dist/{chunk-OWIGEE2Y.js → chunk-OO7QJCJQ.js} +2 -2
  98. package/dist/{chunk-MVGCZ655.js → chunk-OOJTPR7N.js} +1 -1
  99. package/dist/{chunk-NNTO3TNC.js → chunk-Q6CQMS6R.js} +1 -1
  100. package/dist/{chunk-IKBK4A5O.js → chunk-QP2P6GDQ.js} +1 -1
  101. package/dist/{chunk-U44WGRFW.js → chunk-RFPCHMSX.js} +1 -1
  102. package/dist/{chunk-LSRQJDGR.js → chunk-SEPSXOGJ.js} +1 -1
  103. package/dist/{chunk-MCOC3KQA.js → chunk-SQ4JFHO7.js} +1 -1
  104. package/dist/{chunk-DL5ERIFF.js → chunk-SS4XCUUJ.js} +2 -2
  105. package/dist/{chunk-NZWX27J7.js → chunk-TDQ262TB.js} +19 -3
  106. package/dist/{chunk-5GNA4RKP.js → chunk-TGSIVB6H.js} +1 -1
  107. package/dist/{chunk-6MAQ2SVP.js → chunk-TWZEWXNW.js} +3 -3
  108. package/dist/{chunk-UO5VJHWP.js → chunk-U4HOKU6P.js} +2 -2
  109. package/dist/{chunk-X6IJ7DAX.js → chunk-VKFG4FLE.js} +2 -2
  110. package/dist/chunk-XCUUI7E7.js +62 -0
  111. package/dist/{chunk-ENHLVF6Q.js → chunk-XS2FJVMT.js} +1 -1
  112. package/dist/{chunk-FG243QHY.js → chunk-ZCIL5IHU.js} +1 -1
  113. package/dist/generated/index.d.ts +2 -0
  114. package/dist/generated/index.js +76 -74
  115. package/dist/index.js +76 -74
  116. package/dist/styles.css +362 -15
  117. package/package.json +3 -3
  118. package/dist/chunk-NMYGJJJK.js +0 -263
  119. package/dist/{chunk-6IPEPSB5.js → chunk-245IXG5P.js} +0 -0
  120. package/dist/{chunk-OED6LUWE.js → chunk-4A4QG6UC.js} +1 -1
  121. package/dist/{chunk-FYINAYAJ.js → chunk-6AKG2VLR.js} +1 -1
  122. package/dist/{chunk-E6HXFFWO.js → chunk-ISDEXIXH.js} +1 -1
  123. package/dist/{chunk-PCI7ZJ6Z.js → chunk-TMM32U7D.js} +1 -1
@@ -0,0 +1,436 @@
1
+ import { useReorder } from './chunk-XJ2QEBMM.js';
2
+ import { FormField, Textarea } from './chunk-EXRRTKWT.js';
3
+ import { characterCountState, CharacterCount, countCharacters } from './chunk-XCUUI7E7.js';
4
+ import { Kbd } from './chunk-SMBKXWML.js';
5
+ import { announce } from './chunk-RSAQOKH3.js';
6
+ import { Button } from './chunk-OG6CL3EB.js';
7
+ import { isComposing } from './chunk-H5XTJ7GJ.js';
8
+ import { IconButton } from './chunk-LACA4JGC.js';
9
+ import { cx } from './chunk-ODEQTPFM.js';
10
+ import './ListInput-WUP2YITQ.css';
11
+ import { forwardRef, useState, useRef, useImperativeHandle, useLayoutEffect, useId } from 'react';
12
+ import { PlusGlyph, GripVerticalGlyph, ArrowUpGlyph, ArrowDownGlyph, XGlyph } from '@crewlethq/icons/glyphs';
13
+ import { jsx, jsxs } from 'react/jsx-runtime';
14
+
15
+ function withDraft(value, draft) {
16
+ const text = (draft ?? "").trim();
17
+ return text === "" ? [...value] : [...value, text];
18
+ }
19
+ var minted = 0;
20
+ var mint = () => `item-${minted += 1}`;
21
+ var capitalized = (text) => text.charAt(0).toLocaleUpperCase() + text.slice(1);
22
+ var ListInput = forwardRef(function ListInput2({
23
+ label,
24
+ itemName,
25
+ value,
26
+ onChange,
27
+ draft: ownedDraft,
28
+ onDraftChange,
29
+ hideLabel = false,
30
+ multiline = false,
31
+ helper,
32
+ helperOnFocus,
33
+ error,
34
+ placeholder,
35
+ disabled = false,
36
+ optional,
37
+ enterHint = true,
38
+ focusOnMount = false,
39
+ reorderByDrag = false,
40
+ maxItems,
41
+ maxLength,
42
+ undoRemove = false,
43
+ itemError,
44
+ fullMessage = (max) => `The list is full at ${max}. Remove one to add another.`,
45
+ addLabel = (name) => `Add ${name}`,
46
+ itemLabel = (name, position) => `${name} ${position}`,
47
+ newItemLabel = (name) => `New ${name}`,
48
+ moveUpLabel = (name, position) => `Move ${name} ${position} up`,
49
+ moveDownLabel = (name, position) => `Move ${name} ${position} down`,
50
+ removeLabel = (name, position) => `Remove ${name} ${position}`,
51
+ addedMessage = (name, position) => `Added ${name} ${position}`,
52
+ removedMessage = (name, position) => `Removed ${name} ${position}`,
53
+ movedMessage = (name, position, count) => `Moved ${name} to position ${position} of ${count}`,
54
+ removedNotice = (name, position) => `${name} ${position} removed.`,
55
+ undoLabel = "Undo",
56
+ dismissLabel = "Dismiss",
57
+ restoredMessage = (name, position) => `Restored ${name} ${position}`
58
+ }, ref) {
59
+ const [heldDraft, setHeldDraft] = useState("");
60
+ const draft = ownedDraft ?? heldDraft;
61
+ const setDraft = (next) => {
62
+ if (ownedDraft === void 0) setHeldDraft(next);
63
+ onDraftChange?.(next);
64
+ };
65
+ const [removed, setRemoved] = useState(null);
66
+ const ids = useRef([]);
67
+ const emitted = useRef(null);
68
+ if (value !== emitted.current && value.length !== ids.current.length) {
69
+ ids.current = value.map(mint);
70
+ if (removed !== null) setRemoved(null);
71
+ }
72
+ const inputs = useRef(/* @__PURE__ */ new Map());
73
+ const ups = useRef(/* @__PURE__ */ new Map());
74
+ const downs = useRef(/* @__PURE__ */ new Map());
75
+ const addBox = useRef(null);
76
+ const undoButton = useRef(null);
77
+ const focusNext = useRef(null);
78
+ const focusField = (el) => {
79
+ if (!el) return;
80
+ el.focus();
81
+ el.setSelectionRange(el.value.length, el.value.length);
82
+ };
83
+ useImperativeHandle(ref, () => ({
84
+ focusItem: (index) => {
85
+ const id = ids.current[index];
86
+ if (id !== void 0) focusField(inputs.current.get(id));
87
+ },
88
+ focusNew: () => addBox.current?.focus()
89
+ }));
90
+ const focusAtMount = useRef(focusOnMount);
91
+ useLayoutEffect(() => {
92
+ if (focusAtMount.current) addBox.current?.focus();
93
+ }, []);
94
+ useLayoutEffect(() => {
95
+ const want = focusNext.current;
96
+ if (!want) return;
97
+ focusNext.current = null;
98
+ if (want.target === "add") {
99
+ addBox.current?.focus();
100
+ return;
101
+ }
102
+ if (want.target === "undo") {
103
+ undoButton.current?.focus();
104
+ return;
105
+ }
106
+ const up = ups.current.get(want.id);
107
+ const down = downs.current.get(want.id);
108
+ const box = inputs.current.get(want.id);
109
+ const order2 = want.target === "up" ? [up, down, box] : want.target === "down" ? [down, up, box] : [box];
110
+ order2.find((el) => el && !el.disabled)?.focus();
111
+ });
112
+ function emit(next, nextIds, said, leaving = null) {
113
+ ids.current = nextIds;
114
+ emitted.current = next;
115
+ setRemoved(leaving);
116
+ onChange(next);
117
+ if (said) announce(said);
118
+ }
119
+ const name = capitalized(itemName);
120
+ const count = value.length;
121
+ const listId = useId();
122
+ const full = maxItems !== void 0 && count >= maxItems;
123
+ const measured = (text) => countCharacters(text.trim());
124
+ const overLimit = (text) => maxLength !== void 0 && characterCountState(measured(text), maxLength) === "over";
125
+ const draftRefused = draft.trim() === "" || overLimit(draft);
126
+ const draftCount = maxLength !== void 0 && characterCountState(measured(draft), maxLength) !== "within";
127
+ const reorder = useReorder({
128
+ keys: ids.current,
129
+ nameOf: () => itemName,
130
+ onReorder: (nextIds) => {
131
+ const byId = new Map(ids.current.map((id, at) => [id, value[at]]));
132
+ emit(
133
+ nextIds.map((id) => byId.get(id)),
134
+ nextIds
135
+ );
136
+ },
137
+ labels: { moved: (_, position, total) => movedMessage(itemName, position, total) }
138
+ });
139
+ const drags = reorderByDrag && !disabled;
140
+ const order = drags ? reorder.order : ids.current;
141
+ function add() {
142
+ const text = draft.trim();
143
+ if (!text || disabled || full || overLimit(text)) return;
144
+ const id = mint();
145
+ const filled = maxItems !== void 0 && count + 1 >= maxItems;
146
+ emit(
147
+ [...value, text],
148
+ [...ids.current, id],
149
+ addedMessage(itemName, `${count + 1} of ${count + 1}`) + (filled ? `. ${fullMessage(maxItems)}` : "")
150
+ );
151
+ setDraft("");
152
+ focusNext.current = filled ? { id, target: "input" } : { id: "", target: "add" };
153
+ }
154
+ function move(index, by, target) {
155
+ const to = index + by;
156
+ if (disabled || to < 0 || to >= count) return;
157
+ const next = [...value];
158
+ const nextIds = [...ids.current];
159
+ [next[index], next[to]] = [next[to], next[index]];
160
+ [nextIds[index], nextIds[to]] = [nextIds[to], nextIds[index]];
161
+ focusNext.current = { id: nextIds[to], target };
162
+ emit(next, nextIds, movedMessage(itemName, to + 1, count));
163
+ }
164
+ const neighbourOf = (nextIds, index) => {
165
+ const neighbour = nextIds[index] ?? nextIds[index - 1];
166
+ return neighbour ? { id: neighbour, target: "input" } : { id: "", target: "add" };
167
+ };
168
+ function remove(index) {
169
+ if (disabled) return;
170
+ const next = value.filter((_, at) => at !== index);
171
+ const nextIds = ids.current.filter((_, at) => at !== index);
172
+ const leaving = undoRemove ? { id: ids.current[index], text: value[index], index } : null;
173
+ focusNext.current = leaving ? { id: "", target: "undo" } : neighbourOf(nextIds, index);
174
+ emit(next, nextIds, leaving ? void 0 : removedMessage(itemName, `${index + 1} of ${count}`), leaving);
175
+ }
176
+ function restore() {
177
+ if (!removed || disabled) return;
178
+ const at = Math.min(removed.index, count);
179
+ const next = [...value];
180
+ const nextIds = [...ids.current];
181
+ next.splice(at, 0, removed.text);
182
+ nextIds.splice(at, 0, removed.id);
183
+ focusNext.current = { id: removed.id, target: "input" };
184
+ emit(next, nextIds, restoredMessage(itemName, `${at + 1} of ${count + 1}`));
185
+ }
186
+ function dismiss() {
187
+ if (!removed) return;
188
+ focusNext.current = neighbourOf(ids.current, removed.index);
189
+ setRemoved(null);
190
+ }
191
+ const acts = (event) => event.key === "Enter" && !event.metaKey && !event.ctrlKey && !(multiline && event.shiftKey) && !isComposing(event);
192
+ function itemKeys(event, index) {
193
+ if (isComposing(event)) return;
194
+ if (event.altKey && (event.key === "ArrowUp" || event.key === "ArrowDown")) {
195
+ event.preventDefault();
196
+ move(index, event.key === "ArrowUp" ? -1 : 1, "input");
197
+ return;
198
+ }
199
+ if (!acts(event)) return;
200
+ event.preventDefault();
201
+ const next = ids.current[index + 1];
202
+ if (next) inputs.current.get(next)?.focus();
203
+ else addBox.current?.focus();
204
+ }
205
+ const control = (props) => (
206
+ /*
207
+ * ONE LINE THAT GROWS, never a fixed block of rows. A list of sentences
208
+ * read as a list wants each item on its own line; a two-row textarea per
209
+ * item made three of them 256px where the console draws 111, and the
210
+ * second row was empty in every one of them. `autoResize` starts at one
211
+ * line and takes as many as the sentence needs.
212
+ *
213
+ * AND A ONE-LINE ITEM WRAPS TOO. A one-line input scrolled a long
214
+ * policy sideways, so while it was edited only its tail could be read.
215
+ * Without `multiline` the field is a `singleLine` textarea: it wraps to
216
+ * be read whole and still holds one line, with no newline typed, pasted
217
+ * or dropped in.
218
+ */
219
+ /* @__PURE__ */ jsx(
220
+ Textarea,
221
+ {
222
+ rows: 1,
223
+ autoResize: true,
224
+ singleLine: !multiline,
225
+ "aria-label": props.label,
226
+ value: props.value,
227
+ placeholder: props.placeholder,
228
+ disabled,
229
+ spellCheck: true,
230
+ trailing: props.trailing,
231
+ error: props.invalid ?? false,
232
+ "aria-describedby": props.describedBy,
233
+ onChange: (event) => props.onChange(event.target.value),
234
+ onKeyDown: props.onKeyDown,
235
+ ref: props.ref
236
+ }
237
+ )
238
+ );
239
+ const addControl = /* @__PURE__ */ jsx(
240
+ IconButton,
241
+ {
242
+ size: "sm",
243
+ variant: "soft-brand",
244
+ label: addLabel(itemName),
245
+ icon: /* @__PURE__ */ jsx(PlusGlyph, {}),
246
+ disabled: disabled || full || draftRefused,
247
+ onClick: add
248
+ }
249
+ );
250
+ return /* @__PURE__ */ jsxs(
251
+ FormField,
252
+ {
253
+ as: "fieldset",
254
+ label,
255
+ hideLabel,
256
+ optional,
257
+ helper,
258
+ helperOnFocus,
259
+ error,
260
+ className: "crewlet-list-input",
261
+ labelAction: hideLabel ? void 0 : addControl,
262
+ children: [
263
+ full ? (
264
+ /*
265
+ * A FULL LIST SAYS SO WHERE THE BOX WAS, rather than drawing a box
266
+ * that takes nothing. A disabled box is a control a reader reaches
267
+ * and cannot use with no word of why; the sentence is the why, and
268
+ * every item above it still edits, moves and goes.
269
+ */
270
+ /* @__PURE__ */ jsx("p", { className: "crewlet-list-input__full", children: fullMessage(maxItems) })
271
+ ) : /* @__PURE__ */ jsxs("div", { className: "crewlet-list-input__add", children: [
272
+ control({
273
+ label: newItemLabel(itemName),
274
+ value: draft,
275
+ placeholder,
276
+ invalid: overLimit(draft.trim()),
277
+ describedBy: draftCount ? `${listId}-draft-count` : void 0,
278
+ /*
279
+ * THE COUNT TAKES THE KEYCAP'S PLACE once the limit is near: both
280
+ * say what pressing Enter will do, and past the limit the answer
281
+ * is nothing, which the count says and the keycap would not.
282
+ */
283
+ trailing: draftCount ? /* @__PURE__ */ jsx(CharacterCount, { id: `${listId}-draft-count`, length: measured(draft), max: maxLength }) : enterHint ? /* @__PURE__ */ jsx(Kbd, { subtle: true, children: "Enter" }) : void 0,
284
+ onChange: setDraft,
285
+ onKeyDown: (event) => {
286
+ if (!acts(event)) return;
287
+ event.preventDefault();
288
+ add();
289
+ },
290
+ ref: (el) => {
291
+ addBox.current = el;
292
+ }
293
+ }),
294
+ hideLabel ? /* @__PURE__ */ jsx("span", { className: "crewlet-list-input__add-control", children: addControl }) : null
295
+ ] }),
296
+ count > 0 || removed !== null ? /* @__PURE__ */ jsx("ol", { className: "crewlet-list-input__items", ...drags ? reorder.containerProps : {}, children: withRemoved(
297
+ order.map((key) => {
298
+ const index = ids.current.indexOf(key);
299
+ const item = value[index] ?? "";
300
+ const position = `${index + 1} of ${count}`;
301
+ const length = maxLength === void 0 ? 0 : measured(item);
302
+ const counted = maxLength !== void 0 && characterCountState(length, maxLength) !== "within";
303
+ const refusal = itemError?.(index, item);
304
+ const refused = refusal !== void 0 && refusal !== null && refusal !== false && refusal !== "";
305
+ const countId = `${listId}-${key}-count`;
306
+ const errorId = `${listId}-${key}-error`;
307
+ const described = [counted ? countId : null, refused ? errorId : null].filter(Boolean).join(" ");
308
+ const { draggable, onDragStart, onDragEnd } = reorder.handleProps(key);
309
+ return /* @__PURE__ */ jsxs(
310
+ "li",
311
+ {
312
+ className: cx("crewlet-list-input__item", drags && "crewlet-list-input__item--draggable"),
313
+ ...drags ? reorder.itemProps(key) : {},
314
+ children: [
315
+ drags ? /* @__PURE__ */ jsx(
316
+ "span",
317
+ {
318
+ className: "crewlet-list-input__handle",
319
+ "aria-hidden": "true",
320
+ draggable,
321
+ onDragStart,
322
+ onDragEnd,
323
+ children: /* @__PURE__ */ jsx(GripVerticalGlyph, { size: "sm" })
324
+ }
325
+ ) : null,
326
+ /* @__PURE__ */ jsx("span", { className: "crewlet-list-input__index", "aria-hidden": "true", children: index + 1 }),
327
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-list-input__field", children: [
328
+ control({
329
+ label: itemLabel(name, position),
330
+ value: item,
331
+ invalid: refused || overLimit(item),
332
+ describedBy: described || void 0,
333
+ onChange: (next) => {
334
+ const list = [...value];
335
+ list[index] = next;
336
+ emit(list, ids.current);
337
+ },
338
+ onKeyDown: (event) => itemKeys(event, index),
339
+ ref: (el) => {
340
+ if (el) inputs.current.set(key, el);
341
+ else inputs.current.delete(key);
342
+ }
343
+ }),
344
+ counted || refused ? /* @__PURE__ */ jsxs("span", { className: "crewlet-list-input__note", children: [
345
+ refused ? /* @__PURE__ */ jsx("span", { id: errorId, className: "crewlet-list-input__error", children: refusal }) : /* @__PURE__ */ jsx("span", {}),
346
+ counted ? /* @__PURE__ */ jsx(CharacterCount, { id: countId, length, max: maxLength }) : null
347
+ ] }) : null
348
+ ] }),
349
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-list-input__actions", children: [
350
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-list-input__move", children: [
351
+ /* @__PURE__ */ jsx(
352
+ IconButton,
353
+ {
354
+ size: "sm",
355
+ label: moveUpLabel(itemName, position),
356
+ icon: /* @__PURE__ */ jsx(ArrowUpGlyph, {}),
357
+ disabled: disabled || index === 0,
358
+ onClick: () => move(index, -1, "up"),
359
+ ref: (el) => {
360
+ if (el) ups.current.set(key, el);
361
+ else ups.current.delete(key);
362
+ }
363
+ }
364
+ ),
365
+ /* @__PURE__ */ jsx(
366
+ IconButton,
367
+ {
368
+ size: "sm",
369
+ label: moveDownLabel(itemName, position),
370
+ icon: /* @__PURE__ */ jsx(ArrowDownGlyph, {}),
371
+ disabled: disabled || index === count - 1,
372
+ onClick: () => move(index, 1, "down"),
373
+ ref: (el) => {
374
+ if (el) downs.current.set(key, el);
375
+ else downs.current.delete(key);
376
+ }
377
+ }
378
+ )
379
+ ] }),
380
+ /* @__PURE__ */ jsx(
381
+ IconButton,
382
+ {
383
+ size: "sm",
384
+ variant: "ghost-danger",
385
+ label: removeLabel(itemName, position),
386
+ icon: /* @__PURE__ */ jsx(XGlyph, {}),
387
+ disabled,
388
+ onClick: () => remove(index)
389
+ }
390
+ )
391
+ ] })
392
+ ]
393
+ },
394
+ key
395
+ );
396
+ })
397
+ ) }) : null
398
+ ]
399
+ }
400
+ );
401
+ function withRemoved(rows) {
402
+ if (removed === null) return rows;
403
+ const noticeId = `${listId}-removed`;
404
+ const row = /* @__PURE__ */ jsxs("li", { className: "crewlet-list-input__removed", children: [
405
+ /* @__PURE__ */ jsx("span", { id: noticeId, className: "crewlet-list-input__removed-text", children: removedNotice(name, removed.index + 1) }),
406
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-list-input__actions", children: [
407
+ /* @__PURE__ */ jsx(
408
+ Button,
409
+ {
410
+ ref: undoButton,
411
+ size: "small",
412
+ variant: "ghost",
413
+ "aria-describedby": noticeId,
414
+ disabled,
415
+ onClick: restore,
416
+ children: undoLabel
417
+ }
418
+ ),
419
+ /* @__PURE__ */ jsx(
420
+ IconButton,
421
+ {
422
+ size: "sm",
423
+ label: dismissLabel,
424
+ icon: /* @__PURE__ */ jsx(XGlyph, {}),
425
+ "aria-describedby": noticeId,
426
+ onClick: dismiss
427
+ }
428
+ )
429
+ ] })
430
+ ] }, `removed-${removed.id}`);
431
+ const at = Math.min(removed.index, rows.length);
432
+ return [...rows.slice(0, at), row, ...rows.slice(at)];
433
+ }
434
+ });
435
+
436
+ export { ListInput, withDraft };
@@ -1,7 +1,7 @@
1
1
  import { StatusDot } from './chunk-WIATRXEJ.js';
2
2
  import { useRoving, tabStop } from './chunk-EGMQURBR.js';
3
3
  import { Count } from './chunk-BHHIIK3M.js';
4
- import { Menu } from './chunk-PCI7ZJ6Z.js';
4
+ import { Menu } from './chunk-TMM32U7D.js';
5
5
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
6
6
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
7
7
  import { cx } from './chunk-ODEQTPFM.js';
@@ -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-AMO2B54T.js').then(
12
+ loading ??= import('./Editor-MLGK3KOG.js').then(
13
13
  (module) => {
14
14
  engine = module.Editor;
15
15
  return engine;
@@ -1,6 +1,6 @@
1
1
  import { Switch } from './chunk-A722MUNR.js';
2
2
  import { useReorder } from './chunk-XJ2QEBMM.js';
3
- import { Checkbox } from './chunk-EY7LACIR.js';
3
+ import { Checkbox } from './chunk-F57N6ZJG.js';
4
4
  import { IconButton } from './chunk-LACA4JGC.js';
5
5
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,3 +1,4 @@
1
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
1
2
  import { cx } from './chunk-ODEQTPFM.js';
2
3
  import './EditingStatus-NNA2CKIL.css';
3
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -19,6 +20,7 @@ function EditingStatus({ dirty, saving = false, labels, className }) {
19
20
  children: [
20
21
  /* @__PURE__ */ jsx("span", { className: "crewlet-editing-status__dot", "aria-hidden": "true" }),
21
22
  /* @__PURE__ */ jsx("span", { className: "crewlet-editing-status__label", children: text.editing }),
23
+ state && /* @__PURE__ */ jsx(VisuallyHidden, { children: ", " }),
22
24
  state && /* @__PURE__ */ jsx("span", { className: "crewlet-editing-status__state", children: state })
23
25
  ]
24
26
  }
@@ -1,11 +1,11 @@
1
1
  import { Select } from './chunk-XQZ6EWOE.js';
2
2
  import { SHEET_LABELS, SHEET_COLUMN_TYPES, optionHue, retypeColumn } from './chunk-LFSIKGRQ.js';
3
- import { HueSwatch } from './chunk-QOP7QYUW.js';
3
+ import { HueSwatch } from './chunk-34RMTXDZ.js';
4
4
  import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
5
- import { Checkbox } from './chunk-EY7LACIR.js';
6
- import { FormField, Input } from './chunk-ZI5G5RS7.js';
5
+ import { Checkbox } from './chunk-F57N6ZJG.js';
6
+ import { FormField, Input } from './chunk-EXRRTKWT.js';
7
7
  import { Kbd } from './chunk-SMBKXWML.js';
8
- import { Menu } from './chunk-PCI7ZJ6Z.js';
8
+ import { Menu } from './chunk-TMM32U7D.js';
9
9
  import { Button } from './chunk-OG6CL3EB.js';
10
10
  import { IconButton } from './chunk-LACA4JGC.js';
11
11
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
@@ -1,4 +1,4 @@
1
- import { Text } from './chunk-IKBK4A5O.js';
1
+ import { Text } from './chunk-QP2P6GDQ.js';
2
2
  import { Inline, Stack, Spacer } from './chunk-ZAC7SKUN.js';
3
3
  import { Card } from './chunk-INHXF2CL.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,14 +1,14 @@
1
1
  import { PageHeader } from './chunk-HOXGBLEY.js';
2
+ import { DataTable } from './chunk-AS2BMY3E.js';
2
3
  import { DateTimePicker } from './chunk-UFXLNC2N.js';
3
- import { DataTable } from './chunk-GI3S6RMM.js';
4
4
  import { useListbox, useOptionKeys } from './chunk-7KHM2FZH.js';
5
5
  import { Toolbar } from './chunk-NR4CPM4T.js';
6
6
  import { Popover } from './chunk-KHJIEPZV.js';
7
7
  import { RelativeTime } from './chunk-3CZ7XAVY.js';
8
- import { Input } from './chunk-ZI5G5RS7.js';
8
+ import { Input } from './chunk-EXRRTKWT.js';
9
9
  import { Kbd } from './chunk-SMBKXWML.js';
10
10
  import { Count } from './chunk-BHHIIK3M.js';
11
- import { Menu } from './chunk-PCI7ZJ6Z.js';
11
+ import { Menu } from './chunk-TMM32U7D.js';
12
12
  import { Button } from './chunk-OG6CL3EB.js';
13
13
  import { IconButton } from './chunk-LACA4JGC.js';
14
14
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
@@ -9,9 +9,9 @@ import { Popover } from './chunk-KHJIEPZV.js';
9
9
  import { StatusDot } from './chunk-WIATRXEJ.js';
10
10
  import { Tooltip } from './chunk-I33UIUZD.js';
11
11
  import { Avatar } from './chunk-PZKHBB7D.js';
12
- import { Menu } from './chunk-PCI7ZJ6Z.js';
13
- import { isComposing } from './chunk-H5XTJ7GJ.js';
12
+ import { Menu } from './chunk-TMM32U7D.js';
14
13
  import { Button } from './chunk-OG6CL3EB.js';
14
+ import { isComposing } from './chunk-H5XTJ7GJ.js';
15
15
  import { IconButton } from './chunk-LACA4JGC.js';
16
16
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
17
17
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
1
  import { useListbox } from './chunk-7KHM2FZH.js';
2
- import { Input } from './chunk-ZI5G5RS7.js';
2
+ import { Input } from './chunk-EXRRTKWT.js';
3
3
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import './HitArea-QUOS6ZDJ.css';
@@ -1,5 +1,5 @@
1
1
  import { cx } from './chunk-ODEQTPFM.js';
2
- import './TileGrid-I6LNYD2H.css';
2
+ import './TileGrid-UYMVVVJK.css';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function TileGrid({ columns = 3, as: Track = "div", className, children, ...rest }) {
@@ -1,5 +1,5 @@
1
1
  import { cx } from './chunk-ODEQTPFM.js';
2
- import './Text-S3Q4O3IG.css';
2
+ import './Text-XOCOU34C.css';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  function Text({
@@ -1,5 +1,5 @@
1
1
  import { diffLines, diffStat, collapseDiff, DiffSummary, DiffView } from './chunk-BVWSLXTY.js';
2
- import { SegmentedControl } from './chunk-BF5WV7NM.js';
2
+ import { SegmentedControl } from './chunk-6FVGSWLS.js';
3
3
  import { EmptyState } from './chunk-PPUR46MK.js';
4
4
  import { useHeadingLevel, headingTag, nextHeadingLevel, HeadingLevelProvider } from './chunk-PQADV6P6.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
1
  import { useThemePreference, useDensityPreference } from './chunk-Z24ZUSTX.js';
2
- import { SegmentedControl } from './chunk-BF5WV7NM.js';
2
+ import { SegmentedControl } from './chunk-6FVGSWLS.js';
3
3
  import { SunGlyph, MonitorGlyph, MoonGlyph } from '@crewlethq/icons/glyphs';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -1,7 +1,7 @@
1
1
  import { SlideStage } from './chunk-RMEBFYL7.js';
2
2
  import { useReorder } from './chunk-XJ2QEBMM.js';
3
3
  import { Kbd, isApplePlatform } from './chunk-SMBKXWML.js';
4
- import { Menu } from './chunk-PCI7ZJ6Z.js';
4
+ import { Menu } from './chunk-TMM32U7D.js';
5
5
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './SlideFilmstrip-PAT7P4OG.css';
@@ -1,6 +1,6 @@
1
1
  import { Toolbar } from './chunk-NR4CPM4T.js';
2
- import { SegmentedControl } from './chunk-BF5WV7NM.js';
3
- import { tabId } from './chunk-KA75QPFM.js';
2
+ import { SegmentedControl } from './chunk-6FVGSWLS.js';
3
+ import { tabId } from './chunk-ILFEWRLG.js';
4
4
  import { IconButton } from './chunk-LACA4JGC.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './MarkdownEditor-WOKV7CLK.css';
@@ -1,19 +1,35 @@
1
1
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
- import './List-YHLIZFK4.css';
3
+ import './List-XY445TKY.css';
4
4
  import { createContext, useContext, Children, isValidElement, cloneElement } from 'react';
5
5
  import { CircleAlertGlyph } from '@crewlethq/icons/glyphs';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
 
8
8
  var ListContext = createContext({ variant: "divided", templated: false });
9
- function List({ variant = "divided", template, className, style, children, ...rest }) {
9
+ function List({
10
+ variant = "divided",
11
+ template,
12
+ density = "comfortable",
13
+ measure,
14
+ className,
15
+ style,
16
+ children,
17
+ ...rest
18
+ }) {
10
19
  const Tag = variant === "numbered" || variant === "numbered-divided" ? "ol" : "ul";
11
20
  const templated = template !== void 0;
12
21
  return /* @__PURE__ */ jsx(ListContext.Provider, { value: { variant, templated }, children: /* @__PURE__ */ jsx(
13
22
  Tag,
14
23
  {
15
24
  ...rest,
16
- className: cx("crewlet-list", `crewlet-list--${variant}`, templated && "crewlet-list--templated", className),
25
+ className: cx(
26
+ "crewlet-list",
27
+ `crewlet-list--${variant}`,
28
+ templated && "crewlet-list--templated",
29
+ density === "compact" && "crewlet-list--compact",
30
+ measure && `crewlet-list--measure-${measure}`,
31
+ className
32
+ ),
17
33
  style: templated ? { ...style, "--crewlet-list-template": template } : style,
18
34
  children
19
35
  }
@@ -1,6 +1,6 @@
1
1
  import { useHeadingLevel, headingTag } from './chunk-PQADV6P6.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
- import './CatalogTile-VPSLCKJE.css';
3
+ import './CatalogTile-26XN7L2A.css';
4
4
  import { useId } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1,10 +1,10 @@
1
- import { Modal } from './chunk-FYINAYAJ.js';
1
+ import { Modal } from './chunk-6AKG2VLR.js';
2
2
  import { useListbox, useHighlightRest } from './chunk-7KHM2FZH.js';
3
- import { Input } from './chunk-ZI5G5RS7.js';
3
+ import { Input } from './chunk-EXRRTKWT.js';
4
4
  import { Kbd } from './chunk-SMBKXWML.js';
5
5
  import { Count } from './chunk-BHHIIK3M.js';
6
- import { isComposing } from './chunk-H5XTJ7GJ.js';
7
6
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
7
+ import { isComposing } from './chunk-H5XTJ7GJ.js';
8
8
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
9
9
  import { cx } from './chunk-ODEQTPFM.js';
10
10
  import './HitArea-QUOS6ZDJ.css';