quoin-editor 2.0.5 → 2.1.0

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 (215) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/MIGRATION.md +1 -1
  3. package/README.md +4 -3
  4. package/dist/ai.cjs +124 -94
  5. package/dist/ai.d.cts +7 -0
  6. package/dist/ai.d.ts +7 -0
  7. package/dist/ai.js +50 -20
  8. package/dist/ai.js.map +1 -1
  9. package/dist/catalogue.cjs +28 -26
  10. package/dist/catalogue.js +19 -17
  11. package/dist/catalogue.js.map +1 -1
  12. package/dist/{chunk-JGEDJYIV.cjs → chunk-2FUWXPPC.cjs} +92 -98
  13. package/dist/{chunk-NHNW5DK3.js → chunk-3F76QQ65.js} +6 -6
  14. package/dist/{chunk-NHNW5DK3.js.map → chunk-3F76QQ65.js.map} +1 -1
  15. package/dist/{chunk-DBOZFNWU.js → chunk-3QYFAAQR.js} +3 -3
  16. package/dist/{chunk-DBOZFNWU.js.map → chunk-3QYFAAQR.js.map} +1 -1
  17. package/dist/{chunk-I7X7B3WD.cjs → chunk-4JDRDPLC.cjs} +17 -8
  18. package/dist/{chunk-EBSDPHPS.cjs → chunk-4UFWFV43.cjs} +1060 -719
  19. package/dist/{chunk-LM3DHROX.cjs → chunk-5AUIA4B3.cjs} +2 -2
  20. package/dist/{chunk-3INFNIGN.cjs → chunk-5H3BB5VJ.cjs} +131 -78
  21. package/dist/{chunk-DJU25PFC.cjs → chunk-5L2NSIHZ.cjs} +11 -11
  22. package/dist/{chunk-W376L2GM.js → chunk-6Y7JAWYY.js} +8 -8
  23. package/dist/chunk-6Y7JAWYY.js.map +1 -0
  24. package/dist/{chunk-UDBLZILE.js → chunk-ATKDXQEY.js} +12 -7
  25. package/dist/{chunk-UDBLZILE.js.map → chunk-ATKDXQEY.js.map} +1 -1
  26. package/dist/{chunk-A2IQHMIH.js → chunk-BE2SYPK5.js} +49 -54
  27. package/dist/chunk-BE2SYPK5.js.map +1 -0
  28. package/dist/{chunk-PURYVDC3.cjs → chunk-CFICD2JP.cjs} +21 -16
  29. package/dist/{chunk-3HW3WRYC.cjs → chunk-CSIUXYRU.cjs} +2 -2
  30. package/dist/{chunk-N7BSFDDM.cjs → chunk-DBKL524I.cjs} +23 -23
  31. package/dist/{chunk-XE3IYW5B.js → chunk-DEFYFIWW.js} +90 -37
  32. package/dist/chunk-DEFYFIWW.js.map +1 -0
  33. package/dist/{chunk-7E43TURF.cjs → chunk-ECI3PSMS.cjs} +7 -7
  34. package/dist/{chunk-4G645EYO.js → chunk-F73QEF7E.js} +5 -5
  35. package/dist/{chunk-4G645EYO.js.map → chunk-F73QEF7E.js.map} +1 -1
  36. package/dist/{chunk-KHRVCTQQ.cjs → chunk-FUT7XLMP.cjs} +61 -74
  37. package/dist/{chunk-7J63427U.cjs → chunk-GQSBOBOM.cjs} +375 -320
  38. package/dist/{chunk-LU3T3JB4.js → chunk-HPNSQWRD.js} +15 -28
  39. package/dist/chunk-HPNSQWRD.js.map +1 -0
  40. package/dist/{chunk-7Y4B7NHO.js → chunk-I34BFOLL.js} +18 -11
  41. package/dist/chunk-I34BFOLL.js.map +1 -0
  42. package/dist/{chunk-AJT54OMZ.js → chunk-IFRXEFQH.js} +9 -15
  43. package/dist/chunk-IFRXEFQH.js.map +1 -0
  44. package/dist/{chunk-YYW33WUL.cjs → chunk-K3XWVRL4.cjs} +8 -8
  45. package/dist/{chunk-LSI4RMTY.js → chunk-L5L6YNLT.js} +3 -3
  46. package/dist/{chunk-LSI4RMTY.js.map → chunk-L5L6YNLT.js.map} +1 -1
  47. package/dist/{chunk-2BPXVQBP.js → chunk-MO4UMXMT.js} +238 -86
  48. package/dist/chunk-MO4UMXMT.js.map +1 -0
  49. package/dist/{chunk-2QKFRKOP.cjs → chunk-N25EH2GZ.cjs} +351 -205
  50. package/dist/{chunk-CSPCDVCT.js → chunk-NCV2ML25.js} +3 -3
  51. package/dist/{chunk-CSPCDVCT.js.map → chunk-NCV2ML25.js.map} +1 -1
  52. package/dist/{chunk-NUQ64S5B.cjs → chunk-OJSKSQTL.cjs} +26 -26
  53. package/dist/chunk-PIWMU4BV.js +9 -0
  54. package/dist/chunk-PIWMU4BV.js.map +1 -0
  55. package/dist/chunk-QFGWSFOI.cjs +10 -0
  56. package/dist/{chunk-GPTJYWGS.js → chunk-RNBLVGWY.js} +3 -3
  57. package/dist/{chunk-GPTJYWGS.js.map → chunk-RNBLVGWY.js.map} +1 -1
  58. package/dist/{chunk-5RBMZGKV.js → chunk-TL2MJOWM.js} +325 -57
  59. package/dist/chunk-TL2MJOWM.js.map +1 -0
  60. package/dist/{chunk-YEDPBYO5.cjs → chunk-UDQ52EEC.cjs} +4 -4
  61. package/dist/{chunk-EIWPJWY3.js → chunk-UE2NQPNG.js} +5 -5
  62. package/dist/{chunk-EIWPJWY3.js.map → chunk-UE2NQPNG.js.map} +1 -1
  63. package/dist/{chunk-BE2YHZXA.cjs → chunk-ULV3SCYP.cjs} +26 -15
  64. package/dist/{chunk-WDBFGX3U.cjs → chunk-VTTMJGWP.cjs} +72 -77
  65. package/dist/{chunk-556PFYES.js → chunk-WK4UGDZN.js} +290 -235
  66. package/dist/chunk-WK4UGDZN.js.map +1 -0
  67. package/dist/{chunk-JZF6UQH5.cjs → chunk-WMKA37NJ.cjs} +12 -12
  68. package/dist/{chunk-F2ZK6Z52.js → chunk-Y26F2X4E.js} +3 -3
  69. package/dist/{chunk-F2ZK6Z52.js.map → chunk-Y26F2X4E.js.map} +1 -1
  70. package/dist/{chunk-FK7EBZPX.cjs → chunk-Z5EEDCRI.cjs} +549 -276
  71. package/dist/{chunk-G6NBQYMM.js → chunk-ZGFZRVQA.js} +817 -478
  72. package/dist/chunk-ZGFZRVQA.js.map +1 -0
  73. package/dist/{chunk-QLVX7MPS.js → chunk-ZQF45LA4.js} +19 -8
  74. package/dist/chunk-ZQF45LA4.js.map +1 -0
  75. package/dist/comments.cjs +127 -65
  76. package/dist/comments.d.cts +35 -2
  77. package/dist/comments.d.ts +35 -2
  78. package/dist/comments.js +73 -12
  79. package/dist/comments.js.map +1 -1
  80. package/dist/{diagram-extension-22x_njXB.d.ts → diagram-extension-BMlh8GCw.d.ts} +1 -1
  81. package/dist/{diagram-extension-C_FSkoj9.d.cts → diagram-extension-gmndUpti.d.cts} +1 -1
  82. package/dist/diagram.cjs +10 -9
  83. package/dist/diagram.d.cts +2 -2
  84. package/dist/diagram.d.ts +2 -2
  85. package/dist/diagram.js +7 -6
  86. package/dist/diff.cjs +25 -25
  87. package/dist/diff.js +3 -3
  88. package/dist/docx.cjs +31 -30
  89. package/dist/docx.js +5 -4
  90. package/dist/docx.js.map +1 -1
  91. package/dist/embed.cjs +10 -9
  92. package/dist/embed.js +8 -7
  93. package/dist/{emoji-extension-Dk5IQLZf.d.cts → emoji-extension-DD9CQTQj.d.cts} +1 -1
  94. package/dist/{emoji-extension-C832oGeT.d.ts → emoji-extension-U_PWZ2fX.d.ts} +1 -1
  95. package/dist/emoji.cjs +10 -9
  96. package/dist/emoji.d.cts +2 -2
  97. package/dist/emoji.d.ts +2 -2
  98. package/dist/emoji.js +7 -6
  99. package/dist/engine.cjs +58 -58
  100. package/dist/engine.d.cts +3 -3
  101. package/dist/engine.d.ts +3 -3
  102. package/dist/engine.js +3 -3
  103. package/dist/{find-extension-DmK9_N81.d.ts → find-extension-BGlqooZi.d.ts} +1 -1
  104. package/dist/{find-extension-BfruAPLi.d.cts → find-extension-BPnAJ8bY.d.cts} +1 -1
  105. package/dist/find.cjs +11 -10
  106. package/dist/find.d.cts +1 -1
  107. package/dist/find.d.ts +1 -1
  108. package/dist/find.js +7 -6
  109. package/dist/headless.cjs +70 -69
  110. package/dist/headless.d.cts +33 -10
  111. package/dist/headless.d.ts +33 -10
  112. package/dist/headless.js +5 -4
  113. package/dist/highlight.cjs +7 -6
  114. package/dist/highlight.js +6 -5
  115. package/dist/highlight.js.map +1 -1
  116. package/dist/{index-3fYvwqUZ.d.cts → index-DN7vRKFw.d.cts} +1 -1
  117. package/dist/{index-CgxnzCO5.d.ts → index-DyIYI3PM.d.ts} +1 -1
  118. package/dist/index.cjs +82 -81
  119. package/dist/index.d.cts +19 -12
  120. package/dist/index.d.ts +19 -12
  121. package/dist/index.js +6 -5
  122. package/dist/{labels-CiCxj2jP.d.cts → labels-BJORhN93.d.ts} +10 -5
  123. package/dist/{labels-BhRJYo46.d.ts → labels-CVYJ2-1X.d.cts} +10 -5
  124. package/dist/locale-ar.cjs +10 -0
  125. package/dist/locale-ar.d.cts +1 -1
  126. package/dist/locale-ar.d.ts +1 -1
  127. package/dist/locale-ar.js +10 -0
  128. package/dist/locale-ar.js.map +1 -1
  129. package/dist/locale-de.cjs +4 -0
  130. package/dist/locale-de.d.cts +1 -1
  131. package/dist/locale-de.d.ts +1 -1
  132. package/dist/locale-de.js +4 -0
  133. package/dist/locale-de.js.map +1 -1
  134. package/dist/locale-es.cjs +4 -0
  135. package/dist/locale-es.d.cts +1 -1
  136. package/dist/locale-es.d.ts +1 -1
  137. package/dist/locale-es.js +4 -0
  138. package/dist/locale-es.js.map +1 -1
  139. package/dist/locale-fr.cjs +4 -0
  140. package/dist/locale-fr.d.cts +1 -1
  141. package/dist/locale-fr.d.ts +1 -1
  142. package/dist/locale-fr.js +4 -0
  143. package/dist/locale-fr.js.map +1 -1
  144. package/dist/locale-ja.cjs +4 -0
  145. package/dist/locale-ja.d.cts +1 -1
  146. package/dist/locale-ja.d.ts +1 -1
  147. package/dist/locale-ja.js +4 -0
  148. package/dist/locale-ja.js.map +1 -1
  149. package/dist/locale-pt.cjs +4 -0
  150. package/dist/locale-pt.d.cts +1 -1
  151. package/dist/locale-pt.d.ts +1 -1
  152. package/dist/locale-pt.js +4 -0
  153. package/dist/locale-pt.js.map +1 -1
  154. package/dist/locale-zh.cjs +4 -0
  155. package/dist/locale-zh.d.cts +1 -1
  156. package/dist/locale-zh.d.ts +1 -1
  157. package/dist/locale-zh.js +4 -0
  158. package/dist/locale-zh.js.map +1 -1
  159. package/dist/math.cjs +11 -10
  160. package/dist/math.js +9 -8
  161. package/dist/mention.cjs +11 -10
  162. package/dist/mention.js +9 -8
  163. package/dist/{node-reveal-DY6bimv3.d.cts → node-reveal-Be7Xa0BL.d.cts} +1 -1
  164. package/dist/{node-reveal-BnFcnHhz.d.ts → node-reveal-CftIEqF_.d.ts} +1 -1
  165. package/dist/palette-DuIFHYHc.d.cts +10 -0
  166. package/dist/palette-DuIFHYHc.d.ts +10 -0
  167. package/dist/presence.cjs +39 -38
  168. package/dist/presence.js +8 -7
  169. package/dist/presence.js.map +1 -1
  170. package/dist/source.cjs +10 -9
  171. package/dist/source.d.cts +1 -1
  172. package/dist/source.d.ts +1 -1
  173. package/dist/source.js +6 -5
  174. package/dist/source.js.map +1 -1
  175. package/dist/{stats-extension-Dmw0Ujxe.d.ts → stats-extension-Bbpr593p.d.ts} +1 -1
  176. package/dist/{stats-extension-D5HySF0a.d.cts → stats-extension-D7FaeydW.d.cts} +1 -1
  177. package/dist/stats.cjs +12 -10
  178. package/dist/stats.d.cts +2 -2
  179. package/dist/stats.d.ts +2 -2
  180. package/dist/stats.js +9 -7
  181. package/dist/styles.css +1 -1
  182. package/dist/{table-extension-7LkLNK6Q.d.cts → table-extension-DNijjmxV.d.cts} +1 -1
  183. package/dist/{table-extension-DEpV0DnP.d.ts → table-extension-Dp6FYGPh.d.ts} +1 -1
  184. package/dist/table.cjs +26 -25
  185. package/dist/table.d.cts +4 -3
  186. package/dist/table.d.ts +4 -3
  187. package/dist/table.js +7 -6
  188. package/dist/{toc-extension-Dvh37bWQ.d.cts → toc-extension-BGEVAmSY.d.cts} +1 -1
  189. package/dist/{toc-extension-SVckrFmb.d.ts → toc-extension-DZIe40eV.d.ts} +1 -1
  190. package/dist/toc.cjs +10 -9
  191. package/dist/toc.d.cts +2 -2
  192. package/dist/toc.d.ts +2 -2
  193. package/dist/toc.js +7 -6
  194. package/dist/{types-DMuuDBVh.d.ts → types-Byu2a9qk.d.ts} +6 -1
  195. package/dist/{types-Bzhq5AXj.d.cts → types-DdDlCyyZ.d.cts} +6 -1
  196. package/dist/view.cjs +4 -4
  197. package/dist/view.js +2 -2
  198. package/dist/yjs.cjs +121 -121
  199. package/dist/yjs.d.cts +2 -2
  200. package/dist/yjs.d.ts +2 -2
  201. package/dist/yjs.js +5 -5
  202. package/package.json +4 -3
  203. package/dist/chunk-2BPXVQBP.js.map +0 -1
  204. package/dist/chunk-556PFYES.js.map +0 -1
  205. package/dist/chunk-5RBMZGKV.js.map +0 -1
  206. package/dist/chunk-7Y4B7NHO.js.map +0 -1
  207. package/dist/chunk-A2IQHMIH.js.map +0 -1
  208. package/dist/chunk-AJT54OMZ.js.map +0 -1
  209. package/dist/chunk-G6NBQYMM.js.map +0 -1
  210. package/dist/chunk-LU3T3JB4.js.map +0 -1
  211. package/dist/chunk-QLVX7MPS.js.map +0 -1
  212. package/dist/chunk-W376L2GM.js.map +0 -1
  213. package/dist/chunk-XE3IYW5B.js.map +0 -1
  214. package/dist/palette-BrX-hEd-.d.cts +0 -4
  215. package/dist/palette-BrX-hEd-.d.ts +0 -4
@@ -1,5 +1,6 @@
1
- import { toggleMark, hidingToggle, isTextFlow, markRanges, toggleTask, setAttrs, runCommands, setSelection, blockRangeSelection, primaryRegion, isClosedToggle, commonPrefix, commonSuffix, deleteSelection, detectMac, sameSelection, createEditor, endOf, startOf, nodeSelection, mapSelection, textSelection, foreignOrigins, rangeContent, headBlockId, isCollapsed, redo, undo, insertHardBreak, undoInputRule, insertText, nextGraphemeOffset, prevGraphemeOffset, Transaction, replaceInlineStep, selectionRange, regionLength, deleteBackward, deleteToLineEnd, deleteToLineStart, deleteWordForward, deleteWordBackward, deleteForward } from './chunk-5RBMZGKV.js';
2
- import { alignOrUndefined, paletteOrUndefined, optionalString, headingLevel, sameItems, inlineLength, firstNamed, sameAttrs, blockById, orderedStart, nodeLength, inlineText, inlinePlainText, dataAttributes, writtenAttrs, markElement, sanitizeHref, sliceInline, requireBlockIndex } from './chunk-7Y4B7NHO.js';
1
+ import { calloutTone } from './chunk-PIWMU4BV.js';
2
+ import { toggleMark, hidingToggle, isTextFlow, descendantsEnd, toggleTask, setAttrs, runCommands, setSelection, blockRangeSelection, primaryRegion, isClosedToggle, commonPrefix, commonSuffix, detectMac, sameSelection, createEditor, endOf, startOf, nodeSelection, carrySelection, textSelection, foreignOrigins, markRanges, isCollapsed, headBlockId, rangeContent, deleteSelection, redo, undo, insertHardBreak, undoInputRule, insertText, nextGraphemeOffset, prevGraphemeOffset, Transaction, replaceInlineStep, selectionRange, regionLength, deleteBackward, deleteToLineEnd, deleteToLineStart, deleteWordForward, deleteWordBackward, deleteForward, mapSelection } from './chunk-TL2MJOWM.js';
3
+ import { alignOrUndefined, paletteOrUndefined, optionalString, headingLevel, sameItems, inlineLength, sameAttrs, blockById, firstNamed, orderedStart, nodeLength, inlineText, inlinePlainText, dataAttributes, writtenAttrs, markElement, sanitizeHref, sliceInline, requireBlockIndex } from './chunk-I34BFOLL.js';
3
4
  import { createContext, memo, useRef, useContext, useCallback, useSyncExternalStore, useEffect, useLayoutEffect, Component, useState, useId, useMemo } from 'react';
4
5
  import { flushSync } from 'react-dom';
5
6
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -522,6 +523,9 @@ function selectBlock(domSelection, element) {
522
523
  return true;
523
524
  }
524
525
  var drawnUpstream = /* @__PURE__ */ new WeakMap();
526
+ function forgetDrawnSide(domSelection) {
527
+ drawnUpstream.delete(domSelection);
528
+ }
525
529
  function drawUpstream(registry, pos, domSelection, drawn) {
526
530
  const caret = textSelection(pos);
527
531
  const isAt = () => sameSelection(readSelection(registry, domSelection), caret);
@@ -719,13 +723,20 @@ function moveToNeighbour(controller, from, direction) {
719
723
  // src/view/selection/scroll-container.ts
720
724
  var SCROLLS = /* @__PURE__ */ new Set(["auto", "scroll"]);
721
725
  var scrollsVertically = (element) => SCROLLS.has(getComputedStyle(element).overflowY) && element.scrollHeight > element.clientHeight;
722
- function scrollContainerOf(element) {
726
+ function drawnParent(element) {
727
+ if (element.assignedSlot) return element.assignedSlot;
728
+ if (element.parentElement) return element.parentElement;
729
+ const parent = element.parentNode;
730
+ return parent && "host" in parent ? parent.host : null;
731
+ }
732
+ var scrollsItself = (body) => getComputedStyle(body.ownerDocument.documentElement).overflowY !== "visible" && scrollsVertically(body);
733
+ function scrollContainersOf(element) {
723
734
  const { body, documentElement } = element.ownerDocument;
724
- for (let node = element; node !== null; node = node.parentElement) {
725
- if (node === body || node === documentElement) return null;
726
- if (scrollsVertically(node)) return node;
735
+ const containers = [];
736
+ for (let node = element; node !== null && node !== documentElement; node = drawnParent(node)) {
737
+ if (node === body ? scrollsItself(node) : scrollsVertically(node)) containers.push(node);
727
738
  }
728
- return null;
739
+ return containers;
729
740
  }
730
741
 
731
742
  // src/view/selection/auto-scroll.ts
@@ -736,30 +747,41 @@ function edgesOf(container, win) {
736
747
  const top = container.getBoundingClientRect().top + container.clientTop;
737
748
  return { top: Math.max(top, 0), bottom: Math.min(top + container.clientHeight, win.innerHeight) };
738
749
  }
750
+ var hasRoom = (container, delta) => delta < 0 ? container.scrollTop > 0 : Math.ceil(container.scrollTop) + container.clientHeight < container.scrollHeight;
739
751
  function createAutoScroll(element, onScroll, edge = EDGE) {
740
752
  const win = element.ownerDocument.defaultView;
741
- let container;
742
- let delta = 0;
753
+ let scrollers = null;
754
+ let pointerY = 0;
743
755
  let frame = null;
744
756
  const step = (depth) => Math.ceil(Math.min(depth, edge) / edge * MAX_STEP);
757
+ function deltaIn(container) {
758
+ const { top, bottom } = edgesOf(container, win);
759
+ const [upper, lower] = [top + edge, bottom - edge];
760
+ return pointerY < upper ? -step(upper - pointerY) : pointerY > lower ? step(pointerY - lower) : 0;
761
+ }
762
+ function next() {
763
+ scrollers ??= [...scrollContainersOf(element), null];
764
+ for (const scroller of scrollers) {
765
+ const delta = deltaIn(scroller);
766
+ if (delta !== 0 && (scroller === null || hasRoom(scroller, delta))) return { scroller, delta };
767
+ }
768
+ return null;
769
+ }
745
770
  function tick() {
746
771
  frame = null;
747
- if (delta === 0) return;
748
- (container ?? win).scrollBy(0, delta);
772
+ const target = next();
773
+ if (target === null) return;
774
+ (target.scroller ?? win).scrollBy(0, target.delta);
749
775
  onScroll();
750
776
  frame = win.requestAnimationFrame(tick);
751
777
  }
752
778
  return {
753
779
  update(clientY) {
754
- if (container === void 0) container = scrollContainerOf(element);
755
- const { top, bottom } = edgesOf(container, win);
756
- const [upper, lower] = [top + edge, bottom - edge];
757
- delta = clientY < upper ? -step(upper - clientY) : clientY > lower ? step(clientY - lower) : 0;
758
- if (delta !== 0 && frame === null) frame = win.requestAnimationFrame(tick);
780
+ pointerY = clientY;
781
+ if (frame === null && next() !== null) frame = win.requestAnimationFrame(tick);
759
782
  },
760
783
  stop() {
761
- delta = 0;
762
- container = void 0;
784
+ scrollers = null;
763
785
  if (frame !== null) win.cancelAnimationFrame(frame);
764
786
  frame = null;
765
787
  }
@@ -929,18 +951,28 @@ function createCrossBlockPointer(controller) {
929
951
  controller.nodeReveal.pressed(block);
930
952
  select(nodeSelection(block));
931
953
  }
954
+ function followTap(event, block) {
955
+ if (block === void 0 || event.shiftKey) return;
956
+ const lift = (up) => {
957
+ if (up.pointerId !== event.pointerId) return;
958
+ end();
959
+ pressWhole(block);
960
+ };
961
+ unfollow = listen(doc, { pointerup: lift, pointercancel: end });
962
+ }
932
963
  function onPointerDown(event) {
933
964
  end();
934
965
  preventMouseDown = false;
935
- if (event.button !== 0 || event.pointerType === "touch") return;
966
+ if (event.button !== 0) return;
936
967
  const target = event.target;
937
968
  const host = controller.registry.locate(target);
938
- const block = host === null ? controller.blockAt(target) : void 0;
939
969
  const control = target.closest(CONTROLS);
970
+ const block = host === null && !(control && root.contains(control)) ? controller.blockAt(target) : void 0;
971
+ if (event.pointerType === "touch") return followTap(event, block);
940
972
  if (host !== null) {
941
973
  press = { kind: "text", host, anchor: null };
942
974
  if (event.shiftKey) extendFrom(host, event.clientX, event.clientY);
943
- } else if (block !== void 0 && !(control && root.contains(control))) {
975
+ } else if (block !== void 0) {
944
976
  press = { kind: "blocks", start: block, x: event.clientX, y: event.clientY };
945
977
  if (!event.shiftKey) pressWhole(block);
946
978
  } else {
@@ -1064,9 +1096,17 @@ function selectionText(state) {
1064
1096
  var focusInPlace = (sink) => inPlace(sink, () => sink.focus({ preventScroll: true }));
1065
1097
  var focusing = null;
1066
1098
  var focusingSink = (controller) => focusing === controller;
1099
+ function placeSink(controller, sink) {
1100
+ const id = headBlockId(controller.editor.state.selection);
1101
+ const block = id === null ? void 0 : controller.blockElement(id);
1102
+ if (block === void 0) return;
1103
+ const offset = block.getBoundingClientRect().top - sink.getBoundingClientRect().top;
1104
+ if (offset !== 0) sink.style.top = `${(parseFloat(sink.style.top) || 0) + offset}px`;
1105
+ }
1067
1106
  function focusSink(controller) {
1068
1107
  const { sink } = controller;
1069
1108
  if (sink === null) return;
1109
+ placeSink(controller, sink);
1070
1110
  const text = selectionText(controller.editor.state);
1071
1111
  if (sink.textContent !== text) sink.textContent = text;
1072
1112
  if (sink.ownerDocument.activeElement !== sink) {
@@ -1319,6 +1359,26 @@ function ownsFocus(controller, doc) {
1319
1359
  return !active || active === doc.body || active === controller.root || hasFocus(controller, doc);
1320
1360
  }
1321
1361
 
1362
+ // src/view/controller/focus-follow.ts
1363
+ function createFocusFollow(controller, focusElement) {
1364
+ const take = (preventScroll) => {
1365
+ const element = focusElement();
1366
+ if (!element || element.ownerDocument.activeElement === element) return;
1367
+ if (element === controller.sink) focusSink(controller);
1368
+ else element.focus({ preventScroll });
1369
+ };
1370
+ return {
1371
+ take,
1372
+ keep(preventScroll) {
1373
+ if (controller.composingKey === null) take(preventScroll);
1374
+ },
1375
+ rewrite(host) {
1376
+ const inSelection = host.contains(controller.domSelection()?.focusNode ?? null);
1377
+ if (inSelection && hasFocus(controller, host.ownerDocument)) controller.syncSelectionToDom();
1378
+ }
1379
+ };
1380
+ }
1381
+
1322
1382
  // src/view/controller/focus-target.ts
1323
1383
  function focusTarget(state, target) {
1324
1384
  const { doc, schema, selection } = state;
@@ -1418,7 +1478,7 @@ function createOutsideChanges(editorHasFocus, movedFrom) {
1418
1478
  }
1419
1479
  const from = moved ?? (outside && !settled ? movedFrom(tr.before.selection) : null);
1420
1480
  settled ||= outside;
1421
- moved = from && mapSelection(from, (pos, assoc) => tr.mapPos(pos, assoc), tr.before.doc);
1481
+ moved = from && carrySelection(from, (pos, assoc) => tr.mapPos(pos, assoc), tr.before.doc, tr.doc, tr.origin);
1422
1482
  },
1423
1483
  takeFocused() {
1424
1484
  const value = focused;
@@ -1692,10 +1752,12 @@ var transposeChars = (state, dispatch) => {
1692
1752
 
1693
1753
  // src/view/input/replace-range.ts
1694
1754
  function replaceRange(editor, range, text, withRules) {
1695
- const dispatch = (tr) => editor.dispatch(tr);
1696
- dispatch(editor.createTransaction().setSelection(textSelection(range.from, range.to)).setOrigin("input"));
1697
- if (text === "") return deleteSelection(editor.state, (tr) => dispatch(tr.setOrigin("input")));
1698
- return withRules ? editor.insertText(text) : insertText(text, { origin: "input" })(editor.state, dispatch);
1755
+ const { doc, selection } = editor.state;
1756
+ const dispatch = (tr) => editor.dispatch(tr.setOrigin("input"));
1757
+ dispatch(editor.createTransaction().setSelection(textSelection(range.from, range.to)));
1758
+ const replaced = text === "" ? deleteSelection(editor.state, dispatch) : withRules ? editor.insertText(text) : insertText(text, { origin: "input" })(editor.state, dispatch);
1759
+ if (editor.state.doc === doc && selection !== null) dispatch(editor.createTransaction().setSelection(selection));
1760
+ return replaced;
1699
1761
  }
1700
1762
 
1701
1763
  // src/view/input/target-range.ts
@@ -2106,6 +2168,26 @@ function moveHorizontally(controller, direction, extend) {
2106
2168
  return edge !== null && moveHead(controller, selection, edge);
2107
2169
  }
2108
2170
 
2171
+ // src/view/navigation/line-end.ts
2172
+ var leftLines = /* @__PURE__ */ new WeakMap();
2173
+ var toLineEnd = ({ isMac }, { altKey, ctrlKey, metaKey }, key) => !altKey && (isMac ? key === "ArrowRight" && metaKey && !ctrlKey : key === "End" && !ctrlKey && !metaKey);
2174
+ function noteLineEnd(controller, event, key) {
2175
+ leftLines.delete(controller);
2176
+ const { selection } = controller.editor.state;
2177
+ if (selection?.kind !== "text" || event.defaultPrevented || !toLineEnd(controller, event, key)) return;
2178
+ const { head, assoc } = selection;
2179
+ const glyphAt2 = glyphsAround(controller.registry, head);
2180
+ const glyph = assoc !== -1 && glyphAt2(head.offset) || glyphAt2(head.offset - 1);
2181
+ if (glyph) leftLines.set(controller, glyph.rect.top + glyph.rect.height / 2);
2182
+ }
2183
+ function sideOfLineEnd(controller, selection) {
2184
+ const y = leftLines.get(controller);
2185
+ leftLines.delete(controller);
2186
+ if (y === void 0 || selection?.kind !== "text" || !isCollapsed(selection)) return selection;
2187
+ const { head } = selection;
2188
+ return wrapsAt(head, y, glyphsAround(controller.registry, head)) ? { ...selection, assoc: -1 } : selection;
2189
+ }
2190
+
2109
2191
  // src/view/navigation/line-edges.ts
2110
2192
  var TEXT_NODE3 = 3;
2111
2193
  var ELEMENT_NODE2 = 1;
@@ -2115,7 +2197,10 @@ function textCaretRect(text, offset) {
2115
2197
  const range = text.ownerDocument.createRange();
2116
2198
  range.setStart(text, offset);
2117
2199
  const rect = range.getClientRects()[0];
2118
- return hasSize(rect) ? rect : null;
2200
+ if (hasSize(rect) || offset === 0) return hasSize(rect) ? rect : null;
2201
+ range.setStart(text, offset - (/[\uDC00-\uDFFF]/.test(text.data[offset - 1]) ? 2 : 1));
2202
+ const before = [...range.getClientRects()].pop();
2203
+ return hasSize(before) ? edgeOf(before, inlineDirection(text.parentElement) === "ltr") : null;
2119
2204
  }
2120
2205
  function besideNode(node, before) {
2121
2206
  if (node.nodeType === TEXT_NODE3) return textCaretRect(node, before ? 0 : node.length);
@@ -2350,6 +2435,7 @@ function handleKeydown(controller, event) {
2350
2435
  controller.nativeVerticalMove = false;
2351
2436
  for (const intercept of controller.keyInterceptors) if (intercept(event)) return;
2352
2437
  if (handle(controller, event)) event.preventDefault();
2438
+ noteLineEnd(controller, event, written(controller, event.key));
2353
2439
  }
2354
2440
 
2355
2441
  // src/view/input/attach-input.ts
@@ -2451,6 +2537,22 @@ function watchFocusReturn(root, handlers) {
2451
2537
  };
2452
2538
  }
2453
2539
 
2540
+ // src/view/controller/redraw-on-relayout.ts
2541
+ function redrawOnRelayout(controller, root) {
2542
+ const view = root.ownerDocument.defaultView;
2543
+ if (!view?.ResizeObserver) return () => {
2544
+ };
2545
+ const observer = new view.ResizeObserver(() => {
2546
+ const { selection } = controller.editor.state;
2547
+ const domSelection = controller.domSelection();
2548
+ if (selection?.kind !== "text" || selection.assoc !== -1 || !domSelection) return;
2549
+ forgetDrawnSide(domSelection);
2550
+ controller.syncSelectionToDom();
2551
+ });
2552
+ observer.observe(root);
2553
+ return () => observer.disconnect();
2554
+ }
2555
+
2454
2556
  // src/view/controller/selection-sync.ts
2455
2557
  var selectionPoints = (selection) => [
2456
2558
  selection?.anchorNode ?? null,
@@ -2491,6 +2593,7 @@ function bindRoot(controller, root, cross, committed) {
2491
2593
  const input = attachInput(controller, root);
2492
2594
  const unsubscribe = controller.editor.subscribe(committed);
2493
2595
  const detachCross = cross.attach(root);
2596
+ const stopRedrawing = redrawOnRelayout(controller, root);
2494
2597
  const stopFocusReturn = watchFocusReturn(root, {
2495
2598
  pressed: () => controller.nativeVerticalMove = false,
2496
2599
  returned: (target) => {
@@ -2507,6 +2610,7 @@ function bindRoot(controller, root, cross, committed) {
2507
2610
  input.detach();
2508
2611
  unsubscribe();
2509
2612
  detachCross();
2613
+ stopRedrawing();
2510
2614
  stopFocusReturn();
2511
2615
  }
2512
2616
  };
@@ -2515,8 +2619,10 @@ function bindRoot(controller, root, cross, committed) {
2515
2619
  // src/view/controller/selection-io.ts
2516
2620
  function movedSelection(controller, doc, model) {
2517
2621
  if (controller.composingKey !== null || controller.dragging || !doc || !ownsFocus(controller, doc)) return null;
2518
- const selection = readSelection(controller.registry, doc.getSelection(), (node) => controller.blockAt(node));
2519
- const sided = selection?.kind === "text" && model?.kind === "text" ? { ...selection, assoc: model.assoc } : selection;
2622
+ const read = readSelection(controller.registry, doc.getSelection(), (node) => controller.blockAt(node));
2623
+ const selection = sideOfLineEnd(controller, read);
2624
+ const keepsSide = selection?.kind === "text" && model?.kind === "text" && selection.assoc === void 0;
2625
+ const sided = keepsSide ? { ...selection, assoc: model.assoc } : selection;
2520
2626
  return sided === null || sameSelection(sided, model) ? null : selection;
2521
2627
  }
2522
2628
  function writeModelSelection(controller, doc, moved, local) {
@@ -2559,6 +2665,7 @@ var ViewController = class {
2559
2665
  #hosts;
2560
2666
  #drawn = createDrawnElements(this.registry, () => this.editor.state);
2561
2667
  #cross = createCrossMode(this);
2668
+ #focus = createFocusFollow(this, () => this.#drawn.focusElement());
2562
2669
  #outside = createOutsideChanges(
2563
2670
  () => hasFocus(this, this.#ownerDocument()),
2564
2671
  (model) => movedSelection(this, this.#ownerDocument(), model)
@@ -2663,7 +2770,7 @@ var ViewController = class {
2663
2770
  if (this.editor.state.doc !== before.doc) this.goalX = null;
2664
2771
  this.refreshHosts();
2665
2772
  this.#cross.sync();
2666
- if (focused && doc !== null && ownsFocus(this, doc)) this.#keepFocus();
2773
+ if (focused && doc !== null && ownsFocus(this, doc)) this.#focus.keep();
2667
2774
  this.syncSelectionToDom(true);
2668
2775
  return handled;
2669
2776
  }
@@ -2679,7 +2786,7 @@ var ViewController = class {
2679
2786
  if (moved) this.#selectFromDom(moved);
2680
2787
  this.#cross.sync();
2681
2788
  const follow = () => {
2682
- this.#keepFocus(quiet);
2789
+ this.#focus.keep(quiet);
2683
2790
  this.syncSelectionToDom();
2684
2791
  };
2685
2792
  if (!quiet) return follow();
@@ -2697,15 +2804,10 @@ var ViewController = class {
2697
2804
  announce(message) {
2698
2805
  this.announcer.announce(message);
2699
2806
  }
2700
- // A redraw of the decorations alone, such as one that follows a selection the browser made, replaces the nodes that
2701
- // selection sits in, and nothing else writes it back. It is written only while the editor holds focus: written while
2702
- // focus is on the page, it would pull focus into the line.
2703
2807
  renderHost(block, region) {
2704
2808
  const element = this.registry.get(block, region);
2705
2809
  const host = element && { block, region, element };
2706
- if (!host || this.#isComposing(host) || !this.#hosts.render(host)) return;
2707
- const inSelection = element.contains(this.domSelection()?.focusNode ?? null);
2708
- if (inSelection && hasFocus(this, element.ownerDocument)) this.syncSelectionToDom();
2810
+ if (host && !this.#isComposing(host) && this.#hosts.render(host)) this.#focus.rewrite(element);
2709
2811
  }
2710
2812
  domSelection() {
2711
2813
  return this.#ownerDocument()?.getSelection() ?? null;
@@ -2724,14 +2826,14 @@ var ViewController = class {
2724
2826
  this.#flush(() => this.#selectFromDom(selection));
2725
2827
  this.#cross.sync();
2726
2828
  if (!wasCross && !this.#cross.active) return;
2727
- this.#keepFocus();
2829
+ this.#focus.keep();
2728
2830
  this.syncSelectionToDom();
2729
2831
  }
2730
2832
  focus(target) {
2731
2833
  const { editor } = this;
2732
2834
  const selection = focusTarget(editor.state, target);
2733
2835
  if (selection !== null && !sameSelection(selection, editor.state.selection)) dispatchSelection(this, selection);
2734
- this.#takeFocus();
2836
+ this.#focus.take();
2735
2837
  this.syncSelectionToDom();
2736
2838
  }
2737
2839
  setReadOnly(readOnly) {
@@ -2753,17 +2855,6 @@ var ViewController = class {
2753
2855
  #ownerDocument() {
2754
2856
  return (this.#binding?.root ?? this.registry.all().next().value?.element)?.ownerDocument ?? null;
2755
2857
  }
2756
- // React replaces a host whose block changes kind, which drops focus, and Firefox does not move focus into another
2757
- // host when a script selects inside it.
2758
- #keepFocus(preventScroll) {
2759
- if (this.composingKey === null) this.#takeFocus(preventScroll);
2760
- }
2761
- #takeFocus(preventScroll) {
2762
- const element = this.#drawn.focusElement();
2763
- if (!element || element.ownerDocument.activeElement === element) return;
2764
- if (element === this.sink) focusSink(this);
2765
- else element.focus({ preventScroll });
2766
- }
2767
2858
  };
2768
2859
  var QuoinEditorContext = createContext(null);
2769
2860
  function useViewController() {
@@ -2804,7 +2895,31 @@ function useQuoinEditor(options) {
2804
2895
  useEffect(() => () => controller.destroy(), [controller]);
2805
2896
  return controller;
2806
2897
  }
2807
- var headingPlaceholder = (_state, { type, attrs }) => type === "MARKDOWN" && attrs.kind === "heading" ? `Heading ${headingLevel(attrs.level)}` : void 0;
2898
+
2899
+ // src/view/react/renderer-labels.ts
2900
+ var TOGGLE = "Toggle";
2901
+ var englishRendererLabels = {
2902
+ paragraph: "Paragraph",
2903
+ heading: (level) => `Heading ${level}`,
2904
+ bulletItem: "Bullet list item",
2905
+ numberedItem: (n) => `Numbered list item ${n}`,
2906
+ task: "Task",
2907
+ quote: "Quote",
2908
+ callout: (tone) => `Callout, ${tone}`,
2909
+ calloutTones: { info: "info", tip: "tip", success: "success", warning: "warning", danger: "danger" },
2910
+ toggle: TOGGLE,
2911
+ toggleButton: (hidden) => hidden === 0 ? TOGGLE : `${TOGGLE}, ${hidden} ${hidden === 1 ? "block" : "blocks"} hidden`
2912
+ };
2913
+ function rendererLabelsWith(overrides) {
2914
+ if (overrides === void 0) return englishRendererLabels;
2915
+ const given = Object.entries(overrides).filter(([, value]) => value !== void 0);
2916
+ const calloutTones = { ...englishRendererLabels.calloutTones, ...overrides.calloutTones };
2917
+ return { ...englishRendererLabels, ...Object.fromEntries(given), calloutTones };
2918
+ }
2919
+
2920
+ // src/view/react/block-placeholder.ts
2921
+ var headingPlaceholderOf = (heading) => (_state, { type, attrs }) => type === "MARKDOWN" && attrs.kind === "heading" ? heading(headingLevel(attrs.level)) : void 0;
2922
+ var headingPlaceholder = headingPlaceholderOf(englishRendererLabels.heading);
2808
2923
  var BlockPlaceholderContext = createContext(headingPlaceholder);
2809
2924
  function regionPlaceholder(state, blockId, region, placeholderOf) {
2810
2925
  const block = blockById(state.doc, blockId);
@@ -2948,6 +3063,8 @@ function LiveRegion({ blocksSelected }) {
2948
3063
  const { key, message } = useSyncExternalStore(subscribe, read, read);
2949
3064
  return /* @__PURE__ */ jsx("div", { className: "quoin-visually-hidden", role: "status", "aria-live": "polite", "aria-atomic": "true", children: message !== "" && /* @__PURE__ */ jsx("span", { children: message }, key) });
2950
3065
  }
3066
+ var RendererLabelsContext = createContext(englishRendererLabels);
3067
+ var useRendererLabels = () => useContext(RendererLabelsContext);
2951
3068
  function SelectionSink({ label = "Selected content", blockLabel }) {
2952
3069
  const controller = useViewController();
2953
3070
  const ref = useRef(null);
@@ -3033,15 +3150,10 @@ function blockStatus(state, id, choices = NO_CHOICES) {
3033
3150
  if (isHiddenAt(state.doc, index, choices)) return "hidden";
3034
3151
  return covers(state, id, index) ? "selected" : "plain";
3035
3152
  }
3036
-
3037
- // src/view/react/callout-tones.ts
3038
- var CALLOUT_TONES = ["info", "tip", "success", "warning", "danger"];
3039
- function calloutTone(value) {
3040
- return CALLOUT_TONES.find((tone) => tone === value) ?? "info";
3041
- }
3042
3153
  var CalloutBlock = ({ block }) => {
3154
+ const labels = useRendererLabels();
3043
3155
  const tone = calloutTone(block.attrs.tone);
3044
- return /* @__PURE__ */ jsx("div", { className: "quoin-callout", "data-tone": tone, children: /* @__PURE__ */ jsx(EditableRegion, { block: block.id, region: "body", label: `Callout, ${tone}` }) });
3156
+ return /* @__PURE__ */ jsx("div", { className: "quoin-callout", "data-tone": tone, children: /* @__PURE__ */ jsx(EditableRegion, { block: block.id, region: "body", label: labels.callout(labels.calloutTones[tone]) }) });
3045
3157
  };
3046
3158
 
3047
3159
  // src/view/react/block-command.ts
@@ -3122,41 +3234,56 @@ function useOrderedNumber(controller, blockId) {
3122
3234
  });
3123
3235
  }
3124
3236
  var REGION = "text";
3125
- function TextRegion({ block, label }) {
3126
- return /* @__PURE__ */ jsx(EditableRegion, { block: block.id, region: REGION, label });
3237
+ function PlainMarker(props) {
3238
+ return /* @__PURE__ */ jsx("span", { className: "quoin-marker", "aria-hidden": "true", children: props.list === "bullet" ? "\u2022" : `${props.number}.` });
3239
+ }
3240
+ var VIEW_LOOK = { Marker: PlainMarker, headingClassName: () => "quoin-heading" };
3241
+ function TextHost({ block, label, id }) {
3242
+ return /* @__PURE__ */ jsx(EditableRegion, { id, block: block.id, region: REGION, label });
3127
3243
  }
3128
- function NumberedItem({ block, controller }) {
3244
+ function Heading({ block, look }) {
3245
+ const labels = useRendererLabels();
3246
+ const level = headingLevel(block.attrs.level);
3247
+ return /* @__PURE__ */ jsx("div", { role: "heading", "aria-level": level, className: look.headingClassName(level), children: /* @__PURE__ */ jsx(TextHost, { block, label: labels.heading(level) }) });
3248
+ }
3249
+ function NumberedItem({ block, controller, look }) {
3250
+ const labels = useRendererLabels();
3129
3251
  const number = useOrderedNumber(controller, block.id);
3130
3252
  return /* @__PURE__ */ jsxs("div", { className: "quoin-list-item", "data-list": "ordered", children: [
3131
- /* @__PURE__ */ jsx("span", { className: "quoin-marker", "aria-hidden": "true", children: `${number}.` }),
3132
- /* @__PURE__ */ jsx(TextRegion, { block, label: `Numbered list item ${number}` })
3253
+ /* @__PURE__ */ jsx(look.Marker, { list: "ordered", number, depth: block.indent }),
3254
+ /* @__PURE__ */ jsx(TextHost, { block, label: labels.numberedItem(number) })
3255
+ ] });
3256
+ }
3257
+ function TaskItem({ block, controller }) {
3258
+ const { task } = useRendererLabels();
3259
+ const hostId = useRegionDomId(block.id, REGION);
3260
+ return /* @__PURE__ */ jsxs("div", { className: "quoin-task", "data-checked": block.attrs.checked === true, children: [
3261
+ /* @__PURE__ */ jsx(TaskCheckbox, { block, controller, label: task, labelledBy: hostId }),
3262
+ /* @__PURE__ */ jsx(TextHost, { id: hostId, block, label: task })
3133
3263
  ] });
3134
3264
  }
3135
- var MarkdownBlock = (props) => {
3265
+ function MarkdownText({ look = VIEW_LOOK, ...props }) {
3136
3266
  const { block } = props;
3267
+ const labels = useRendererLabels();
3137
3268
  switch (block.attrs.kind) {
3138
- case "heading": {
3139
- const level = headingLevel(block.attrs.level);
3140
- return /* @__PURE__ */ jsx("div", { role: "heading", "aria-level": level, className: "quoin-heading", children: /* @__PURE__ */ jsx(TextRegion, { block, label: `Heading ${level}` }) });
3141
- }
3269
+ case "heading":
3270
+ return /* @__PURE__ */ jsx(Heading, { ...props, look });
3142
3271
  case "bullet":
3143
3272
  return /* @__PURE__ */ jsxs("div", { className: "quoin-list-item", "data-list": "bullet", children: [
3144
- /* @__PURE__ */ jsx("span", { className: "quoin-marker", "aria-hidden": "true", children: "\u2022" }),
3145
- /* @__PURE__ */ jsx(TextRegion, { block, label: "Bullet list item" })
3273
+ /* @__PURE__ */ jsx(look.Marker, { list: "bullet", depth: block.indent }),
3274
+ /* @__PURE__ */ jsx(TextHost, { block, label: labels.bulletItem })
3146
3275
  ] });
3147
3276
  case "ordered":
3148
- return /* @__PURE__ */ jsx(NumberedItem, { ...props });
3277
+ return /* @__PURE__ */ jsx(NumberedItem, { ...props, look });
3149
3278
  case "task":
3150
- return /* @__PURE__ */ jsxs("div", { className: "quoin-task", "data-checked": block.attrs.checked === true, children: [
3151
- /* @__PURE__ */ jsx(TaskCheckbox, { block, controller: props.controller }),
3152
- /* @__PURE__ */ jsx(TextRegion, { block, label: "Task" })
3153
- ] });
3279
+ return /* @__PURE__ */ jsx(TaskItem, { ...props });
3154
3280
  case "quote":
3155
- return /* @__PURE__ */ jsx("blockquote", { className: "quoin-quote", children: /* @__PURE__ */ jsx(TextRegion, { block, label: "Quote" }) });
3281
+ return /* @__PURE__ */ jsx("blockquote", { className: "quoin-quote", children: /* @__PURE__ */ jsx(TextHost, { block, label: labels.quote }) });
3156
3282
  default:
3157
- return /* @__PURE__ */ jsx(TextRegion, { block, label: "Paragraph" });
3283
+ return /* @__PURE__ */ jsx(TextHost, { block, label: labels.paragraph });
3158
3284
  }
3159
- };
3285
+ }
3286
+ var MarkdownBlock = MarkdownText;
3160
3287
  function useReaderChoices(controller) {
3161
3288
  const store = readerToggles(controller);
3162
3289
  return useSyncExternalStore(store.subscribe, () => store.choices, () => store.choices);
@@ -3187,11 +3314,33 @@ function ToggleChevron({ block, controller, label = "Toggle", controls }) {
3187
3314
  }
3188
3315
  );
3189
3316
  }
3317
+
3318
+ // src/view/react/use-nested-blocks.ts
3319
+ function nestedBlockIds({ doc }, blockId) {
3320
+ const index = doc.index.get(blockId);
3321
+ if (index === void 0) return [];
3322
+ return doc.blocks.slice(index + 1, descendantsEnd(doc, index)).map((block) => block.id);
3323
+ }
3324
+ function useNestedBlocks(controller, blockId) {
3325
+ return useEditorState(controller, (state) => nestedBlockIds(state, blockId), sameItems);
3326
+ }
3190
3327
  var ToggleBlock = ({ block, controller }) => {
3328
+ const labels = useRendererLabels();
3329
+ const domId = useBlockDomId();
3330
+ const nested = useNestedBlocks(controller, block.id);
3191
3331
  const open = useToggleOpen(controller, block);
3332
+ const hidden = open ? 0 : nested.length;
3192
3333
  return /* @__PURE__ */ jsxs("div", { className: "quoin-toggle", "data-open": open, children: [
3193
- /* @__PURE__ */ jsx(ToggleChevron, { block, controller }),
3194
- /* @__PURE__ */ jsx(EditableRegion, { block: block.id, region: "text", label: "Toggle" })
3334
+ /* @__PURE__ */ jsx(
3335
+ ToggleChevron,
3336
+ {
3337
+ block,
3338
+ controller,
3339
+ label: hidden === 0 ? labels.toggle : labels.toggleButton(hidden),
3340
+ controls: nested.length === 0 ? void 0 : nested.map(domId).join(" ")
3341
+ }
3342
+ ),
3343
+ /* @__PURE__ */ jsx(EditableRegion, { block: block.id, region: "text", label: labels.toggle })
3195
3344
  ] });
3196
3345
  };
3197
3346
  var defaultRenderers = {
@@ -3227,7 +3376,7 @@ var BlockShell = memo(function BlockShell2({ block, renderers }) {
3227
3376
  const choices = useReaderChoices(controller);
3228
3377
  const status = useEditorState(controller, (state) => blockStatus(state, block.id, choices));
3229
3378
  const engaged = useEngaged(controller, status === "selected");
3230
- const decorations = useEditorState(controller, () => hostDecorations(controller.editor, block.id, ""), sameDecorations);
3379
+ const decorations = useEditorState(controller, () => controller.decorationsFor(block.id, ""), sameDecorations);
3231
3380
  const hidden = status === "hidden";
3232
3381
  useIsomorphicLayoutEffect(() => {
3233
3382
  const element = ref.current;
@@ -3277,6 +3426,7 @@ function EditorView({
3277
3426
  id,
3278
3427
  "aria-label": label = "Editor",
3279
3428
  hint = HINT,
3429
+ rendererLabels,
3280
3430
  paragraphLabel,
3281
3431
  selectedContentLabel,
3282
3432
  blockLabel,
@@ -3284,7 +3434,7 @@ function EditorView({
3284
3434
  blockErrorLabel = BLOCK_ERROR,
3285
3435
  onBlockError,
3286
3436
  placeholder,
3287
- blockPlaceholder = headingPlaceholder,
3437
+ blockPlaceholder,
3288
3438
  blocksSelectedLabel = BLOCKS_SELECTED,
3289
3439
  children
3290
3440
  }) {
@@ -3293,6 +3443,8 @@ function EditorView({
3293
3443
  const blockIdScope = useId();
3294
3444
  const blocks = useEditorState(controller, (state) => state.doc.blocks);
3295
3445
  const blockError = useMemo(() => ({ label: blockErrorLabel, report: onBlockError }), [blockErrorLabel, onBlockError]);
3446
+ const labels = useMemo(() => rendererLabelsWith(rendererLabels), [rendererLabels]);
3447
+ const headingPlaceholder2 = useMemo(() => headingPlaceholderOf(labels.heading), [labels.heading]);
3296
3448
  const shells = useBlockElements(blocks, renderers);
3297
3449
  useIsomorphicLayoutEffect(() => root.current ? controller.attach(root.current) : void 0, [controller]);
3298
3450
  return /* @__PURE__ */ jsx(QuoinEditorContext.Provider, { value: controller, children: /* @__PURE__ */ jsxs(
@@ -3309,7 +3461,7 @@ function EditorView({
3309
3461
  if (focusOwners.get(event.target) === controller) controller.engagement.engage();
3310
3462
  },
3311
3463
  children: [
3312
- /* @__PURE__ */ jsx(BlockDomIdScope.Provider, { value: blockIdScope, children: /* @__PURE__ */ jsx(UnsupportedBlockLabel.Provider, { value: unsupportedBlockLabel, children: /* @__PURE__ */ jsx(BlockErrorContext.Provider, { value: blockError, children: /* @__PURE__ */ jsx(BlockPlaceholderContext.Provider, { value: blockPlaceholder, children: blocks.length === 0 ? /* @__PURE__ */ jsx(EmptyDocumentHost, { placeholder, label: paragraphLabel }) : shells }) }) }) }),
3464
+ /* @__PURE__ */ jsx(BlockDomIdScope.Provider, { value: blockIdScope, children: /* @__PURE__ */ jsx(UnsupportedBlockLabel.Provider, { value: unsupportedBlockLabel, children: /* @__PURE__ */ jsx(BlockErrorContext.Provider, { value: blockError, children: /* @__PURE__ */ jsx(BlockPlaceholderContext.Provider, { value: blockPlaceholder ?? headingPlaceholder2, children: /* @__PURE__ */ jsx(RendererLabelsContext.Provider, { value: labels, children: blocks.length === 0 ? /* @__PURE__ */ jsx(EmptyDocumentHost, { placeholder, label: paragraphLabel ?? labels.paragraph }) : shells }) }) }) }) }),
3313
3465
  children,
3314
3466
  /* @__PURE__ */ jsx(SelectionSink, { label: selectedContentLabel, blockLabel }),
3315
3467
  /* @__PURE__ */ jsx("div", { id: hintId, className: "quoin-visually-hidden", children: hint }),
@@ -3320,6 +3472,6 @@ function EditorView({
3320
3472
  ) });
3321
3473
  }
3322
3474
 
3323
- export { BlockErrorContext, CALLOUT_TONES, EditableRegion, EditorView, NATIVE_INTERACTION, NODE_ENTRY, TaskCheckbox, ToggleChevron, ViewController, arrowAsWritten, calloutTone, caretClientRect, caretFromPoint, createAutoScroll, dispatchSelection, domMapOf, domToPos, drawnBlockCount, focusOwners, handleCopy, hostKey, inlineDirection, isComposingKey, isOnFirstLine, isOnLastLine, lineEdgeRect, listen, moveToNeighbour, neighbourBlock, onBlock, posToDom, regionInline, renderInline, textDiff, useBlockDomId, useEditorState, useIsomorphicLayoutEffect, useOrderedNumber, useQuoinEditor, useReadOnly, useRegionDomId, useToggleOpen, useViewController, visibleBlockIndexes, wholeState };
3324
- //# sourceMappingURL=chunk-2BPXVQBP.js.map
3325
- //# sourceMappingURL=chunk-2BPXVQBP.js.map
3475
+ export { BlockErrorContext, EditableRegion, EditorView, MarkdownText, NATIVE_INTERACTION, NODE_ENTRY, ToggleBlock, ViewController, arrowAsWritten, caretClientRect, caretFromPoint, createAutoScroll, dispatchSelection, domMapOf, domToPos, drawnBlockCount, englishRendererLabels, focusOwners, hostKey, inlineDirection, isComposingKey, isOnFirstLine, isOnLastLine, lineEdgeRect, listen, moveToNeighbour, neighbourBlock, onBlock, posToDom, regionInline, renderInline, textDiff, useEditorState, useIsomorphicLayoutEffect, useQuoinEditor, useReadOnly, useViewController, visibleBlockIndexes, wholeState };
3476
+ //# sourceMappingURL=chunk-MO4UMXMT.js.map
3477
+ //# sourceMappingURL=chunk-MO4UMXMT.js.map