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.
- package/dist/cli.js +1064 -176
- package/dist/viewer/assets/index-BOLNePag.css +2 -0
- package/dist/viewer/assets/index-BrtsfBgT.js +163 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer-lib/index.js +4280 -1822
- package/dist/viewer-lib/styles.css +140 -5
- package/dist/viewer-lib/types/src/shared/drawings.d.ts +153 -0
- package/dist/viewer-lib/types/viewer/src/lib/drawings.d.ts +61 -0
- package/dist/viewer-lib/types/viewer/src/lib/source.d.ts +6 -0
- package/dist/viewer-lib/types/viewer/src/lib/viewer.d.ts +3 -0
- package/dist/viewer-lib/types/viewer/src/library.d.ts +1 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/board.d.ts +16 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/camera.d.ts +7 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/canvas-bar.d.ts +14 -3
- package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing/editor.d.ts +68 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing/strokes.d.ts +15 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/drawing-capture.d.ts +18 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/layout.d.ts +2 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/markup.d.ts +26 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/view-state.d.ts +2 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/viewport.d.ts +4 -2
- package/dist/viewer-lib/types/viewer/src/ui/combobox.d.ts +25 -0
- package/dist/viewer-lib/types/viewer/src/ui/icon-paths.d.ts +8 -0
- package/package.json +4 -1
- package/dist/viewer/assets/index-Cy6JlR85.css +0 -2
- 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
|
-
/**
|
|
17
|
-
|
|
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
|
-
|
|
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;
|