@tldraw/editor 3.14.0-canary.744f8a453221 → 3.14.0-canary.766a02a82239

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 (74) hide show
  1. package/dist-cjs/index.d.ts +50 -149
  2. package/dist-cjs/index.js +1 -4
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +25 -82
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +1 -3
  7. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  8. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +42 -73
  9. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  10. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
  11. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +6 -13
  13. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +3 -3
  14. package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
  15. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  16. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  17. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  18. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -1
  19. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  20. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -6
  21. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  22. package/dist-cjs/lib/primitives/geometry/Group2d.js +6 -11
  23. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  24. package/dist-cjs/lib/utils/dom.js +1 -1
  25. package/dist-cjs/lib/utils/dom.js.map +2 -2
  26. package/dist-cjs/version.js +3 -3
  27. package/dist-cjs/version.js.map +1 -1
  28. package/dist-esm/index.d.mts +50 -149
  29. package/dist-esm/index.mjs +1 -4
  30. package/dist-esm/index.mjs.map +2 -2
  31. package/dist-esm/lib/editor/Editor.mjs +25 -82
  32. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  33. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +1 -3
  34. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  35. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +42 -73
  36. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  37. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
  38. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  39. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +6 -13
  40. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +3 -3
  41. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
  42. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  43. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -1
  44. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  45. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -6
  46. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  47. package/dist-esm/lib/primitives/geometry/Group2d.mjs +6 -11
  48. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  49. package/dist-esm/lib/utils/dom.mjs +1 -1
  50. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  51. package/dist-esm/version.mjs +3 -3
  52. package/dist-esm/version.mjs.map +1 -1
  53. package/editor.css +483 -440
  54. package/package.json +7 -7
  55. package/src/index.ts +0 -7
  56. package/src/lib/editor/Editor.ts +36 -103
  57. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +1 -3
  58. package/src/lib/editor/managers/TextManager/TextManager.test.ts +5 -1
  59. package/src/lib/editor/managers/TextManager/TextManager.ts +86 -118
  60. package/src/lib/editor/shapes/ShapeUtil.ts +15 -47
  61. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +17 -25
  62. package/src/lib/editor/tools/StateNode.ts +3 -3
  63. package/src/lib/editor/types/emit-types.ts +0 -4
  64. package/src/lib/editor/types/external-content.ts +2 -11
  65. package/src/lib/hooks/useCanvasEvents.ts +1 -0
  66. package/src/lib/primitives/geometry/Geometry2d.ts +2 -7
  67. package/src/lib/primitives/geometry/Group2d.ts +5 -11
  68. package/src/lib/utils/dom.ts +1 -1
  69. package/src/version.ts +3 -3
  70. package/dist-cjs/lib/utils/reparenting.js +0 -232
  71. package/dist-cjs/lib/utils/reparenting.js.map +0 -7
  72. package/dist-esm/lib/utils/reparenting.mjs +0 -216
  73. package/dist-esm/lib/utils/reparenting.mjs.map +0 -7
  74. package/src/lib/utils/reparenting.ts +0 -383
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,27 +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
- --color-danger: hsl(0, 90%, 43%);
176
+ --color-error: hsl(0, 65%, 51%);
177
+ --color-warn: hsl(0, 90%, 43%);
178
+ --color-text: hsl(0, 0%, 0%);
180
179
  --color-laser: hsl(0, 100%, 50%);
181
180
  /* Shadows */
182
181
  --shadow-1: 0px 1px 2px hsl(0, 0%, 0%, 25%), 0px 1px 3px hsl(0, 0%, 0%, 9%);
@@ -192,15 +191,11 @@
192
191
  }
193
192
 
194
193
  .tl-theme__dark {
195
- /* Canvas */
196
- --color-snap: hsl(0, 76%, 60%);
197
- --color-selection-fill: hsl(209, 100%, 57%, 20%);
198
- --color-selection-stroke: hsl(214, 84%, 56%);
194
+ --color-accent: hsl(0, 76%, 60%);
199
195
  --color-background: hsl(240, 5%, 6.5%);
200
196
  --color-brush-fill: hsl(0, 0%, 71%, 5.1%);
201
197
  --color-brush-stroke: hsl(0, 0%, 71%, 25.1%);
202
198
  --color-grid: hsl(0, 0%, 40%);
203
- /* UI */
204
199
  --color-low: hsl(260, 4.5%, 10.5%);
205
200
  --color-low-border: hsl(207, 10%, 10%);
206
201
  --color-culled: hsl(210, 11%, 19%);
@@ -211,27 +206,28 @@
211
206
  --color-hint: hsl(0, 0%, 100%, 7%);
212
207
  --color-overlay: hsl(0, 0%, 0%, 50%);
213
208
  --color-divider: hsl(240, 9%, 22%);
214
- --color-panel: hsl(235, 6.8%, 13.5%);
215
209
  --color-panel-contrast: hsl(245, 12%, 23%);
210
+ --color-panel: hsl(235, 6.8%, 13.5%);
216
211
  --color-panel-overlay: hsl(210, 10%, 24%, 82%);
217
212
  --color-panel-transparent: hsla(235, 6.8%, 13.5%, 0%);
213
+ --color-focus: hsl(217, 76%, 80%);
218
214
  --color-selected: hsl(217, 89%, 61%);
219
215
  --color-selected-contrast: hsl(0, 0%, 100%);
220
- --color-focus: hsl(217, 76%, 80%);
221
- /* Text */
222
- --color-text: hsl(210, 17%, 98%);
216
+ --color-selection-fill: hsl(209, 100%, 57%, 20%);
217
+ --color-selection-stroke: hsl(214, 84%, 56%);
223
218
  --color-text-0: hsl(0, 9%, 94%);
224
219
  --color-text-1: hsl(0, 0%, 85%);
225
220
  --color-text-3: hsl(210, 6%, 45%);
226
221
  --color-text-shadow: hsl(210, 13%, 18%);
227
222
  --color-text-highlight: hsl(52, 100%, 41%);
228
223
  --color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
229
- /* Named */
230
224
  --color-primary: hsl(214, 84%, 56%);
231
225
  --color-success: hsl(123, 38%, 57%);
232
226
  --color-info: hsl(199, 92%, 56%);
233
227
  --color-warning: hsl(36, 100%, 57%);
234
- --color-danger: hsl(0, 82%, 66%);
228
+ --color-error: hsl(4, 90%, 58%);
229
+ --color-warn: hsl(0, 81%, 66%);
230
+ --color-text: hsl(210, 17%, 98%);
235
231
  --color-laser: hsl(0, 100%, 50%);
236
232
  /* Shadows */
237
233
  --shadow-1:
@@ -277,7 +273,9 @@ input,
277
273
  user-select: text;
278
274
  }
279
275
 
280
- /* --------------------- Canvas --------------------- */
276
+ /* -------------------------------------------------- */
277
+ /* Canvas */
278
+ /* -------------------------------------------------- */
281
279
 
282
280
  .tl-canvas {
283
281
  position: absolute;
@@ -370,6 +368,64 @@ input,
370
368
  contain: layout style size;
371
369
  }
372
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
+
373
429
  /* --------------- Overlay Stack --------------- */
374
430
 
375
431
  /* back of the stack, behind user's stuff */
@@ -393,6 +449,14 @@ input,
393
449
  z-index: var(--layer-overlays-user-brush);
394
450
  }
395
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
+
396
460
  .tl-user-handles {
397
461
  z-index: var(--layer-overlays-user-handles);
398
462
  }
@@ -428,7 +492,16 @@ input,
428
492
  overflow: visible;
429
493
  }
430
494
 
431
- /* -------------- 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 ------------------ */
432
505
 
433
506
  .tl-selection__bg {
434
507
  position: absolute;
@@ -487,12 +560,132 @@ input,
487
560
  stroke: transparent;
488
561
  }
489
562
 
490
- .tl-hidden {
491
- 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));
492
579
  pointer-events: none;
493
580
  }
494
581
 
495
- /* -------------- 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
+ }
496
689
 
497
690
  .tl-nametag {
498
691
  position: absolute;
@@ -573,11 +766,25 @@ input,
573
766
  text-shadow: none;
574
767
  }
575
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
+
576
776
  .tl-cursor-chat::placeholder {
577
777
  color: var(--color-selected-contrast);
578
778
  opacity: 0.7;
579
779
  }
580
780
 
781
+ /* --------------------- Spinner -------------------- */
782
+ @keyframes spinner {
783
+ to {
784
+ transform: rotate(360deg);
785
+ }
786
+ }
787
+
581
788
  /* ---------------------- Text ---------------------- */
582
789
 
583
790
  .tl-text-shape-label {
@@ -691,9 +898,6 @@ input,
691
898
  border: none;
692
899
  user-select: none;
693
900
  contain: style paint;
694
- visibility: hidden;
695
- /* 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. */
696
- unicode-bidi: plaintext;
697
901
  -webkit-user-select: none;
698
902
  }
699
903
 
@@ -739,41 +943,6 @@ input,
739
943
  overflow: hidden;
740
944
  }
741
945
 
742
- .tl-text-input::selection {
743
- background: var(--color-selected);
744
- color: var(--color-selected-contrast);
745
- text-shadow: none;
746
- }
747
-
748
- /* Text label */
749
-
750
- .tl-text-label {
751
- display: flex;
752
- justify-content: center;
753
- align-items: center;
754
- color: var(--color-text);
755
- text-shadow: var(--tl-text-outline);
756
- line-height: inherit;
757
- position: absolute;
758
- inset: 0px;
759
- height: 100%;
760
- width: 100%;
761
- }
762
-
763
- .tl-text-label[data-hastext='false'][data-isediting='false'] > .tl-text-label__inner {
764
- width: 40px;
765
- height: 40px;
766
- }
767
-
768
- .tl-text-label[data-hastext='true'][data-isediting='false'] .tl-text-content {
769
- pointer-events: all;
770
- }
771
-
772
- .tl-text-label__inner > .tl-text-input.tl-rich-text {
773
- display: none;
774
- position: static;
775
- }
776
-
777
946
  .tl-text-wrapper[data-isediting='false'] .tl-text-input,
778
947
  .tl-arrow-label[data-isediting='false'] .tl-text-input {
779
948
  opacity: 0;
@@ -785,60 +954,10 @@ input,
785
954
  cursor: var(--tl-cursor-text);
786
955
  }
787
956
 
788
- .tl-text-label[data-textwrap='true'] > .tl-text-label__inner {
789
- max-width: 100%;
790
- }
791
-
792
- .tl-text-label[data-isediting='true'] {
793
- background-color: transparent;
794
- min-height: auto;
795
- }
796
-
797
- .tl-text-wrapper .tl-text-content {
798
- pointer-events: all;
799
- z-index: var(--layer-text-content);
800
- }
801
-
802
- .tl-text-label__inner > .tl-text-content {
803
- position: relative;
804
- top: 0px;
805
- left: 0px;
806
- padding: inherit;
807
- height: fit-content;
808
- width: fit-content;
809
- border-radius: var(--radius-1);
810
- max-width: 100%;
811
- }
812
-
813
- .tl-text-label__inner > .tl-text-input {
814
- position: absolute;
815
- inset: 0px;
816
- height: 100%;
817
- width: 100%;
818
- padding: inherit;
819
- }
820
-
821
- .tl-text-wrapper[data-isselected='true'] .tl-text-input {
822
- z-index: var(--layer-text-editor);
823
- pointer-events: all;
824
- }
825
-
826
- /* This part of the rule helps preserve the occlusion rules for the shapes so we
827
- * don't click on shapes that are behind other shapes.
828
- * One extra nuance is we don't use this behavior for:
829
- * - arrows which have weird geometry and just gets in the way.
830
- * - draw/line shapes, because it feels restrictive to have them be 'in the way' of clicking on a textfield
831
- * - shapes that are not filled
832
- */
833
- .tl-canvas:is([data-iseditinganything='true'], [data-isselectinganything='true'])
834
- .tl-shape:not(
835
- [data-shape-type='arrow'],
836
- [data-shape-type='draw'],
837
- [data-shape-type='line'],
838
- [data-shape-type='highlight'],
839
- [data-shape-is-filled='false']
840
- ) {
841
- pointer-events: all;
957
+ .tl-text-input::selection {
958
+ background: var(--color-selected);
959
+ color: var(--color-selected-contrast);
960
+ text-shadow: none;
842
961
  }
843
962
 
844
963
  .tl-rich-text .ProseMirror {
@@ -949,307 +1068,38 @@ input,
949
1068
  }
950
1069
  }
951
1070
 
952
- .tl-text-wrapper[data-isediting='true'] .tl-rich-text {
953
- display: block;
954
- }
955
-
956
- /* --------------------- Loading -------------------- */
957
-
958
- .tl-loading {
959
- background-color: var(--color-background);
960
- color: var(--color-text-1);
961
- height: 100%;
962
- width: 100%;
963
- display: flex;
964
- flex-direction: column;
965
- justify-content: center;
966
- align-items: center;
967
- gap: var(--space-2);
968
- font-size: 14px;
969
- font-weight: 500;
970
- opacity: 0;
971
- animation: fade-in 0.2s ease-in-out forwards;
972
- animation-delay: 0.2s;
973
- position: absolute;
974
- inset: 0px;
975
- z-index: var(--layer-canvas-blocker);
976
- }
977
-
978
- @keyframes fade-in {
979
- 0% {
980
- opacity: 0;
981
- }
982
- 100% {
983
- opacity: 1;
984
- }
985
- }
986
-
987
- /* ---------------------- Brush --------------------- */
988
-
989
- .tl-brush {
990
- stroke-width: calc(var(--tl-scale) * 1px);
991
- contain: size layout;
992
- }
993
-
994
- .tl-brush__default {
995
- stroke: var(--color-brush-stroke);
996
- fill: var(--color-brush-fill);
997
- }
998
-
999
- /* -------------------- Scribble -------------------- */
1000
-
1001
- .tl-scribble {
1002
- stroke-linejoin: round;
1003
- stroke-linecap: round;
1004
- pointer-events: none;
1005
- contain: size layout;
1006
- }
1007
-
1008
- /* ---------------------- Snaps --------------------- */
1009
-
1010
- .tl-snap-indicator {
1011
- stroke: var(--color-snap);
1012
- stroke-width: calc(1px * var(--tl-scale));
1013
- fill: none;
1014
- }
1015
-
1016
- .tl-snap-point {
1017
- stroke: var(--color-snap);
1018
- stroke-width: calc(1px * var(--tl-scale));
1019
- fill: none;
1020
- }
1021
-
1022
- /* ---------------- Hyperlink Button ---------------- */
1023
-
1024
- .tl-hyperlink-button {
1025
- background: none;
1026
- margin: 0px;
1027
- position: absolute;
1028
- top: 0px;
1029
- right: 0px;
1030
- height: 44px;
1031
- width: 44px;
1032
- display: flex;
1033
- align-items: center;
1034
- justify-content: center;
1035
- font-size: 12px;
1036
- font-weight: 400;
1037
- color: var(--color-text-1);
1038
- padding: 13px;
1039
- cursor: var(--tl-cursor-pointer);
1040
- border: none;
1041
- outline: none;
1042
- pointer-events: all;
1043
- z-index: 1;
1044
- }
1045
-
1046
- .tl-hyperlink-button::after {
1047
- content: '';
1048
- z-index: -1;
1049
- position: absolute;
1050
- right: 6px;
1051
- bottom: 6px;
1052
- display: block;
1053
- width: calc(100% - 12px);
1054
- height: calc(100% - 12px);
1055
- border-radius: var(--radius-1);
1056
- background-color: var(--color-background);
1057
- pointer-events: none;
1058
- }
1059
-
1060
- .tl-hyperlink-button:focus-visible {
1061
- color: var(--color-selected);
1062
- }
1063
-
1064
- .tl-hyperlink__icon {
1065
- width: 15px;
1066
- height: 15px;
1067
- background-color: currentColor;
1068
- pointer-events: none;
1069
- }
1070
-
1071
- .tl-hyperlink-button__hidden {
1072
- display: none;
1073
- }
1074
-
1075
- /* --------------------- Handles -------------------- */
1076
-
1077
- .tl-handle {
1078
- pointer-events: all;
1079
- }
1080
-
1081
- .tl-handle__bg {
1082
- fill: transparent;
1083
- stroke: transparent;
1084
- pointer-events: all;
1085
- }
1086
-
1087
- .tl-handle__fg {
1088
- fill: var(--color-selected-contrast);
1089
- stroke: var(--color-selection-stroke);
1090
- stroke-width: calc(1.5px * var(--tl-scale));
1091
- pointer-events: none;
1092
- }
1093
-
1094
- .tl-handle__create {
1095
- opacity: 0;
1096
- }
1097
-
1098
- .tl-handle__clone > .tl-handle__fg {
1099
- fill: var(--color-selection-stroke);
1100
- stroke: none;
1101
- }
1102
-
1103
- .tl-handle__bg:active {
1104
- fill: none;
1105
- }
1106
-
1107
- @media (pointer: coarse) {
1108
- .tl-handle__bg:active {
1109
- fill: var(--color-selection-fill);
1110
- }
1111
-
1112
- .tl-handle__create {
1113
- opacity: 1;
1114
- }
1115
- }
1116
-
1117
- .tl-rotate-corner:not(:hover),
1118
- .tl-resize-handle:not(:hover) {
1119
- cursor: none;
1120
- }
1121
-
1122
- /* ----------------- Shape indicator ---------------- */
1123
-
1124
- .tl-shape-indicator {
1125
- transform-origin: top left;
1126
- fill: none;
1127
- stroke-width: calc(1.5px * var(--tl-scale));
1128
- contain: size layout;
1129
- }
1130
-
1131
- /* ---------------------- Shape --------------------- */
1132
-
1133
- .tl-shape {
1134
- position: absolute;
1135
- pointer-events: none;
1136
- overflow: visible;
1137
- transform-origin: top left;
1138
- contain: size layout;
1139
- }
1140
-
1141
- /* ---------------- Shape Containers ---------------- */
1142
-
1143
- .tl-svg-container {
1144
- position: absolute;
1145
- inset: 0px;
1146
- height: 100%;
1147
- width: 100%;
1148
- pointer-events: none;
1149
- stroke-linecap: round;
1150
- stroke-linejoin: round;
1151
- transform-origin: top left;
1152
- overflow: visible;
1153
- }
1154
-
1155
- .tl-html-container {
1156
- position: absolute;
1157
- inset: 0px;
1158
- height: 100%;
1159
- width: 100%;
1160
- pointer-events: none;
1161
- stroke-linecap: round;
1162
- stroke-linejoin: round;
1163
- /* content-visibility: auto; */
1164
- transform-origin: top left;
1165
- color: var(--color-text-1);
1166
- }
1167
-
1168
- /* -------------------- Group shape ------------------ */
1169
-
1170
- .tl-group {
1171
- stroke: var(--color-text);
1172
- stroke-width: calc(1px * var(--tl-scale));
1173
- opacity: 0.5;
1174
- }
1175
-
1176
- /* --------------------- Arrow shape -------------------- */
1177
-
1178
- .tl-arrow-label {
1179
- position: absolute;
1180
- top: -1px;
1181
- left: -1px;
1182
- width: 2px;
1183
- height: 2px;
1184
- padding: 0px;
1185
- display: flex;
1186
- justify-content: center;
1187
- align-items: center;
1188
- text-align: center;
1189
- color: var(--color-text);
1190
- text-shadow: var(--tl-text-outline);
1191
- }
1192
-
1193
- .tl-arrow-label[data-isediting='true'] p {
1194
- opacity: 0;
1195
- }
1196
-
1197
- .tl-arrow-label__inner {
1198
- border-radius: var(--radius-1);
1199
- box-sizing: content-box;
1200
- position: relative;
1201
- height: max-content;
1202
- width: max-content;
1203
- pointer-events: none;
1204
- display: flex;
1205
- justify-content: center;
1206
- align-items: center;
1207
- }
1208
-
1209
- .tl-arrow-label .tl-arrow {
1210
- position: relative;
1211
- height: max-content;
1212
- padding: inherit;
1213
- overflow: visible;
1214
- }
1215
-
1216
- .tl-arrow-label textarea {
1217
- padding: inherit;
1218
- /* Don't allow textarea to be zero width */
1219
- min-width: 4px;
1220
- }
1221
-
1222
- .tl-arrow-hint {
1223
- stroke: var(--color-text-1);
1224
- fill: none;
1225
- stroke-linecap: round;
1226
- overflow: visible;
1071
+ .tl-text-label__inner > .tl-text-input.tl-rich-text {
1072
+ display: none;
1073
+ position: static;
1227
1074
  }
1228
1075
 
1229
- .tl-arrow-hint-handle {
1230
- fill: var(--color-selected-contrast);
1231
- stroke: var(--color-selection-stroke);
1232
- stroke-width: calc(1.5px * var(--tl-scale));
1233
- r: calc(4px * var(--tl-scale));
1076
+ .tl-text-wrapper[data-isediting='true'] .tl-rich-text {
1077
+ display: block;
1234
1078
  }
1235
1079
 
1236
- .tl-arrow-hint-snap {
1237
- stroke: transparent;
1238
- fill: var(--color-selection-fill);
1239
- 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;
1240
1086
  }
1241
1087
 
1242
- .tl-arrow-hint-snap__none,
1243
- .tl-arrow-hint-snap__center,
1244
- .tl-arrow-hint-snap__axis {
1245
- display: none;
1088
+ .tl-snap-point {
1089
+ stroke: var(--color-accent);
1090
+ stroke-width: calc(1px * var(--tl-scale));
1091
+ fill: none;
1246
1092
  }
1247
1093
 
1248
- .tl-arrow-hint-snap__edge {
1249
- 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;
1250
1100
  }
1251
1101
 
1252
- /* ------------------- Bookmark shape ------------------- */
1102
+ /* ------------------- Bookmark Shape ------------------- */
1253
1103
 
1254
1104
  .tl-bookmark__container {
1255
1105
  width: 100%;
@@ -1277,7 +1127,6 @@ input,
1277
1127
  display: flex;
1278
1128
  justify-content: flex-end;
1279
1129
  align-items: flex-start;
1280
- box-shadow: inset 0px 0px 0px 1px var(--color-divider);
1281
1130
  }
1282
1131
 
1283
1132
  .tl-bookmark__image_container > .tl-hyperlink-button::after {
@@ -1300,7 +1149,7 @@ input,
1300
1149
  }
1301
1150
 
1302
1151
  .tl-bookmark__copy_container {
1303
- background-color: var(--color-muted-0);
1152
+ background-color: var(--color-muted);
1304
1153
  padding: var(--space-4);
1305
1154
  pointer-events: all;
1306
1155
  display: flex;
@@ -1319,11 +1168,11 @@ input,
1319
1168
 
1320
1169
  .tl-bookmark__heading {
1321
1170
  font-size: 16px;
1322
- line-height: 1.6;
1171
+ line-height: 1.5;
1323
1172
  font-weight: bold;
1324
1173
  padding-bottom: var(--space-2);
1325
1174
  overflow: hidden;
1326
- max-height: calc((16px * 1.6) * 2);
1175
+ max-height: calc((16px * 1.5) * 2);
1327
1176
  -webkit-box-orient: vertical;
1328
1177
  -webkit-line-clamp: 2;
1329
1178
  line-clamp: 2;
@@ -1379,44 +1228,193 @@ input,
1379
1228
  flex-shrink: 0;
1380
1229
  }
1381
1230
 
1382
- /* -------------- Image and video shape ------------- */
1231
+ /* ---------------- Hyperlink Button ---------------- */
1383
1232
 
1384
- .tl-image,
1385
- .tl-video {
1386
- object-fit: cover;
1387
- background-size: cover;
1388
- width: 100%;
1389
- 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;
1390
1253
  }
1391
1254
 
1392
- .tl-video-container,
1393
- .tl-image-container,
1394
- .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%;
1395
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;
1396
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);
1397
1334
  pointer-events: all;
1398
- /* 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
+ }
1399
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;
1400
1380
  display: flex;
1401
1381
  justify-content: center;
1402
1382
  align-items: center;
1383
+ text-align: center;
1384
+ color: var(--color-text);
1385
+ text-shadow: var(--tl-text-outline);
1403
1386
  }
1404
1387
 
1405
- .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;
1406
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;
1407
1402
  }
1408
1403
 
1409
- .tl-image {
1410
- position: absolute;
1411
- inset: 0;
1404
+ .tl-arrow-label .tl-arrow {
1405
+ position: relative;
1406
+ height: max-content;
1407
+ padding: inherit;
1408
+ overflow: visible;
1412
1409
  }
1413
1410
 
1414
- .tl-video.tl-video-is-fullscreen {
1415
- object-fit: contain;
1416
- background-size: contain;
1411
+ .tl-arrow-label textarea {
1412
+ padding: inherit;
1413
+ /* Don't allow textarea to be zero width */
1414
+ min-width: 4px;
1417
1415
  }
1418
1416
 
1419
- /* -------------------- Note shape ------------------- */
1417
+ /* -------------------- NoteShape ------------------- */
1420
1418
 
1421
1419
  .tl-note__container {
1422
1420
  position: relative;
@@ -1433,7 +1431,38 @@ input,
1433
1431
  color: currentColor;
1434
1432
  }
1435
1433
 
1436
- /* ------------------- 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 ------------------- */
1437
1466
 
1438
1467
  .tl-frame__body {
1439
1468
  stroke-width: calc(1px * var(--tl-scale));
@@ -1526,14 +1555,14 @@ input,
1526
1555
  }
1527
1556
  }
1528
1557
 
1529
- /* ------------------- Embed Shape ------------------ */
1558
+ /* ------------------ iFrames Detail ----------------- */
1530
1559
 
1531
1560
  .tl-embed {
1532
1561
  border: none;
1533
1562
  border-radius: var(--radius-2);
1534
1563
  }
1535
1564
 
1536
- /* -------------- Shape error boundary -------------- */
1565
+ /* -------------- Shape Error Boundary -------------- */
1537
1566
 
1538
1567
  .tl-shape-error-boundary {
1539
1568
  width: 100%;
@@ -1562,7 +1591,7 @@ input,
1562
1591
  color: var(--color-text-0);
1563
1592
  }
1564
1593
 
1565
- /* ----------------- Error boundary ----------------- */
1594
+ /* ----------------- Error Boundary ----------------- */
1566
1595
 
1567
1596
  .tl-error-boundary {
1568
1597
  width: 100%;
@@ -1712,7 +1741,7 @@ it from receiving any pointer events or affecting the cursor. */
1712
1741
  gap: var(--space-4);
1713
1742
  }
1714
1743
  .tl-error-boundary__content .tl-error-boundary__reset {
1715
- color: var(--color-danger);
1744
+ color: var(--color-warn);
1716
1745
  }
1717
1746
  .tl-error-boundary__content .tl-error-boundary__refresh {
1718
1747
  background-color: var(--color-primary);
@@ -1724,6 +1753,22 @@ it from receiving any pointer events or affecting the cursor. */
1724
1753
  outline-offset: 0;
1725
1754
  }
1726
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
+
1727
1772
  /* ---------------- Hit test blocker ---------------- */
1728
1773
 
1729
1774
  .tl-hit-test-blocker {
@@ -1739,8 +1784,6 @@ it from receiving any pointer events or affecting the cursor. */
1739
1784
  display: none;
1740
1785
  }
1741
1786
 
1742
- /* --------------------- Hovers --------------------- */
1743
-
1744
1787
  @media (hover: hover) {
1745
1788
  .tl-handle__create:hover {
1746
1789
  opacity: 1;