@crewlethq/ui 0.34.1 → 0.35.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 (113) hide show
  1. package/README.md +51 -0
  2. package/dist/AppShell/index.js +2 -2
  3. package/dist/ArtifactBar/ArtifactBar.d.ts +7 -1
  4. package/dist/ArtifactBar/index.d.ts +1 -0
  5. package/dist/ArtifactBar/index.js +4 -14
  6. package/dist/{ArtifactBar-C462VD4C.css → ArtifactBar-HV5AT4RG.css} +39 -2
  7. package/dist/ArtifactCard/ArtifactCard.d.ts +1 -10
  8. package/dist/ArtifactCard/index.d.ts +5 -2
  9. package/dist/ArtifactCard/index.js +3 -2
  10. package/dist/{ArtifactCard-XHRLAL7C.css → ArtifactCard-OGTMO2KI.css} +15 -16
  11. package/dist/ArtifactCover/index.js +2 -14
  12. package/dist/ArtifactIcon/ArtifactIcon.d.ts +1 -1
  13. package/dist/ArtifactIcon/index.js +2 -15
  14. package/dist/ArtifactKindGlyph/ArtifactKindGlyph.d.ts +10 -0
  15. package/dist/ArtifactKindGlyph/index.d.ts +2 -0
  16. package/dist/ArtifactKindGlyph/index.js +1 -0
  17. package/dist/ArtifactKindIllustration/ArtifactKindIllustration.d.ts +15 -2
  18. package/dist/ArtifactKindIllustration/index.d.ts +1 -0
  19. package/dist/ArtifactKindIllustration/index.js +1 -1
  20. package/dist/{ArtifactKindIllustration-4NG6IE3C.css → ArtifactKindIllustration-5FPRJQ3P.css} +32 -26
  21. package/dist/ArtifactKinds-CVD3FCYO.css +15 -0
  22. package/dist/AvatarPicker/index.js +3 -3
  23. package/dist/CanvasBoard/CanvasBoard.d.ts +30 -12
  24. package/dist/CanvasBoard/index.js +1 -1
  25. package/dist/ChangeMark/index.js +2 -2
  26. package/dist/ChoiceList/ChoiceList.d.ts +7 -1
  27. package/dist/ChoiceList/index.js +1 -1
  28. package/dist/{ChoiceList-2PQJS4DX.css → ChoiceList-RBL7FNQL.css} +39 -0
  29. package/dist/CommentThread/index.js +2 -2
  30. package/dist/DataTable/index.js +2 -2
  31. package/dist/DataView/index.js +5 -5
  32. package/dist/DateTimePicker/index.js +2 -2
  33. package/dist/DocTabsEditor/index.js +2 -2
  34. package/dist/{Editor-UUZ7XKCU.js → Editor-BVQHBF7L.js} +4 -4
  35. package/dist/FileDrop/FileDrop.d.ts +64 -0
  36. package/dist/FileDrop/index.d.ts +3 -0
  37. package/dist/FileDrop/index.js +4 -0
  38. package/dist/FileDrop-WE7BNZGV.css +80 -0
  39. package/dist/FindingList/FindingList.d.ts +35 -0
  40. package/dist/FindingList/index.d.ts +3 -0
  41. package/dist/FindingList/index.js +3 -0
  42. package/dist/FindingList-PMYA2R6Q.css +71 -0
  43. package/dist/HuePicker/HuePicker.d.ts +9 -0
  44. package/dist/HuePicker/index.d.ts +1 -1
  45. package/dist/HuePicker/index.js +1 -1
  46. package/dist/Markdown/index.js +1 -1
  47. package/dist/Menu/Menu.d.ts +6 -1
  48. package/dist/Menu/index.js +1 -1
  49. package/dist/OrgTable/index.js +1 -1
  50. package/dist/RichEditor/index.js +3 -3
  51. package/dist/RichEditorMarkdown/index.js +3 -3
  52. package/dist/SheetColumnEditor/SheetColumnEditor.d.ts +94 -0
  53. package/dist/SheetColumnEditor/index.d.ts +3 -0
  54. package/dist/SheetColumnEditor/index.js +23 -0
  55. package/dist/SheetColumnEditor-BO2HKFRB.css +73 -0
  56. package/dist/SheetGrid/SheetGrid.d.ts +19 -1
  57. package/dist/SheetGrid/index.js +5 -4
  58. package/dist/{SheetGrid-GDPCCZ4V.css → SheetGrid-YRDXTIIZ.css} +48 -0
  59. package/dist/SheetModel/index.js +1 -1
  60. package/dist/SheetModel/labels.d.ts +6 -0
  61. package/dist/SlideFilmstrip/SlideFilmstrip.d.ts +30 -1
  62. package/dist/SlideFilmstrip/index.js +5 -1
  63. package/dist/{SlideFilmstrip-5U6Z55GS.css → SlideFilmstrip-4ITZLMO4.css} +49 -0
  64. package/dist/SourceEditor/SourceEditor.d.ts +62 -0
  65. package/dist/SourceEditor/index.d.ts +3 -0
  66. package/dist/SourceEditor/index.js +3 -0
  67. package/dist/SourceEditor-G2C3STPX.css +160 -0
  68. package/dist/ThemeGallery/ThemeGallery.d.ts +10 -3
  69. package/dist/ThemeGallery/index.js +1 -1
  70. package/dist/{ThemeGallery-NITASULQ.css → ThemeGallery-HSUKBDWY.css} +9 -0
  71. package/dist/TimeWindowPicker/index.js +2 -2
  72. package/dist/{chunk-UXXJDIYE.js → chunk-22CQQDFW.js} +1 -1
  73. package/dist/{chunk-E4NNGC6X.js → chunk-3VD3G3IL.js} +2 -2
  74. package/dist/{chunk-EWAFN2IU.js → chunk-5VCG26CV.js} +281 -234
  75. package/dist/{chunk-XTOVADJU.js → chunk-7UYONN6K.js} +7 -18
  76. package/dist/{chunk-CFAJP777.js → chunk-AXBRWRGV.js} +1 -1
  77. package/dist/{chunk-KK5OYNAF.js → chunk-BAKPMH3S.js} +8 -4
  78. package/dist/{chunk-3EB2AV3H.js → chunk-BUVCV3WI.js} +1 -1
  79. package/dist/chunk-CE2THTQR.js +19 -0
  80. package/dist/{chunk-4B6LSFDS.js → chunk-CSQTDGTS.js} +1 -1
  81. package/dist/{chunk-WPX6A5BV.js → chunk-E35CMI5D.js} +22 -6
  82. package/dist/{chunk-EBCHVFCS.js → chunk-FJJHD73S.js} +2 -2
  83. package/dist/{chunk-SGHIAGPR.js → chunk-HAKTRTRP.js} +1 -1
  84. package/dist/{chunk-PLDUNXAO.js → chunk-ILDNJHRU.js} +1 -1
  85. package/dist/chunk-MAD6WPER.js +342 -0
  86. package/dist/{chunk-IUD5VA2Z.js → chunk-NKZCJRKO.js} +10 -5
  87. package/dist/chunk-NTB5LRRD.js +52 -0
  88. package/dist/{chunk-VI5FWDZW.js → chunk-OOMXLJ3S.js} +4 -1
  89. package/dist/{chunk-UOR7TOAU.js → chunk-OSFA5ROT.js} +86 -1
  90. package/dist/{chunk-T46NR3WP.js → chunk-PGZ2R3ON.js} +1 -1
  91. package/dist/chunk-PI7HKLIT.js +245 -0
  92. package/dist/{chunk-YZFLH463.js → chunk-QEFHYUCY.js} +1 -1
  93. package/dist/{chunk-7Q7WDXHG.js → chunk-QFNWMWWY.js} +3 -3
  94. package/dist/{chunk-C7DKX453.js → chunk-QH6VYJ3X.js} +1 -1
  95. package/dist/{chunk-XV32RKQZ.js → chunk-QIXMNOBD.js} +67 -6
  96. package/dist/{chunk-GPHWCK7M.js → chunk-SUXP4OBT.js} +6 -3
  97. package/dist/{chunk-TRQCHF2F.js → chunk-SWD4QBL6.js} +1 -1
  98. package/dist/chunk-THDGBD6Y.js +154 -0
  99. package/dist/{chunk-C2FRTWKO.js → chunk-W3UVOZKL.js} +3 -2
  100. package/dist/{chunk-UDQW6UK7.js → chunk-W7QBBKUE.js} +34 -7
  101. package/dist/{chunk-QBXZLGK2.js → chunk-ZU3DUXD2.js} +3 -2
  102. package/dist/generated/index.d.ts +5 -0
  103. package/dist/generated/index.js +73 -68
  104. package/dist/index.js +73 -68
  105. package/dist/styles.css +652 -51
  106. package/dist/utils/csv.d.ts +35 -0
  107. package/dist/utils/index.d.ts +2 -1
  108. package/dist/utils/index.js +1 -1
  109. package/package.json +3 -3
  110. package/dist/{chunk-YCARLYI6.js → chunk-3WCNHYXE.js} +0 -0
  111. package/dist/{chunk-IYO2N5ZH.js → chunk-6JVRY5DQ.js} +1 -1
  112. package/dist/{chunk-BY4N65PM.js → chunk-73A7D5CE.js} +1 -1
  113. package/dist/{chunk-AORVEG5V.js → chunk-F2KY4RLI.js} +1 -1
@@ -1,29 +1,18 @@
1
1
  import { Skeleton } from './chunk-TEUQWOWZ.js';
2
2
  import { PrincipalAvatar } from './chunk-CI3VPIJN.js';
3
3
  import { RelativeTime } from './chunk-3CZ7XAVY.js';
4
+ import { ArtifactKindGround } from './chunk-W7QBBKUE.js';
4
5
  import { Card } from './chunk-ACA27MZH.js';
5
6
  import { AvatarStack } from './chunk-5AQBPHZD.js';
6
- import { ArtifactKindGround } from './chunk-UDQW6UK7.js';
7
+ import { ArtifactKindGlyph } from './chunk-CE2THTQR.js';
7
8
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
8
9
  import { cx } from './chunk-ODEQTPFM.js';
9
- import './ArtifactCard-XHRLAL7C.css';
10
+ import './ArtifactKinds-CVD3FCYO.css';
11
+ import './ArtifactCard-OGTMO2KI.css';
10
12
  import { useId } from 'react';
11
- import { TableGlyph, LayoutDashboardGlyph, PaletteGlyph, PresentationGlyph, FileTextGlyph, FileCodeGlyph, PinGlyph, BuildingComplexGlyph, UsersGlyph, LockGlyph } from '@crewlethq/icons/glyphs';
13
+ import { PinGlyph, BuildingComplexGlyph, UsersGlyph, LockGlyph } from '@crewlethq/icons/glyphs';
12
14
  import { jsx, jsxs } from 'react/jsx-runtime';
13
15
 
14
- var ARTIFACT_KINDS = ["html", "doc", "slides", "design", "dashboard", "sheet"];
15
- var KIND_GLYPHS = {
16
- html: FileCodeGlyph,
17
- doc: FileTextGlyph,
18
- slides: PresentationGlyph,
19
- design: PaletteGlyph,
20
- dashboard: LayoutDashboardGlyph,
21
- sheet: TableGlyph
22
- };
23
- function ArtifactKindGlyph({ kind, size = "md" }) {
24
- const Drawn = KIND_GLYPHS[kind];
25
- return /* @__PURE__ */ jsx(Drawn, { size });
26
- }
27
16
  function ArtifactPreviewGlyph({ kind }) {
28
17
  return /* @__PURE__ */ jsx(ArtifactKindGround, { kind });
29
18
  }
@@ -128,7 +117,7 @@ function ArtifactCard({
128
117
  /* @__PURE__ */ jsxs("a", { href, className: "crewlet-artifact-card__link", "aria-labelledby": titleId, "aria-describedby": factsId, children: [
129
118
  /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-card__preview", "aria-hidden": true, children: preview ?? /* @__PURE__ */ jsx(ArtifactPreviewGlyph, { kind }) }),
130
119
  /* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-card__body", children: [
131
- /* @__PURE__ */ jsx("span", { className: cx("crewlet-artifact-card__badge", `crewlet-kind--${kind}`), "aria-hidden": true, children: /* @__PURE__ */ jsx(ArtifactKindGlyph, { kind, size: "md" }) }),
120
+ /* @__PURE__ */ jsx("span", { className: cx("crewlet-artifact-card__badge", `crewlet-kind--${kind}`), "aria-hidden": true, children: /* @__PURE__ */ jsx(ArtifactKindGlyph, { kind, size: "sm" }) }),
132
121
  /* @__PURE__ */ jsxs("span", { className: "crewlet-artifact-card__title-row", children: [
133
122
  /* @__PURE__ */ jsx("span", { id: titleId, className: "crewlet-artifact-card__title", title, children: title }),
134
123
  pinned ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-card__pin", title: text.pinned, "aria-hidden": true, children: /* @__PURE__ */ jsx(PinGlyph, { size: "sm" }) }) : null
@@ -167,4 +156,4 @@ function ArtifactCardSkeleton({ className }) {
167
156
  ] });
168
157
  }
169
158
 
170
- export { ARTIFACT_KINDS, ArtifactCard, ArtifactCardSkeleton, ArtifactKindGlyph, ArtifactPreviewGlyph };
159
+ export { ArtifactCard, ArtifactCardSkeleton, ArtifactPreviewGlyph };
@@ -1,5 +1,5 @@
1
1
  import { Document } from './chunk-TYKQ33CL.js';
2
- import { ArtifactKindGlyph } from './chunk-XTOVADJU.js';
2
+ import { ArtifactKindGlyph } from './chunk-CE2THTQR.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './ArtifactCover-D4MBEJ5H.css';
5
5
  import './DashboardCover-KYGYMRKW.css';
@@ -20,12 +20,16 @@ function safeHref(raw) {
20
20
  var HEADING = /^(#{1,6})\s+(.*)$/;
21
21
  var FENCE = /^(```|~~~)\s*([A-Za-z0-9_+-]*)\s*$/;
22
22
  var RULE = /^(?:\s*(?:-{3,}|\*{3,}|_{3,})\s*)$/;
23
- var BULLET = /^(\s*)([-*+])\s+(.*)$/;
24
- var ORDERED = /^(\s*)(\d{1,9})([.)])\s+(.*)$/;
23
+ var BULLET = /^(\s*)([-*+])(?:\s+(.*))?$/;
24
+ var ORDERED = /^(\s*)(\d{1,9})([.)])(?:\s+(.*))?$/;
25
25
  var QUOTE = /^\s{0,3}>\s?(.*)$/;
26
26
  var TABLE_RULE = /^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/;
27
27
  var CALLOUT = /^\[!(note|tip|important|warning|caution)\]\s*$/i;
28
- var TASK = /^\[([ xX])\]\s+(.*)$/;
28
+ var TASK = /^\[([ xX])\](?:\s+(.*))?$/;
29
+ function bareMarker(line) {
30
+ const found = BULLET.exec(line) ?? ORDERED.exec(line);
31
+ return found !== null && (found[found.length - 1] ?? "").trim() === "";
32
+ }
29
33
  var FENCE_CLOSE = {
30
34
  "```": /^`{3,}[ \t]*$/,
31
35
  "~~~": /^~{3,}[ \t]*$/
@@ -140,7 +144,7 @@ function blocksOf(lines) {
140
144
  out.push({ block: { kind: "table", head, align, rows }, start, end: i });
141
145
  continue;
142
146
  }
143
- if (BULLET.test(line) || ORDERED.test(line)) {
147
+ if ((BULLET.test(line) || ORDERED.test(line)) && !(paragraph.length > 0 && bareMarker(line))) {
144
148
  flush();
145
149
  const [list, next] = parseList(lines, i);
146
150
  out.push({ block: list, start, end: next });
@@ -279,7 +279,7 @@ function Menu({
279
279
  onKeyDown: onTriggerKeyDown
280
280
  };
281
281
  return /* @__PURE__ */ jsxs("span", { className: "crewlet-menu-anchor", children: [
282
- renderTrigger ? renderTrigger(shared) : trigger === void 0 ? /* @__PURE__ */ jsx(IconButton, { ...shared, label, icon: icon ?? /* @__PURE__ */ jsx(EllipsisVerticalGlyph, {}), size: "sm" }) : /* @__PURE__ */ jsx(Button, { ...shared, variant: triggerVariant, size: "small", leadingIcon: icon, trailingIcon, children: trigger }),
282
+ renderTrigger ? renderTrigger(shared) : trigger === void 0 ? /* @__PURE__ */ jsx(IconButton, { ...shared, label, icon: icon ?? /* @__PURE__ */ jsx(EllipsisVerticalGlyph, {}), size: "sm" }) : /* @__PURE__ */ jsx(Button, { ...shared, "aria-label": label, variant: triggerVariant, size: "small", leadingIcon: icon, trailingIcon, children: trigger }),
283
283
  list && container ? createPortal(list, container) : null
284
284
  ] });
285
285
  }
@@ -0,0 +1,19 @@
1
+ import { TableGlyph, LayoutDashboardGlyph, PaletteGlyph, PresentationGlyph, FileTextGlyph, FileCodeGlyph } from '@crewlethq/icons/glyphs';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/ArtifactKindGlyph/ArtifactKindGlyph.tsx
5
+ var ARTIFACT_KINDS = ["html", "doc", "slides", "design", "dashboard", "sheet"];
6
+ var KIND_GLYPHS = {
7
+ html: FileCodeGlyph,
8
+ doc: FileTextGlyph,
9
+ slides: PresentationGlyph,
10
+ design: PaletteGlyph,
11
+ dashboard: LayoutDashboardGlyph,
12
+ sheet: TableGlyph
13
+ };
14
+ function ArtifactKindGlyph({ kind, size = "md" }) {
15
+ const Drawn = KIND_GLYPHS[kind];
16
+ return /* @__PURE__ */ jsx(Drawn, { size });
17
+ }
18
+
19
+ export { ARTIFACT_KINDS, ArtifactKindGlyph };
@@ -1,4 +1,4 @@
1
- import { MARKDOWN_CALLOUT_NAMES } from './chunk-KK5OYNAF.js';
1
+ import { MARKDOWN_CALLOUT_NAMES } from './chunk-BAKPMH3S.js';
2
2
 
3
3
  // src/RichEditor/types.ts
4
4
  var RICH_EDITOR_LABELS = {
@@ -5,7 +5,7 @@ import { IconButton } from './chunk-4FQT6ZAY.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './CanvasBoard-5NNSKY6A.css';
7
7
  import { useState, useRef, useImperativeHandle, useCallback, useMemo, useEffect } from 'react';
8
- import { MaximizeGlyph, PencilGlyph, TrashGlyph, MousePointer2Glyph, HandGlyph, TypeGlyph, StickyNoteGlyph } from '@crewlethq/icons/glyphs';
8
+ import { MaximizeGlyph, PencilGlyph, TrashGlyph, MousePointer2Glyph, HandGlyph, FrameGlyph, TypeGlyph, StickyNoteGlyph } from '@crewlethq/icons/glyphs';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
10
 
11
11
  // src/CanvasBoard/budget.ts
@@ -65,12 +65,14 @@ var LABELS = {
65
65
  tools: "Tools",
66
66
  moveTool: "Move",
67
67
  handTool: "Hand",
68
+ frameTool: "Frame",
68
69
  textTool: "Text",
69
70
  stickyTool: "Sticky note"
70
71
  };
71
72
  var TOOL_CURSOR = {
72
73
  move: "pointer",
73
74
  hand: "hand",
75
+ frame: "crosshair",
74
76
  text: "text",
75
77
  sticky: "crosshair"
76
78
  };
@@ -228,6 +230,8 @@ function CanvasBoard({
228
230
  onNoteChange,
229
231
  onNoteRemove,
230
232
  onNoteCreate,
233
+ onBoardCreate,
234
+ onBoardRemove,
231
235
  onOpen,
232
236
  onActivate,
233
237
  selected: heldSelection,
@@ -256,9 +260,11 @@ function CanvasBoard({
256
260
  const canvas = useRef(null);
257
261
  useImperativeHandle(canvasRef, () => canvas.current, []);
258
262
  const creates = editable && onNoteCreate !== void 0;
263
+ const frames = editable && onBoardCreate !== void 0;
259
264
  const tools = [
260
265
  { id: "move", label: text.moveTool, icon: /* @__PURE__ */ jsx(MousePointer2Glyph, {}), shortcut: "V" },
261
266
  { id: "hand", label: text.handTool, icon: /* @__PURE__ */ jsx(HandGlyph, {}), shortcut: "H" },
267
+ ...frames ? [{ id: "frame", label: text.frameTool, icon: /* @__PURE__ */ jsx(FrameGlyph, {}), shortcut: "F" }] : [],
262
268
  ...creates ? [
263
269
  { id: "text", label: text.textTool, icon: /* @__PURE__ */ jsx(TypeGlyph, {}), shortcut: "T" },
264
270
  { id: "sticky", label: text.stickyTool, icon: /* @__PURE__ */ jsx(StickyNoteGlyph, {}), shortcut: "S" }
@@ -328,11 +334,14 @@ function CanvasBoard({
328
334
  if (!event.repeat) setSpaceHeld(true);
329
335
  return;
330
336
  }
331
- if ((event.key === "Delete" || event.key === "Backspace") && editable && shownSelection?.kind === "note") {
332
- event.preventDefault();
333
- onNoteRemove?.(shownSelection.id);
334
- setSelected(null);
335
- return;
337
+ if ((event.key === "Delete" || event.key === "Backspace") && editable && shownSelection !== null) {
338
+ const remove = shownSelection.kind === "note" ? onNoteRemove : onBoardRemove;
339
+ if (remove) {
340
+ event.preventDefault();
341
+ remove(shownSelection.id);
342
+ setSelected(null);
343
+ return;
344
+ }
336
345
  }
337
346
  const picked = toolForKey(tools, event);
338
347
  if (picked !== void 0) {
@@ -344,6 +353,13 @@ function CanvasBoard({
344
353
  const target = event.target instanceof Element ? event.target : null;
345
354
  if (!target?.closest(".crewlet-canvas__viewport")) return;
346
355
  if (target.closest(".crewlet-canvas-board__board, .crewlet-canvas-board__note")) return;
356
+ if (acting === "frame" && onBoardCreate && canvas.current) {
357
+ const at = canvas.current.worldAt({ x: event.clientX, y: event.clientY });
358
+ const id = onBoardCreate({ x: Math.round(at.x), y: Math.round(at.y) });
359
+ setTool("move");
360
+ if (id !== void 0) setSelected({ kind: "board", id });
361
+ return;
362
+ }
347
363
  if ((acting === "text" || acting === "sticky") && onNoteCreate && canvas.current) {
348
364
  const at = canvas.current.worldAt({ x: event.clientX, y: event.clientY });
349
365
  const id = onNoteCreate(acting === "text" ? "title" : "sticky", {
@@ -1,7 +1,7 @@
1
- import { HuePicker } from './chunk-GPHWCK7M.js';
1
+ import { HuePicker } from './chunk-SUXP4OBT.js';
2
2
  import { Popover } from './chunk-K3IJQNB7.js';
3
- import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
4
3
  import { CharacterPicker } from './chunk-YEVG2X5R.js';
4
+ import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
5
5
  import { Avatar } from './chunk-PZKHBB7D.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './AvatarPicker-PREY36MG.css';
@@ -1,4 +1,4 @@
1
- import { changeText, sheetLabels } from './chunk-VI5FWDZW.js';
1
+ import { changeText, sheetLabels } from './chunk-OOMXLJ3S.js';
2
2
  import { Tooltip } from './chunk-6ZJ3N7QI.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './ChangeMark-3VMTW7MT.css';
@@ -1,4 +1,4 @@
1
- import { ArtifactKindGlyph } from './chunk-XTOVADJU.js';
1
+ import { ArtifactKindGlyph } from './chunk-CE2THTQR.js';
2
2
  import { ShieldGlyph, ActivityGlyph, GaugeGlyph, PackageGlyph, FolderGlyph, ClockGlyph, DatabaseGlyph, Settings2Glyph, BookOpenGlyph, FlagGlyph, StarGlyph, WandSparklesGlyph, BugGlyph, TargetGlyph, ImageGlyph, CodeGlyph, CoinsGlyph, UserGlyph, UsersGlyph, ChartNoAxesGanttGlyph, SquareKanbanGlyph, ListChecksGlyph, ListGlyph, GlobeGlyph, CompassGlyph, FileTextGlyph, TableGlyph, CalendarGlyph, LayoutDashboardGlyph, ChartPieGlyph, ChartColumnGlyph } from '@crewlethq/icons/glyphs';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -0,0 +1,342 @@
1
+ import { Select } from './chunk-BQ7AKL2N.js';
2
+ import { SHEET_LABELS, SHEET_COLUMN_TYPES, optionHue } from './chunk-OOMXLJ3S.js';
3
+ import { HueSwatch } from './chunk-SUXP4OBT.js';
4
+ import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
5
+ import { Checkbox } from './chunk-CPEPST4S.js';
6
+ import { FormField, Input } from './chunk-6QFAK2WV.js';
7
+ import { Kbd } from './chunk-SMBKXWML.js';
8
+ import { Menu } from './chunk-BUVCV3WI.js';
9
+ import { Button } from './chunk-OG6CL3EB.js';
10
+ import { IconButton } from './chunk-4FQT6ZAY.js';
11
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
12
+ import { cx } from './chunk-ODEQTPFM.js';
13
+ import './SheetColumnEditor-BO2HKFRB.css';
14
+ import { useId, useRef, useState, useEffect } from 'react';
15
+ import { StarGlyph, LinkGlyph, CalendarGlyph, UserGlyph, CircleCheckGlyph, ListChecksGlyph, ListGlyph, CheckGlyph, HashGlyph, TextAlignStartGlyph, TypeGlyph, XGlyph, ChevronLeftGlyph, ChevronRightGlyph, TrashGlyph } from '@crewlethq/icons/glyphs';
16
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
17
+
18
+ function SheetColumnTypeGlyph({ type, size = "sm" }) {
19
+ const Glyph = TYPE_GLYPHS[type];
20
+ return /* @__PURE__ */ jsx(Glyph, { size });
21
+ }
22
+ var TYPE_GLYPHS = {
23
+ text: TypeGlyph,
24
+ longtext: TextAlignStartGlyph,
25
+ number: HashGlyph,
26
+ checkbox: CheckGlyph,
27
+ select: ListGlyph,
28
+ multiselect: ListChecksGlyph,
29
+ status: CircleCheckGlyph,
30
+ person: UserGlyph,
31
+ date: CalendarGlyph,
32
+ url: LinkGlyph,
33
+ rating: StarGlyph
34
+ };
35
+ var CATEGORIES = ["todo", "in_progress", "done", "blocked"];
36
+ var SHEET_COLUMN_EDITOR_LABELS = {
37
+ name: "Name",
38
+ nameMissing: "Give the column a name.",
39
+ type: "Type",
40
+ types: SHEET_LABELS.types,
41
+ typeDetails: {
42
+ text: "One line of text",
43
+ longtext: "Paragraphs and notes",
44
+ number: "A figure, a count or an amount",
45
+ checkbox: "Yes or no",
46
+ select: "One choice from a list",
47
+ multiselect: "Any choices from a list",
48
+ status: "Where a row stands",
49
+ person: "A person or an agent",
50
+ date: "A calendar date",
51
+ url: "A web address",
52
+ rating: "A score in stars"
53
+ },
54
+ suggestion: (type) => `Looks like ${type.toLowerCase()}`,
55
+ useType: (type) => `Use ${type}`,
56
+ choices: "Choices",
57
+ addChoice: "Add a choice",
58
+ choiceName: (index) => `Choice ${index}`,
59
+ choiceColor: (choice) => `Color of ${choice}`,
60
+ noColor: "Plain",
61
+ choiceCategory: (choice) => `Category of ${choice}`,
62
+ categories: { todo: "To do", in_progress: "In progress", done: "Done", blocked: "Blocked" },
63
+ removeChoice: (choice) => `Remove ${choice}`,
64
+ noChoices: "Add at least one choice.",
65
+ duplicateChoice: (choice) => `There is already a choice called \u201C${choice}\u201D.`,
66
+ statusStarters: [
67
+ { label: "Not started", category: "todo" },
68
+ { label: "In progress", category: "in_progress" },
69
+ { label: "Done", category: "done" }
70
+ ],
71
+ required: "Required",
72
+ requiredDetail: "A row is not saved with this left empty.",
73
+ stars: "Stars",
74
+ moveBefore: "Move left",
75
+ moveAfter: "Move right",
76
+ deleteColumn: "Delete column",
77
+ done: "Done"
78
+ };
79
+ function defaultOptionId(label, taken) {
80
+ const base = label.normalize("NFKD").replace(/\p{M}+/gu, "").replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase().slice(0, 56) || "option";
81
+ if (!taken.includes(base)) return base;
82
+ for (let n = 2; ; n += 1) {
83
+ const id = `${base}_${n}`;
84
+ if (!taken.includes(id)) return id;
85
+ }
86
+ }
87
+ var hasChoices = (type) => type === "select" || type === "multiselect" || type === "status";
88
+ function nextHue(options) {
89
+ const used = new Set(options.map((option) => optionHue(option.color)));
90
+ return NODE_HUES.find((hue) => !used.has(hue)) ?? NODE_HUES[options.length % NODE_HUES.length];
91
+ }
92
+ function SheetColumnEditor({
93
+ column,
94
+ onChange,
95
+ onDone,
96
+ onDelete,
97
+ deleteDisabledReason,
98
+ onMove,
99
+ canMoveBefore = true,
100
+ canMoveAfter = true,
101
+ types = SHEET_COLUMN_TYPES,
102
+ typeLockedReason,
103
+ suggestedType,
104
+ nameError,
105
+ optionId = defaultOptionId,
106
+ selectName = false,
107
+ labels: overrides,
108
+ className
109
+ }) {
110
+ const labels = {
111
+ ...SHEET_COLUMN_EDITOR_LABELS,
112
+ ...overrides,
113
+ types: { ...SHEET_COLUMN_EDITOR_LABELS.types, ...overrides?.types },
114
+ typeDetails: { ...SHEET_COLUMN_EDITOR_LABELS.typeDetails, ...overrides?.typeDetails },
115
+ categories: { ...SHEET_COLUMN_EDITOR_LABELS.categories, ...overrides?.categories }
116
+ };
117
+ const id = useId();
118
+ const nameRef = useRef(null);
119
+ const addRef = useRef(null);
120
+ const [name, setName] = useState(column.label);
121
+ const [draft, setDraft] = useState("");
122
+ const [choiceError, setChoiceError] = useState(null);
123
+ const options = column.options ?? [];
124
+ useEffect(() => {
125
+ setName((now) => now.trim() === column.label ? now : column.label);
126
+ }, [column.label]);
127
+ useEffect(() => {
128
+ if (!selectName) return;
129
+ nameRef.current?.focus({ preventScroll: true });
130
+ nameRef.current?.select();
131
+ }, [selectName]);
132
+ const change = (patch) => onChange({ ...column, ...patch });
133
+ const setType = (type) => {
134
+ if (type === column.type) return;
135
+ const { options: _options, min: _min, max: _max, maxItems: _maxItems, precision: _precision, numberStyle: _style, currency: _currency, ...rest } = column;
136
+ const next = { ...rest, type };
137
+ if (hasChoices(type)) {
138
+ const kept = hasChoices(column.type) ? options : [];
139
+ next.options = type === "status" ? kept.length > 0 ? kept.map((option) => ({ ...option, category: option.category ?? "todo" })) : starters(labels.statusStarters, optionId) : kept.map(({ category: _category, ...option }) => ({ ...option, color: option.color ?? nextHue(kept) }));
140
+ }
141
+ if (type === "rating") next.max = 5;
142
+ if (type === "checkbox") delete next.required;
143
+ onChange(next);
144
+ if (hasChoices(type) && type !== "status") window.requestAnimationFrame(() => addRef.current?.focus({ preventScroll: true }));
145
+ };
146
+ const setOption = (index, patch) => change({ options: options.map((option, at) => at === index ? { ...option, ...patch } : option) });
147
+ const addChoice = () => {
148
+ const label = draft.trim();
149
+ if (label === "") return;
150
+ if (options.some((option) => option.label.trim().toLowerCase() === label.toLowerCase())) {
151
+ setChoiceError(labels.duplicateChoice(label));
152
+ return;
153
+ }
154
+ const added = column.type === "status" ? { id: optionId(label, options.map((option) => option.id)), label, category: "todo" } : { id: optionId(label, options.map((option) => option.id)), label, color: nextHue(options) };
155
+ change({ options: [...options, added] });
156
+ setDraft("");
157
+ setChoiceError(null);
158
+ };
159
+ const onNameKey = (event) => {
160
+ if (event.key === "Enter" && !event.nativeEvent.isComposing) {
161
+ event.preventDefault();
162
+ onDone?.();
163
+ }
164
+ };
165
+ const typeName = (type) => labels.types[type];
166
+ const offered = types.includes(column.type) ? types : [column.type, ...types];
167
+ const suggestion = suggestedType && suggestedType !== column.type && !typeLockedReason && types.includes(suggestedType) ? suggestedType : void 0;
168
+ const nameMissing = name.trim() === "";
169
+ return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-sheet-column-editor", className), children: [
170
+ /* @__PURE__ */ jsx(FormField, { label: labels.name, error: nameMissing ? labels.nameMissing : nameError, children: (field) => /* @__PURE__ */ jsx(
171
+ Input,
172
+ {
173
+ ref: nameRef,
174
+ id: field.id,
175
+ "aria-describedby": field.describedBy,
176
+ error: field.invalid,
177
+ inputSize: "sm",
178
+ width: "full",
179
+ value: name,
180
+ maxLength: 120,
181
+ onChange: (event) => {
182
+ setName(event.target.value);
183
+ if (event.target.value.trim() !== "") change({ label: event.target.value.trim() });
184
+ },
185
+ onBlur: () => {
186
+ if (nameMissing) setName(column.label);
187
+ },
188
+ onKeyDown: onNameKey
189
+ }
190
+ ) }),
191
+ /* @__PURE__ */ jsx(FormField, { label: labels.type, helper: typeLockedReason, children: (field) => /* @__PURE__ */ jsx(
192
+ Select,
193
+ {
194
+ id: field.id,
195
+ "aria-describedby": field.describedBy,
196
+ size: "sm",
197
+ width: "full",
198
+ disabled: typeLockedReason !== void 0,
199
+ value: column.type,
200
+ onChange: (value) => {
201
+ if (typeof value === "string" && SHEET_COLUMN_TYPES.includes(value)) setType(value);
202
+ },
203
+ options: offered.map((type) => ({
204
+ value: type,
205
+ label: typeName(type),
206
+ description: labels.typeDetails[type],
207
+ leading: /* @__PURE__ */ jsx(SheetColumnTypeGlyph, { type }),
208
+ text: typeName(type)
209
+ }))
210
+ }
211
+ ) }),
212
+ suggestion ? /* @__PURE__ */ jsxs("div", { className: "crewlet-sheet-column-editor__suggestion", children: [
213
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-sheet-column-editor__suggestion-text", children: [
214
+ /* @__PURE__ */ jsx(SheetColumnTypeGlyph, { type: suggestion, size: "xs" }),
215
+ labels.suggestion(typeName(suggestion))
216
+ ] }),
217
+ /* @__PURE__ */ jsx(Button, { size: "small", variant: "ghost", onClick: () => setType(suggestion), children: labels.useType(typeName(suggestion)) })
218
+ ] }) : null,
219
+ hasChoices(column.type) ? /* @__PURE__ */ jsxs(FormField, { as: "fieldset", label: labels.choices, error: options.length === 0 ? labels.noChoices : choiceError ?? void 0, children: [
220
+ /* @__PURE__ */ jsx("ul", { className: "crewlet-sheet-column-editor__choices", "aria-label": labels.choices, children: options.map((option, index) => /* @__PURE__ */ jsxs("li", { className: "crewlet-sheet-column-editor__choice", children: [
221
+ column.type === "status" ? null : /* @__PURE__ */ jsx(
222
+ Menu,
223
+ {
224
+ label: labels.choiceColor(option.label),
225
+ renderTrigger: (trigger) => /* @__PURE__ */ jsx(
226
+ IconButton,
227
+ {
228
+ ...trigger,
229
+ label: labels.choiceColor(option.label),
230
+ icon: /* @__PURE__ */ jsx(HueSwatch, { hue: optionHue(option.color) === "neutral" ? "none" : optionHue(option.color) }),
231
+ size: "sm"
232
+ }
233
+ ),
234
+ items: [
235
+ { key: "none", label: labels.noColor, icon: /* @__PURE__ */ jsx(HueSwatch, { hue: "none" }), checked: optionHue(option.color) === "neutral", onSelect: () => setOption(index, { color: "neutral" }) },
236
+ ...NODE_HUES.map((hue) => ({
237
+ key: hue,
238
+ label: NODE_HUE_NAMES[hue],
239
+ icon: /* @__PURE__ */ jsx(HueSwatch, { hue }),
240
+ checked: optionHue(option.color) === hue,
241
+ onSelect: () => setOption(index, { color: hue })
242
+ }))
243
+ ]
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx(
247
+ Input,
248
+ {
249
+ "aria-label": labels.choiceName(index + 1),
250
+ inputSize: "sm",
251
+ width: "full",
252
+ value: option.label,
253
+ maxLength: 120,
254
+ onChange: (event) => setOption(index, { label: event.target.value }),
255
+ onBlur: (event) => {
256
+ if (event.target.value.trim() === "") setOption(index, { label: option.id });
257
+ }
258
+ }
259
+ ),
260
+ column.type === "status" ? /* @__PURE__ */ jsxs(Fragment, { children: [
261
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx("label", { htmlFor: `${id}-category-${index}`, children: labels.choiceCategory(option.label) }) }),
262
+ /* @__PURE__ */ jsx(
263
+ Select,
264
+ {
265
+ id: `${id}-category-${index}`,
266
+ size: "sm",
267
+ width: "auto",
268
+ value: option.category ?? "todo",
269
+ onChange: (value) => setOption(index, { category: value }),
270
+ options: CATEGORIES.map((category) => ({ value: category, label: labels.categories[category] }))
271
+ }
272
+ )
273
+ ] }) : null,
274
+ /* @__PURE__ */ jsx(
275
+ IconButton,
276
+ {
277
+ label: labels.removeChoice(option.label),
278
+ icon: /* @__PURE__ */ jsx(XGlyph, { size: "sm" }),
279
+ size: "sm",
280
+ variant: "ghost-danger",
281
+ onClick: () => change({ options: options.filter((_, at) => at !== index) })
282
+ }
283
+ )
284
+ ] }, option.id)) }),
285
+ /* @__PURE__ */ jsx(
286
+ Input,
287
+ {
288
+ ref: addRef,
289
+ "aria-label": labels.addChoice,
290
+ placeholder: labels.addChoice,
291
+ inputSize: "sm",
292
+ width: "full",
293
+ value: draft,
294
+ maxLength: 120,
295
+ trailing: draft.trim() ? /* @__PURE__ */ jsx(Kbd, { subtle: true, children: "Enter" }) : void 0,
296
+ onChange: (event) => {
297
+ setDraft(event.target.value);
298
+ setChoiceError(null);
299
+ },
300
+ onKeyDown: (event) => {
301
+ if (event.key === "Enter" && !event.nativeEvent.isComposing) {
302
+ event.preventDefault();
303
+ addChoice();
304
+ }
305
+ }
306
+ }
307
+ )
308
+ ] }) : null,
309
+ column.type === "rating" ? /* @__PURE__ */ jsx(FormField, { label: labels.stars, children: (field) => /* @__PURE__ */ jsx(
310
+ Select,
311
+ {
312
+ id: field.id,
313
+ size: "sm",
314
+ width: "auto",
315
+ value: String(column.max ?? 5),
316
+ onChange: (value) => change({ max: Number(value) }),
317
+ options: [3, 4, 5, 6, 7, 8, 9, 10].map((n) => ({ value: String(n), label: String(n) }))
318
+ }
319
+ ) }) : null,
320
+ column.type === "checkbox" ? null : /* @__PURE__ */ jsx(Checkbox, { size: "sm", label: labels.required, description: labels.requiredDetail, checked: column.required ?? false, onChange: (event) => change({ required: event.target.checked || void 0 }) }),
321
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-sheet-column-editor__foot", children: [
322
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-sheet-column-editor__foot-start", children: [
323
+ onMove ? /* @__PURE__ */ jsxs(Fragment, { children: [
324
+ /* @__PURE__ */ jsx(IconButton, { label: labels.moveBefore, icon: /* @__PURE__ */ jsx(ChevronLeftGlyph, { size: "sm" }), size: "sm", disabledReason: canMoveBefore ? void 0 : labels.moveBefore, onClick: () => onMove(-1) }),
325
+ /* @__PURE__ */ jsx(IconButton, { label: labels.moveAfter, icon: /* @__PURE__ */ jsx(ChevronRightGlyph, { size: "sm" }), size: "sm", disabledReason: canMoveAfter ? void 0 : labels.moveAfter, onClick: () => onMove(1) })
326
+ ] }) : null,
327
+ onDelete ? /* @__PURE__ */ jsx(IconButton, { label: labels.deleteColumn, icon: /* @__PURE__ */ jsx(TrashGlyph, { size: "sm" }), size: "sm", variant: "ghost-danger", disabledReason: deleteDisabledReason, onClick: onDelete }) : null
328
+ ] }),
329
+ onDone ? /* @__PURE__ */ jsx(Button, { size: "small", variant: "primary", onClick: onDone, children: labels.done }) : null
330
+ ] })
331
+ ] });
332
+ }
333
+ function starters(list, optionId) {
334
+ const taken = [];
335
+ return list.map(({ label, category }) => {
336
+ const id = optionId(label, taken);
337
+ taken.push(id);
338
+ return { id, label, category };
339
+ });
340
+ }
341
+
342
+ export { SHEET_COLUMN_EDITOR_LABELS, SheetColumnEditor, SheetColumnTypeGlyph };
@@ -1,12 +1,13 @@
1
1
  import { isApplePlatform, Kbd } from './chunk-SMBKXWML.js';
2
2
  import { Tooltip } from './chunk-6ZJ3N7QI.js';
3
3
  import { SegmentedControl } from './chunk-CCAXYHQS.js';
4
- import { ArtifactIcon } from './chunk-PLDUNXAO.js';
5
- import { Menu } from './chunk-3EB2AV3H.js';
4
+ import { ArtifactIcon } from './chunk-ILDNJHRU.js';
5
+ import { Menu } from './chunk-BUVCV3WI.js';
6
6
  import { Button } from './chunk-OG6CL3EB.js';
7
7
  import { IconButton } from './chunk-4FQT6ZAY.js';
8
8
  import { cx } from './chunk-ODEQTPFM.js';
9
- import './ArtifactBar-C462VD4C.css';
9
+ import './ArtifactKinds-CVD3FCYO.css';
10
+ import './ArtifactBar-HV5AT4RG.css';
10
11
  import { useId, useState, useRef, useEffect } from 'react';
11
12
  import { ChevronLeftGlyph, EllipsisGlyph, ChevronDownGlyph } from '@crewlethq/icons/glyphs';
12
13
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -82,7 +83,7 @@ function ArtifactBar({
82
83
  /* @__PURE__ */ jsxs("div", { className: "crewlet-artifact-bar__lead", children: [
83
84
  start,
84
85
  back ? /* @__PURE__ */ jsx(Tooltip, { content: back.label, placement: "bottom", children: /* @__PURE__ */ jsx(IconButton, { asChild: true, label: back.label, size: "sm", variant: "ghost", title: "", children: /* @__PURE__ */ jsx("a", { href: back.href, children: /* @__PURE__ */ jsx(ChevronLeftGlyph, { size: "sm" }) }) }) }) : null,
85
- /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__glyph", role: "img", "aria-label": kindLabel, title: kindLabel, children: /* @__PURE__ */ jsx(ArtifactIcon, { icon: icon ?? void 0, kind, size: "sm" }) }),
86
+ /* @__PURE__ */ jsx("span", { className: cx("crewlet-artifact-bar__glyph", `crewlet-kind--${kind}`), role: "img", "aria-label": kindLabel, title: kindLabel, children: /* @__PURE__ */ jsx(ArtifactIcon, { icon: icon ?? void 0, kind, size: "sm" }) }),
86
87
  pending ? /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__placeholder", "aria-hidden": true }) : /* @__PURE__ */ jsx(
87
88
  BarTitle,
88
89
  {
@@ -175,8 +176,12 @@ function LabelledTool({ tool, apple }) {
175
176
  leadingIcon: tool.icon,
176
177
  disabledReason: tool.disabledReason,
177
178
  "aria-keyshortcuts": shortcut,
179
+ "aria-label": tool.shortLabel ? tool.label : void 0,
178
180
  onClick: tool.onSelect,
179
- children: tool.label
181
+ children: tool.shortLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [
182
+ /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__word-full", children: tool.label }),
183
+ /* @__PURE__ */ jsx("span", { className: "crewlet-artifact-bar__word-short", children: tool.shortLabel })
184
+ ] }) : tool.label
180
185
  }
181
186
  ) });
182
187
  }