@tldraw/editor 3.14.0-canary.f2737654a470 → 3.14.0-canary.f27d19561239

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 (37) hide show
  1. package/dist-cjs/index.d.ts +37 -51
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +1 -25
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +42 -73
  7. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  8. package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
  9. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  10. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  11. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -1
  12. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  13. package/dist-cjs/version.js +3 -3
  14. package/dist-cjs/version.js.map +1 -1
  15. package/dist-esm/index.d.mts +37 -51
  16. package/dist-esm/index.mjs +1 -1
  17. package/dist-esm/index.mjs.map +2 -2
  18. package/dist-esm/lib/editor/Editor.mjs +1 -25
  19. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  20. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +42 -73
  21. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  22. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
  23. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  24. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -1
  25. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  26. package/dist-esm/version.mjs +3 -3
  27. package/dist-esm/version.mjs.map +1 -1
  28. package/editor.css +482 -433
  29. package/package.json +7 -7
  30. package/src/index.ts +0 -2
  31. package/src/lib/editor/Editor.ts +1 -28
  32. package/src/lib/editor/managers/TextManager/TextManager.test.ts +5 -1
  33. package/src/lib/editor/managers/TextManager/TextManager.ts +86 -117
  34. package/src/lib/editor/tools/StateNode.ts +3 -3
  35. package/src/lib/editor/types/external-content.ts +2 -11
  36. package/src/lib/hooks/useCanvasEvents.ts +1 -0
  37. package/src/version.ts +3 -3
package/editor.css CHANGED
@@ -37,6 +37,8 @@
37
37
  --layer-overlays-collaborator-shape-indicator: 30;
38
38
  --layer-overlays-user-scribble: 40;
39
39
  --layer-overlays-user-brush: 50;
40
+ --layer-overlays-user-indicator-selected: 60;
41
+ --layer-overlays-user-indicator-hovered: 70;
40
42
  --layer-overlays-user-snapline: 90;
41
43
  --layer-overlays-selection-fg: 100;
42
44
  /* User handles need to be above selection edges / corners, matters for sticky note clone handles */
@@ -137,15 +139,11 @@
137
139
  }
138
140
 
139
141
  .tl-theme__light {
140
- /* Canvas */
141
- --color-snap: hsl(0, 76%, 60%);
142
- --color-selection-fill: hsl(210, 100%, 56%, 24%);
143
- --color-selection-stroke: hsl(214, 84%, 56%);
142
+ --color-accent: hsl(0, 76%, 60%);
144
143
  --color-background: hsl(210, 20%, 98%);
145
144
  --color-brush-fill: hsl(0, 0%, 56%, 10.2%);
146
145
  --color-brush-stroke: hsl(0, 0%, 56%, 25.1%);
147
146
  --color-grid: hsl(0, 0%, 43%);
148
- /* UI */
149
147
  --color-low: hsl(204, 16%, 94%);
150
148
  --color-low-border: hsl(204, 16%, 92%);
151
149
  --color-culled: hsl(204, 14%, 93%);
@@ -156,28 +154,28 @@
156
154
  --color-hint: hsl(0, 0%, 0%, 5.5%);
157
155
  --color-overlay: hsl(0, 0%, 0%, 20%);
158
156
  --color-divider: hsl(0, 0%, 91%);
159
- --color-panel: hsl(0, 0%, 99%);
160
157
  --color-panel-contrast: hsl(0, 0%, 100%);
161
158
  --color-panel-overlay: hsl(0, 0%, 100%, 82%);
159
+ --color-panel: hsl(0, 0%, 99%);
162
160
  --color-panel-transparent: hsla(0, 0%, 99%, 0%);
161
+ --color-focus: hsl(219, 65%, 50%);
163
162
  --color-selected: hsl(214, 84%, 56%);
164
163
  --color-selected-contrast: hsl(0, 0%, 100%);
165
- --color-focus: hsl(219, 65%, 50%);
166
- /* Text */
167
- --color-text: hsl(0, 0%, 0%);
164
+ --color-selection-fill: hsl(210, 100%, 56%, 24%);
165
+ --color-selection-stroke: hsl(214, 84%, 56%);
168
166
  --color-text-0: hsl(0, 0%, 11%);
169
167
  --color-text-1: hsl(0, 0%, 18%);
170
168
  --color-text-3: hsl(220, 2%, 65%);
171
169
  --color-text-shadow: hsl(0, 0%, 100%);
172
170
  --color-text-highlight: hsl(52, 100%, 50%);
173
171
  --color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
174
- /* Named */
175
172
  --color-primary: hsl(214, 84%, 56%);
176
173
  --color-success: hsl(123, 46%, 34%);
177
174
  --color-info: hsl(201, 98%, 41%);
178
175
  --color-warning: hsl(27, 98%, 47%);
179
176
  --color-error: hsl(0, 65%, 51%);
180
177
  --color-warn: hsl(0, 90%, 43%);
178
+ --color-text: hsl(0, 0%, 0%);
181
179
  --color-laser: hsl(0, 100%, 50%);
182
180
  /* Shadows */
183
181
  --shadow-1: 0px 1px 2px hsl(0, 0%, 0%, 25%), 0px 1px 3px hsl(0, 0%, 0%, 9%);
@@ -193,15 +191,11 @@
193
191
  }
194
192
 
195
193
  .tl-theme__dark {
196
- /* Canvas */
197
- --color-snap: hsl(0, 76%, 60%);
198
- --color-selection-fill: hsl(209, 100%, 57%, 20%);
199
- --color-selection-stroke: hsl(214, 84%, 56%);
194
+ --color-accent: hsl(0, 76%, 60%);
200
195
  --color-background: hsl(240, 5%, 6.5%);
201
196
  --color-brush-fill: hsl(0, 0%, 71%, 5.1%);
202
197
  --color-brush-stroke: hsl(0, 0%, 71%, 25.1%);
203
198
  --color-grid: hsl(0, 0%, 40%);
204
- /* UI */
205
199
  --color-low: hsl(260, 4.5%, 10.5%);
206
200
  --color-low-border: hsl(207, 10%, 10%);
207
201
  --color-culled: hsl(210, 11%, 19%);
@@ -212,28 +206,28 @@
212
206
  --color-hint: hsl(0, 0%, 100%, 7%);
213
207
  --color-overlay: hsl(0, 0%, 0%, 50%);
214
208
  --color-divider: hsl(240, 9%, 22%);
215
- --color-panel: hsl(235, 6.8%, 13.5%);
216
209
  --color-panel-contrast: hsl(245, 12%, 23%);
210
+ --color-panel: hsl(235, 6.8%, 13.5%);
217
211
  --color-panel-overlay: hsl(210, 10%, 24%, 82%);
218
212
  --color-panel-transparent: hsla(235, 6.8%, 13.5%, 0%);
213
+ --color-focus: hsl(217, 76%, 80%);
219
214
  --color-selected: hsl(217, 89%, 61%);
220
215
  --color-selected-contrast: hsl(0, 0%, 100%);
221
- --color-focus: hsl(217, 76%, 80%);
222
- /* Text */
223
- --color-text: hsl(210, 17%, 98%);
216
+ --color-selection-fill: hsl(209, 100%, 57%, 20%);
217
+ --color-selection-stroke: hsl(214, 84%, 56%);
224
218
  --color-text-0: hsl(0, 9%, 94%);
225
219
  --color-text-1: hsl(0, 0%, 85%);
226
220
  --color-text-3: hsl(210, 6%, 45%);
227
221
  --color-text-shadow: hsl(210, 13%, 18%);
228
222
  --color-text-highlight: hsl(52, 100%, 41%);
229
223
  --color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
230
- /* Named */
231
224
  --color-primary: hsl(214, 84%, 56%);
232
225
  --color-success: hsl(123, 38%, 57%);
233
226
  --color-info: hsl(199, 92%, 56%);
234
227
  --color-warning: hsl(36, 100%, 57%);
235
228
  --color-error: hsl(4, 90%, 58%);
236
229
  --color-warn: hsl(0, 81%, 66%);
230
+ --color-text: hsl(210, 17%, 98%);
237
231
  --color-laser: hsl(0, 100%, 50%);
238
232
  /* Shadows */
239
233
  --shadow-1:
@@ -247,6 +241,13 @@
247
241
  inset 0px 0px 0px 1px var(--color-panel-contrast);
248
242
  }
249
243
 
244
+ .tl-counter-scaled {
245
+ transform: scale(var(--tl-scale));
246
+ transform-origin: top left;
247
+ width: calc(100% * var(--tl-zoom));
248
+ height: calc(100% * var(--tl-zoom));
249
+ }
250
+
250
251
  .tl-container,
251
252
  .tl-container * {
252
253
  -webkit-touch-callout: none;
@@ -272,7 +273,9 @@ input,
272
273
  user-select: text;
273
274
  }
274
275
 
275
- /* --------------------- Canvas --------------------- */
276
+ /* -------------------------------------------------- */
277
+ /* Canvas */
278
+ /* -------------------------------------------------- */
276
279
 
277
280
  .tl-canvas {
278
281
  position: absolute;
@@ -365,6 +368,64 @@ input,
365
368
  contain: layout style size;
366
369
  }
367
370
 
371
+ /* ---------------------- Brush --------------------- */
372
+
373
+ .tl-brush {
374
+ stroke-width: calc(var(--tl-scale) * 1px);
375
+ contain: size layout;
376
+ }
377
+
378
+ .tl-brush__default {
379
+ stroke: var(--color-brush-stroke);
380
+ fill: var(--color-brush-fill);
381
+ }
382
+
383
+ /* -------------------- Scribble -------------------- */
384
+
385
+ .tl-scribble {
386
+ stroke-linejoin: round;
387
+ stroke-linecap: round;
388
+ pointer-events: none;
389
+ contain: size layout;
390
+ }
391
+
392
+ /* ---------------------- Shape --------------------- */
393
+
394
+ .tl-shape {
395
+ position: absolute;
396
+ pointer-events: none;
397
+ overflow: visible;
398
+ transform-origin: top left;
399
+ contain: size layout;
400
+ }
401
+
402
+ /* ---------------- Shape Containers ---------------- */
403
+
404
+ .tl-svg-container {
405
+ position: absolute;
406
+ inset: 0px;
407
+ height: 100%;
408
+ width: 100%;
409
+ pointer-events: none;
410
+ stroke-linecap: round;
411
+ stroke-linejoin: round;
412
+ transform-origin: top left;
413
+ overflow: visible;
414
+ }
415
+
416
+ .tl-html-container {
417
+ position: absolute;
418
+ inset: 0px;
419
+ height: 100%;
420
+ width: 100%;
421
+ pointer-events: none;
422
+ stroke-linecap: round;
423
+ stroke-linejoin: round;
424
+ /* content-visibility: auto; */
425
+ transform-origin: top left;
426
+ color: inherit;
427
+ }
428
+
368
429
  /* --------------- Overlay Stack --------------- */
369
430
 
370
431
  /* back of the stack, behind user's stuff */
@@ -388,6 +449,14 @@ input,
388
449
  z-index: var(--layer-overlays-user-brush);
389
450
  }
390
451
 
452
+ .tl-user-indicator__selected {
453
+ z-index: var(--layer-overlays-user-indicator-selected);
454
+ }
455
+
456
+ .tl-user-indicator__hovered {
457
+ z-index: var(--layer-overlays-user-indicator-hovered);
458
+ }
459
+
391
460
  .tl-user-handles {
392
461
  z-index: var(--layer-overlays-user-handles);
393
462
  }
@@ -423,7 +492,16 @@ input,
423
492
  overflow: visible;
424
493
  }
425
494
 
426
- /* -------------- Selection foreground -------------- */
495
+ /* -------------------- Indicator ------------------- */
496
+
497
+ .tl-shape-indicator {
498
+ transform-origin: top left;
499
+ fill: none;
500
+ stroke-width: calc(1.5px * var(--tl-scale));
501
+ contain: size layout;
502
+ }
503
+
504
+ /* ------------------ SelectionBox ------------------ */
427
505
 
428
506
  .tl-selection__bg {
429
507
  position: absolute;
@@ -482,12 +560,132 @@ input,
482
560
  stroke: transparent;
483
561
  }
484
562
 
485
- .tl-hidden {
486
- opacity: 0;
563
+ /* --------------------- Handles -------------------- */
564
+
565
+ .tl-handle {
566
+ pointer-events: all;
567
+ }
568
+
569
+ .tl-handle__bg {
570
+ fill: transparent;
571
+ stroke: transparent;
572
+ pointer-events: all;
573
+ }
574
+
575
+ .tl-handle__fg {
576
+ fill: var(--color-selected-contrast);
577
+ stroke: var(--color-selection-stroke);
578
+ stroke-width: calc(1.5px * var(--tl-scale));
487
579
  pointer-events: none;
488
580
  }
489
581
 
490
- /* -------------- Nametag / cursor chat ------------- */
582
+ .tl-handle__create {
583
+ opacity: 0;
584
+ }
585
+
586
+ .tl-handle__clone > .tl-handle__fg {
587
+ fill: var(--color-selection-stroke);
588
+ stroke: none;
589
+ }
590
+
591
+ .tl-handle__bg:active {
592
+ fill: none;
593
+ }
594
+
595
+ @media (pointer: coarse) {
596
+ .tl-handle__bg:active {
597
+ fill: var(--color-selection-fill);
598
+ }
599
+
600
+ .tl-handle__create {
601
+ opacity: 1;
602
+ }
603
+ }
604
+
605
+ .tl-rotate-corner:not(:hover),
606
+ .tl-resize-handle:not(:hover) {
607
+ cursor: none;
608
+ }
609
+
610
+ /* --------------------- Arrow Hints -------------------- */
611
+
612
+ .tl-arrow-hint-handle {
613
+ fill: var(--color-selected-contrast);
614
+ stroke: var(--color-selection-stroke);
615
+ stroke-width: calc(1.5px * var(--tl-scale));
616
+ r: calc(4px * var(--tl-scale));
617
+ }
618
+
619
+ .tl-arrow-hint-snap {
620
+ stroke: transparent;
621
+ fill: var(--color-selection-fill);
622
+ r: calc(12px * var(--tl-scale));
623
+ }
624
+
625
+ .tl-arrow-hint-snap__none,
626
+ .tl-arrow-hint-snap__center,
627
+ .tl-arrow-hint-snap__axis {
628
+ display: none;
629
+ }
630
+
631
+ .tl-arrow-hint-snap__edge {
632
+ r: calc(8px * var(--tl-scale));
633
+ }
634
+
635
+ /* ------------------ Bounds Detail ----------------- */
636
+
637
+ .tl-image,
638
+ .tl-video {
639
+ object-fit: cover;
640
+ background-size: cover;
641
+ width: 100%;
642
+ height: 100%;
643
+ }
644
+
645
+ .tl-video.tl-video-is-fullscreen {
646
+ object-fit: contain;
647
+ background-size: contain;
648
+ }
649
+
650
+ .tl-video-container,
651
+ .tl-image-container,
652
+ .tl-embed-container {
653
+ width: 100%;
654
+ height: 100%;
655
+ pointer-events: all;
656
+ /* background-color: var(--color-background); */
657
+
658
+ display: flex;
659
+ justify-content: center;
660
+ align-items: center;
661
+ }
662
+
663
+ .tl-image-container {
664
+ position: relative;
665
+ overflow: hidden;
666
+ }
667
+ .tl-image {
668
+ position: absolute;
669
+ inset: 0;
670
+ }
671
+
672
+ .tl-image__tg {
673
+ --scale: calc(min(2, var(--tl-scale)));
674
+ position: absolute;
675
+ top: calc(var(--scale) * 8px);
676
+ right: calc(var(--scale) * 8px);
677
+ font-size: 10px;
678
+ transform-origin: top right;
679
+ background-color: var(--color-background);
680
+ padding: 2px 4px;
681
+ border-radius: var(--radius-1);
682
+ }
683
+
684
+ /* --------------------- Nametag -------------------- */
685
+
686
+ .tl-collaborator-cursor {
687
+ position: absolute;
688
+ }
491
689
 
492
690
  .tl-nametag {
493
691
  position: absolute;
@@ -568,11 +766,25 @@ input,
568
766
  text-shadow: none;
569
767
  }
570
768
 
769
+ .tl-cursor-chat-fade {
770
+ /* Setting to zero causes it to immediately disappear */
771
+ /* Setting to near-zero causes it to fade out gradually */
772
+ opacity: 0.0001;
773
+ transition: opacity 5s ease-in-out;
774
+ }
775
+
571
776
  .tl-cursor-chat::placeholder {
572
777
  color: var(--color-selected-contrast);
573
778
  opacity: 0.7;
574
779
  }
575
780
 
781
+ /* --------------------- Spinner -------------------- */
782
+ @keyframes spinner {
783
+ to {
784
+ transform: rotate(360deg);
785
+ }
786
+ }
787
+
576
788
  /* ---------------------- Text ---------------------- */
577
789
 
578
790
  .tl-text-shape-label {
@@ -686,9 +898,6 @@ input,
686
898
  border: none;
687
899
  user-select: none;
688
900
  contain: style paint;
689
- visibility: hidden;
690
- /* N.B. This property, while discouraged ("intended for Document Type Definition (DTD) designers") is necessary for ensuring correct mixed RTL/LTR behavior when exporting SVGs. */
691
- unicode-bidi: plaintext;
692
901
  -webkit-user-select: none;
693
902
  }
694
903
 
@@ -734,41 +943,6 @@ input,
734
943
  overflow: hidden;
735
944
  }
736
945
 
737
- .tl-text-input::selection {
738
- background: var(--color-selected);
739
- color: var(--color-selected-contrast);
740
- text-shadow: none;
741
- }
742
-
743
- /* Text label */
744
-
745
- .tl-text-label {
746
- display: flex;
747
- justify-content: center;
748
- align-items: center;
749
- color: var(--color-text);
750
- text-shadow: var(--tl-text-outline);
751
- line-height: inherit;
752
- position: absolute;
753
- inset: 0px;
754
- height: 100%;
755
- width: 100%;
756
- }
757
-
758
- .tl-text-label[data-hastext='false'][data-isediting='false'] > .tl-text-label__inner {
759
- width: 40px;
760
- height: 40px;
761
- }
762
-
763
- .tl-text-label[data-hastext='true'][data-isediting='false'] .tl-text-content {
764
- pointer-events: all;
765
- }
766
-
767
- .tl-text-label__inner > .tl-text-input.tl-rich-text {
768
- display: none;
769
- position: static;
770
- }
771
-
772
946
  .tl-text-wrapper[data-isediting='false'] .tl-text-input,
773
947
  .tl-arrow-label[data-isediting='false'] .tl-text-input {
774
948
  opacity: 0;
@@ -780,60 +954,10 @@ input,
780
954
  cursor: var(--tl-cursor-text);
781
955
  }
782
956
 
783
- .tl-text-label[data-textwrap='true'] > .tl-text-label__inner {
784
- max-width: 100%;
785
- }
786
-
787
- .tl-text-label[data-isediting='true'] {
788
- background-color: transparent;
789
- min-height: auto;
790
- }
791
-
792
- .tl-text-wrapper .tl-text-content {
793
- pointer-events: all;
794
- z-index: var(--layer-text-content);
795
- }
796
-
797
- .tl-text-label__inner > .tl-text-content {
798
- position: relative;
799
- top: 0px;
800
- left: 0px;
801
- padding: inherit;
802
- height: fit-content;
803
- width: fit-content;
804
- border-radius: var(--radius-1);
805
- max-width: 100%;
806
- }
807
-
808
- .tl-text-label__inner > .tl-text-input {
809
- position: absolute;
810
- inset: 0px;
811
- height: 100%;
812
- width: 100%;
813
- padding: inherit;
814
- }
815
-
816
- .tl-text-wrapper[data-isselected='true'] .tl-text-input {
817
- z-index: var(--layer-text-editor);
818
- pointer-events: all;
819
- }
820
-
821
- /* This part of the rule helps preserve the occlusion rules for the shapes so we
822
- * don't click on shapes that are behind other shapes.
823
- * One extra nuance is we don't use this behavior for:
824
- * - arrows which have weird geometry and just gets in the way.
825
- * - draw/line shapes, because it feels restrictive to have them be 'in the way' of clicking on a textfield
826
- * - shapes that are not filled
827
- */
828
- .tl-canvas:is([data-iseditinganything='true'], [data-isselectinganything='true'])
829
- .tl-shape:not(
830
- [data-shape-type='arrow'],
831
- [data-shape-type='draw'],
832
- [data-shape-type='line'],
833
- [data-shape-type='highlight'],
834
- [data-shape-is-filled='false']
835
- ) {
836
- pointer-events: all;
957
+ .tl-text-input::selection {
958
+ background: var(--color-selected);
959
+ color: var(--color-selected-contrast);
960
+ text-shadow: none;
837
961
  }
838
962
 
839
963
  .tl-rich-text .ProseMirror {
@@ -944,307 +1068,38 @@ input,
944
1068
  }
945
1069
  }
946
1070
 
947
- .tl-text-wrapper[data-isediting='true'] .tl-rich-text {
948
- display: block;
949
- }
950
-
951
- /* --------------------- Loading -------------------- */
952
-
953
- .tl-loading {
954
- background-color: var(--color-background);
955
- color: var(--color-text-1);
956
- height: 100%;
957
- width: 100%;
958
- display: flex;
959
- flex-direction: column;
960
- justify-content: center;
961
- align-items: center;
962
- gap: var(--space-2);
963
- font-size: 14px;
964
- font-weight: 500;
965
- opacity: 0;
966
- animation: fade-in 0.2s ease-in-out forwards;
967
- animation-delay: 0.2s;
968
- position: absolute;
969
- inset: 0px;
970
- z-index: var(--layer-canvas-blocker);
971
- }
972
-
973
- @keyframes fade-in {
974
- 0% {
975
- opacity: 0;
976
- }
977
- 100% {
978
- opacity: 1;
979
- }
980
- }
981
-
982
- /* ---------------------- Brush --------------------- */
983
-
984
- .tl-brush {
985
- stroke-width: calc(var(--tl-scale) * 1px);
986
- contain: size layout;
987
- }
988
-
989
- .tl-brush__default {
990
- stroke: var(--color-brush-stroke);
991
- fill: var(--color-brush-fill);
992
- }
993
-
994
- /* -------------------- Scribble -------------------- */
995
-
996
- .tl-scribble {
997
- stroke-linejoin: round;
998
- stroke-linecap: round;
999
- pointer-events: none;
1000
- contain: size layout;
1001
- }
1002
-
1003
- /* ---------------------- Snaps --------------------- */
1004
-
1005
- .tl-snap-indicator {
1006
- stroke: var(--color-snap);
1007
- stroke-width: calc(1px * var(--tl-scale));
1008
- fill: none;
1009
- }
1010
-
1011
- .tl-snap-point {
1012
- stroke: var(--color-snap);
1013
- stroke-width: calc(1px * var(--tl-scale));
1014
- fill: none;
1015
- }
1016
-
1017
- /* ---------------- Hyperlink Button ---------------- */
1018
-
1019
- .tl-hyperlink-button {
1020
- background: none;
1021
- margin: 0px;
1022
- position: absolute;
1023
- top: 0px;
1024
- right: 0px;
1025
- height: 44px;
1026
- width: 44px;
1027
- display: flex;
1028
- align-items: center;
1029
- justify-content: center;
1030
- font-size: 12px;
1031
- font-weight: 400;
1032
- color: var(--color-text-1);
1033
- padding: 13px;
1034
- cursor: var(--tl-cursor-pointer);
1035
- border: none;
1036
- outline: none;
1037
- pointer-events: all;
1038
- z-index: 1;
1039
- }
1040
-
1041
- .tl-hyperlink-button::after {
1042
- content: '';
1043
- z-index: -1;
1044
- position: absolute;
1045
- right: 6px;
1046
- bottom: 6px;
1047
- display: block;
1048
- width: calc(100% - 12px);
1049
- height: calc(100% - 12px);
1050
- border-radius: var(--radius-1);
1051
- background-color: var(--color-background);
1052
- pointer-events: none;
1053
- }
1054
-
1055
- .tl-hyperlink-button:focus-visible {
1056
- color: var(--color-selected);
1057
- }
1058
-
1059
- .tl-hyperlink__icon {
1060
- width: 16px;
1061
- height: 16px;
1062
- background-color: currentColor;
1063
- pointer-events: none;
1064
- }
1065
-
1066
- .tl-hyperlink-button__hidden {
1067
- display: none;
1068
- }
1069
-
1070
- /* --------------------- Handles -------------------- */
1071
-
1072
- .tl-handle {
1073
- pointer-events: all;
1074
- }
1075
-
1076
- .tl-handle__bg {
1077
- fill: transparent;
1078
- stroke: transparent;
1079
- pointer-events: all;
1080
- }
1081
-
1082
- .tl-handle__fg {
1083
- fill: var(--color-selected-contrast);
1084
- stroke: var(--color-selection-stroke);
1085
- stroke-width: calc(1.5px * var(--tl-scale));
1086
- pointer-events: none;
1087
- }
1088
-
1089
- .tl-handle__create {
1090
- opacity: 0;
1091
- }
1092
-
1093
- .tl-handle__clone > .tl-handle__fg {
1094
- fill: var(--color-selection-stroke);
1095
- stroke: none;
1096
- }
1097
-
1098
- .tl-handle__bg:active {
1099
- fill: none;
1100
- }
1101
-
1102
- @media (pointer: coarse) {
1103
- .tl-handle__bg:active {
1104
- fill: var(--color-selection-fill);
1105
- }
1106
-
1107
- .tl-handle__create {
1108
- opacity: 1;
1109
- }
1110
- }
1111
-
1112
- .tl-rotate-corner:not(:hover),
1113
- .tl-resize-handle:not(:hover) {
1114
- cursor: none;
1115
- }
1116
-
1117
- /* ----------------- Shape indicator ---------------- */
1118
-
1119
- .tl-shape-indicator {
1120
- transform-origin: top left;
1121
- fill: none;
1122
- stroke-width: calc(1.5px * var(--tl-scale));
1123
- contain: size layout;
1124
- }
1125
-
1126
- /* ---------------------- Shape --------------------- */
1127
-
1128
- .tl-shape {
1129
- position: absolute;
1130
- pointer-events: none;
1131
- overflow: visible;
1132
- transform-origin: top left;
1133
- contain: size layout;
1134
- }
1135
-
1136
- /* ---------------- Shape Containers ---------------- */
1137
-
1138
- .tl-svg-container {
1139
- position: absolute;
1140
- inset: 0px;
1141
- height: 100%;
1142
- width: 100%;
1143
- pointer-events: none;
1144
- stroke-linecap: round;
1145
- stroke-linejoin: round;
1146
- transform-origin: top left;
1147
- overflow: visible;
1148
- }
1149
-
1150
- .tl-html-container {
1151
- position: absolute;
1152
- inset: 0px;
1153
- height: 100%;
1154
- width: 100%;
1155
- pointer-events: none;
1156
- stroke-linecap: round;
1157
- stroke-linejoin: round;
1158
- /* content-visibility: auto; */
1159
- transform-origin: top left;
1160
- color: inherit;
1161
- }
1162
-
1163
- /* -------------------- Group shape ------------------ */
1164
-
1165
- .tl-group {
1166
- stroke: var(--color-text);
1167
- stroke-width: calc(1px * var(--tl-scale));
1168
- opacity: 0.5;
1169
- }
1170
-
1171
- /* --------------------- Arrow shape -------------------- */
1172
-
1173
- .tl-arrow-label {
1174
- position: absolute;
1175
- top: -1px;
1176
- left: -1px;
1177
- width: 2px;
1178
- height: 2px;
1179
- padding: 0px;
1180
- display: flex;
1181
- justify-content: center;
1182
- align-items: center;
1183
- text-align: center;
1184
- color: var(--color-text);
1185
- text-shadow: var(--tl-text-outline);
1186
- }
1187
-
1188
- .tl-arrow-label[data-isediting='true'] p {
1189
- opacity: 0;
1190
- }
1191
-
1192
- .tl-arrow-label__inner {
1193
- border-radius: var(--radius-1);
1194
- box-sizing: content-box;
1195
- position: relative;
1196
- height: max-content;
1197
- width: max-content;
1198
- pointer-events: none;
1199
- display: flex;
1200
- justify-content: center;
1201
- align-items: center;
1202
- }
1203
-
1204
- .tl-arrow-label .tl-arrow {
1205
- position: relative;
1206
- height: max-content;
1207
- padding: inherit;
1208
- overflow: visible;
1209
- }
1210
-
1211
- .tl-arrow-label textarea {
1212
- padding: inherit;
1213
- /* Don't allow textarea to be zero width */
1214
- min-width: 4px;
1215
- }
1216
-
1217
- .tl-arrow-hint {
1218
- stroke: var(--color-text-1);
1219
- fill: none;
1220
- stroke-linecap: round;
1221
- overflow: visible;
1071
+ .tl-text-label__inner > .tl-text-input.tl-rich-text {
1072
+ display: none;
1073
+ position: static;
1222
1074
  }
1223
1075
 
1224
- .tl-arrow-hint-handle {
1225
- fill: var(--color-selected-contrast);
1226
- stroke: var(--color-selection-stroke);
1227
- stroke-width: calc(1.5px * var(--tl-scale));
1228
- r: calc(4px * var(--tl-scale));
1076
+ .tl-text-wrapper[data-isediting='true'] .tl-rich-text {
1077
+ display: block;
1229
1078
  }
1230
1079
 
1231
- .tl-arrow-hint-snap {
1232
- stroke: transparent;
1233
- fill: var(--color-selection-fill);
1234
- r: calc(12px * var(--tl-scale));
1080
+ /* ------------------- Snap Lines ------------------- */
1081
+
1082
+ .tl-snap-indicator {
1083
+ stroke: var(--color-accent);
1084
+ stroke-width: calc(1px * var(--tl-scale));
1085
+ fill: none;
1235
1086
  }
1236
1087
 
1237
- .tl-arrow-hint-snap__none,
1238
- .tl-arrow-hint-snap__center,
1239
- .tl-arrow-hint-snap__axis {
1240
- display: none;
1088
+ .tl-snap-point {
1089
+ stroke: var(--color-accent);
1090
+ stroke-width: calc(1px * var(--tl-scale));
1091
+ fill: none;
1241
1092
  }
1242
1093
 
1243
- .tl-arrow-hint-snap__edge {
1244
- r: calc(8px * var(--tl-scale));
1094
+ /* -------------------- Groups ------------------ */
1095
+
1096
+ .tl-group {
1097
+ stroke: var(--color-text);
1098
+ stroke-width: calc(1px * var(--tl-scale));
1099
+ opacity: 0.5;
1245
1100
  }
1246
1101
 
1247
- /* ------------------- Bookmark shape ------------------- */
1102
+ /* ------------------- Bookmark Shape ------------------- */
1248
1103
 
1249
1104
  .tl-bookmark__container {
1250
1105
  width: 100%;
@@ -1373,44 +1228,193 @@ input,
1373
1228
  flex-shrink: 0;
1374
1229
  }
1375
1230
 
1376
- /* -------------- Image and video shape ------------- */
1231
+ /* ---------------- Hyperlink Button ---------------- */
1377
1232
 
1378
- .tl-image,
1379
- .tl-video {
1380
- object-fit: cover;
1381
- background-size: cover;
1382
- width: 100%;
1383
- height: 100%;
1233
+ .tl-hyperlink-button {
1234
+ background: none;
1235
+ margin: 0px;
1236
+ position: absolute;
1237
+ top: 0px;
1238
+ right: 0px;
1239
+ height: 44px;
1240
+ width: 44px;
1241
+ display: flex;
1242
+ align-items: center;
1243
+ justify-content: center;
1244
+ font-size: 12px;
1245
+ font-weight: 400;
1246
+ color: var(--color-text-1);
1247
+ padding: 13px;
1248
+ cursor: var(--tl-cursor-pointer);
1249
+ border: none;
1250
+ outline: none;
1251
+ pointer-events: all;
1252
+ z-index: 1;
1384
1253
  }
1385
1254
 
1386
- .tl-video-container,
1387
- .tl-image-container,
1388
- .tl-embed-container {
1255
+ .tl-hyperlink-button::after {
1256
+ content: '';
1257
+ z-index: -1;
1258
+ position: absolute;
1259
+ right: 6px;
1260
+ bottom: 6px;
1261
+ display: block;
1262
+ width: calc(100% - 12px);
1263
+ height: calc(100% - 12px);
1264
+ border-radius: var(--radius-1);
1265
+ background-color: var(--color-background);
1266
+ pointer-events: none;
1267
+ }
1268
+
1269
+ .tl-hyperlink-button:focus-visible {
1270
+ color: var(--color-selected);
1271
+ }
1272
+
1273
+ .tl-hyperlink__icon {
1274
+ width: 16px;
1275
+ height: 16px;
1276
+ background-color: currentColor;
1277
+ pointer-events: none;
1278
+ }
1279
+
1280
+ .tl-hyperlink-button__hidden {
1281
+ display: none;
1282
+ }
1283
+
1284
+ /* ---------------- Geo shape ---------------- */
1285
+
1286
+ .tl-text-label {
1287
+ display: flex;
1288
+ justify-content: center;
1289
+ align-items: center;
1290
+ color: var(--color-text);
1291
+ text-shadow: var(--tl-text-outline);
1292
+ line-height: inherit;
1293
+ position: absolute;
1294
+ inset: 0px;
1295
+ height: 100%;
1389
1296
  width: 100%;
1297
+ }
1298
+
1299
+ .tl-text-label[data-hastext='false'][data-isediting='false'] > .tl-text-label__inner {
1300
+ width: 40px;
1301
+ height: 40px;
1302
+ }
1303
+
1304
+ .tl-text-label[data-hastext='true'][data-isediting='false'] .tl-text-content {
1305
+ pointer-events: all;
1306
+ }
1307
+
1308
+ .tl-text-wrapper .tl-text-content {
1309
+ pointer-events: all;
1310
+ z-index: var(--layer-text-content);
1311
+ }
1312
+
1313
+ .tl-text-label__inner > .tl-text-content {
1314
+ position: relative;
1315
+ top: 0px;
1316
+ left: 0px;
1317
+ padding: inherit;
1318
+ height: fit-content;
1319
+ width: fit-content;
1320
+ border-radius: var(--radius-1);
1321
+ max-width: 100%;
1322
+ }
1323
+
1324
+ .tl-text-label__inner > .tl-text-input {
1325
+ position: absolute;
1326
+ inset: 0px;
1390
1327
  height: 100%;
1328
+ width: 100%;
1329
+ padding: inherit;
1330
+ }
1331
+
1332
+ .tl-text-wrapper[data-isselected='true'] .tl-text-input {
1333
+ z-index: var(--layer-text-editor);
1391
1334
  pointer-events: all;
1392
- /* background-color: var(--color-background); */
1335
+ }
1336
+
1337
+ /* This part of the rule helps preserve the occlusion rules for the shapes so we
1338
+ * don't click on shapes that are behind other shapes.
1339
+ * One extra nuance is we don't use this behavior for:
1340
+ * - arrows which have weird geometry and just gets in the way.
1341
+ * - draw/line shapes, because it feels restrictive to have them be 'in the way' of clicking on a textfield
1342
+ * - shapes that are not filled
1343
+ */
1344
+ .tl-canvas:is([data-iseditinganything='true'], [data-isselectinganything='true'])
1345
+ .tl-shape:not(
1346
+ [data-shape-type='arrow'],
1347
+ [data-shape-type='draw'],
1348
+ [data-shape-type='line'],
1349
+ [data-shape-type='highlight'],
1350
+ [data-shape-is-filled='false']
1351
+ ) {
1352
+ pointer-events: all;
1353
+ }
1354
+
1355
+ .tl-text-label[data-textwrap='true'] > .tl-text-label__inner {
1356
+ max-width: 100%;
1357
+ }
1358
+
1359
+ .tl-text-label[data-isediting='true'] {
1360
+ background-color: transparent;
1361
+ min-height: auto;
1362
+ }
1363
+
1364
+ .tl-arrow-hint {
1365
+ stroke: var(--color-text-1);
1366
+ fill: none;
1367
+ stroke-linecap: round;
1368
+ overflow: visible;
1369
+ }
1393
1370
 
1371
+ /* ------------------- Arrow Shape ------------------ */
1372
+
1373
+ .tl-arrow-label {
1374
+ position: absolute;
1375
+ top: -1px;
1376
+ left: -1px;
1377
+ width: 2px;
1378
+ height: 2px;
1379
+ padding: 0px;
1394
1380
  display: flex;
1395
1381
  justify-content: center;
1396
1382
  align-items: center;
1383
+ text-align: center;
1384
+ color: var(--color-text);
1385
+ text-shadow: var(--tl-text-outline);
1397
1386
  }
1398
1387
 
1399
- .tl-image-container {
1388
+ .tl-arrow-label[data-isediting='true'] p {
1389
+ opacity: 0;
1390
+ }
1391
+
1392
+ .tl-arrow-label__inner {
1393
+ border-radius: var(--radius-1);
1394
+ box-sizing: content-box;
1400
1395
  position: relative;
1396
+ height: max-content;
1397
+ width: max-content;
1398
+ pointer-events: none;
1399
+ display: flex;
1400
+ justify-content: center;
1401
+ align-items: center;
1401
1402
  }
1402
1403
 
1403
- .tl-image {
1404
- position: absolute;
1405
- inset: 0;
1404
+ .tl-arrow-label .tl-arrow {
1405
+ position: relative;
1406
+ height: max-content;
1407
+ padding: inherit;
1408
+ overflow: visible;
1406
1409
  }
1407
1410
 
1408
- .tl-video.tl-video-is-fullscreen {
1409
- object-fit: contain;
1410
- background-size: contain;
1411
+ .tl-arrow-label textarea {
1412
+ padding: inherit;
1413
+ /* Don't allow textarea to be zero width */
1414
+ min-width: 4px;
1411
1415
  }
1412
1416
 
1413
- /* -------------------- Note shape ------------------- */
1417
+ /* -------------------- NoteShape ------------------- */
1414
1418
 
1415
1419
  .tl-note__container {
1416
1420
  position: relative;
@@ -1427,7 +1431,38 @@ input,
1427
1431
  color: currentColor;
1428
1432
  }
1429
1433
 
1430
- /* ------------------- Frame shape ------------------- */
1434
+ /* --------------------- Loading -------------------- */
1435
+
1436
+ .tl-loading {
1437
+ background-color: var(--color-background);
1438
+ color: var(--color-text-1);
1439
+ height: 100%;
1440
+ width: 100%;
1441
+ display: flex;
1442
+ flex-direction: column;
1443
+ justify-content: center;
1444
+ align-items: center;
1445
+ gap: var(--space-2);
1446
+ font-size: 14px;
1447
+ font-weight: 500;
1448
+ opacity: 0;
1449
+ animation: fade-in 0.2s ease-in-out forwards;
1450
+ animation-delay: 0.2s;
1451
+ position: absolute;
1452
+ inset: 0px;
1453
+ z-index: var(--layer-canvas-blocker);
1454
+ }
1455
+
1456
+ @keyframes fade-in {
1457
+ 0% {
1458
+ opacity: 0;
1459
+ }
1460
+ 100% {
1461
+ opacity: 1;
1462
+ }
1463
+ }
1464
+
1465
+ /* -------------------- FrameShape ------------------- */
1431
1466
 
1432
1467
  .tl-frame__body {
1433
1468
  stroke-width: calc(1px * var(--tl-scale));
@@ -1520,14 +1555,14 @@ input,
1520
1555
  }
1521
1556
  }
1522
1557
 
1523
- /* ------------------- Embed Shape ------------------ */
1558
+ /* ------------------ iFrames Detail ----------------- */
1524
1559
 
1525
1560
  .tl-embed {
1526
1561
  border: none;
1527
1562
  border-radius: var(--radius-2);
1528
1563
  }
1529
1564
 
1530
- /* -------------- Shape error boundary -------------- */
1565
+ /* -------------- Shape Error Boundary -------------- */
1531
1566
 
1532
1567
  .tl-shape-error-boundary {
1533
1568
  width: 100%;
@@ -1556,7 +1591,7 @@ input,
1556
1591
  color: var(--color-text-0);
1557
1592
  }
1558
1593
 
1559
- /* ----------------- Error boundary ----------------- */
1594
+ /* ----------------- Error Boundary ----------------- */
1560
1595
 
1561
1596
  .tl-error-boundary {
1562
1597
  width: 100%;
@@ -1718,6 +1753,22 @@ it from receiving any pointer events or affecting the cursor. */
1718
1753
  outline-offset: 0;
1719
1754
  }
1720
1755
 
1756
+ /* --------------------- Coarse --------------------- */
1757
+
1758
+ .tl-hidden {
1759
+ opacity: 0;
1760
+ pointer-events: none;
1761
+ }
1762
+
1763
+ .debug__ui-logger {
1764
+ position: absolute;
1765
+ top: 62px;
1766
+ left: 16px;
1767
+ color: #555;
1768
+ font-size: 12px;
1769
+ font-family: monospace;
1770
+ }
1771
+
1721
1772
  /* ---------------- Hit test blocker ---------------- */
1722
1773
 
1723
1774
  .tl-hit-test-blocker {
@@ -1733,8 +1784,6 @@ it from receiving any pointer events or affecting the cursor. */
1733
1784
  display: none;
1734
1785
  }
1735
1786
 
1736
- /* --------------------- Hovers --------------------- */
1737
-
1738
1787
  @media (hover: hover) {
1739
1788
  .tl-handle__create:hover {
1740
1789
  opacity: 1;