@crewlethq/ui 0.31.1 → 0.32.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 (44) hide show
  1. package/README.md +21 -1
  2. package/dist/Canvas/Canvas.d.ts +48 -2
  3. package/dist/Canvas/ShortcutTip.d.ts +22 -0
  4. package/dist/Canvas/geometry.d.ts +13 -3
  5. package/dist/Canvas/index.d.ts +3 -1
  6. package/dist/Canvas/index.js +3 -1
  7. package/dist/{Canvas-YVXHMWLN.css → Canvas-LRVNW7XN.css} +39 -3
  8. package/dist/CanvasBoard/CanvasBoard.d.ts +75 -12
  9. package/dist/CanvasBoard/index.d.ts +2 -2
  10. package/dist/CanvasBoard/index.js +6 -2
  11. package/dist/{CanvasBoard-ZLPDINSM.css → CanvasBoard-MBZVBWDO.css} +135 -30
  12. package/dist/CanvasToolbar/CanvasToolbar.d.ts +48 -0
  13. package/dist/CanvasToolbar/index.d.ts +3 -0
  14. package/dist/CanvasToolbar/index.js +12 -0
  15. package/dist/CanvasToolbar-AE5MXH7T.css +32 -0
  16. package/dist/DataView/index.js +2 -2
  17. package/dist/PresenterView/index.js +2 -2
  18. package/dist/RichEditor/index.js +1 -1
  19. package/dist/SheetGrid/index.js +3 -3
  20. package/dist/SlideCompare/index.js +2 -2
  21. package/dist/SlideFilmstrip/index.js +2 -2
  22. package/dist/SlideGrid/index.js +2 -2
  23. package/dist/SlideStage/SlideStage.d.ts +6 -1
  24. package/dist/SlideStage/index.js +1 -1
  25. package/dist/TreeCanvas/index.js +4 -2
  26. package/dist/{chunk-ALMSY7RL.js → chunk-CRKFL423.js} +1 -1
  27. package/dist/{chunk-O63MWA4G.js → chunk-E6CR5PEV.js} +2 -1
  28. package/dist/chunk-E6EWK5YY.js +33 -0
  29. package/dist/{chunk-OGAAHVF6.js → chunk-MBNFJSZS.js} +1 -1
  30. package/dist/{chunk-OJ45PPCV.js → chunk-OTN35CI4.js} +113 -30
  31. package/dist/{chunk-JODJS7MR.js → chunk-PJD2KFHX.js} +243 -39
  32. package/dist/{chunk-LR5QTFOE.js → chunk-RV7SZAHR.js} +1 -1
  33. package/dist/{chunk-VOX3YRFO.js → chunk-V5IGUXMZ.js} +1 -1
  34. package/dist/{chunk-3C3BRIMY.js → chunk-VS3KOOOL.js} +1 -1
  35. package/dist/{chunk-S6VG5ZFZ.js → chunk-WTNUVQVI.js} +1 -1
  36. package/dist/generated/index.d.ts +1 -0
  37. package/dist/generated/index.js +40 -39
  38. package/dist/index.js +40 -39
  39. package/dist/styles.css +211 -35
  40. package/package.json +3 -3
  41. package/dist/{Editor-YZ7KG2RD.js → Editor-YWBUJAQU.js} +1 -1
  42. package/dist/{chunk-RODMM35O.js → chunk-3ZAFJ4GK.js} +1 -1
  43. package/dist/{chunk-CT4EZF62.js → chunk-LWXRD6L6.js} +2 -2
  44. /package/dist/{chunk-OC46246T.js → chunk-TF2P3OPS.js} +0 -0
@@ -16,6 +16,25 @@
16
16
  position: relative;
17
17
  }
18
18
 
19
+ /*
20
+ * UNDER HAND, TEXT AND STICKY NOTHING ON THE CANVAS TAKES A PRESS: every press
21
+ * reaches the field, which pans it (Hand) or places a note on it (Text and
22
+ * Sticky), and nothing is outlined under a pointer that cannot select it.
23
+ */
24
+ .crewlet-canvas-board:not([data-tool='move']) .crewlet-canvas-board__layer {
25
+ pointer-events: none;
26
+ }
27
+
28
+ /* ---- the tool palette, floating at the foot of the field ----------------- */
29
+
30
+ .crewlet-canvas-board__tools {
31
+ position: absolute;
32
+ bottom: var(--spacing-3);
33
+ left: 50%;
34
+ z-index: var(--z-index-raised);
35
+ transform: translateX(-50%);
36
+ }
37
+
19
38
  /* ---- a board ------------------------------------------------------------ */
20
39
 
21
40
  .crewlet-canvas-board__board {
@@ -23,13 +42,37 @@
23
42
  box-sizing: border-box;
24
43
  }
25
44
 
45
+ /*
46
+ * A BOARD'S EDGE IS A HAIRLINE, one screen pixel at every zoom, drawn as a
47
+ * ring outside the box rather than a border inside it: a border would take
48
+ * its width out of the page the board runs, and counter-scaled to stay one
49
+ * pixel it would take more the further out the canvas is zoomed. The strong
50
+ * hairline's ink, so a white page still has an edge on a light field and a
51
+ * dark one on a dark field.
52
+ */
26
53
  .crewlet-canvas-board__body {
27
54
  position: absolute;
28
55
  inset: 0;
29
56
  overflow: hidden;
30
57
  background: var(--color-surface-elevated);
31
- border: 1px solid var(--color-border-default);
32
- box-shadow: var(--shadow-xs);
58
+ box-shadow: 0 0 0 calc(1px * var(--crewlet-canvas-board-unzoom)) var(--color-border-strong);
59
+ }
60
+
61
+ /*
62
+ * HOVER, then SELECTION, in the accent: one screen pixel and then two, over
63
+ * the hairline. Hovering a board's name is hovering its board, which is how a
64
+ * reader finds the board a name belongs to on a crowded canvas.
65
+ */
66
+ .crewlet-canvas-board__board:hover .crewlet-canvas-board__body,
67
+ .crewlet-canvas-board__note:hover {
68
+ outline: calc(1px * var(--crewlet-canvas-board-unzoom)) solid var(--color-brand-accent);
69
+ outline-offset: 0;
70
+ }
71
+
72
+ .crewlet-canvas-board__board[data-selected] .crewlet-canvas-board__body,
73
+ .crewlet-canvas-board__note[data-selected] {
74
+ outline: calc(2px * var(--crewlet-canvas-board-unzoom)) solid var(--color-brand-accent);
75
+ outline-offset: 0;
33
76
  }
34
77
 
35
78
  /* The page a live board runs fills its frame exactly. */
@@ -51,11 +94,7 @@
51
94
  .crewlet-canvas-board__shield {
52
95
  position: absolute;
53
96
  inset: 0;
54
- cursor: pointer;
55
- }
56
-
57
- .crewlet-canvas-board[data-editable] .crewlet-canvas-board__shield {
58
- cursor: inherit;
97
+ cursor: var(--crewlet-canvas-cursor-pointer, default);
59
98
  }
60
99
 
61
100
  /* A board that is not running draws its title and size at screen size. */
@@ -105,14 +144,21 @@
105
144
  transform-origin: bottom left;
106
145
  }
107
146
 
147
+ /* The board's name: small, quiet, and the accent once its board is picked out. */
108
148
  .crewlet-canvas-board__title {
109
149
  min-width: 0;
110
150
  overflow: hidden;
111
- color: var(--color-text-secondary);
151
+ color: var(--color-text-tertiary);
112
152
  font-size: var(--font-size-xs);
113
153
  font-weight: var(--font-weight-medium);
114
154
  text-overflow: ellipsis;
115
155
  white-space: nowrap;
156
+ cursor: var(--crewlet-canvas-cursor-pointer, default);
157
+ }
158
+
159
+ .crewlet-canvas-board__board:hover .crewlet-canvas-board__title,
160
+ .crewlet-canvas-board__board[data-selected] .crewlet-canvas-board__title {
161
+ color: var(--color-brand-accent-ink);
116
162
  }
117
163
 
118
164
  .crewlet-canvas-board__handle {
@@ -123,7 +169,7 @@
123
169
  border-radius: var(--radius-sm);
124
170
  background: transparent;
125
171
  font: inherit;
126
- cursor: move;
172
+ cursor: var(--crewlet-canvas-cursor-pointer, default);
127
173
  touch-action: none;
128
174
  }
129
175
 
@@ -139,55 +185,114 @@
139
185
  outline-offset: var(--size-focus-ring-inset-offset);
140
186
  }
141
187
 
188
+ /*
189
+ * A RESIZE CORNER: a full pointer target, drawn as the small square a design
190
+ * tool draws, centred on its corner and counter-scaled so it is one size on
191
+ * screen. Drawn on a selected item, and on the keyboard's corner while it has
192
+ * focus; otherwise it is neither seen nor pressed.
193
+ */
142
194
  .crewlet-canvas-board__resize {
143
195
  position: absolute;
144
- right: 0;
145
- bottom: 0;
146
- width: var(--spacing-4);
147
- height: var(--spacing-4);
196
+ display: grid;
197
+ place-items: center;
198
+ width: var(--spacing-6);
199
+ height: var(--spacing-6);
148
200
  margin: 0;
149
201
  padding: 0;
150
- border: 2px solid var(--color-brand-accent);
202
+ border: none;
203
+ background: transparent;
204
+ opacity: 0;
205
+ pointer-events: none;
206
+ touch-action: none;
207
+ }
208
+
209
+ .crewlet-canvas-board__resize::before {
210
+ content: '';
211
+ width: var(--spacing-2);
212
+ height: var(--spacing-2);
213
+ box-sizing: border-box;
214
+ border: 1px solid var(--color-brand-accent);
151
215
  border-radius: var(--radius-xs);
152
216
  background: var(--color-surface-elevated);
217
+ }
218
+
219
+ .crewlet-canvas-board__board[data-selected] > .crewlet-canvas-board__resize,
220
+ .crewlet-canvas-board__note[data-selected] .crewlet-canvas-board__resize,
221
+ .crewlet-canvas-board__resize:focus-visible {
222
+ opacity: 1;
223
+ pointer-events: auto;
224
+ }
225
+
226
+ .crewlet-canvas-board__resize[data-corner='resize-nw'] {
227
+ top: 0;
228
+ left: 0;
153
229
  cursor: nwse-resize;
154
- touch-action: none;
155
- transform: translate(50%, 50%) scale(var(--crewlet-canvas-board-unzoom));
230
+ transform: translate(-50%, -50%) scale(var(--crewlet-canvas-board-unzoom));
156
231
  }
157
232
 
158
- .crewlet-canvas-board__hint {
159
- position: absolute;
160
- top: 100%;
233
+ .crewlet-canvas-board__resize[data-corner='resize-ne'] {
234
+ top: 0;
235
+ right: 0;
236
+ cursor: nesw-resize;
237
+ transform: translate(50%, -50%) scale(var(--crewlet-canvas-board-unzoom));
238
+ }
239
+
240
+ .crewlet-canvas-board__resize[data-corner='resize-sw'] {
241
+ bottom: 0;
161
242
  left: 0;
162
- margin: 0;
163
- padding-top: var(--spacing-1);
164
- color: var(--color-text-tertiary);
165
- font-size: var(--font-size-xs);
166
- white-space: nowrap;
167
- transform: scale(var(--crewlet-canvas-board-unzoom));
168
- transform-origin: top left;
243
+ cursor: nesw-resize;
244
+ transform: translate(-50%, 50%) scale(var(--crewlet-canvas-board-unzoom));
169
245
  }
170
246
 
247
+ .crewlet-canvas-board__resize[data-corner='resize-se'] {
248
+ right: 0;
249
+ bottom: 0;
250
+ cursor: nwse-resize;
251
+ transform: translate(50%, 50%) scale(var(--crewlet-canvas-board-unzoom));
252
+ }
253
+
254
+
171
255
  /* ---- a note ------------------------------------------------------------- */
172
256
 
173
257
  .crewlet-canvas-board__note {
174
258
  position: absolute;
175
259
  box-sizing: border-box;
260
+ cursor: var(--crewlet-canvas-cursor-pointer, default);
261
+ }
262
+
263
+ /*
264
+ * A sticky's tools and corners sit outside its paper, so the paper does not
265
+ * clip; its words are held to the paper instead.
266
+ */
267
+ .crewlet-canvas-board__note[data-kind='sticky'] {
268
+ overflow: visible;
269
+ }
270
+
271
+ .crewlet-canvas-board__note[data-kind='sticky'] .crewlet-canvas-board__note-text {
272
+ max-height: 100%;
273
+ overflow: hidden;
176
274
  }
177
275
 
178
276
  /*
179
- * A TITLE IS SET IN ITS BOX'S OWN HEIGHT, so the author's frame is the type
180
- * size: a heading over a group of boards is as large as the box drawn for it.
277
+ * A TITLE IS SET TO FILL ITS BOX, so the author's frame is the type size: a
278
+ * heading over a group of boards is as large as the box drawn for it, and a
279
+ * long one is set smaller rather than run over the boards beside it.
181
280
  */
182
281
  .crewlet-canvas-board__note[data-kind='title'] {
183
- container-type: size;
184
282
  display: flex;
185
283
  align-items: center;
186
284
  color: var(--color-text-primary);
187
285
  }
188
286
 
287
+ /*
288
+ * The size is the component's (`titleSize`), fitted to the box both ways. The
289
+ * TEXT clips at the box, not the box itself: the box's tools and corners sit
290
+ * outside it, and a box that clipped would cut them away.
291
+ */
189
292
  .crewlet-canvas-board__note[data-kind='title'] .crewlet-canvas-board__note-text {
190
- font-size: 60cqh;
293
+ min-width: 0;
294
+ max-width: 100%;
295
+ overflow: hidden;
191
296
  font-weight: var(--font-weight-semibold);
192
297
  letter-spacing: var(--font-letter-spacing-tight);
193
298
  line-height: var(--font-line-height-tight);
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The floating palette of a canvas's tools: Move, Hand, and whatever a surface
3
+ * places (a text, a sticky), one of them in hand at a time.
4
+ *
5
+ * WHAT IT IS. A toolbar (one tab stop, walked with the arrows; see Toolbar)
6
+ * of toggle buttons, exactly one pressed. Each tool names its key, and the tip
7
+ * that opens on hover or focus says it, so a reader learns `V` and `H` from the
8
+ * palette rather than from a help page.
9
+ *
10
+ * WHAT IT IS NOT. It does not listen for the keys itself: which keys reach a
11
+ * canvas is the canvas's question (a page full of fields must not lose its `V`
12
+ * to a palette), so the surface that holds the tools matches its own presses
13
+ * against [toolForKey] and sets the tool it finds.
14
+ *
15
+ * Drawn as a glass bar like the canvas's zoom bar, so the two read as one
16
+ * family of chrome over the field.
17
+ */
18
+ import type { ReactNode } from 'react';
19
+ /** One tool in the palette. */
20
+ export interface CanvasTool<Id extends string = string> {
21
+ id: Id;
22
+ /** What the tool does, in words: its accessible name and the tip's first words. */
23
+ label: string;
24
+ /** The glyph. A component from @crewlethq/icons/glyphs. */
25
+ icon: ReactNode;
26
+ /**
27
+ * The key that picks the tool, as Kbd names it: one letter, pressed alone.
28
+ * A letter rather than a chord, because a tool is picked dozens of times a
29
+ * minute and design tools have taught every reader their letters.
30
+ */
31
+ shortcut: string;
32
+ }
33
+ export interface CanvasToolbarProps<Id extends string = string> {
34
+ /** The palette's accessible name, such as "Tools". */
35
+ label: string;
36
+ tools: readonly CanvasTool<Id>[];
37
+ /** The tool in hand. */
38
+ value: Id;
39
+ onChange: (id: Id) => void;
40
+ className?: string | undefined;
41
+ }
42
+ /**
43
+ * The tool a key press picks, or undefined. A bare letter only: a press with
44
+ * Control, Command or Alt is somebody else's chord, and Shift is a different
45
+ * key in every design tool.
46
+ */
47
+ export declare function toolForKey<Id extends string>(tools: readonly CanvasTool<Id>[], event: Pick<KeyboardEvent, 'key' | 'ctrlKey' | 'metaKey' | 'altKey' | 'shiftKey'>): Id | undefined;
48
+ export declare function CanvasToolbar<Id extends string>({ label, tools, value, onChange, className, }: CanvasToolbarProps<Id>): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './CanvasToolbar.css';
2
+ export { CanvasToolbar, toolForKey } from './CanvasToolbar.js';
3
+ export type { CanvasTool, CanvasToolbarProps } from './CanvasToolbar.js';
@@ -0,0 +1,12 @@
1
+ export { CanvasToolbar, toolForKey } from '../chunk-E6EWK5YY.js';
2
+ import '../chunk-PGRPNDWM.js';
3
+ import '../chunk-OTN35CI4.js';
4
+ import '../chunk-VYOKRN2I.js';
5
+ import '../chunk-SMBKXWML.js';
6
+ import '../chunk-QWOPX2MN.js';
7
+ import '../chunk-HMPFGIWM.js';
8
+ import '../chunk-R25RGPUB.js';
9
+ import '../chunk-OG6CL3EB.js';
10
+ import '../chunk-4FQT6ZAY.js';
11
+ import '../chunk-BZFWDIV6.js';
12
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,32 @@
1
+ /*
2
+ * A canvas's tool palette (CanvasToolbar.tsx): the zoom bar's glass surface,
3
+ * with the tool in hand drawn SOLID in the accent rather than the soft tint a
4
+ * toggle takes elsewhere, because it is the one fact about the palette a
5
+ * reader checks from across the field before every press.
6
+ */
7
+
8
+ .crewlet-canvas-toolbar.crewlet-toolbar {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: var(--spacing-1);
12
+ padding: var(--spacing-1);
13
+ background: var(--color-surface-glass);
14
+ backdrop-filter: blur(var(--blur-sm));
15
+ border: 1px solid var(--color-border-default);
16
+ border-radius: var(--radius-md);
17
+ box-shadow: var(--shadow-sm);
18
+ }
19
+
20
+ .crewlet-canvas-toolbar .crewlet-icon-btn {
21
+ border-radius: var(--radius-chip);
22
+ }
23
+
24
+ .crewlet-canvas-toolbar .crewlet-icon-btn[aria-pressed='true'] {
25
+ color: var(--color-text-on-accent);
26
+ background: var(--color-brand-accent);
27
+ }
28
+
29
+ .crewlet-canvas-toolbar .crewlet-icon-btn[aria-pressed='true']:hover:not(:disabled) {
30
+ color: var(--color-text-on-accent);
31
+ background: var(--color-brand-accent-hover);
32
+ }
@@ -1,12 +1,12 @@
1
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-RODMM35O.js';
1
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-3ZAFJ4GK.js';
2
2
  import '../chunk-HOXGBLEY.js';
3
- import '../chunk-PGRPNDWM.js';
4
3
  import '../chunk-Y5NQ2LMS.js';
5
4
  import '../chunk-EBJREOKS.js';
6
5
  import '../chunk-STJ7QBC3.js';
7
6
  import '../chunk-DTIW4CHZ.js';
8
7
  import '../chunk-I3KKZ2O3.js';
9
8
  import '../chunk-F73MC7EZ.js';
9
+ import '../chunk-PGRPNDWM.js';
10
10
  import '../chunk-BWRGFKJP.js';
11
11
  import '../chunk-GXQ3B46I.js';
12
12
  import '../chunk-7T42VQQT.js';
@@ -1,5 +1,5 @@
1
- export { PresenterView, formatStopwatch } from '../chunk-OGAAHVF6.js';
2
- import '../chunk-O63MWA4G.js';
1
+ export { PresenterView, formatStopwatch } from '../chunk-MBNFJSZS.js';
2
+ import '../chunk-E6CR5PEV.js';
3
3
  import '../chunk-HMPFGIWM.js';
4
4
  import '../chunk-R25RGPUB.js';
5
5
  import '../chunk-OG6CL3EB.js';
@@ -1,4 +1,4 @@
1
- export { RichEditor, preloadRichEditor } from '../chunk-VOX3YRFO.js';
1
+ export { RichEditor, preloadRichEditor } from '../chunk-V5IGUXMZ.js';
2
2
  export { RICH_EDITOR_LABELS, richEditorLabels } from '../chunk-A4E5YLXO.js';
3
3
  import '../chunk-W5J7R5EB.js';
4
4
  import '../chunk-SKOYC2CF.js';
@@ -1,10 +1,10 @@
1
- export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-CT4EZF62.js';
1
+ export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-LWXRD6L6.js';
2
2
  import '../chunk-O2EGEONV.js';
3
3
  import '../chunk-CENOOTAV.js';
4
- import '../chunk-3BYIWOTV.js';
5
- import '../chunk-I6POAB4V.js';
6
4
  import '../chunk-GFV4LJHH.js';
7
5
  import '../chunk-WIATRXEJ.js';
6
+ import '../chunk-3BYIWOTV.js';
7
+ import '../chunk-I6POAB4V.js';
8
8
  import '../chunk-YEKYVJQR.js';
9
9
  import '../chunk-NHBP2XS5.js';
10
10
  import '../chunk-Z7JYG5TF.js';
@@ -1,5 +1,5 @@
1
- export { SLIDE_COMPARE_LABELS, SlideCompare } from '../chunk-ALMSY7RL.js';
2
- import '../chunk-O63MWA4G.js';
1
+ export { SLIDE_COMPARE_LABELS, SlideCompare } from '../chunk-CRKFL423.js';
2
+ import '../chunk-E6CR5PEV.js';
3
3
  import '../chunk-HMPFGIWM.js';
4
4
  import '../chunk-R25RGPUB.js';
5
5
  import '../chunk-OG6CL3EB.js';
@@ -1,5 +1,5 @@
1
- export { SlideFilmstrip } from '../chunk-LR5QTFOE.js';
2
- import '../chunk-O63MWA4G.js';
1
+ export { SlideFilmstrip } from '../chunk-RV7SZAHR.js';
2
+ import '../chunk-E6CR5PEV.js';
3
3
  import '../chunk-XJ2QEBMM.js';
4
4
  import '../chunk-HMPFGIWM.js';
5
5
  import '../chunk-R25RGPUB.js';
@@ -1,5 +1,5 @@
1
- export { SlideGrid } from '../chunk-3C3BRIMY.js';
2
- import '../chunk-O63MWA4G.js';
1
+ export { SlideGrid } from '../chunk-VS3KOOOL.js';
2
+ import '../chunk-E6CR5PEV.js';
3
3
  import '../chunk-HMPFGIWM.js';
4
4
  import '../chunk-R25RGPUB.js';
5
5
  import '../chunk-ODEQTPFM.js';
@@ -28,6 +28,11 @@ export interface SlideStageProps {
28
28
  /** The stage's own size, for a format other than 16:9 at 1920. */
29
29
  width?: number | undefined;
30
30
  height?: number | undefined;
31
+ /**
32
+ * What a screen reader calls what the stage holds: "slide" by default,
33
+ * "artboard" for a design's board shown at its own layout.
34
+ */
35
+ roleDescription?: string | undefined;
31
36
  className?: string | undefined;
32
37
  }
33
38
  /**
@@ -55,4 +60,4 @@ export interface SlideStageProps {
55
60
  * A GROUP NAMED AS A SLIDE, so a screen reader announces "slide" with its
56
61
  * name and reads its text in source order, which is the slide's reading order.
57
62
  */
58
- export declare function SlideStage({ children, label, fit, scale, width, height, className, }: SlideStageProps): import("react").JSX.Element;
63
+ export declare function SlideStage({ children, label, fit, scale, width, height, roleDescription, className, }: SlideStageProps): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- export { SLIDE_HEIGHT, SLIDE_WIDTH, SlideStage, useSlideKeys } from '../chunk-O63MWA4G.js';
1
+ export { SLIDE_HEIGHT, SLIDE_WIDTH, SlideStage, useSlideKeys } from '../chunk-E6CR5PEV.js';
2
2
  import '../chunk-HMPFGIWM.js';
3
3
  import '../chunk-R25RGPUB.js';
4
4
  import '../chunk-ODEQTPFM.js';
@@ -1,7 +1,9 @@
1
- export { TreeCanvas } from '../chunk-S6VG5ZFZ.js';
1
+ export { TreeCanvas } from '../chunk-WTNUVQVI.js';
2
2
  import '../chunk-MY374UUD.js';
3
- import '../chunk-OJ45PPCV.js';
3
+ import '../chunk-OTN35CI4.js';
4
4
  import '../chunk-VYOKRN2I.js';
5
+ import '../chunk-SMBKXWML.js';
6
+ import '../chunk-QWOPX2MN.js';
5
7
  import '../chunk-HMPFGIWM.js';
6
8
  import '../chunk-R25RGPUB.js';
7
9
  import '../chunk-OG6CL3EB.js';
@@ -1,4 +1,4 @@
1
- import { SlideStage } from './chunk-O63MWA4G.js';
1
+ import { SlideStage } from './chunk-E6CR5PEV.js';
2
2
  import { Button } from './chunk-OG6CL3EB.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './SlideCompare-MGM3U2ME.css';
@@ -75,6 +75,7 @@ function SlideStage({
75
75
  scale,
76
76
  width = SLIDE_WIDTH,
77
77
  height = SLIDE_HEIGHT,
78
+ roleDescription = "slide",
78
79
  className
79
80
  }) {
80
81
  const box = useRef(null);
@@ -123,7 +124,7 @@ function SlideStage({
123
124
  className: cx("crewlet-slide-stage", `crewlet-slide-stage--${fit}`, className),
124
125
  style: boxStyle,
125
126
  role: "group",
126
- "aria-roledescription": "slide",
127
+ "aria-roledescription": roleDescription,
127
128
  "aria-label": label,
128
129
  children: /* @__PURE__ */ jsx("div", { className: "crewlet-slide-stage__frame", style: frameStyle, children })
129
130
  }
@@ -0,0 +1,33 @@
1
+ import { Toolbar } from './chunk-PGRPNDWM.js';
2
+ import { ShortcutTip } from './chunk-OTN35CI4.js';
3
+ import { IconButton } from './chunk-4FQT6ZAY.js';
4
+ import { cx } from './chunk-ODEQTPFM.js';
5
+ import './CanvasToolbar-AE5MXH7T.css';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ function toolForKey(tools, event) {
9
+ if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return void 0;
10
+ const pressed = event.key.toLowerCase();
11
+ return tools.find((tool) => tool.shortcut.toLowerCase() === pressed)?.id;
12
+ }
13
+ function CanvasToolbar({
14
+ label,
15
+ tools,
16
+ value,
17
+ onChange,
18
+ className
19
+ }) {
20
+ return /* @__PURE__ */ jsx(Toolbar, { label, className: cx("crewlet-canvas-toolbar", className), children: tools.map((tool) => /* @__PURE__ */ jsx(ShortcutTip, { label: tool.label, keys: [tool.shortcut], children: /* @__PURE__ */ jsx(
21
+ IconButton,
22
+ {
23
+ size: "md",
24
+ label: tool.label,
25
+ title: "",
26
+ icon: tool.icon,
27
+ pressed: tool.id === value,
28
+ onClick: () => onChange(tool.id)
29
+ }
30
+ ) }, tool.id)) });
31
+ }
32
+
33
+ export { CanvasToolbar, toolForKey };
@@ -1,4 +1,4 @@
1
- import { SlideStage } from './chunk-O63MWA4G.js';
1
+ import { SlideStage } from './chunk-E6CR5PEV.js';
2
2
  import { Button } from './chunk-OG6CL3EB.js';
3
3
  import { IconButton } from './chunk-4FQT6ZAY.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';