foss-design 0.9.11 → 0.9.13

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 (26) hide show
  1. package/dist/cli.js +1064 -176
  2. package/dist/viewer/assets/index-BOLNePag.css +2 -0
  3. package/dist/viewer/assets/index-BrtsfBgT.js +163 -0
  4. package/dist/viewer/index.html +2 -2
  5. package/dist/viewer-lib/index.js +4280 -1822
  6. package/dist/viewer-lib/styles.css +140 -5
  7. package/dist/viewer-lib/types/src/shared/drawings.d.ts +153 -0
  8. package/dist/viewer-lib/types/viewer/src/lib/drawings.d.ts +61 -0
  9. package/dist/viewer-lib/types/viewer/src/lib/source.d.ts +6 -0
  10. package/dist/viewer-lib/types/viewer/src/lib/viewer.d.ts +3 -0
  11. package/dist/viewer-lib/types/viewer/src/library.d.ts +1 -0
  12. package/dist/viewer-lib/types/viewer/src/pages/canvas/board.d.ts +16 -0
  13. package/dist/viewer-lib/types/viewer/src/pages/canvas/camera.d.ts +7 -0
  14. package/dist/viewer-lib/types/viewer/src/pages/canvas/canvas-bar.d.ts +14 -3
  15. package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing/editor.d.ts +68 -0
  16. package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing/strokes.d.ts +15 -0
  17. package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing-capture.d.ts +18 -0
  18. package/dist/viewer-lib/types/viewer/src/pages/canvas/layout.d.ts +2 -0
  19. package/dist/viewer-lib/types/viewer/src/pages/canvas/markup.d.ts +26 -0
  20. package/dist/viewer-lib/types/viewer/src/pages/canvas/view-state.d.ts +2 -0
  21. package/dist/viewer-lib/types/viewer/src/pages/canvas/viewport.d.ts +4 -2
  22. package/dist/viewer-lib/types/viewer/src/ui/combobox.d.ts +25 -0
  23. package/dist/viewer-lib/types/viewer/src/ui/icon-paths.d.ts +8 -0
  24. package/package.json +4 -1
  25. package/dist/viewer/assets/index-Cy6JlR85.css +0 -2
  26. package/dist/viewer/assets/index-mvGp1q3N.js +0 -159
@@ -74,6 +74,7 @@
74
74
  --animate-spin: spin 1s linear infinite;
75
75
  --animate-pulse: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;
76
76
  --blur-sm: 8px;
77
+ --blur-md: 12px;
77
78
  --default-transition-duration: .15s;
78
79
  --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
79
80
  --default-font-family: "IBM Plex Sans", system-ui, sans-serif;
@@ -417,6 +418,10 @@
417
418
  pointer-events: none;
418
419
  }
419
420
 
421
+ .invisible {
422
+ visibility: hidden;
423
+ }
424
+
420
425
  .visible {
421
426
  visibility: visible;
422
427
  }
@@ -461,10 +466,22 @@
461
466
  inset: 0;
462
467
  }
463
468
 
469
+ .inset-4 {
470
+ inset: calc(var(--spacing) * 4);
471
+ }
472
+
464
473
  .inset-x-0 {
465
474
  inset-inline: 0;
466
475
  }
467
476
 
477
+ .inset-x-4 {
478
+ inset-inline: calc(var(--spacing) * 4);
479
+ }
480
+
481
+ .inset-x-5 {
482
+ inset-inline: calc(var(--spacing) * 5);
483
+ }
484
+
468
485
  .inset-x-6 {
469
486
  inset-inline: calc(var(--spacing) * 6);
470
487
  }
@@ -525,6 +542,14 @@
525
542
  bottom: calc(var(--spacing) * 5);
526
543
  }
527
544
 
545
+ .bottom-\[76px\] {
546
+ bottom: 76px;
547
+ }
548
+
549
+ .bottom-full {
550
+ bottom: 100%;
551
+ }
552
+
528
553
  .left-0 {
529
554
  left: 0;
530
555
  }
@@ -726,11 +751,21 @@
726
751
  height: 7px;
727
752
  }
728
753
 
754
+ .size-\[12px\] {
755
+ width: 12px;
756
+ height: 12px;
757
+ }
758
+
729
759
  .size-\[14px\] {
730
760
  width: 14px;
731
761
  height: 14px;
732
762
  }
733
763
 
764
+ .size-\[92px\] {
765
+ width: 92px;
766
+ height: 92px;
767
+ }
768
+
734
769
  .size-full {
735
770
  width: 100%;
736
771
  height: 100%;
@@ -894,6 +929,10 @@
894
929
  max-height: min(56vh, 520px);
895
930
  }
896
931
 
932
+ .max-h-\[min\(296px\,var\(--radix-popover-content-available-height\)\)\] {
933
+ max-height: min(296px, var(--radix-popover-content-available-height));
934
+ }
935
+
897
936
  .max-h-\[min\(560px\,76vh\)\] {
898
937
  max-height: min(560px, 76vh);
899
938
  }
@@ -914,6 +953,10 @@
914
953
  min-height: 38px;
915
954
  }
916
955
 
956
+ .min-h-\[44px\] {
957
+ min-height: 44px;
958
+ }
959
+
917
960
  .min-h-\[46px\] {
918
961
  min-height: 46px;
919
962
  }
@@ -940,6 +983,10 @@
940
983
  }
941
984
  }
942
985
 
986
+ .w-4 {
987
+ width: calc(var(--spacing) * 4);
988
+ }
989
+
943
990
  .w-5 {
944
991
  width: calc(var(--spacing) * 5);
945
992
  }
@@ -952,6 +999,10 @@
952
999
  width: calc(var(--spacing) * 14);
953
1000
  }
954
1001
 
1002
+ .w-\[26px\] {
1003
+ width: 26px;
1004
+ }
1005
+
955
1006
  .w-\[32px\] {
956
1007
  width: 32px;
957
1008
  }
@@ -1120,6 +1171,10 @@
1120
1171
  flex-basis: 0;
1121
1172
  }
1122
1173
 
1174
+ .origin-top-left {
1175
+ transform-origin: 0 0;
1176
+ }
1177
+
1123
1178
  .-translate-x-1\/2 {
1124
1179
  --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
1125
1180
  translate: var(--tw-translate-x) var(--tw-translate-y);
@@ -1130,6 +1185,10 @@
1130
1185
  translate: var(--tw-translate-x) var(--tw-translate-y);
1131
1186
  }
1132
1187
 
1188
+ .rotate-180 {
1189
+ rotate: 180deg;
1190
+ }
1191
+
1133
1192
  .transform {
1134
1193
  transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
1135
1194
  }
@@ -1138,10 +1197,6 @@
1138
1197
  animation: .16s ease-out q-fade-in;
1139
1198
  }
1140
1199
 
1141
- .animate-\[q-pop_120ms_ease-out\] {
1142
- animation: .12s ease-out q-pop;
1143
- }
1144
-
1145
1200
  .animate-pulse {
1146
1201
  animation: var(--animate-pulse);
1147
1202
  }
@@ -1170,6 +1225,10 @@
1170
1225
  cursor: pointer;
1171
1226
  }
1172
1227
 
1228
+ .cursor-text {
1229
+ cursor: text;
1230
+ }
1231
+
1173
1232
  .touch-none {
1174
1233
  touch-action: none;
1175
1234
  }
@@ -1178,6 +1237,10 @@
1178
1237
  resize: both;
1179
1238
  }
1180
1239
 
1240
+ .resize-none {
1241
+ resize: none;
1242
+ }
1243
+
1181
1244
  .resize-y {
1182
1245
  resize: vertical;
1183
1246
  }
@@ -1190,6 +1253,10 @@
1190
1253
  grid-template-columns: 92px minmax(0, 1fr);
1191
1254
  }
1192
1255
 
1256
+ .grid-cols-\[minmax\(var\(--dock-left\,0px\)\,1fr\)_minmax\(0\,auto\)_minmax\(var\(--dock-right\,0px\)\,1fr\)\] {
1257
+ grid-template-columns: minmax(var(--dock-left, 0px),1fr) minmax(0,auto) minmax(var(--dock-right, 0px),1fr);
1258
+ }
1259
+
1193
1260
  .grid-rows-\[20px_auto_20px\] {
1194
1261
  grid-template-rows: 20px auto 20px;
1195
1262
  }
@@ -1320,6 +1387,10 @@
1320
1387
  overflow: hidden;
1321
1388
  }
1322
1389
 
1390
+ .overflow-visible {
1391
+ overflow: visible;
1392
+ }
1393
+
1323
1394
  .overflow-x-auto {
1324
1395
  overflow-x: auto;
1325
1396
  }
@@ -1376,6 +1447,11 @@
1376
1447
  border-radius: 3.40282e38px;
1377
1448
  }
1378
1449
 
1450
+ .rounded-t-\[7px\] {
1451
+ border-top-left-radius: 7px;
1452
+ border-top-right-radius: 7px;
1453
+ }
1454
+
1379
1455
  .rounded-t-\[14px\] {
1380
1456
  border-top-left-radius: 14px;
1381
1457
  border-top-right-radius: 14px;
@@ -1411,6 +1487,11 @@
1411
1487
  border-bottom-width: 1px;
1412
1488
  }
1413
1489
 
1490
+ .border-b-0 {
1491
+ border-bottom-style: var(--tw-border-style);
1492
+ border-bottom-width: 0;
1493
+ }
1494
+
1414
1495
  .border-l {
1415
1496
  border-left-style: var(--tw-border-style);
1416
1497
  border-left-width: 1px;
@@ -1558,6 +1639,16 @@
1558
1639
  }
1559
1640
  }
1560
1641
 
1642
+ .bg-surface\/80 {
1643
+ background-color: var(--surface);
1644
+ }
1645
+
1646
+ @supports (color: color-mix(in lab, red, red)) {
1647
+ .bg-surface\/80 {
1648
+ background-color: color-mix(in oklab, var(--surface) 80%, transparent);
1649
+ }
1650
+ }
1651
+
1561
1652
  .bg-surface\/90 {
1562
1653
  background-color: var(--surface);
1563
1654
  }
@@ -1624,6 +1715,10 @@
1624
1715
  padding: var(--spacing);
1625
1716
  }
1626
1717
 
1718
+ .p-1\.5 {
1719
+ padding: calc(var(--spacing) * 1.5);
1720
+ }
1721
+
1627
1722
  .p-2 {
1628
1723
  padding: calc(var(--spacing) * 2);
1629
1724
  }
@@ -2156,6 +2251,24 @@
2156
2251
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2157
2252
  }
2158
2253
 
2254
+ .ring-2 {
2255
+ --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2256
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2257
+ }
2258
+
2259
+ .ring-action {
2260
+ --tw-ring-color: var(--action);
2261
+ }
2262
+
2263
+ .ring-offset-2 {
2264
+ --tw-ring-offset-width: 2px;
2265
+ --tw-ring-offset-shadow: var(--tw-ring-inset, ) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
2266
+ }
2267
+
2268
+ .ring-offset-surface {
2269
+ --tw-ring-offset-color: var(--surface);
2270
+ }
2271
+
2159
2272
  .outline {
2160
2273
  outline-style: var(--tw-outline-style);
2161
2274
  outline-width: 1px;
@@ -2186,6 +2299,12 @@
2186
2299
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
2187
2300
  }
2188
2301
 
2302
+ .backdrop-blur-md {
2303
+ --tw-backdrop-blur: blur(var(--blur-md));
2304
+ -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
2305
+ backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
2306
+ }
2307
+
2189
2308
  .backdrop-blur-sm {
2190
2309
  --tw-backdrop-blur: blur(var(--blur-sm));
2191
2310
  -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
@@ -2345,6 +2464,10 @@
2345
2464
  outline-offset: -2px;
2346
2465
  }
2347
2466
 
2467
+ .active\:scale-\[0\.94\]:active {
2468
+ scale: .94;
2469
+ }
2470
+
2348
2471
  .active\:bg-soft2:active {
2349
2472
  background-color: var(--soft2);
2350
2473
  }
@@ -2512,6 +2635,10 @@
2512
2635
  flex-wrap: wrap;
2513
2636
  }
2514
2637
  }
2638
+
2639
+ .\[\&\>\:not\(\:first-child\)\]\:shrink-0 > :not(:first-child) {
2640
+ flex-shrink: 0;
2641
+ }
2515
2642
  }
2516
2643
 
2517
2644
  @font-face {
@@ -2795,6 +2922,10 @@
2795
2922
  --grid-dot: #c9ced5;
2796
2923
  --note: #fdf3e3;
2797
2924
  --note-line: #edd6b1;
2925
+ --draw-ink: #1b1f24;
2926
+ --draw-red: #e03131;
2927
+ --draw-blue: #1971c2;
2928
+ --draw-green: #2b8a3e;
2798
2929
  --scrollbar: #c3c9d0;
2799
2930
  --scrollbar-hover: #9aa2ac;
2800
2931
  color-scheme: light;
@@ -2829,6 +2960,10 @@
2829
2960
  --grid-dot: #30343a;
2830
2961
  --note: #2a2415;
2831
2962
  --note-line: #574420;
2963
+ --draw-ink: #e6e8eb;
2964
+ --draw-red: #ff6b6b;
2965
+ --draw-blue: #4dabf7;
2966
+ --draw-green: #51cf66;
2832
2967
  --scrollbar: #3a3f46;
2833
2968
  --scrollbar-hover: #565d66;
2834
2969
  color-scheme: dark;
@@ -3082,9 +3217,9 @@
3082
3217
  }
3083
3218
 
3084
3219
  .canvas-overlay .section-title {
3220
+ translate: 0 max(-100%, min(0px, calc(var(--body) * var(--z) * 1px - 44px)));
3085
3221
  padding-bottom: 8px;
3086
3222
  display: none;
3087
- translate: 0 -100%;
3088
3223
  }
3089
3224
 
3090
3225
  .canvas-overlay[data-titles="on"] .section-title {
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Drawings: an idea board for each canvas page and markup over each screen. They are not screens:
3
+ * people draw them in the viewer, agents read them, and in the cloud every member sees the same
4
+ * ones as they are drawn. A drawing is a set of strokes plus the ids of erased ones, so two copies
5
+ * merge by union whatever order their changes arrive in.
6
+ */
7
+ /** `board:<page id>` or `markup:<item id>`. */
8
+ export type DrawingKey = string;
9
+ export declare const INKS: readonly ['ink', 'red', 'blue', 'green'];
10
+ export type Ink = (typeof INKS)[number];
11
+ export declare const STROKE_KINDS: readonly ['pen', 'arrow', 'rect', 'text'];
12
+ export type StrokeKind = (typeof STROKE_KINDS)[number];
13
+ export interface Stroke {
14
+ id: string;
15
+ kind: StrokeKind;
16
+ ink: Ink;
17
+ /** Line width in drawing pixels; the font size for text. */
18
+ size: number;
19
+ /** pen: x, y, pressure triples; arrow and rect: x1, y1, x2, y2; text: x, y of its top left. */
20
+ points: number[];
21
+ text?: string;
22
+ }
23
+ export interface Drawing {
24
+ strokes: Stroke[];
25
+ /** Erased strokes stay erased, even when a copy that still has them merges in later. */
26
+ erased: string[];
27
+ }
28
+ export interface DrawingOps {
29
+ add?: Stroke[];
30
+ erase?: string[];
31
+ }
32
+ export declare const MAX_STROKES = 4000;
33
+ /** Longest message either side takes. */
34
+ export declare const MAX_MESSAGE: number;
35
+ export declare const boardKey: (page: string) => DrawingKey;
36
+ export declare const markupKey: (item: string) => DrawingKey;
37
+ export declare const isDrawingKey: (value: unknown) => value is DrawingKey;
38
+ export declare const emptyDrawing: () => Drawing;
39
+ /** A random stroke id. */
40
+ export declare function strokeId(): string;
41
+ export declare function parseStroke(value: unknown): Stroke | null;
42
+ export declare function parseOps(value: unknown): DrawingOps | null;
43
+ export declare function parseDrawing(value: unknown): Drawing | null;
44
+ /** `{ [key]: Drawing }`, dropping what does not parse. */
45
+ export declare function parseDrawings(value: unknown): Record<DrawingKey, Drawing>;
46
+ /** `drawing` with `ops` applied, or null when they change nothing. Strokes past MAX_STROKES are not added. */
47
+ export declare function applyOps(drawing: Drawing, ops: DrawingOps): Drawing | null;
48
+ /** What `from` has that `to` lacks, as ops that bring `to` up to it. */
49
+ export declare function diffDrawings(from: Drawing, to: Drawing): DrawingOps | null;
50
+ export declare function isEmptyDrawing(drawing: Drawing | undefined): boolean;
51
+ export interface Box {
52
+ x: number;
53
+ y: number;
54
+ w: number;
55
+ h: number;
56
+ }
57
+ /** Text lines are this many font sizes apart. */
58
+ export declare const TEXT_LINE_HEIGHT = 1.25;
59
+ /** The box a text stroke takes, roughly (no font metrics here): for erasing, cropping and its editor. */
60
+ export declare function textBox(stroke: Stroke): Box;
61
+ /** The box a stroke takes, its line width, arrowhead and text included. */
62
+ export declare function strokeBounds(stroke: Stroke): Box;
63
+ /** The box all the strokes take; null for none. */
64
+ export declare function drawingBounds(strokes: Stroke[]): Box | null;
65
+ /** Strokes closer than this belong to one idea on a board. */
66
+ export declare const GROUP_GAP = 240;
67
+ /**
68
+ * A board's strokes in groups: what is drawn close together (less than GROUP_GAP apart) is one
69
+ * group, empty space between sketches parts them. In reading order: rows top to bottom, then left
70
+ * to right. A picture of a board is one per group, so far-apart ideas do not shrink into specks.
71
+ */
72
+ export declare function drawingGroups(strokes: Stroke[]): {
73
+ box: Box;
74
+ strokes: Stroke[];
75
+ }[];
76
+ /**
77
+ * A stroke on its way, sent every few frames while it is drawn and not kept: `points` continue the
78
+ * stroke's points from index `at` (0 starts it over, as a shape does on every move).
79
+ */
80
+ export interface LiveStroke {
81
+ id: string;
82
+ kind: StrokeKind;
83
+ ink: Ink;
84
+ size: number;
85
+ text?: string;
86
+ at: number;
87
+ points: number[];
88
+ }
89
+ /** Messages to the server over the drawings socket of one canvas. */
90
+ export type ClientMessage = {
91
+ type: 'ops';
92
+ id: number;
93
+ key: DrawingKey;
94
+ add?: Stroke[];
95
+ erase?: string[];
96
+ } | {
97
+ type: 'live';
98
+ key: DrawingKey;
99
+ stroke: LiveStroke;
100
+ } | {
101
+ type: 'live-end';
102
+ key: DrawingKey;
103
+ id: string;
104
+ };
105
+ /** Messages from the server. */
106
+ export type ServerMessage =
107
+ /** First thing on a connection: every drawing of the canvas, and whether this peer may draw. */
108
+ {
109
+ type: 'hello';
110
+ peer: string;
111
+ canDraw: boolean;
112
+ drawings: Record<DrawingKey, Drawing>;
113
+ }
114
+ /** Someone's change, this peer's own included. */
115
+ | {
116
+ type: 'ops';
117
+ key: DrawingKey;
118
+ add?: Stroke[];
119
+ erase?: string[];
120
+ peer: string;
121
+ }
122
+ /** The server kept the ops the client numbered `id`. */
123
+ | {
124
+ type: 'ack';
125
+ id: number;
126
+ }
127
+ /** The whole drawing, where a change came some other way than ops (a file edited here, another server). */
128
+ | {
129
+ type: 'doc';
130
+ key: DrawingKey;
131
+ drawing: Drawing;
132
+ } | {
133
+ type: 'live';
134
+ key: DrawingKey;
135
+ stroke: LiveStroke;
136
+ peer: string;
137
+ name?: string;
138
+ } | {
139
+ type: 'live-end';
140
+ key: DrawingKey;
141
+ id: string;
142
+ peer: string;
143
+ }
144
+ /** A peer left: its strokes on the way go with it. */
145
+ | {
146
+ type: 'gone';
147
+ peer: string;
148
+ } | {
149
+ type: 'error';
150
+ message: string;
151
+ };
152
+ export declare function parseClientMessage(raw: string): ClientMessage | null;
153
+ export declare function parseServerMessage(raw: string): ServerMessage | null;
@@ -0,0 +1,61 @@
1
+ import { type Drawing, type DrawingKey, type DrawingOps, type Stroke } from '../../../src/shared/drawings';
2
+ import { Store } from './store';
3
+ /** A stroke someone else is drawing right now. */
4
+ export interface Ghost {
5
+ peer: string;
6
+ name?: string;
7
+ stroke: Stroke;
8
+ seen: number;
9
+ }
10
+ export interface DrawingsState {
11
+ /** The server said hello: the drawings are the real ones. */
12
+ ready: boolean;
13
+ online: boolean;
14
+ canDraw: boolean;
15
+ drawings: Record<DrawingKey, Drawing>;
16
+ ghosts: Record<DrawingKey, Ghost[]>;
17
+ }
18
+ /**
19
+ * The drawings of one canvas over its socket. What shows is the server's drawings with this user's
20
+ * changes it has not acknowledged yet on top: they show at once, go out numbered, and go out again
21
+ * after a reconnect (applying them twice changes nothing). A change the server refuses comes back
22
+ * as the stored drawing, then the acknowledgement, and so drops out of view.
23
+ */
24
+ export declare class DrawingClient {
25
+ private readonly url;
26
+ readonly store: Store<DrawingsState>;
27
+ private socket;
28
+ /** The server's drawings, as far as it told. */
29
+ private confirmed;
30
+ private pending;
31
+ private nextId;
32
+ private delay;
33
+ private timer;
34
+ private sweep;
35
+ private closed;
36
+ constructor(url: string);
37
+ private connect;
38
+ private retry;
39
+ private send;
40
+ /** The drawing to show: the server's, with the changes still on their way applied. */
41
+ private shown;
42
+ private show;
43
+ private receive;
44
+ private dropGhosts;
45
+ private dropStale;
46
+ /** A change of this user's: shown at once, sent, and sent again after a reconnect until acknowledged. */
47
+ apply(key: DrawingKey, ops: DrawingOps): void;
48
+ /** A stroke on its way: its points from `at` on (0 sends it whole). */
49
+ live(key: DrawingKey, stroke: Stroke, at: number): void;
50
+ liveEnd(key: DrawingKey, id: string): void;
51
+ close(): void;
52
+ }
53
+ /** The drawings of a canvas while it is open, or null when the source has none. */
54
+ export declare function useDrawingClient(canvas: string, enabled?: boolean): DrawingClient | null;
55
+ /** One drawing and the strokes on their way onto it. */
56
+ export declare function useDrawing(client: DrawingClient, key: DrawingKey): {
57
+ drawing: Drawing | undefined;
58
+ ghosts: Ghost[];
59
+ };
60
+ /** For hooks that need a store before the canvas's drawings are there. */
61
+ export declare const noDrawings: Store<DrawingsState>;
@@ -29,6 +29,12 @@ export interface ViewerSource {
29
29
  source(path: string, unit: string): Promise<string>;
30
30
  /** Set the project icon (an SVG, PNG or WebP), or remove it with null. Without it the viewer offers no icon controls. */
31
31
  setIcon?(file: Blob | null): Promise<void>;
32
+ /**
33
+ * The WebSocket URL of a canvas's drawings: the idea board of each page and the markup over each
34
+ * screen, live for everyone who has the canvas open (`src/shared/drawings.ts` holds the protocol).
35
+ * Without it the viewer shows no drawings.
36
+ */
37
+ drawings?(canvas: string): string;
32
38
  }
33
39
  export declare class ApiError extends Error {
34
40
  readonly status: number;
@@ -1,3 +1,4 @@
1
+ import type { CanvasItem } from '../../../src/shared/types';
1
2
  import { type ReactNode } from 'react';
2
3
  import type { ViewerSource } from './source';
3
4
  /** Places where an app that embeds the viewer adds its own controls. */
@@ -28,6 +29,8 @@ export interface ViewerSlots {
28
29
  canvasesAfter?: ReactNode;
29
30
  /** Below the panels of the home page, full width. */
30
31
  homeAfter?: ReactNode;
32
+ /** In the bar of the item selected on a canvas, before the way to zoom to it: sharing that screen, say. */
33
+ selectionActions?: (canvasId: string, item: CanvasItem) => ReactNode;
31
34
  /**
32
35
  * On a screen's full-window page, the corner plate with the way out: `note` is a muted line under it
33
36
  * (whose content the screen is), `actions` sit next to the way out, and with `badge` the plate folds
@@ -16,6 +16,7 @@ export { Avatar, initials } from './ui/avatar';
16
16
  export { Badge, Count, type Tone } from './ui/badge';
17
17
  export { Button, ButtonAnchor, type ButtonKind, ButtonLink, type ButtonProps, buttonClass, IconButton, type IconButtonProps, iconButtonClass, } from './ui/button';
18
18
  export { Segmented, Switch } from './ui/choice';
19
+ export { Combobox, type ComboboxOption } from './ui/combobox';
19
20
  export { CopyButton } from './ui/copy-button';
20
21
  export { Dialog } from './ui/dialog';
21
22
  export { Icon, type IconName } from './ui/icon';
@@ -0,0 +1,16 @@
1
+ import type { CanvasPage } from '../../../../src/shared/types';
2
+ import { type DrawingClient } from '../../lib/drawings';
3
+ import { type ToolSizes } from './drawing/editor';
4
+ export declare const BOARD_SIZES: ToolSizes;
5
+ /**
6
+ * The page's idea board: a tile above the zoom controls with what is drawn on it, which opens over
7
+ * the canvas. The board has no edges: it pans and zooms like the canvas, and a picture of it is
8
+ * cropped to what is drawn. Whether it is open, and where it looks, is kept per page for the
9
+ * session. Everyone with the canvas open sees it change as it is drawn on; those who may not draw
10
+ * see it only once there is something on it.
11
+ */
12
+ export declare function IdeaBoard({ client, canvasId, page }: {
13
+ client: DrawingClient;
14
+ canvasId: string;
15
+ page: CanvasPage;
16
+ }): import("react").JSX.Element | null;
@@ -34,10 +34,17 @@ export declare class CameraStore {
34
34
  y: number;
35
35
  };
36
36
  }
37
+ /** A camera saved in the session under `key`, or null. */
38
+ export declare function loadCamera(key: string): Camera | null;
37
39
  /**
38
40
  * The camera that shows `rect` inside a viewport of `w`×`h` with `pad` screen pixels around it.
39
41
  * When `rect` does not fit even at `minZoom`, it lines up with the top (and the left, if it is too wide).
40
42
  */
41
43
  export declare function fitRect(rect: Rect, w: number, h: number, pad?: number, maxZoom?: number, minZoom?: number): Camera;
44
+ /**
45
+ * Keeps a `.canvas-grid` layer in step with a camera. The dot grid is a layer of its own: panning
46
+ * only moves it, zooming repaints it.
47
+ */
48
+ export declare function gridMover(grid: HTMLElement): (c: Camera) => void;
42
49
  export declare function intersects(a: Rect, b: Rect): boolean;
43
50
  export {};
@@ -1,4 +1,5 @@
1
1
  import type { CanvasDoc, CanvasItem, CanvasPage as Page, Theme } from '../../../../src/shared/types';
2
+ import { type ReactNode } from 'react';
2
3
  import type { ViewStore } from './view-state';
3
4
  /** The canvas page's top bar: the canvas and its pages, screen theme, inspect and play. */
4
5
  export declare function CanvasBar({ canvas, page, theme, onTheme, sidebar, onSidebar, onPlay, canPlay, inspect, onInspect, }: {
@@ -13,15 +14,25 @@ export declare function CanvasBar({ canvas, page, theme, onTheme, sidebar, onSid
13
14
  inspect: boolean;
14
15
  onInspect(value: boolean): void;
15
16
  }): import("react").JSX.Element;
16
- /** The selected item's name and actions, floating over the bottom of the canvas. */
17
- export declare function SelectionBar({ canvas, store, layoutItems, theme, onPlay, inspect, }: {
17
+ /**
18
+ * The strip along the canvas's bottom edge that holds a bar: centred while there is room, moved aside
19
+ * when there is not, and never under the controls in the corners, whose widths come in as
20
+ * `--dock-left` and `--dock-right` (see useDock).
21
+ */
22
+ export declare function BottomDock({ children }: {
23
+ children: ReactNode;
24
+ }): import("react").JSX.Element;
25
+ /** The selected item's name and actions, floating over the bottom of the canvas; it eases in and out. */
26
+ export declare function SelectionBar({ canvas, store, layoutItems, theme, onPlay, inspect, onMarkup, }: {
18
27
  canvas: CanvasDoc;
19
28
  store: ViewStore;
20
29
  layoutItems: CanvasItem[];
21
30
  theme: Theme;
22
31
  onPlay(id: string): void;
23
32
  inspect: boolean;
24
- }): import("react").JSX.Element | null;
33
+ /** Mark up a screen; without it, where no one may draw, there is no such button. */
34
+ onMarkup?: (id: string) => void;
35
+ }): import("react").JSX.Element;
25
36
  /** The inspect mode switch: a button that stays pressed while on. */
26
37
  export declare function InspectToggle({ on, onChange, compact, }: {
27
38
  on: boolean;