@crewlethq/ui 0.31.0 → 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 (47) hide show
  1. package/README.md +25 -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 +3 -3
  17. package/dist/EditingStatus/index.js +1 -1
  18. package/dist/{EditingStatus-NFADEPSX.css → EditingStatus-L6THUAN7.css} +21 -0
  19. package/dist/PresenterView/index.js +2 -2
  20. package/dist/RichEditor/index.js +1 -1
  21. package/dist/SheetGrid/index.js +3 -3
  22. package/dist/SlideCompare/index.js +2 -2
  23. package/dist/SlideFilmstrip/index.js +2 -2
  24. package/dist/SlideGrid/index.js +2 -2
  25. package/dist/SlideStage/SlideStage.d.ts +6 -1
  26. package/dist/SlideStage/index.js +1 -1
  27. package/dist/TreeCanvas/index.js +4 -2
  28. package/dist/{chunk-ALMSY7RL.js → chunk-CRKFL423.js} +1 -1
  29. package/dist/{chunk-O63MWA4G.js → chunk-E6CR5PEV.js} +2 -1
  30. package/dist/chunk-E6EWK5YY.js +33 -0
  31. package/dist/{chunk-3DPIU2Q7.js → chunk-FPS3JIPQ.js} +1 -1
  32. package/dist/{chunk-OGAAHVF6.js → chunk-MBNFJSZS.js} +1 -1
  33. package/dist/{chunk-OJ45PPCV.js → chunk-OTN35CI4.js} +113 -30
  34. package/dist/{chunk-JODJS7MR.js → chunk-PJD2KFHX.js} +243 -39
  35. package/dist/{chunk-LR5QTFOE.js → chunk-RV7SZAHR.js} +1 -1
  36. package/dist/{chunk-VOX3YRFO.js → chunk-V5IGUXMZ.js} +1 -1
  37. package/dist/{chunk-3C3BRIMY.js → chunk-VS3KOOOL.js} +1 -1
  38. package/dist/{chunk-S6VG5ZFZ.js → chunk-WTNUVQVI.js} +1 -1
  39. package/dist/generated/index.d.ts +1 -0
  40. package/dist/generated/index.js +49 -48
  41. package/dist/index.js +49 -48
  42. package/dist/styles.css +233 -36
  43. package/package.json +3 -3
  44. package/dist/{Editor-YZ7KG2RD.js → Editor-YWBUJAQU.js} +1 -1
  45. package/dist/{chunk-UVJ5FF5V.js → chunk-3ZAFJ4GK.js} +2 -2
  46. package/dist/{chunk-CT4EZF62.js → chunk-LWXRD6L6.js} +2 -2
  47. /package/dist/{chunk-OC46246T.js → chunk-TF2P3OPS.js} +0 -0
@@ -1,10 +1,11 @@
1
1
  import { Note } from './chunk-CJKMURZO.js';
2
- import { IDENTITY_VIEW, Canvas } from './chunk-OJ45PPCV.js';
2
+ import { CanvasToolbar, toolForKey } from './chunk-E6EWK5YY.js';
3
+ import { IDENTITY_VIEW, Canvas } from './chunk-OTN35CI4.js';
3
4
  import { IconButton } from './chunk-4FQT6ZAY.js';
4
5
  import { cx } from './chunk-ODEQTPFM.js';
5
- import './CanvasBoard-ZLPDINSM.css';
6
- import { useState, useCallback, useMemo, useRef } from 'react';
7
- import { MaximizeGlyph, PencilGlyph, TrashGlyph } from '@crewlethq/icons/glyphs';
6
+ import './CanvasBoard-MBZVBWDO.css';
7
+ import { useState, useRef, useImperativeHandle, useCallback, useMemo, useEffect } from 'react';
8
+ import { MaximizeGlyph, PencilGlyph, TrashGlyph, MousePointer2Glyph, HandGlyph, TypeGlyph, StickyNoteGlyph } from '@crewlethq/icons/glyphs';
8
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
10
 
10
11
  // src/CanvasBoard/budget.ts
@@ -41,6 +42,11 @@ var NOTE_TONES = {
41
42
  green: "green",
42
43
  purple: "purple"
43
44
  };
45
+ function titleSize(note) {
46
+ const chars = Math.max(1, Array.from(note.text.trim()).length);
47
+ return Math.max(1, Math.min(note.h * 0.6, note.w / (chars * TITLE_GLYPH_EM)));
48
+ }
49
+ var TITLE_GLYPH_EM = 0.58;
44
50
  function noteName(note) {
45
51
  const words = note.text.trim().replace(/\s+/g, " ");
46
52
  return words.length > 40 ? `${words.slice(0, 39)}\u2026` : words;
@@ -54,8 +60,21 @@ var LABELS = {
54
60
  removeNote: "Delete note",
55
61
  noteText: "Note text",
56
62
  paused: "Zoom in to run this board",
57
- active: "Press Escape to return to the canvas"
63
+ active: "Press Escape to return to the canvas",
64
+ interact: "Double-click to use this board",
65
+ tools: "Tools",
66
+ moveTool: "Move",
67
+ handTool: "Hand",
68
+ textTool: "Text",
69
+ stickyTool: "Sticky note"
70
+ };
71
+ var TOOL_CURSOR = {
72
+ move: "pointer",
73
+ hand: "hand",
74
+ text: "text",
75
+ sticky: "crosshair"
58
76
  };
77
+ var CANVAS_BOARD_MIN_ZOOM = 0.02;
59
78
  var KEY_STEP = 8;
60
79
  var KEY_STEP_LARGE = 64;
61
80
  var CONTENT_MARGIN = 160;
@@ -80,23 +99,37 @@ function contentOf(boards, notes) {
80
99
  };
81
100
  }
82
101
  var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
102
+ var CONTROL = "button, a[href], input, select, textarea, [contenteditable='true']";
103
+ var POINTER_CORNERS = ["resize-nw", "resize-ne", "resize-sw"];
83
104
  function useFrameGestures(zoom, minSide, maxSide, commit) {
84
105
  const [preview, setPreview] = useState(null);
85
106
  const drag = useRef(null);
86
107
  const next = useCallback(
87
- (d, dx, dy) => d.mode === "move" ? { ...d.from, x: Math.round(d.from.x + dx), y: Math.round(d.from.y + dy) } : {
88
- ...d.from,
89
- w: clamp(Math.round(d.from.w + dx), minSide, maxSide),
90
- h: clamp(Math.round(d.from.h + dy), minSide, maxSide)
108
+ (d, dx, dy) => {
109
+ const { from } = d;
110
+ if (d.mode === "move") return { ...from, x: Math.round(from.x + dx), y: Math.round(from.y + dy) };
111
+ const west = d.mode === "resize-nw" || d.mode === "resize-sw";
112
+ const north = d.mode === "resize-nw" || d.mode === "resize-ne";
113
+ const w = clamp(Math.round(from.w + (west ? -dx : dx)), minSide, maxSide);
114
+ const h = clamp(Math.round(from.h + (north ? -dy : dy)), minSide, maxSide);
115
+ return {
116
+ x: west ? from.x + from.w - w : from.x,
117
+ y: north ? from.y + from.h - h : from.y,
118
+ w,
119
+ h
120
+ };
91
121
  },
92
122
  [minSide, maxSide]
93
123
  );
94
- const handle = (id, mode, item) => {
124
+ const pointer = (id, mode, item) => {
95
125
  const from = { x: item.x, y: item.y, w: item.w, h: item.h };
96
126
  return {
97
127
  onPointerDown: (event) => {
98
128
  if (event.pointerType === "mouse" && event.button !== 0) return;
129
+ const control = event.target instanceof Element ? event.target.closest(CONTROL) : null;
130
+ if (control !== null && control !== event.currentTarget) return;
99
131
  event.preventDefault();
132
+ event.stopPropagation();
100
133
  try {
101
134
  event.currentTarget.setPointerCapture(event.pointerId);
102
135
  } catch {
@@ -135,7 +168,12 @@ function useFrameGestures(zoom, minSide, maxSide, commit) {
135
168
  onPointerCancel: () => {
136
169
  drag.current = null;
137
170
  setPreview(null);
138
- },
171
+ }
172
+ };
173
+ };
174
+ const keys = (id, mode, item) => {
175
+ const from = { x: item.x, y: item.y, w: item.w, h: item.h };
176
+ return {
139
177
  onKeyDown: (event) => {
140
178
  const step = event.shiftKey ? KEY_STEP_LARGE : KEY_STEP;
141
179
  const delta = {
@@ -159,8 +197,13 @@ function useFrameGestures(zoom, minSide, maxSide, commit) {
159
197
  }
160
198
  };
161
199
  };
162
- return { preview, handle };
200
+ const handle = (id, mode, item) => ({
201
+ ...pointer(id, mode, item),
202
+ ...keys(id, mode, item)
203
+ });
204
+ return { preview, handle, pointer };
163
205
  }
206
+ var TYPING = "input, textarea, select, [contenteditable='true']";
164
207
  function CanvasBoard({
165
208
  label,
166
209
  boards,
@@ -174,9 +217,11 @@ function CanvasBoard({
174
217
  onBoardChange,
175
218
  onNoteChange,
176
219
  onNoteRemove,
220
+ onNoteCreate,
177
221
  onOpen,
178
222
  onActivate,
179
223
  controlsExtra,
224
+ toolbar = true,
180
225
  labels,
181
226
  canvasLabels,
182
227
  canvasRef,
@@ -187,6 +232,22 @@ function CanvasBoard({
187
232
  const [viewport, setViewport] = useState({ width: 0, height: 0 });
188
233
  const [active, setActive] = useState(null);
189
234
  const [editing, setEditing] = useState(null);
235
+ const [selected, setSelected] = useState(null);
236
+ const [chosenTool, setTool] = useState("move");
237
+ const [spaceHeld, setSpaceHeld] = useState(false);
238
+ const canvas = useRef(null);
239
+ useImperativeHandle(canvasRef, () => canvas.current, []);
240
+ const creates = editable && onNoteCreate !== void 0;
241
+ const tools = [
242
+ { id: "move", label: text.moveTool, icon: /* @__PURE__ */ jsx(MousePointer2Glyph, {}), shortcut: "V" },
243
+ { id: "hand", label: text.handTool, icon: /* @__PURE__ */ jsx(HandGlyph, {}), shortcut: "H" },
244
+ ...creates ? [
245
+ { id: "text", label: text.textTool, icon: /* @__PURE__ */ jsx(TypeGlyph, {}), shortcut: "T" },
246
+ { id: "sticky", label: text.stickyTool, icon: /* @__PURE__ */ jsx(StickyNoteGlyph, {}), shortcut: "S" }
247
+ ] : []
248
+ ];
249
+ const tool = tools.some((t) => t.id === chosenTool) ? chosenTool : "move";
250
+ const acting = spaceHeld ? "hand" : tool;
190
251
  const activate = (id) => {
191
252
  setActive(id);
192
253
  onActivate?.(id);
@@ -215,15 +276,77 @@ function CanvasBoard({
215
276
  );
216
277
  const largest = boards.reduce((w, b) => Math.max(w, b.w), 0);
217
278
  const live = new Set(liveBoards(drawnBoards, view, viewport, maxLive, minLiveWidth));
279
+ const shownSelection = selected !== null && (selected.kind === "board" ? boards : notes).some((item) => item.id === selected.id) ? selected : null;
280
+ const isSelected = (kind, id) => shownSelection?.kind === kind && shownSelection.id === id;
281
+ useEffect(() => {
282
+ if (!spaceHeld) return;
283
+ const release = (event) => {
284
+ if (event instanceof KeyboardEvent && event.key !== " ") return;
285
+ setSpaceHeld(false);
286
+ };
287
+ window.addEventListener("keyup", release);
288
+ window.addEventListener("blur", release);
289
+ return () => {
290
+ window.removeEventListener("keyup", release);
291
+ window.removeEventListener("blur", release);
292
+ };
293
+ }, [spaceHeld]);
218
294
  const onKeyDown = (event) => {
219
- if (event.key === "Escape" && active !== null) {
220
- event.stopPropagation();
221
- activate(null);
295
+ const target = event.target instanceof Element ? event.target : null;
296
+ if (event.key === "Escape") {
297
+ if (active !== null) {
298
+ event.stopPropagation();
299
+ activate(null);
300
+ } else if (shownSelection !== null) {
301
+ event.stopPropagation();
302
+ setSelected(null);
303
+ }
304
+ return;
305
+ }
306
+ if (event.defaultPrevented || target?.closest(TYPING)) return;
307
+ if (event.key === " ") {
308
+ if (target?.closest(CONTROL)) return;
309
+ event.preventDefault();
310
+ if (!event.repeat) setSpaceHeld(true);
311
+ return;
312
+ }
313
+ if ((event.key === "Delete" || event.key === "Backspace") && editable && shownSelection?.kind === "note") {
314
+ event.preventDefault();
315
+ onNoteRemove?.(shownSelection.id);
316
+ setSelected(null);
317
+ return;
318
+ }
319
+ const picked = toolForKey(tools, event);
320
+ if (picked !== void 0) {
321
+ event.preventDefault();
322
+ setTool(picked);
323
+ }
324
+ };
325
+ const onClick = (event) => {
326
+ const target = event.target instanceof Element ? event.target : null;
327
+ if (!target?.closest(".crewlet-canvas__viewport")) return;
328
+ if (target.closest(".crewlet-canvas-board__board, .crewlet-canvas-board__note")) return;
329
+ if ((acting === "text" || acting === "sticky") && onNoteCreate && canvas.current) {
330
+ const at = canvas.current.worldAt({ x: event.clientX, y: event.clientY });
331
+ const id = onNoteCreate(acting === "text" ? "title" : "sticky", {
332
+ x: Math.round(at.x),
333
+ y: Math.round(at.y)
334
+ });
335
+ setTool("move");
336
+ if (id !== void 0) {
337
+ setSelected({ kind: "note", id });
338
+ setEditing(id);
339
+ }
340
+ return;
222
341
  }
342
+ if (acting === "move") setSelected(null);
223
343
  };
224
344
  const zoomVar = { "--crewlet-canvas-board-zoom": String(view.k) };
345
+ const activeBoard = boards.find((b) => b.id === active && live.has(b.id));
346
+ const chosenBoard = shownSelection?.kind === "board" ? shownSelection.id : null;
347
+ const hint = !editable && activeBoard ? text.active : !editable && chosenBoard !== null && live.has(chosenBoard) ? text.interact : "";
225
348
  return (
226
- // The wrapper only hears Escape bubbling from inside the canvas; the
349
+ // The wrapper hears keys and clicks bubbling from inside the canvas; the
227
350
  // canvas's own viewport is the focusable, labelled control.
228
351
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
229
352
  /* @__PURE__ */ jsx(
@@ -231,7 +354,9 @@ function CanvasBoard({
231
354
  {
232
355
  className: cx("crewlet-canvas-board", className),
233
356
  "data-editable": editable || void 0,
357
+ "data-tool": acting,
234
358
  onKeyDown,
359
+ onClick,
235
360
  children: /* @__PURE__ */ jsx(
236
361
  Canvas,
237
362
  {
@@ -239,23 +364,31 @@ function CanvasBoard({
239
364
  content,
240
365
  largestItemWidth: largest || void 0,
241
366
  ground: "dotted",
367
+ cursor: TOOL_CURSOR[acting],
368
+ minZoom: CANVAS_BOARD_MIN_ZOOM,
369
+ refitOnResize: true,
370
+ controlsActualSize: true,
242
371
  controlsExtra,
372
+ hint,
243
373
  labels: canvasLabels,
374
+ overlay: toolbar ? /* @__PURE__ */ jsx("div", { className: "crewlet-canvas-board__tools", children: /* @__PURE__ */ jsx(CanvasToolbar, { label: text.tools, tools, value: tool, onChange: setTool }) }) : void 0,
244
375
  onViewChange: (nextView, size) => {
245
376
  setView(nextView);
246
377
  setViewport(size);
247
378
  },
248
- ref: canvasRef,
379
+ ref: canvas,
249
380
  children: /* @__PURE__ */ jsxs("div", { className: "crewlet-canvas-board__layer", style: zoomVar, children: [
250
381
  drawnBoards.map((b) => {
251
382
  const isLive = live.has(b.id);
252
383
  const isActive = !editable && active === b.id && isLive;
384
+ const chosen = isSelected("board", b.id);
253
385
  return /* @__PURE__ */ jsxs(
254
386
  "section",
255
387
  {
256
388
  className: "crewlet-canvas-board__board",
257
389
  "data-live": isLive || void 0,
258
390
  "data-active": isActive || void 0,
391
+ "data-selected": chosen || void 0,
259
392
  "aria-label": `${b.title}, ${text.size(b.w, b.h)}`,
260
393
  style: { left: b.x, top: b.y, width: b.w, height: b.h },
261
394
  children: [
@@ -266,10 +399,25 @@ function CanvasBoard({
266
399
  type: "button",
267
400
  className: "crewlet-canvas-board__title crewlet-canvas-board__handle",
268
401
  "aria-label": text.move(b.title),
402
+ "aria-pressed": chosen,
403
+ onFocus: () => setSelected({ kind: "board", id: b.id }),
269
404
  ...boardGestures.handle(b.id, "move", b),
270
405
  children: b.title
271
406
  }
272
- ) : /* @__PURE__ */ jsx("span", { className: "crewlet-canvas-board__title", children: b.title }),
407
+ ) : (
408
+ // The name selects its board, as a press on the board
409
+ // does; the board's keyboard route is its own page and
410
+ // its open control, so the name is pointer only.
411
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
412
+ /* @__PURE__ */ jsx(
413
+ "span",
414
+ {
415
+ className: "crewlet-canvas-board__title",
416
+ onClick: () => setSelected({ kind: "board", id: b.id }),
417
+ children: b.title
418
+ }
419
+ )
420
+ ),
273
421
  onOpen && /* @__PURE__ */ jsx(
274
422
  IconButton,
275
423
  {
@@ -287,27 +435,29 @@ function CanvasBoard({
287
435
  /* @__PURE__ */ jsx("span", { children: text.size(b.w, b.h) }),
288
436
  /* @__PURE__ */ jsx("span", { children: text.paused })
289
437
  ] }) }),
290
- isLive && !isActive && // A press here pans the canvas like the field around it;
291
- // a click without a drag hands this board the pointer.
292
- // The board's page stays reachable by keyboard through
293
- // its own frame, so the shield is pointer only.
294
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events
438
+ !isActive && // A press here pans the canvas like the field around it;
439
+ // a click selects the board and a double-click hands a
440
+ // live board the pointer. The board's page stays
441
+ // reachable by keyboard through its own frame, so the
442
+ // shield is pointer only.
443
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
295
444
  /* @__PURE__ */ jsx(
296
445
  "div",
297
446
  {
298
447
  className: "crewlet-canvas-board__shield",
299
- onClick: editable ? void 0 : () => activate(b.id)
448
+ onClick: () => setSelected({ kind: "board", id: b.id }),
449
+ onDoubleClick: editable || !isLive ? void 0 : () => activate(b.id)
300
450
  }
301
451
  )
302
452
  ] }),
303
- isActive && /* @__PURE__ */ jsx("p", { className: "crewlet-canvas-board__hint", children: text.active }),
304
453
  editable && /* @__PURE__ */ jsx(
305
- "button",
454
+ Corners,
306
455
  {
307
- type: "button",
308
- className: "crewlet-canvas-board__resize",
309
- "aria-label": text.resize(b.title),
310
- ...boardGestures.handle(b.id, "resize", b)
456
+ title: b.title,
457
+ selected: chosen,
458
+ text,
459
+ keyed: boardGestures.handle(b.id, "resize-se", b),
460
+ pointer: (mode) => boardGestures.pointer(b.id, mode, b)
311
461
  }
312
462
  )
313
463
  ]
@@ -321,9 +471,13 @@ function CanvasBoard({
321
471
  note: n,
322
472
  editable,
323
473
  editing: editing === n.id,
474
+ selected: isSelected("note", n.id),
324
475
  text,
325
476
  moveHandle: noteGestures.handle(n.id, "move", n),
326
- resizeHandle: noteGestures.handle(n.id, "resize", n),
477
+ dragPaper: noteGestures.pointer(n.id, "move", n),
478
+ resizeHandle: noteGestures.handle(n.id, "resize-se", n),
479
+ resizePointer: (mode) => noteGestures.pointer(n.id, mode, n),
480
+ onSelect: () => setSelected({ kind: "note", id: n.id }),
327
481
  onEdit: () => setEditing(n.id),
328
482
  onDone: (value) => {
329
483
  setEditing(null);
@@ -345,13 +499,47 @@ function CanvasBoard({
345
499
  )
346
500
  );
347
501
  }
502
+ function Corners({
503
+ title,
504
+ selected,
505
+ text,
506
+ keyed,
507
+ pointer
508
+ }) {
509
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
510
+ selected && POINTER_CORNERS.map((mode) => /* @__PURE__ */ jsx(
511
+ "span",
512
+ {
513
+ "aria-hidden": true,
514
+ className: "crewlet-canvas-board__resize",
515
+ "data-corner": mode,
516
+ ...pointer(mode)
517
+ },
518
+ mode
519
+ )),
520
+ /* @__PURE__ */ jsx(
521
+ "button",
522
+ {
523
+ type: "button",
524
+ className: "crewlet-canvas-board__resize",
525
+ "data-corner": "resize-se",
526
+ "aria-label": text.resize(title),
527
+ ...keyed
528
+ }
529
+ )
530
+ ] });
531
+ }
348
532
  function NoteView({
349
533
  note,
350
534
  editable,
351
535
  editing,
536
+ selected,
352
537
  text,
353
538
  moveHandle,
539
+ dragPaper,
354
540
  resizeHandle,
541
+ resizePointer,
542
+ onSelect,
355
543
  onEdit,
356
544
  onDone,
357
545
  onCancel,
@@ -365,6 +553,7 @@ function NoteView({
365
553
  "aria-label": text.noteText,
366
554
  defaultValue: note.text,
367
555
  autoFocus: true,
556
+ onFocus: (event) => event.currentTarget.select(),
368
557
  onBlur: (event) => onDone(event.currentTarget.value),
369
558
  onKeyDown: (event) => {
370
559
  if (event.key === "Escape") {
@@ -377,7 +566,14 @@ function NoteView({
377
566
  }
378
567
  }
379
568
  }
380
- ) : /* @__PURE__ */ jsx("p", { className: "crewlet-canvas-board__note-text", children: note.text }),
569
+ ) : /* @__PURE__ */ jsx(
570
+ "p",
571
+ {
572
+ className: "crewlet-canvas-board__note-text",
573
+ style: note.kind === "title" ? { fontSize: titleSize(note) } : void 0,
574
+ children: note.text
575
+ }
576
+ ),
381
577
  editable && !editing && /* @__PURE__ */ jsxs("div", { className: "crewlet-canvas-board__note-tools", children: [
382
578
  /* @__PURE__ */ jsx(
383
579
  "button",
@@ -385,6 +581,7 @@ function NoteView({
385
581
  type: "button",
386
582
  className: "crewlet-canvas-board__handle crewlet-canvas-board__note-move",
387
583
  "aria-label": text.move(noteName(note)),
584
+ onFocus: onSelect,
388
585
  ...moveHandle
389
586
  }
390
587
  ),
@@ -410,16 +607,22 @@ function NoteView({
410
607
  )
411
608
  ] }),
412
609
  editable && !editing && /* @__PURE__ */ jsx(
413
- "button",
610
+ Corners,
414
611
  {
415
- type: "button",
416
- className: "crewlet-canvas-board__resize",
417
- "aria-label": text.resize(noteName(note)),
418
- ...resizeHandle
612
+ title: noteName(note),
613
+ selected,
614
+ text,
615
+ keyed: resizeHandle,
616
+ pointer: resizePointer
419
617
  }
420
618
  )
421
619
  ] });
422
620
  const frame = { left: note.x, top: note.y, width: note.w, height: note.h };
621
+ const paper = {
622
+ "data-selected": selected || void 0,
623
+ onClick: onSelect,
624
+ ...editable && !editing ? { ...dragPaper, onDoubleClick: onEdit } : {}
625
+ };
423
626
  if (note.kind === "sticky") {
424
627
  return /* @__PURE__ */ jsx(
425
628
  Note,
@@ -428,11 +631,12 @@ function NoteView({
428
631
  className: "crewlet-canvas-board__note",
429
632
  "data-kind": "sticky",
430
633
  style: frame,
634
+ ...paper,
431
635
  children: body
432
636
  }
433
637
  );
434
638
  }
435
- return /* @__PURE__ */ jsx("div", { className: "crewlet-canvas-board__note", "data-kind": "title", style: frame, children: body });
639
+ return /* @__PURE__ */ jsx("div", { className: "crewlet-canvas-board__note", "data-kind": "title", style: frame, ...paper, children: body });
436
640
  }
437
641
 
438
- export { CANVAS_BOARD_MAX_LIVE, CANVAS_BOARD_MIN_LIVE_WIDTH, CANVAS_NOTE_COLORS, CanvasBoard, liveBoards };
642
+ export { CANVAS_BOARD_MAX_LIVE, CANVAS_BOARD_MIN_LIVE_WIDTH, CANVAS_BOARD_MIN_ZOOM, CANVAS_NOTE_COLORS, CanvasBoard, TITLE_GLYPH_EM, liveBoards, titleSize };
@@ -1,4 +1,4 @@
1
- import { SlideStage } from './chunk-O63MWA4G.js';
1
+ import { SlideStage } from './chunk-E6CR5PEV.js';
2
2
  import { useReorder } from './chunk-XJ2QEBMM.js';
3
3
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
@@ -9,7 +9,7 @@ import { jsx } from 'react/jsx-runtime';
9
9
  var engine = null;
10
10
  var loading = null;
11
11
  function loadEngine() {
12
- loading ??= import('./Editor-YZ7KG2RD.js').then(
12
+ loading ??= import('./Editor-YWBUJAQU.js').then(
13
13
  (module) => {
14
14
  engine = module.Editor;
15
15
  return engine;
@@ -1,4 +1,4 @@
1
- import { SlideStage } from './chunk-O63MWA4G.js';
1
+ import { SlideStage } from './chunk-E6CR5PEV.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './SlideGrid-RT6QEQEE.css';
4
4
  import { EyeOffGlyph } from '@crewlethq/icons/glyphs';
@@ -1,5 +1,5 @@
1
1
  import { useTreeState, useMeasuredSizes, layoutForest, treeAncestors, useLayoutAnchor, treeExpandable, layoutConnectors, treeItemAction, treeStep, treePosInSet, treeSetSize, treeLevel, placeGroups } from './chunk-MY374UUD.js';
2
- import { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, Canvas } from './chunk-OJ45PPCV.js';
2
+ import { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, Canvas } from './chunk-OTN35CI4.js';
3
3
  import { focusables } from './chunk-R25RGPUB.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import './TreeCanvas-L2XYONWL.css';
@@ -24,6 +24,7 @@ export * from '../Callout/index.js';
24
24
  export * from '../Canvas/index.js';
25
25
  export * from '../CanvasBoard/index.js';
26
26
  export * from '../CanvasSchematic/index.js';
27
+ export * from '../CanvasToolbar/index.js';
27
28
  export * from '../Card/index.js';
28
29
  export * from '../ChangeMark/index.js';
29
30
  export * from '../CharacterPicker/index.js';