@crewlethq/ui 0.24.0 → 0.26.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 (172) hide show
  1. package/README.md +85 -3
  2. package/dist/ArrangeList/index.js +2 -2
  3. package/dist/ArtifactCover/ArtifactCover.d.ts +37 -0
  4. package/dist/ArtifactCover/DashboardCover.d.ts +46 -0
  5. package/dist/ArtifactCover/index.d.ts +6 -0
  6. package/dist/ArtifactCover/index.js +14 -0
  7. package/dist/ArtifactCover-D4MBEJ5H.css +67 -0
  8. package/dist/ArtifactIcon/ArtifactIcon.d.ts +29 -0
  9. package/dist/ArtifactIcon/index.d.ts +2 -0
  10. package/dist/ArtifactIcon/index.js +13 -0
  11. package/dist/AvatarPicker/index.js +6 -6
  12. package/dist/Canvas/Canvas.d.ts +13 -2
  13. package/dist/Canvas/index.js +1 -1
  14. package/dist/CanvasBoard/CanvasBoard.d.ts +117 -0
  15. package/dist/CanvasBoard/budget.d.ts +38 -0
  16. package/dist/CanvasBoard/index.d.ts +5 -0
  17. package/dist/CanvasBoard/index.js +10 -0
  18. package/dist/CanvasBoard-ZLPDINSM.css +236 -0
  19. package/dist/CanvasSchematic/CanvasSchematic.d.ts +31 -0
  20. package/dist/CanvasSchematic/index.d.ts +3 -0
  21. package/dist/CanvasSchematic/index.js +2 -0
  22. package/dist/CanvasSchematic-PLB3N46J.css +36 -0
  23. package/dist/ChangeMark/index.js +3 -3
  24. package/dist/CharacterPicker/index.js +2 -2
  25. package/dist/Checkbox/Checkbox.d.ts +6 -0
  26. package/dist/Checkbox/index.js +1 -1
  27. package/dist/{Checkbox-KT7RS6QQ.css → Checkbox-5UORUG3F.css} +16 -0
  28. package/dist/CommentThread/index.js +2 -2
  29. package/dist/DashboardCover-RMINBODB.css +143 -0
  30. package/dist/DataTable/index.js +3 -3
  31. package/dist/DataView/index.js +5 -5
  32. package/dist/DatasetSource/DatasetSource.d.ts +83 -0
  33. package/dist/DatasetSource/index.d.ts +3 -0
  34. package/dist/DatasetSource/index.js +7 -0
  35. package/dist/DatasetSource-47LBDMPR.css +129 -0
  36. package/dist/DocTabsEditor/DocTabsEditor.d.ts +60 -0
  37. package/dist/DocTabsEditor/index.d.ts +3 -0
  38. package/dist/DocTabsEditor/index.js +9 -0
  39. package/dist/DocTabsEditor-RCOWHX5J.css +78 -0
  40. package/dist/DownloadButton/index.js +2 -2
  41. package/dist/HuePicker/index.js +4 -4
  42. package/dist/LinkInterstitial/index.js +2 -2
  43. package/dist/MarkdownEditor/index.js +5 -5
  44. package/dist/MergeConflicts/MergeConflicts.d.ts +51 -0
  45. package/dist/MergeConflicts/index.d.ts +3 -0
  46. package/dist/MergeConflicts/index.js +9 -0
  47. package/dist/MergeConflicts-O44ESH4T.css +77 -0
  48. package/dist/Meter/index.js +1 -1
  49. package/dist/{Meter-5VCSFMZW.css → Meter-ZZRFUEOH.css} +15 -0
  50. package/dist/ObjectHeader/ObjectHeader.d.ts +7 -1
  51. package/dist/ObjectHeader/index.js +1 -1
  52. package/dist/{ObjectHeader-UNVYM2KD.css → ObjectHeader-D7GU7QNI.css} +15 -0
  53. package/dist/PeopleRail/index.js +2 -2
  54. package/dist/PresenceModel/index.d.ts +1 -1
  55. package/dist/PresenceModel/index.js +1 -1
  56. package/dist/PresenceModel/presence.d.ts +10 -2
  57. package/dist/PresenceStack/index.js +2 -2
  58. package/dist/PresenterView/PresenterView.d.ts +52 -0
  59. package/dist/PresenterView/index.d.ts +3 -0
  60. package/dist/PresenterView/index.js +8 -0
  61. package/dist/PresenterView-T2C6ZZ3N.css +103 -0
  62. package/dist/Section/index.js +1 -1
  63. package/dist/{Section-QRUPRIQ2.css → Section-QR3ILQVK.css} +4 -1
  64. package/dist/SegmentedControl/SegmentedControl.d.ts +17 -0
  65. package/dist/SegmentedControl/index.js +4 -4
  66. package/dist/{SegmentedControl-PKBLJVSA.css → SegmentedControl-FLI45IOW.css} +13 -0
  67. package/dist/ShareDialog/index.js +3 -3
  68. package/dist/SheetGrid/SheetGrid.d.ts +24 -2
  69. package/dist/SheetGrid/index.js +10 -6
  70. package/dist/{SheetGrid-4HOXDVIB.css → SheetGrid-J3TKKXZL.css} +87 -17
  71. package/dist/SheetModel/edits.d.ts +7 -1
  72. package/dist/SheetModel/index.js +2 -2
  73. package/dist/SheetModel/labels.d.ts +9 -0
  74. package/dist/SheetModel/types.d.ts +6 -0
  75. package/dist/SlideCompare/SlideCompare.d.ts +52 -0
  76. package/dist/SlideCompare/index.d.ts +3 -0
  77. package/dist/SlideCompare/index.js +7 -0
  78. package/dist/SlideCompare-MGM3U2ME.css +80 -0
  79. package/dist/SlideFilmstrip/SlideFilmstrip.d.ts +50 -0
  80. package/dist/SlideFilmstrip/index.d.ts +3 -0
  81. package/dist/SlideFilmstrip/index.js +8 -0
  82. package/dist/SlideFilmstrip-BCLNAHFX.css +108 -0
  83. package/dist/SlideGrid/SlideGrid.d.ts +32 -0
  84. package/dist/SlideGrid/index.d.ts +3 -0
  85. package/dist/SlideGrid/index.js +5 -0
  86. package/dist/SlideGrid-RT6QEQEE.css +82 -0
  87. package/dist/SlideStage/SlideStage.d.ts +47 -0
  88. package/dist/SlideStage/index.d.ts +5 -0
  89. package/dist/SlideStage/index.js +4 -0
  90. package/dist/SlideStage/useSlideKeys.d.ts +21 -0
  91. package/dist/SlideStage-XIOTMMRU.css +32 -0
  92. package/dist/Switcher/index.js +2 -2
  93. package/dist/TableCells/index.js +2 -2
  94. package/dist/Tabs/index.js +2 -2
  95. package/dist/Tabs/roving.d.ts +1 -0
  96. package/dist/TagGroup/TagGroup.d.ts +16 -1
  97. package/dist/TagGroup/index.js +1 -1
  98. package/dist/{TagGroup-BCQZD7ZD.css → TagGroup-NAXTJHDS.css} +22 -0
  99. package/dist/ThemeGallery/index.js +2 -2
  100. package/dist/ThemeSwitcher/index.js +5 -5
  101. package/dist/TreeCanvas/index.js +2 -2
  102. package/dist/VersionCompare/VersionCompare.d.ts +8 -1
  103. package/dist/VersionCompare/index.js +5 -5
  104. package/dist/VersionTimeline/index.js +1 -1
  105. package/dist/{VersionTimeline-EBJ6MIPJ.css → VersionTimeline-6KRXEEOO.css} +7 -7
  106. package/dist/WidgetFrame/WidgetFrame.d.ts +73 -0
  107. package/dist/WidgetFrame/index.d.ts +3 -0
  108. package/dist/WidgetFrame/index.js +6 -0
  109. package/dist/WidgetFrame-4EFJOJMW.css +127 -0
  110. package/dist/chunk-3D7PSL2L.js +438 -0
  111. package/dist/{chunk-SJCKMSQK.js → chunk-5LUI3WQP.js} +1 -1
  112. package/dist/{chunk-IASV5UCP.js → chunk-7T42VQQT.js} +3 -1
  113. package/dist/{chunk-BJCFNRGH.js → chunk-BEHFTRMZ.js} +1 -1
  114. package/dist/chunk-BQYQWJPK.js +80 -0
  115. package/dist/{chunk-KLIEPFEZ.js → chunk-C2FRTWKO.js} +1 -1
  116. package/dist/{chunk-APS747CR.js → chunk-EHQTPVV4.js} +5 -3
  117. package/dist/{chunk-A2UXBCLO.js → chunk-FAQGGX2Z.js} +1 -1
  118. package/dist/chunk-FQCLKD7U.js +2 -0
  119. package/dist/{chunk-J4OKGJQ6.js → chunk-FVLCTCMV.js} +1 -1
  120. package/dist/{chunk-XJFOOXCF.js → chunk-HJEVSQN6.js} +1 -1
  121. package/dist/chunk-HONZQ4UR.js +107 -0
  122. package/dist/{chunk-5PSXBL73.js → chunk-HVIX5ECM.js} +1 -1
  123. package/dist/{chunk-36CWC2NH.js → chunk-INTEH4F3.js} +271 -143
  124. package/dist/{chunk-F6NZOVWL.js → chunk-IW55G7XG.js} +6 -2
  125. package/dist/chunk-KNLJL3VP.js +101 -0
  126. package/dist/chunk-KSSSFLE2.js +105 -0
  127. package/dist/{chunk-TXAFKH2A.js → chunk-KZOGQXSP.js} +6 -0
  128. package/dist/{chunk-CS65QSIJ.js → chunk-LZHLSQYK.js} +2 -2
  129. package/dist/chunk-MQEEQVG6.js +62 -0
  130. package/dist/chunk-NBWNLYWZ.js +62 -0
  131. package/dist/{chunk-YYZRLLLY.js → chunk-NHBP2XS5.js} +19 -3
  132. package/dist/chunk-O2EGEONV.js +90 -0
  133. package/dist/{chunk-YM3GJHGW.js → chunk-ODT5H4MN.js} +1 -1
  134. package/dist/{chunk-JCSXFAXG.js → chunk-OJRDEVHV.js} +1 -1
  135. package/dist/{chunk-U63Y5OCW.js → chunk-PRNX5AFE.js} +2 -2
  136. package/dist/chunk-Q4A5CGUB.js +43 -0
  137. package/dist/{chunk-7QL2OFP6.js → chunk-RCQXUT5K.js} +25 -9
  138. package/dist/{chunk-CBOICT64.js → chunk-RKKO7QHH.js} +2 -0
  139. package/dist/{chunk-TBIZSQHB.js → chunk-RSC7UJCR.js} +1 -1
  140. package/dist/chunk-RWA4H2TV.js +73 -0
  141. package/dist/{chunk-OQT7GSKJ.js → chunk-SGIQCI6Y.js} +1 -1
  142. package/dist/{chunk-35UKQ33X.js → chunk-SVW3VG72.js} +2 -2
  143. package/dist/{chunk-4PZ6FJKW.js → chunk-UGNUUVRI.js} +2 -2
  144. package/dist/chunk-UOR7TOAU.js +191 -0
  145. package/dist/{chunk-XMGB3ZAT.js → chunk-URUGEAFB.js} +3 -2
  146. package/dist/chunk-UZ7ZUSLH.js +179 -0
  147. package/dist/chunk-V2Z24W2Z.js +75 -0
  148. package/dist/{chunk-I7WXZOWA.js → chunk-VGE3G3T4.js} +3 -1
  149. package/dist/{chunk-UNZ7TVV5.js → chunk-W4XYY73O.js} +7 -9
  150. package/dist/{chunk-IPM2E6UI.js → chunk-WJDQ7XQA.js} +1 -1
  151. package/dist/{chunk-PPAQFGS2.js → chunk-YEKYVJQR.js} +1 -1
  152. package/dist/chunk-Z54BPRL6.js +74 -0
  153. package/dist/{chunk-S35G6PNC.js → chunk-Z7JYG5TF.js} +5 -4
  154. package/dist/chunk-ZZDY4XL7.js +112 -0
  155. package/dist/generated/index.d.ts +13 -0
  156. package/dist/generated/index.js +84 -71
  157. package/dist/index.js +84 -71
  158. package/dist/styles.css +1644 -153
  159. package/dist/utils/csv.d.ts +18 -0
  160. package/dist/utils/elementToPng.d.ts +49 -0
  161. package/dist/utils/index.d.ts +4 -1
  162. package/dist/utils/index.js +2 -2
  163. package/dist/utils/useDownload.d.ts +14 -4
  164. package/package.json +3 -3
  165. package/dist/chunk-E6UWRXNM.js +0 -52
  166. package/dist/chunk-M54K52ZU.js +0 -2
  167. package/dist/chunk-U5LQ2AS5.js +0 -1
  168. package/dist/{chunk-KG6XRG5Z.js → chunk-5OY4LJFH.js} +1 -1
  169. package/dist/{chunk-ZM7HLFOA.js → chunk-L2OQRPXJ.js} +1 -1
  170. package/dist/{chunk-MUGM7SEG.js → chunk-LFNUH4GY.js} +1 -1
  171. package/dist/{chunk-PBNP7H2C.js → chunk-M2VJGNCD.js} +1 -1
  172. /package/dist/{chunk-MSSZHDZI.js → chunk-SLRKS5PF.js} +0 -0
@@ -0,0 +1,101 @@
1
+ import { isComposing } from './chunk-R25RGPUB.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './SlideStage-XIOTMMRU.css';
4
+ import { useRef, useState, useLayoutEffect, useEffect } from 'react';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var SLIDE_WIDTH = 1920;
8
+ var SLIDE_HEIGHT = 1080;
9
+ function SlideStage({
10
+ children,
11
+ label,
12
+ fit = "width",
13
+ scale,
14
+ width = SLIDE_WIDTH,
15
+ height = SLIDE_HEIGHT,
16
+ className
17
+ }) {
18
+ const box = useRef(null);
19
+ const [measured, setMeasured] = useState({
20
+ scale: 0,
21
+ left: 0,
22
+ top: 0
23
+ });
24
+ useLayoutEffect(() => {
25
+ const el = box.current;
26
+ if (!el || scale !== void 0) return void 0;
27
+ const read = () => {
28
+ const w = el.clientWidth;
29
+ const h = el.clientHeight;
30
+ if (fit === "contain") {
31
+ const s2 = Math.min(w / width, h / height);
32
+ setMeasured({ scale: s2, left: (w - width * s2) / 2, top: (h - height * s2) / 2 });
33
+ } else {
34
+ setMeasured({ scale: w / width, left: 0, top: 0 });
35
+ }
36
+ };
37
+ read();
38
+ if (typeof ResizeObserver === "undefined") return void 0;
39
+ const observer = new ResizeObserver(read);
40
+ observer.observe(el);
41
+ return () => observer.disconnect();
42
+ }, [fit, scale, width, height]);
43
+ const s = scale ?? measured.scale;
44
+ const boxStyle = fit === "width" || scale !== void 0 ? { aspectRatio: `${width} / ${height}`, ...scale !== void 0 ? { width: width * scale } : {} } : {};
45
+ const frameStyle = {
46
+ width,
47
+ height,
48
+ transform: `translate(${scale === void 0 ? measured.left : 0}px, ${scale === void 0 ? measured.top : 0}px) scale(${s})`,
49
+ // Hidden until measured, so a slide is never painted at full size for
50
+ // one frame inside a thumbnail.
51
+ visibility: s > 0 ? "visible" : "hidden"
52
+ };
53
+ return /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ ref: box,
57
+ className: cx("crewlet-slide-stage", `crewlet-slide-stage--${fit}`, className),
58
+ style: boxStyle,
59
+ role: "group",
60
+ "aria-roledescription": "slide",
61
+ "aria-label": label,
62
+ children: /* @__PURE__ */ jsx("div", { className: "crewlet-slide-stage__frame", style: frameStyle, children })
63
+ }
64
+ );
65
+ }
66
+ function typing(target) {
67
+ if (!(target instanceof HTMLElement)) return false;
68
+ return target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
69
+ }
70
+ function useSlideKeys({ onNext, onPrevious, onFirst, onLast, onExit, enabled = true }) {
71
+ useEffect(() => {
72
+ if (!enabled) return void 0;
73
+ const onKeyDown = (event) => {
74
+ if (event.defaultPrevented || isComposing(event) || typing(event.target)) return;
75
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
76
+ const act = {
77
+ ArrowRight: onNext,
78
+ ArrowDown: onNext,
79
+ PageDown: onNext,
80
+ " ": onNext,
81
+ Enter: onNext,
82
+ ArrowLeft: onPrevious,
83
+ ArrowUp: onPrevious,
84
+ PageUp: onPrevious,
85
+ Backspace: onPrevious,
86
+ Home: onFirst,
87
+ End: onLast,
88
+ Escape: onExit
89
+ };
90
+ const fn = act[event.key];
91
+ if (!fn) return;
92
+ if ((event.key === "Enter" || event.key === " ") && event.target instanceof HTMLButtonElement) return;
93
+ event.preventDefault();
94
+ fn();
95
+ };
96
+ document.addEventListener("keydown", onKeyDown);
97
+ return () => document.removeEventListener("keydown", onKeyDown);
98
+ }, [enabled, onNext, onPrevious, onFirst, onLast, onExit]);
99
+ }
100
+
101
+ export { SLIDE_HEIGHT, SLIDE_WIDTH, SlideStage, useSlideKeys };
@@ -0,0 +1,105 @@
1
+ import { SlideStage } from './chunk-KNLJL3VP.js';
2
+ import { useReorder } from './chunk-XJ2QEBMM.js';
3
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
+ import { cx } from './chunk-ODEQTPFM.js';
5
+ import './SlideFilmstrip-BCLNAHFX.css';
6
+ import { useRef } from 'react';
7
+ import { EyeOffGlyph, GripVerticalGlyph } from '@crewlethq/icons/glyphs';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
9
+
10
+ var LABELS = {
11
+ list: "Slides",
12
+ slide: (position, title) => `Slide ${position}, ${title}`,
13
+ hidden: "Hidden when presenting",
14
+ untitled: "Untitled"
15
+ };
16
+ function SlideFilmstrip({
17
+ slides,
18
+ selected,
19
+ onSelect,
20
+ renderSlide,
21
+ onReorder,
22
+ className,
23
+ labels
24
+ }) {
25
+ const text = { ...LABELS, ...labels };
26
+ const ids = slides.map((s) => s.id);
27
+ const byId = new Map(slides.map((s) => [s.id, s]));
28
+ const titleOf = (id) => byId.get(id)?.title || text.untitled;
29
+ const reorder = useReorder({
30
+ keys: ids,
31
+ onReorder: (next) => onReorder?.(next),
32
+ nameOf: (id) => text.slide(ids.indexOf(id) + 1, titleOf(id)),
33
+ axis: "vertical"
34
+ });
35
+ const order = onReorder ? reorder.order : ids;
36
+ const options = useRef(/* @__PURE__ */ new Map());
37
+ const go = (id) => {
38
+ if (!id) return;
39
+ onSelect(id);
40
+ options.current.get(id)?.focus();
41
+ };
42
+ const onKeyDown = (event) => {
43
+ const at = order.indexOf(selected);
44
+ const to = {
45
+ ArrowDown: order[at + 1],
46
+ ArrowUp: order[at - 1],
47
+ Home: order[0],
48
+ End: order[order.length - 1]
49
+ }[event.key];
50
+ if (to === void 0) return;
51
+ event.preventDefault();
52
+ go(to);
53
+ };
54
+ return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-slide-filmstrip", className), children: [
55
+ onReorder ? /* @__PURE__ */ jsx(VisuallyHidden, { id: reorder.hintId, children: reorder.hint }) : null,
56
+ /* @__PURE__ */ jsx(
57
+ "ol",
58
+ {
59
+ className: "crewlet-slide-filmstrip__list",
60
+ "aria-label": text.list,
61
+ ...onReorder ? reorder.containerProps : {},
62
+ children: order.map((id, i) => {
63
+ const slide = byId.get(id);
64
+ const isSelected = id === selected;
65
+ return /* @__PURE__ */ jsxs(
66
+ "li",
67
+ {
68
+ className: "crewlet-slide-filmstrip__item",
69
+ "data-selected": isSelected ? "true" : void 0,
70
+ "data-hidden": slide?.hidden ? "true" : void 0,
71
+ ...onReorder ? reorder.itemProps(id) : {},
72
+ children: [
73
+ /* @__PURE__ */ jsx("span", { className: "crewlet-slide-filmstrip__number", "aria-hidden": "true", children: i + 1 }),
74
+ /* @__PURE__ */ jsxs(
75
+ "button",
76
+ {
77
+ type: "button",
78
+ ref: (node) => {
79
+ if (node) options.current.set(id, node);
80
+ else options.current.delete(id);
81
+ },
82
+ className: "crewlet-slide-filmstrip__thumb",
83
+ "aria-current": isSelected ? "true" : void 0,
84
+ "aria-label": text.slide(i + 1, titleOf(id)) + (slide?.hidden ? `, ${text.hidden}` : ""),
85
+ tabIndex: isSelected ? 0 : -1,
86
+ onClick: () => go(id),
87
+ onKeyDown,
88
+ children: [
89
+ /* @__PURE__ */ jsx(SlideStage, { label: text.slide(i + 1, titleOf(id)), children: renderSlide(id) }),
90
+ slide?.hidden ? /* @__PURE__ */ jsx("span", { className: "crewlet-slide-filmstrip__hidden", children: /* @__PURE__ */ jsx(EyeOffGlyph, { size: "sm" }) }) : null
91
+ ]
92
+ }
93
+ ),
94
+ onReorder ? /* @__PURE__ */ jsx("button", { type: "button", className: "crewlet-slide-filmstrip__handle", ...reorder.handleProps(id), children: /* @__PURE__ */ jsx(GripVerticalGlyph, { size: "sm" }) }) : null
95
+ ]
96
+ },
97
+ id
98
+ );
99
+ })
100
+ }
101
+ )
102
+ ] });
103
+ }
104
+
105
+ export { SlideFilmstrip };
@@ -168,6 +168,7 @@ function Canvas({
168
168
  touch = true,
169
169
  labels,
170
170
  onReady,
171
+ onViewChange,
171
172
  ref,
172
173
  className
173
174
  }) {
@@ -225,6 +226,11 @@ function Canvas({
225
226
  useLayoutEffect(() => {
226
227
  if (ready) apply(viewNow.current);
227
228
  }, [ready, size, content, apply]);
229
+ const reportView = useRef(onViewChange);
230
+ reportView.current = onViewChange;
231
+ useLayoutEffect(() => {
232
+ if (ready) reportView.current?.(view, size);
233
+ }, [ready, view, size]);
228
234
  useLayoutEffect(() => {
229
235
  layer?.dispatchEvent(new CustomEvent(LAYER_REPOSITION_EVENT, { detail: view }));
230
236
  }, [view, layer]);
@@ -1,6 +1,6 @@
1
1
  import { Toolbar } from './chunk-PGRPNDWM.js';
2
- import { SegmentedControl } from './chunk-7QL2OFP6.js';
3
- import { tabId } from './chunk-XJFOOXCF.js';
2
+ import { SegmentedControl } from './chunk-RCQXUT5K.js';
3
+ import { tabId } from './chunk-HJEVSQN6.js';
4
4
  import { IconButton } from './chunk-4FQT6ZAY.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './MarkdownEditor-WOKV7CLK.css';
@@ -0,0 +1,62 @@
1
+ import { Document } from './chunk-WI6K5M5X.js';
2
+ import { ArtifactKindGlyph } from './chunk-6J35F334.js';
3
+ import { cx } from './chunk-ODEQTPFM.js';
4
+ import './ArtifactCover-D4MBEJ5H.css';
5
+ import './DashboardCover-RMINBODB.css';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+
8
+ function DocCover({ children, className }) {
9
+ return /* @__PURE__ */ jsx("span", { className: cx("crewlet-artifact-cover crewlet-doc-cover", className), children: /* @__PURE__ */ jsx(Document, { className: "crewlet-doc-cover__page", size: "sm", measure: "none", children }) });
10
+ }
11
+ var SHEET_COVER_COLUMNS = 4;
12
+ var SHEET_COVER_ROWS = 5;
13
+ function SheetCover({ columns, rows, className }) {
14
+ const shown = columns.slice(0, SHEET_COVER_COLUMNS);
15
+ return /* @__PURE__ */ jsxs("span", { className: cx("crewlet-artifact-cover crewlet-sheet-cover", className), style: { ["--crewlet-sheet-cover-columns"]: Math.max(shown.length, 1) }, children: [
16
+ shown.map((c, i) => /* @__PURE__ */ jsx("span", { className: "crewlet-sheet-cover__cell crewlet-sheet-cover__cell--head", children: c }, `h${i}`)),
17
+ rows.slice(0, SHEET_COVER_ROWS).map(
18
+ (row, r) => shown.map((_, i) => /* @__PURE__ */ jsx("span", { className: "crewlet-sheet-cover__cell", children: row[i] ?? "" }, `${r}-${i}`))
19
+ )
20
+ ] });
21
+ }
22
+ var MAX_STATS = 3;
23
+ var MAX_SCHEMATIC = 8;
24
+ var GRID_COLUMNS = 12;
25
+ var COVER = "crewlet-artifact-cover crewlet-dashboard-cover";
26
+ function DashboardCover({ stats = [], layout = [], className, ...rest }) {
27
+ const shown = stats.slice(0, MAX_STATS);
28
+ if (shown.length > 0) {
29
+ return /* @__PURE__ */ jsx("div", { ...rest, className: cx(COVER, "crewlet-dashboard-cover--stats", className), children: shown.map((stat, index) => /* @__PURE__ */ jsxs("div", { className: "crewlet-dashboard-cover__stat", children: [
30
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__label", children: stat.label }),
31
+ stat.value !== void 0 && stat.value !== "" ? /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__value", children: stat.value }) : stat.source ? /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__source", children: stat.source }) : null
32
+ ] }, `${index}:${stat.label}`)) });
33
+ }
34
+ const blocks = layout.slice(0, MAX_SCHEMATIC);
35
+ if (blocks.length > 0) {
36
+ return /* @__PURE__ */ jsx("div", { ...rest, className: cx(COVER, "crewlet-dashboard-cover--layout", className), children: blocks.map((block, index) => /* @__PURE__ */ jsx(
37
+ "span",
38
+ {
39
+ className: cx("crewlet-dashboard-cover__block", `crewlet-dashboard-cover__block--${block.kind}`),
40
+ style: { gridColumn: `span ${clampColumns(block.w)}` },
41
+ children: block.kind === "chart" ? /* @__PURE__ */ jsxs(Fragment, { children: [
42
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__bar" }),
43
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__bar" }),
44
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__bar" }),
45
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__bar" })
46
+ ] }) : block.kind === "table" || block.kind === "note" ? /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__line" }),
48
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__line" }),
49
+ /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__line" })
50
+ ] }) : /* @__PURE__ */ jsx("span", { className: "crewlet-dashboard-cover__figure" })
51
+ },
52
+ index
53
+ )) });
54
+ }
55
+ return /* @__PURE__ */ jsx("div", { ...rest, className: cx(COVER, "crewlet-dashboard-cover--empty", className), children: /* @__PURE__ */ jsx(ArtifactKindGlyph, { kind: "dashboard", size: 32 }) });
56
+ }
57
+ function clampColumns(w) {
58
+ if (!Number.isFinite(w)) return GRID_COLUMNS;
59
+ return Math.min(GRID_COLUMNS, Math.max(1, Math.round(w)));
60
+ }
61
+
62
+ export { DashboardCover, DocCover, SHEET_COVER_COLUMNS, SHEET_COVER_ROWS, SheetCover };
@@ -0,0 +1,62 @@
1
+ import { cx } from './chunk-ODEQTPFM.js';
2
+ import './CanvasSchematic-PLB3N46J.css';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var MARGIN = 0.06;
6
+ function CanvasSchematic({
7
+ label,
8
+ boards,
9
+ notes = [],
10
+ cover,
11
+ className,
12
+ ...rest
13
+ }) {
14
+ const all = [...boards, ...notes];
15
+ const minX = Math.min(...all.map((r) => r.x));
16
+ const minY = Math.min(...all.map((r) => r.y));
17
+ const maxX = Math.max(...all.map((r) => r.x + r.w));
18
+ const maxY = Math.max(...all.map((r) => r.y + r.h));
19
+ const side = Math.max(maxX - minX, maxY - minY, 1);
20
+ const pad = side * MARGIN;
21
+ const viewBox = all.length === 0 ? "0 0 1 1" : `${minX - pad} ${minY - pad} ${maxX - minX + 2 * pad} ${maxY - minY + 2 * pad}`;
22
+ const coverBoard = boards.find((b) => b.id === cover);
23
+ return /* @__PURE__ */ jsx("div", { className: cx("crewlet-canvas-schematic", className), ...rest, children: /* @__PURE__ */ jsxs("svg", { viewBox, preserveAspectRatio: "xMidYMid meet", role: "img", "aria-label": label, children: [
24
+ notes.map((n, i) => /* @__PURE__ */ jsx(
25
+ "rect",
26
+ {
27
+ className: "crewlet-canvas-schematic__note",
28
+ x: n.x,
29
+ y: n.y,
30
+ width: n.w,
31
+ height: n.h
32
+ },
33
+ `note-${i}`
34
+ )),
35
+ boards.map((b) => /* @__PURE__ */ jsx(
36
+ "rect",
37
+ {
38
+ className: "crewlet-canvas-schematic__board",
39
+ "data-cover": b.id === cover || void 0,
40
+ x: b.x,
41
+ y: b.y,
42
+ width: b.w,
43
+ height: b.h,
44
+ vectorEffect: "non-scaling-stroke"
45
+ },
46
+ b.id
47
+ )),
48
+ coverBoard?.title && /* @__PURE__ */ jsx(
49
+ "text",
50
+ {
51
+ className: "crewlet-canvas-schematic__title",
52
+ x: coverBoard.x + coverBoard.w * 0.08,
53
+ y: coverBoard.y + coverBoard.h * 0.5,
54
+ fontSize: Math.min(coverBoard.h * 0.16, side * 0.06),
55
+ dominantBaseline: "middle",
56
+ children: coverBoard.title
57
+ }
58
+ )
59
+ ] }) });
60
+ }
61
+
62
+ export { CanvasSchematic };
@@ -1,4 +1,4 @@
1
- import { PRESENCE_LABELS } from './chunk-S35G6PNC.js';
1
+ import { PRESENCE_LABELS } from './chunk-Z7JYG5TF.js';
2
2
  import { isNodeHue } from './chunk-AYKXMIOR.js';
3
3
 
4
4
  // src/SheetModel/types.ts
@@ -69,10 +69,16 @@ var SHEET_LABELS = {
69
69
  return state.saving === 0 ? "Offline." : `Offline. ${changes(state.saving)} will sync when you reconnect.`;
70
70
  }
71
71
  if (state.failed !== void 0 && state.failed > 0) return "Could not save.";
72
+ if (state.refused !== void 0 && state.refused > 0) return `${changes(state.refused)} not saved`;
72
73
  if (state.saving > 0) return `Saving ${changes(state.saving)}`;
73
74
  return "Saved";
74
75
  },
75
76
  retry: "Retry",
77
+ dismiss: "Dismiss",
78
+ notSaved: (reason) => `Not saved: ${reason}`,
79
+ rowActions: (row) => `Row actions for row ${row}`,
80
+ deleteRow: "Delete row",
81
+ rowActionsHelp: "Shift and F10 opens the actions of the row.",
76
82
  filter: "Filter options",
77
83
  noOptions: "No matching options",
78
84
  clear: "Clear",
@@ -693,9 +699,19 @@ var SheetPendingEdits = class {
693
699
  for (const value of this.waiting.values()) count += value;
694
700
  return count;
695
701
  }
696
- /** The sync strip's state. Refusals are said on their cells, so they do not count as failures to retry. */
702
+ /** Clears every refusal at once: the strip's Dismiss. */
703
+ dismissAll() {
704
+ if (this.refusals.size === 0) return;
705
+ this.refusals.clear();
706
+ this.emit();
707
+ }
708
+ /**
709
+ * The sync strip's state. A refusal is not a failure to retry (the engine
710
+ * decided it), but it is counted, so the strip holds "not saved" until the
711
+ * reader dismisses it rather than going back to "Saved".
712
+ */
697
713
  sync(offline = false) {
698
- return { saving: this.saving, offline };
714
+ return { saving: this.saving, offline, refused: this.refusals.size };
699
715
  }
700
716
  /** Every refusal since the last `resetFailures`, for a host that reports them. */
701
717
  get failures() {
@@ -0,0 +1,90 @@
1
+ import { useAnnouncer } from './chunk-RSAQOKH3.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './TagGroup-NAXTJHDS.css';
4
+ import { useState, useRef, Children, useLayoutEffect } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function TagGroup({
8
+ label,
9
+ max = 6,
10
+ overflow = "expand",
11
+ moreLabel = (hidden) => `+${hidden} more`,
12
+ countLabel = (hidden) => `+${hidden}`,
13
+ expandedMessage = (total) => `Showing all ${total}.`,
14
+ className,
15
+ children
16
+ }) {
17
+ const [open, setOpen] = useState(false);
18
+ const announce = useAnnouncer();
19
+ const list = useRef(null);
20
+ const all = Children.toArray(children);
21
+ const fit = overflow === "fit";
22
+ const fitted = useFitted(list, fit, all.length);
23
+ const shown = fit ? all.slice(0, fitted) : open ? all : all.slice(0, max);
24
+ const hidden = all.length - shown.length;
25
+ return /* @__PURE__ */ jsxs(
26
+ "ul",
27
+ {
28
+ ref: list,
29
+ tabIndex: -1,
30
+ className: cx("crewlet-tag-group", fit && "crewlet-tag-group--fit", className),
31
+ "aria-label": `${label}, ${all.length}`,
32
+ children: [
33
+ shown.map((tag, index) => (
34
+ // Keyed by position: the list only ever grows at the end, as the tail
35
+ // is revealed, so no item ever changes the index it sits at.
36
+ /* @__PURE__ */ jsx("li", { className: "crewlet-tag-group__item", children: tag }, index)
37
+ )),
38
+ hidden > 0 && fit ? /* @__PURE__ */ jsx("li", { className: "crewlet-tag-group__item", "data-count": "", children: /* @__PURE__ */ jsx("span", { className: "crewlet-tag-group__count", children: countLabel(hidden) }) }) : hidden > 0 ? /* @__PURE__ */ jsx("li", { className: "crewlet-tag-group__item", children: /* @__PURE__ */ jsx(
39
+ "button",
40
+ {
41
+ type: "button",
42
+ className: "crewlet-tag-group__more",
43
+ onClick: () => {
44
+ setOpen(true);
45
+ list.current?.focus();
46
+ announce(expandedMessage(all.length));
47
+ },
48
+ children: moreLabel(hidden)
49
+ }
50
+ ) }) : null
51
+ ]
52
+ }
53
+ );
54
+ }
55
+ function useFitted(list, active, total) {
56
+ const [fitted, setFitted] = useState(total);
57
+ const width = useRef(null);
58
+ useLayoutEffect(() => {
59
+ if (!active) return;
60
+ setFitted(total);
61
+ }, [active, total]);
62
+ useLayoutEffect(() => {
63
+ const box = list.current;
64
+ if (!active || !box) return;
65
+ const items = [...box.children];
66
+ const first = items[0];
67
+ if (!first) return;
68
+ const top = first.offsetTop;
69
+ const tags = items.filter((item) => !item.hasAttribute("data-count"));
70
+ const count = items.find((item) => item.hasAttribute("data-count"));
71
+ const onLine = tags.filter((item) => item.offsetTop === top).length;
72
+ const room = count && count.offsetTop !== top ? onLine - 1 : onLine;
73
+ const next = Math.max(1, Math.min(room, tags.length));
74
+ if (next < tags.length) setFitted(next);
75
+ }, [list, active, fitted, total]);
76
+ useLayoutEffect(() => {
77
+ const box = list.current;
78
+ if (!active || !box || typeof ResizeObserver !== "function") return void 0;
79
+ const observer = new ResizeObserver(([entry]) => {
80
+ const now = entry?.contentRect.width ?? 0;
81
+ if (width.current !== null && width.current !== now) setFitted(total);
82
+ width.current = now;
83
+ });
84
+ observer.observe(box);
85
+ return () => observer.disconnect();
86
+ }, [list, active, total]);
87
+ return active ? fitted : total;
88
+ }
89
+
90
+ export { TagGroup };
@@ -1,5 +1,5 @@
1
1
  import { presenceHueClass } from './chunk-I6POAB4V.js';
2
- import { presenceLabels, presenceOrder } from './chunk-S35G6PNC.js';
2
+ import { presenceLabels, presenceOrder } from './chunk-Z7JYG5TF.js';
3
3
  import { AVATAR_SIZES, Avatar } from './chunk-5OM447RW.js';
4
4
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
1
  import { PageHeader } from './chunk-HOXGBLEY.js';
2
2
  import { Toolbar } from './chunk-PGRPNDWM.js';
3
- import { DataTable } from './chunk-35UKQ33X.js';
3
+ import { DataTable } from './chunk-SVW3VG72.js';
4
4
  import { DateTimePicker } from './chunk-WG5WUFBX.js';
5
5
  import { useListbox, useOptionKeys } from './chunk-F73MC7EZ.js';
6
6
  import { Kbd } from './chunk-SMBKXWML.js';
@@ -1,7 +1,7 @@
1
- import { HuePicker } from './chunk-OQT7GSKJ.js';
1
+ import { HuePicker } from './chunk-SGIQCI6Y.js';
2
2
  import { Popover } from './chunk-BWRGFKJP.js';
3
3
  import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
4
- import { CharacterPicker } from './chunk-5PSXBL73.js';
4
+ import { CharacterPicker } from './chunk-HVIX5ECM.js';
5
5
  import { Avatar } from './chunk-5OM447RW.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './AvatarPicker-PREY36MG.css';
@@ -0,0 +1,43 @@
1
+ import { SlideStage } from './chunk-KNLJL3VP.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './SlideGrid-RT6QEQEE.css';
4
+ import { EyeOffGlyph } from '@crewlethq/icons/glyphs';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ var LABELS = {
8
+ slide: (position, title) => `Slide ${position}, ${title}`,
9
+ hidden: "Hidden when presenting",
10
+ untitled: "Untitled"
11
+ };
12
+ function SlideGrid({ sections, renderSlide, onOpen, current, className, labels }) {
13
+ const text = { ...LABELS, ...labels };
14
+ let n = 0;
15
+ return /* @__PURE__ */ jsx("div", { className: cx("crewlet-slide-grid", className), children: sections.map((section, s) => /* @__PURE__ */ jsxs("section", { className: "crewlet-slide-grid__section", children: [
16
+ section.title ? /* @__PURE__ */ jsx("h3", { className: "crewlet-slide-grid__heading", children: section.title }) : null,
17
+ /* @__PURE__ */ jsx("ol", { className: "crewlet-slide-grid__list", children: section.slides.map((slide) => {
18
+ n += 1;
19
+ const name = text.slide(n, slide.title || text.untitled);
20
+ return /* @__PURE__ */ jsx("li", { className: "crewlet-slide-grid__item", children: /* @__PURE__ */ jsxs(
21
+ "button",
22
+ {
23
+ type: "button",
24
+ className: "crewlet-slide-grid__card",
25
+ "aria-label": slide.hidden ? `${name}, ${text.hidden}` : name,
26
+ "aria-current": slide.id === current ? "true" : void 0,
27
+ "data-hidden": slide.hidden ? "true" : void 0,
28
+ onClick: () => onOpen(slide.id),
29
+ children: [
30
+ /* @__PURE__ */ jsx(SlideStage, { label: name, children: renderSlide(slide.id) }),
31
+ /* @__PURE__ */ jsxs("span", { className: "crewlet-slide-grid__caption", children: [
32
+ /* @__PURE__ */ jsx("span", { className: "crewlet-slide-grid__number", children: n }),
33
+ /* @__PURE__ */ jsx("span", { className: "crewlet-slide-grid__title", children: slide.title || text.untitled }),
34
+ slide.hidden ? /* @__PURE__ */ jsx(EyeOffGlyph, { size: "sm" }) : null
35
+ ] })
36
+ ]
37
+ }
38
+ ) }, slide.id);
39
+ }) })
40
+ ] }, `${s}:${section.title}`)) });
41
+ }
42
+
43
+ export { SlideGrid };
@@ -1,9 +1,9 @@
1
- import { tabId } from './chunk-XJFOOXCF.js';
2
- import { useRoving, tabStop } from './chunk-CBOICT64.js';
1
+ import { tabId } from './chunk-HJEVSQN6.js';
2
+ import { useRoving, tabStop } from './chunk-RKKO7QHH.js';
3
3
  import { Count } from './chunk-BHHIIK3M.js';
4
4
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
- import { useId } from 'react';
6
+ import { useState, useId } from 'react';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
8
8
 
9
9
  var ACTIVATE_HINT = "Press Enter or Space to choose the option you land on.";
@@ -25,16 +25,27 @@ function SegmentedControl({
25
25
  const radio = semantics === "radio";
26
26
  const manual = radio && activate === "manual";
27
27
  const cards = options.some((option) => option.description !== void 0);
28
- const { buttons, onKeyDown, onFocusAt, focused } = useRoving(
28
+ const { buttons, onKeyDown, onFocusAt, reset, focused } = useRoving(
29
29
  options.length,
30
- radio && !manual ? (index) => onValueChange(options[index].value) : null,
30
+ radio && !manual ? (index) => {
31
+ const option = options[index];
32
+ if (!option.disabled) onValueChange(option.value);
33
+ } : null,
31
34
  { followFocus: manual }
32
35
  );
36
+ const [seen, setSeen] = useState(value);
37
+ if (seen !== value) {
38
+ setSeen(value);
39
+ reset();
40
+ }
33
41
  const chosenIndex = Math.max(
34
42
  0,
35
43
  options.findIndex((option) => option.value === value)
36
44
  );
37
- const stop = tabStop(options, focused ?? chosenIndex);
45
+ const stop = tabStop(
46
+ options.map((option) => ({ disabled: option.disabled === true && option.describedBy === void 0 })),
47
+ focused ?? chosenIndex
48
+ );
38
49
  const hintId = useId();
39
50
  const hint = manual ? activateHint === void 0 ? ACTIVATE_HINT : activateHint : null;
40
51
  return /* @__PURE__ */ jsxs(
@@ -66,6 +77,7 @@ function SegmentedControl({
66
77
  options.map((option, index) => {
67
78
  const chosen = option.value === value;
68
79
  const named = option.srLabel ?? (option.label ? void 0 : option.title);
80
+ const explained = option.disabled === true && option.describedBy !== void 0;
69
81
  return /* @__PURE__ */ jsxs(
70
82
  "button",
71
83
  {
@@ -81,14 +93,18 @@ function SegmentedControl({
81
93
  "aria-label": named,
82
94
  tabIndex: index === stop ? 0 : -1,
83
95
  title: option.title,
84
- disabled: option.disabled,
96
+ disabled: option.disabled && !explained,
97
+ "aria-disabled": explained || void 0,
98
+ "aria-describedby": option.describedBy,
85
99
  className: cx(
86
100
  "crewlet-tabs__tab",
87
101
  "crewlet-segmented__option",
88
102
  chosen && "is-active",
89
103
  option.disabled && "is-disabled"
90
104
  ),
91
- onClick: () => onValueChange(option.value),
105
+ onClick: () => {
106
+ if (!option.disabled) onValueChange(option.value);
107
+ },
92
108
  onFocus: () => onFocusAt(index),
93
109
  onKeyDown: (event) => onKeyDown(event, radio),
94
110
  children: [
@@ -97,7 +113,7 @@ function SegmentedControl({
97
113
  /* @__PURE__ */ jsx("span", { className: "crewlet-tabs__label", children: option.label }),
98
114
  option.description ? /* @__PURE__ */ jsx("span", { className: "crewlet-segmented__description", children: option.description }) : null
99
115
  ] }) : null,
100
- option.count != null ? /* @__PURE__ */ jsx(Count, { value: option.count }) : null
116
+ option.count != null ? /* @__PURE__ */ jsx(Count, { value: option.capped ? `${option.count.toLocaleString()}+` : option.count }) : null
101
117
  ]
102
118
  },
103
119
  option.value
@@ -57,10 +57,12 @@ function useRoving(count, select, { followFocus = false, columns } = {}) {
57
57
  onFocusAt(next);
58
58
  select?.(next);
59
59
  };
60
+ const reset = () => setLanded(null);
60
61
  return {
61
62
  buttons,
62
63
  onKeyDown,
63
64
  onFocusAt,
65
+ reset,
64
66
  /*
65
67
  * Where the stop belongs, or null for "on the caller's selection, as
66
68
  * ever". Bounded by the CURRENT count, because a row whose options