@ibodr/editor 0.2.6 → 0.2.7

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/editor.css CHANGED
@@ -29,15 +29,20 @@
29
29
  * background, grid, shapes, overlays, and blocker are all children of .dr-canvas,
30
30
  * so their z-indices are relative to the canvas, not the container.
31
31
  *
32
- * watermark and canvas-in-front are siblings of .dr-canvas (outside it),
33
- * so they compete with the UI layer (.tlui-layout at z-index 300).
32
+ * collaborators, watermark, and canvas-in-front are siblings of .dr-canvas
33
+ * (outside it), so they compete with the UI layer (.tlui-layout at z-index 300).
34
34
  * canvas-in-front must be below the UI layer (300) to sit between
35
- * the canvas and the UI.
35
+ * the canvas and the UI; collaborator cursors sit above canvas content
36
+ * (and layers that anchor to it, like comment pins) but below the
37
+ * in-front content and the UI panels. The watermark (a licensing element)
38
+ * sits above that content so it can't be occluded, but still below the
39
+ * in-front content and the UI.
36
40
  */
37
41
  --dr-layer-canvas-hidden: -999999;
38
42
  --dr-layer-canvas-background: 100;
39
43
  --dr-layer-canvas-grid: 150;
40
- --dr-layer-watermark: 200;
44
+ --dr-layer-collaborators: 245;
45
+ --dr-layer-watermark: 248;
41
46
  --dr-layer-canvas-in-front: 250;
42
47
  --dr-layer-canvas-shapes: 300;
43
48
  --dr-layer-canvas-overlays: 500;
@@ -74,9 +79,10 @@
74
79
 
75
80
  /* Cursor SVGs */
76
81
  --dr-cursor-none: none;
82
+ /* Hotspot sits between the white outline tip and the black tip: on either tip alone, hit-testing feels offset from one direction (#10855) */
77
83
  --dr-cursor-default:
78
84
  url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z' fill='white'/><path d='m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z' fill='white'/><path d='m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z' fill='black'/><path d='m13 10.814v11.188l2.969-2.866.428-.139h4.768z' fill='black'/></g></svg>")
79
- 12 8,
85
+ 12 10,
80
86
  default;
81
87
  --dr-cursor-pointer:
82
88
  url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m13.3315 21.3799c-.284-.359-.629-1.093-1.243-1.984-.348-.504-1.211-1.453-1.468-1.935-.223-.426-.199-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.307.302.459.214.121-.071-.496-.187-1.343-.355-2.092-.128-.568-.159-.657-.281-1.093-.129-.464-.195-.789-.316-1.281-.084-.348-.235-1.059-.276-1.459-.057-.547-.087-1.439.264-1.849.275-.321.906-.418 1.297-.22.512.259.803 1.003.936 1.3.239.534.387 1.151.516 1.961.164 1.031.466 2.462.476 2.763.024-.369-.068-1.146-.004-1.5.058-.321.328-.694.666-.795.286-.085.621-.116.916-.055.313.064.643.288.766.499.362.624.369 1.899.384 1.831.086-.376.071-1.229.284-1.584.14-.234.497-.445.687-.479.294-.052.655-.068.964-.008.249.049.586.345.677.487.218.344.342 1.317.379 1.658.015.141.074-.392.293-.736.406-.639 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.012.828-.04 1.202-.031.4-.117 1.304-.242 1.742-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.191 1.813-.118.562-.079.566-.102.965-.023.398.121.922.121.922s-.802.104-1.234.035c-.391-.063-.875-.841-1-1.079-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.031-3.139.02 0 0 .185-1.011-.227-1.358-.305-.259-.83-.784-1.144-1.06z' fill='white'/><g stroke='black' stroke-linecap='round' stroke-width='.75'><path d='m13.3315 21.3799c-.284-.359-.629-1.093-1.243-1.984-.348-.504-1.211-1.453-1.468-1.935-.223-.426-.199-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.307.302.459.214.121-.071-.496-.187-1.343-.355-2.092-.128-.568-.159-.657-.281-1.093-.129-.464-.195-.789-.316-1.281-.084-.348-.235-1.059-.276-1.459-.057-.547-.087-1.439.264-1.849.275-.321.906-.418 1.297-.22.512.259.803 1.003.936 1.3.239.534.387 1.151.516 1.961.164 1.031.466 2.462.476 2.763.024-.369-.068-1.146-.004-1.5.058-.321.328-.694.666-.795.286-.085.621-.116.916-.055.313.064.643.288.766.499.362.624.369 1.899.384 1.831.086-.376.071-1.229.284-1.584.14-.234.497-.445.687-.479.294-.052.655-.068.964-.008.249.049.586.345.677.487.218.344.342 1.317.379 1.658.015.141.074-.392.293-.736.406-.639 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.012.828-.04 1.202-.031.4-.117 1.304-.242 1.742-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.191 1.813-.118.562-.079.566-.102.965-.023.398.121.922.121.922s-.802.104-1.234.035c-.391-.063-.875-.841-1-1.079-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.031-3.139.02 0 0 .185-1.011-.227-1.358-.305-.259-.83-.784-1.144-1.06z' stroke-linejoin='round'/><path d='m21.5664 21.7344v-3.459'/><path d='m19.5508 21.7461-.016-3.473'/><path d='m17.5547 18.3047.021 3.426'/></g></g></svg>")
@@ -86,6 +92,10 @@
86
92
  url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m25 16h-6.01v-6h-2.98v6h-6.01v3h6.01v6h2.98v-6h6.01z' fill='white'/><path d='m23.9902 17.0103h-6v-6.01h-.98v6.01h-6v.98h6v6.01h.98v-6.01h6z' fill='%23231f1f'/></g></svg>")
87
93
  16 16,
88
94
  crosshair;
95
+ --dr-cursor-comment:
96
+ url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g filter='url(%23shadow)'><path d='M5 19.5 L5 11 A8 8 0 0 1 13 3 A8 8 0 0 1 21 11 A8 8 0 0 1 13 19 Z' fill='white' stroke='black' stroke-width='1' stroke-linejoin='round'/></g></svg>")
97
+ 5 19,
98
+ crosshair;
89
99
  --dr-cursor-move:
90
100
  url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m19 14h1v1h-1zm1 6h-1v-1h1zm-5-5h-1v-1h1zm0 5h-1v-1h1zm2-10.987-7.985 7.988 5.222 5.221 2.763 2.763 7.984-7.985z' fill='white'/><g fill='black'><path d='m23.5664 16.9971-2.557-2.809v1.829h-4.009-4.001v-1.829l-2.571 2.809 2.572 2.808-.001-1.808h4.001 4.009l-.001 1.808z'/><path d='m17.9873 17h.013v-4.001l1.807.001-2.807-2.571-2.809 2.57h1.809v4.001h.008v4.002l-1.828-.001 2.807 2.577 2.805-2.576h-1.805z'/></g></g></svg>")
91
101
  16 16,
@@ -187,6 +197,7 @@
187
197
  --dr-color-text-0: hsl(0, 0%, 11%);
188
198
  --dr-color-text-1: hsl(0, 0%, 18%);
189
199
  --dr-color-text-3: hsl(204, 4%, 45%);
200
+ --dr-color-text-disabled: hsl(204, 4%, 55%);
190
201
  --dr-color-text-shadow: hsl(0, 0%, 100%);
191
202
  --dr-color-text-highlight: hsl(52, 100%, 50%);
192
203
  --dr-color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
@@ -247,6 +258,7 @@
247
258
  --dr-color-text-0: hsl(0, 9%, 94%);
248
259
  --dr-color-text-1: hsl(0, 0%, 85%);
249
260
  --dr-color-text-3: hsl(204, 4%, 75%);
261
+ --dr-color-text-disabled: hsl(204, 4%, 50%);
250
262
  --dr-color-text-shadow: hsl(210, 13%, 18%);
251
263
  --dr-color-text-highlight: hsl(52, 100%, 41%);
252
264
  --dr-color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
@@ -295,6 +307,12 @@
295
307
  outline: 1px solid var(--dr-color-low);
296
308
  }
297
309
 
310
+ /* The host for <EditorPortal>, last among the container's children. It's a position in the DOM
311
+ rather than a box: `display: contents` keeps what it holds positioned against the container. */
312
+ .dr-portal-host {
313
+ display: contents;
314
+ }
315
+
298
316
  input,
299
317
  *[contenteditable],
300
318
  *[contenteditable] * {
@@ -410,6 +428,30 @@ input,
410
428
  z-index: var(--dr-layer-canvas-shapes);
411
429
  }
412
430
 
431
+ /* The collaborator cursor layer: a sibling of .dr-canvas, above all canvas content, below the
432
+ in-front layer (250) and the UI panels (300). Display-only — pointer events pass through. */
433
+ .dr-collaborators {
434
+ position: absolute;
435
+ inset: 0px;
436
+ z-index: var(--dr-layer-collaborators);
437
+ pointer-events: none;
438
+ overflow: clip;
439
+ contain: layout style size;
440
+ }
441
+
442
+ .dr-collaborators__item {
443
+ position: absolute;
444
+ top: 0px;
445
+ left: 0px;
446
+ overflow: visible;
447
+ pointer-events: none;
448
+ transform-origin: top left;
449
+ }
450
+
451
+ .dr-cursor {
452
+ overflow: visible;
453
+ }
454
+
413
455
  /* --------------- Overlay Stack --------------- */
414
456
 
415
457
  /* -------------- Selection foreground -------------- */
@@ -649,7 +691,15 @@ input,
649
691
  overflow: hidden;
650
692
  }
651
693
 
652
- .dr-text-input::selection {
694
+ /**
695
+ * Only when there's actually a highlight to style. ProseMirror hides the native selection whenever
696
+ * it holds a NodeSelection — triple-clicking a list's bullet selects the whole list, for one — by
697
+ * zeroing the ::selection background and nothing else. Painting the selected-contrast color with
698
+ * no highlight behind it leaves the text invisible against the shape, and `inherit` can't undo it:
699
+ * highlight pseudo-elements inherit from the ancestor's ::selection, so it just picks the same
700
+ * color back up.
701
+ */
702
+ .dr-text-input:not(:has(.ProseMirror-hideselection))::selection {
653
703
  background: var(--dr-color-selected);
654
704
  color: var(--dr-color-selected-contrast);
655
705
  text-shadow: none;
@@ -802,17 +852,17 @@ input,
802
852
  .dr-rich-text ol {
803
853
  text-align: left;
804
854
  margin: 0;
805
- padding-left: 3.25ch;
855
+ padding-left: 1.625ch;
806
856
  /* Some resets, like Tailwind, nix the list styling. */
807
857
  list-style: revert;
808
858
  }
809
859
 
810
860
  .dr-rich-text ol:has(> li:nth-child(10)) {
811
- padding-left: 4.25ch;
861
+ padding-left: 2.625ch;
812
862
  }
813
863
 
814
864
  .dr-rich-text ol:has(> li:nth-child(100)) {
815
- padding-left: 5.25ch;
865
+ padding-left: 3.625ch;
816
866
  }
817
867
 
818
868
  .dr-rich-text h1,
@@ -823,6 +873,16 @@ input,
823
873
  .dr-rich-text h6 {
824
874
  margin-top: 5px;
825
875
  margin-bottom: 10px;
876
+ /**
877
+ * Headings render at a larger font-size than the body text (via the browser's
878
+ * default h1–h6 sizing), so they can't inherit the container's resolved
879
+ * whole-pixel line-height — that value is derived from the base font size and
880
+ * would cram the taller lines together. Instead, scale line-height with each
881
+ * heading's own font-size using tldraw's unitless line-height multiplier, which
882
+ * the rich-text render/measure paths expose here. The 1.35 fallback mirrors the
883
+ * default theme line-height (see defaultThemes.ts).
884
+ */
885
+ line-height: var(--dr-rich-text-heading-line-height, 1.35);
826
886
  }
827
887
 
828
888
  .dr-rich-text a {
@@ -851,6 +911,7 @@ input,
851
911
  .dr-theme__dark .dr-rich-text mark {
852
912
  background-color: var(--dr-color-text-highlight);
853
913
  color: currentColor;
914
+ text-shadow: none;
854
915
  }
855
916
 
856
917
  @supports (color: color(display-p3 1 1 1)) {
@@ -1023,6 +1084,15 @@ input,
1023
1084
  color: var(--dr-color-text-1);
1024
1085
  }
1025
1086
 
1087
+ .dr-content-slot {
1088
+ position: absolute;
1089
+ inset: 0px;
1090
+ height: 100%;
1091
+ width: 100%;
1092
+ pointer-events: none;
1093
+ transform-origin: top left;
1094
+ }
1095
+
1026
1096
  /* -------------------- Group shape ------------------ */
1027
1097
 
1028
1098
  .dr-group {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibodr/editor",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -29,12 +29,12 @@
29
29
  "eventemitter3": "^4.0.7",
30
30
  "idb": "^7.1.1",
31
31
  "rbush": "^3.0.1",
32
- "@ibodr/state": "0.2.6",
33
- "@ibodr/schema": "0.2.6",
34
- "@ibodr/store": "0.2.6",
35
- "@ibodr/state-react": "0.2.6",
36
- "@ibodr/validate": "0.2.6",
37
- "@ibodr/utils": "0.2.6"
32
+ "@ibodr/state": "0.2.7",
33
+ "@ibodr/store": "0.2.7",
34
+ "@ibodr/validate": "0.2.7",
35
+ "@ibodr/state-react": "0.2.7",
36
+ "@ibodr/schema": "0.2.7",
37
+ "@ibodr/utils": "0.2.7"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "react": "^18.2.0 || ^19.2.1",