@jackuait/blok 0.7.0-beta.4 → 0.7.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 (462) hide show
  1. package/dist/blok.mjs +3 -7
  2. package/dist/chunks/blok-Ufr5cPq-.mjs +12435 -0
  3. package/dist/chunks/constants-DT17zmu_.mjs +2934 -0
  4. package/dist/chunks/i18next-DymC16cN.mjs +1146 -0
  5. package/dist/chunks/i18next-loader-qjweOJ-t.mjs +35 -0
  6. package/dist/chunks/lightweight-i18n-vbtPx5C4.mjs +105 -0
  7. package/dist/chunks/messages-3bOAVT3X2.mjs +80 -0
  8. package/dist/chunks/messages-43N0Vfg42.mjs +80 -0
  9. package/dist/chunks/messages-B0cg-ThO2.mjs +80 -0
  10. package/dist/chunks/messages-B3StvafX.mjs +80 -0
  11. package/dist/chunks/messages-B7LU-b6n2.mjs +80 -0
  12. package/dist/chunks/messages-B87-89os.mjs +80 -0
  13. package/dist/chunks/messages-BFiMCfDX2.mjs +80 -0
  14. package/dist/chunks/messages-BLxyso1L.mjs +80 -0
  15. package/dist/chunks/messages-BQZtOYxr2.mjs +80 -0
  16. package/dist/chunks/messages-BRrtoRdw2.mjs +80 -0
  17. package/dist/chunks/messages-BU_YdaAf.mjs +80 -0
  18. package/dist/chunks/messages-BWbZYIs12.mjs +80 -0
  19. package/dist/chunks/messages-B_Qcy8kr2.mjs +80 -0
  20. package/dist/chunks/messages-B_uTiuQ-.mjs +80 -0
  21. package/dist/chunks/messages-BdWTM73p.mjs +80 -0
  22. package/dist/chunks/messages-BhZcNoIQ.mjs +80 -0
  23. package/dist/chunks/messages-Bn6LwI4B.mjs +80 -0
  24. package/dist/chunks/messages-BoTtYEct2.mjs +80 -0
  25. package/dist/chunks/messages-BrvAiuWT.mjs +80 -0
  26. package/dist/chunks/messages-Byp0YFMg.mjs +80 -0
  27. package/dist/chunks/messages-C0ZWDShx2.mjs +80 -0
  28. package/dist/chunks/messages-CA-jms9R.mjs +80 -0
  29. package/dist/chunks/messages-CFr0Ha6p2.mjs +80 -0
  30. package/dist/chunks/messages-CG2xl0IV.mjs +80 -0
  31. package/dist/chunks/messages-CIGX0FfW.mjs +80 -0
  32. package/dist/chunks/messages-CRMdL0jG.mjs +80 -0
  33. package/dist/chunks/messages-CRdl14uE.mjs +80 -0
  34. package/dist/chunks/messages-Cimsel4e.mjs +80 -0
  35. package/dist/chunks/messages-CjcSWeud.mjs +80 -0
  36. package/dist/chunks/messages-ClDJuy8K2.mjs +80 -0
  37. package/dist/chunks/messages-Cn1AC0Qk.mjs +80 -0
  38. package/dist/chunks/messages-CpnXbVOK2.mjs +80 -0
  39. package/dist/chunks/messages-CqsES1wk2.mjs +80 -0
  40. package/dist/chunks/messages-Csq7JatN.mjs +80 -0
  41. package/dist/chunks/messages-CtufKbaD.mjs +80 -0
  42. package/dist/chunks/messages-Cuk0QaLM.mjs +80 -0
  43. package/dist/chunks/messages-CvamFN6x.mjs +80 -0
  44. package/dist/chunks/messages-CwRhVVui.mjs +80 -0
  45. package/dist/chunks/messages-CzCezryo.mjs +80 -0
  46. package/dist/chunks/messages-D0v0Xa_i2.mjs +80 -0
  47. package/dist/chunks/messages-D3JVx_CH2.mjs +80 -0
  48. package/dist/chunks/messages-D4jR5Oc-.mjs +80 -0
  49. package/dist/chunks/messages-D7fI9Pj52.mjs +80 -0
  50. package/dist/chunks/messages-DGodJU2R.mjs +80 -0
  51. package/dist/chunks/messages-DLrmLkco2.mjs +80 -0
  52. package/dist/chunks/messages-DPe7kW6J.mjs +80 -0
  53. package/dist/chunks/messages-DRYKKPk8.mjs +80 -0
  54. package/dist/chunks/messages-DV5c_ZRQ.mjs +80 -0
  55. package/dist/chunks/messages-Dg6kSnxq.mjs +80 -0
  56. package/dist/chunks/messages-Dgfbmyf-.mjs +80 -0
  57. package/dist/chunks/messages-DihczS7L.mjs +80 -0
  58. package/dist/chunks/messages-DkSwQvmi2.mjs +80 -0
  59. package/dist/chunks/messages-Doxcj7Qy.mjs +80 -0
  60. package/dist/chunks/messages-DqGQvcXv2.mjs +80 -0
  61. package/dist/chunks/messages-Dr7yA3xM.mjs +80 -0
  62. package/dist/chunks/messages-DriB5lEF.mjs +80 -0
  63. package/dist/chunks/messages-FB_MePlt.mjs +80 -0
  64. package/dist/chunks/messages-JyZvGvrN.mjs +80 -0
  65. package/dist/chunks/messages-KdvbGwLH.mjs +80 -0
  66. package/dist/chunks/messages-M0HT-kBW.mjs +80 -0
  67. package/dist/chunks/messages-M8noQ6Kp2.mjs +80 -0
  68. package/dist/chunks/messages-elZUbCrN.mjs +80 -0
  69. package/dist/chunks/messages-iWMOMK822.mjs +80 -0
  70. package/dist/chunks/messages-kC92TJI72.mjs +80 -0
  71. package/dist/chunks/messages-tfyq1JIh2.mjs +80 -0
  72. package/dist/chunks/messages-v1HkA3kF2.mjs +80 -0
  73. package/dist/chunks/messages-yuqArCc6.mjs +80 -0
  74. package/dist/chunks/notifier-BqYxvxnV.mjs +96 -0
  75. package/dist/chunks/objectSpread2-CyPxu8-u.mjs +62 -0
  76. package/dist/chunks/tools-CJIETS-H.mjs +6004 -0
  77. package/dist/chunks/tw-DmW6-pCY.mjs +237 -0
  78. package/dist/cli.mjs +36 -49
  79. package/dist/full.mjs +26 -52
  80. package/dist/locales.mjs +181 -254
  81. package/dist/messages-2iHnlF0U.mjs +80 -0
  82. package/dist/messages-49ZJ_ISf.mjs +80 -0
  83. package/dist/messages-B8jjwMLK.mjs +80 -0
  84. package/dist/messages-BEDVb3ZX.mjs +80 -0
  85. package/dist/messages-BEEr6Vh82.mjs +80 -0
  86. package/dist/messages-BFT0F9pw.mjs +80 -0
  87. package/dist/messages-BHOI7R4K.mjs +80 -0
  88. package/dist/messages-BRPH_a6a.mjs +80 -0
  89. package/dist/messages-BSlQrYwp.mjs +80 -0
  90. package/dist/messages-BTNuOkhL.mjs +80 -0
  91. package/dist/messages-BX2KVzJp2.mjs +80 -0
  92. package/dist/messages-BaGwIHPb2.mjs +80 -0
  93. package/dist/messages-BdA_xvxj.mjs +80 -0
  94. package/dist/messages-BeJaje7e2.mjs +80 -0
  95. package/dist/messages-BfgHOkAy.mjs +80 -0
  96. package/dist/messages-BflWzIcP2.mjs +80 -0
  97. package/dist/messages-BigRnQS92.mjs +80 -0
  98. package/dist/messages-BjnJajTO2.mjs +80 -0
  99. package/dist/messages-BpA30dPf.mjs +80 -0
  100. package/dist/messages-BrPEPj382.mjs +80 -0
  101. package/dist/messages-Bt_9ptDu.mjs +80 -0
  102. package/dist/messages-C0cXOCHN2.mjs +80 -0
  103. package/dist/messages-C3tLCwJp2.mjs +80 -0
  104. package/dist/messages-C45IBZtA2.mjs +80 -0
  105. package/dist/messages-CA0hwajz.mjs +80 -0
  106. package/dist/messages-CCKZS2f4.mjs +80 -0
  107. package/dist/messages-CCm71gq3.mjs +80 -0
  108. package/dist/messages-CERs9LC9.mjs +80 -0
  109. package/dist/messages-CLQvtc_8.mjs +80 -0
  110. package/dist/messages-CPx1R-PH.mjs +80 -0
  111. package/dist/messages-CYFdbooL2.mjs +80 -0
  112. package/dist/messages-CYLYnOV82.mjs +80 -0
  113. package/dist/messages-CYZVFnaF.mjs +80 -0
  114. package/dist/messages-CaAdEXoh2.mjs +80 -0
  115. package/dist/messages-CicggErN2.mjs +80 -0
  116. package/dist/messages-CkAWTSc4.mjs +80 -0
  117. package/dist/messages-CkVfziK_2.mjs +80 -0
  118. package/dist/messages-CsM2iz1H2.mjs +80 -0
  119. package/dist/messages-D-12TeCM2.mjs +80 -0
  120. package/dist/messages-D0i5Vdyy2.mjs +80 -0
  121. package/dist/messages-D5KmRsUV2.mjs +80 -0
  122. package/dist/messages-DBwaWI0X.mjs +80 -0
  123. package/dist/messages-DDGzypb4.mjs +80 -0
  124. package/dist/messages-DQGzw4IC.mjs +80 -0
  125. package/dist/messages-DWZyaZNA.mjs +80 -0
  126. package/dist/messages-DYlxQEIv.mjs +80 -0
  127. package/dist/messages-DZo0x7Bd.mjs +80 -0
  128. package/dist/messages-Dc1yFFBM.mjs +80 -0
  129. package/dist/messages-DdUpYaJ1.mjs +80 -0
  130. package/dist/messages-DgstU8GH.mjs +80 -0
  131. package/dist/messages-DhdWq5oQ2.mjs +80 -0
  132. package/dist/messages-DmX52AQr.mjs +80 -0
  133. package/dist/messages-Dr-YJYIK2.mjs +80 -0
  134. package/dist/messages-DuubRyFf.mjs +80 -0
  135. package/dist/messages-DvTVsLOK2.mjs +80 -0
  136. package/dist/messages-DwPfgL_u.mjs +80 -0
  137. package/dist/messages-DxKIxLKw.mjs +80 -0
  138. package/dist/messages-DzhR8Klk.mjs +80 -0
  139. package/dist/messages-MBBSKGjJ2.mjs +80 -0
  140. package/dist/messages-RNusm48G2.mjs +80 -0
  141. package/dist/messages-XwPD18Kk.mjs +80 -0
  142. package/dist/messages-YfjdnhUF.mjs +80 -0
  143. package/dist/messages-aNMLsF8T2.mjs +80 -0
  144. package/dist/messages-cOqXp22e.mjs +80 -0
  145. package/dist/messages-g58itYPI.mjs +80 -0
  146. package/dist/messages-vfkwiKQo.mjs +80 -0
  147. package/dist/messages-vssmW7KO.mjs +80 -0
  148. package/dist/react.mjs +108 -0
  149. package/dist/tools.mjs +3 -7485
  150. package/dist/vendor.LICENSE.txt +86 -86
  151. package/package.json +56 -29
  152. package/src/blok.ts +52 -2
  153. package/src/components/block/api.ts +8 -0
  154. package/src/components/block/mutation-handler.ts +29 -4
  155. package/src/components/block/style-manager.ts +1 -1
  156. package/src/components/block-tunes/block-tune-width.ts +39 -0
  157. package/src/components/blocks.ts +56 -2
  158. package/src/components/core.ts +1 -0
  159. package/src/components/i18n/locales/am/messages.json +6 -1
  160. package/src/components/i18n/locales/ar/messages.json +6 -1
  161. package/src/components/i18n/locales/az/messages.json +6 -1
  162. package/src/components/i18n/locales/bg/messages.json +8 -3
  163. package/src/components/i18n/locales/bn/messages.json +6 -1
  164. package/src/components/i18n/locales/bs/messages.json +6 -1
  165. package/src/components/i18n/locales/cs/messages.json +6 -1
  166. package/src/components/i18n/locales/da/messages.json +6 -1
  167. package/src/components/i18n/locales/de/messages.json +8 -3
  168. package/src/components/i18n/locales/dv/messages.json +6 -1
  169. package/src/components/i18n/locales/el/messages.json +8 -3
  170. package/src/components/i18n/locales/en/messages.json +5 -0
  171. package/src/components/i18n/locales/es/messages.json +6 -1
  172. package/src/components/i18n/locales/et/messages.json +6 -1
  173. package/src/components/i18n/locales/fa/messages.json +8 -3
  174. package/src/components/i18n/locales/fi/messages.json +6 -1
  175. package/src/components/i18n/locales/fil/messages.json +21 -16
  176. package/src/components/i18n/locales/fr/messages.json +6 -1
  177. package/src/components/i18n/locales/gu/messages.json +6 -1
  178. package/src/components/i18n/locales/he/messages.json +6 -1
  179. package/src/components/i18n/locales/hi/messages.json +6 -1
  180. package/src/components/i18n/locales/hr/messages.json +6 -1
  181. package/src/components/i18n/locales/hu/messages.json +6 -1
  182. package/src/components/i18n/locales/hy/messages.json +8 -3
  183. package/src/components/i18n/locales/id/messages.json +12 -7
  184. package/src/components/i18n/locales/it/messages.json +6 -1
  185. package/src/components/i18n/locales/ja/messages.json +6 -1
  186. package/src/components/i18n/locales/ka/messages.json +6 -1
  187. package/src/components/i18n/locales/km/messages.json +6 -1
  188. package/src/components/i18n/locales/kn/messages.json +6 -1
  189. package/src/components/i18n/locales/ko/messages.json +6 -1
  190. package/src/components/i18n/locales/ku/messages.json +7 -2
  191. package/src/components/i18n/locales/lo/messages.json +7 -2
  192. package/src/components/i18n/locales/lt/messages.json +6 -1
  193. package/src/components/i18n/locales/lv/messages.json +6 -1
  194. package/src/components/i18n/locales/mk/messages.json +6 -1
  195. package/src/components/i18n/locales/ml/messages.json +6 -1
  196. package/src/components/i18n/locales/mn/messages.json +6 -1
  197. package/src/components/i18n/locales/mr/messages.json +6 -1
  198. package/src/components/i18n/locales/ms/messages.json +6 -1
  199. package/src/components/i18n/locales/my/messages.json +6 -1
  200. package/src/components/i18n/locales/ne/messages.json +9 -4
  201. package/src/components/i18n/locales/nl/messages.json +6 -1
  202. package/src/components/i18n/locales/no/messages.json +6 -1
  203. package/src/components/i18n/locales/pa/messages.json +6 -1
  204. package/src/components/i18n/locales/pl/messages.json +6 -1
  205. package/src/components/i18n/locales/ps/messages.json +8 -3
  206. package/src/components/i18n/locales/pt/messages.json +6 -1
  207. package/src/components/i18n/locales/ro/messages.json +6 -1
  208. package/src/components/i18n/locales/ru/messages.json +10 -5
  209. package/src/components/i18n/locales/sd/messages.json +6 -1
  210. package/src/components/i18n/locales/si/messages.json +6 -1
  211. package/src/components/i18n/locales/sk/messages.json +6 -1
  212. package/src/components/i18n/locales/sl/messages.json +6 -1
  213. package/src/components/i18n/locales/sq/messages.json +6 -1
  214. package/src/components/i18n/locales/sr/messages.json +6 -1
  215. package/src/components/i18n/locales/sv/messages.json +6 -1
  216. package/src/components/i18n/locales/sw/messages.json +6 -1
  217. package/src/components/i18n/locales/ta/messages.json +6 -1
  218. package/src/components/i18n/locales/te/messages.json +9 -4
  219. package/src/components/i18n/locales/th/messages.json +6 -1
  220. package/src/components/i18n/locales/tr/messages.json +6 -1
  221. package/src/components/i18n/locales/ug/messages.json +7 -2
  222. package/src/components/i18n/locales/uk/messages.json +6 -1
  223. package/src/components/i18n/locales/ur/messages.json +6 -1
  224. package/src/components/i18n/locales/vi/messages.json +6 -1
  225. package/src/components/i18n/locales/yi/messages.json +7 -2
  226. package/src/components/i18n/locales/zh/messages.json +6 -1
  227. package/src/components/icons/index.ts +16 -0
  228. package/src/components/inline-tools/inline-tool-link.ts +1 -1
  229. package/src/components/modules/api/blocks.ts +45 -2
  230. package/src/components/modules/api/index.ts +1 -0
  231. package/src/components/modules/api/width.ts +17 -0
  232. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +99 -0
  233. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +109 -2
  234. package/src/components/modules/blockEvents/constants.ts +7 -0
  235. package/src/components/modules/blockManager/blockManager.ts +113 -9
  236. package/src/components/modules/blockManager/hierarchy.ts +61 -0
  237. package/src/components/modules/blockManager/operations.ts +133 -15
  238. package/src/components/modules/blockManager/yjs-sync.ts +112 -4
  239. package/src/components/modules/blockSelection.ts +36 -2
  240. package/src/components/modules/crossBlockSelection.ts +22 -2
  241. package/src/components/modules/drag/DragController.ts +178 -4
  242. package/src/components/modules/drag/operations/DragOperations.ts +48 -9
  243. package/src/components/modules/drag/preview/DragPreview.ts +21 -1
  244. package/src/components/modules/drag/state/DragStateMachine.ts +6 -1
  245. package/src/components/modules/drag/target/DropTargetDetector.ts +80 -4
  246. package/src/components/modules/drag/utils/ToggleSpringLoader.ts +71 -0
  247. package/src/components/modules/index.ts +7 -1
  248. package/src/components/modules/modificationsObserver.ts +19 -0
  249. package/src/components/modules/paste/constants.ts +2 -0
  250. package/src/components/modules/paste/handlers/base.ts +33 -1
  251. package/src/components/modules/paste/handlers/html-handler.ts +121 -54
  252. package/src/components/modules/paste/index.ts +5 -0
  253. package/src/components/modules/paste/types.ts +5 -0
  254. package/src/components/modules/rectangleSelection.ts +74 -81
  255. package/src/components/modules/toolbar/blockSettings.ts +25 -7
  256. package/src/components/modules/toolbar/index.ts +9 -7
  257. package/src/components/modules/toolbar/inline/index.ts +6 -1
  258. package/src/components/modules/toolbar/plus-button.ts +2 -6
  259. package/src/components/modules/toolbar/positioning.ts +10 -1
  260. package/src/components/modules/toolbar/settings-toggler.ts +1 -1
  261. package/src/components/modules/toolbar/styles.ts +3 -7
  262. package/src/components/modules/ui.ts +59 -5
  263. package/src/components/modules/uiControllers/handlers/click.ts +3 -2
  264. package/src/components/modules/widthManager.ts +69 -0
  265. package/src/components/modules/yjs/document-store.ts +11 -0
  266. package/src/components/modules/yjs/index.ts +11 -0
  267. package/src/components/shared/color-picker.ts +3 -3
  268. package/src/components/tools/block.ts +1 -11
  269. package/src/components/ui/toolbox.ts +52 -8
  270. package/src/components/utils/blocks.ts +37 -7
  271. package/src/components/utils/mutations.ts +2 -2
  272. package/src/components/utils/notifier/draw.ts +1 -1
  273. package/src/components/utils/placeholder.ts +5 -6
  274. package/src/components/utils/popover/components/popover-header/popover-header.const.ts +1 -1
  275. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +4 -4
  276. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -6
  277. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
  278. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
  279. package/src/components/utils/popover/components/search-input/search-input.ts +7 -11
  280. package/src/components/utils/popover/components/search-input/search-input.types.ts +149 -10
  281. package/src/components/utils/popover/popover-abstract.ts +3 -2
  282. package/src/components/utils/popover/popover-desktop.ts +133 -11
  283. package/src/components/utils/popover/popover-inline.ts +1 -1
  284. package/src/components/utils/popover/popover.const.ts +3 -3
  285. package/src/components/utils/shortcut.ts +2 -0
  286. package/src/components/utils/tooltip.ts +11 -1
  287. package/src/react/BlokContent.tsx +46 -0
  288. package/src/react/holder-map.ts +17 -0
  289. package/src/react/index.ts +3 -0
  290. package/src/react/types.ts +16 -0
  291. package/src/react/useBlok.ts +173 -0
  292. package/src/stories/Placeholder.stories.ts +0 -59
  293. package/src/styles/main.css +663 -52
  294. package/src/tools/header/header-toggle-keyboard.ts +115 -0
  295. package/src/tools/header/index.ts +382 -187
  296. package/src/tools/list/block-operations.ts +1 -1
  297. package/src/tools/list/caret-manager.ts +9 -12
  298. package/src/tools/list/index.ts +2 -6
  299. package/src/tools/list/list-keyboard.ts +2 -2
  300. package/src/tools/paragraph/index.ts +1 -1
  301. package/src/tools/table/index.ts +37 -3
  302. package/src/tools/table/table-add-controls.ts +97 -8
  303. package/src/tools/table/table-cell-blocks.ts +17 -8
  304. package/src/tools/table/table-cell-clipboard.ts +1 -1
  305. package/src/tools/table/table-cell-selection.ts +27 -2
  306. package/src/tools/table/table-operations.ts +3 -2
  307. package/src/tools/toggle/block-operations.ts +4 -2
  308. package/src/tools/toggle/constants.ts +26 -2
  309. package/src/tools/toggle/dom-builder.ts +90 -25
  310. package/src/tools/toggle/index.ts +112 -9
  311. package/src/tools/toggle/toggle-keyboard.ts +5 -3
  312. package/src/tools/toggle/toggle-lifecycle.ts +79 -7
  313. package/src/tools/toggle/toggle-shortcuts.ts +214 -20
  314. package/src/tools/toggle/types.ts +2 -0
  315. package/src/types-internal/blok-modules.d.ts +4 -0
  316. package/types/api/block.d.ts +5 -0
  317. package/types/api/blocks.d.ts +29 -0
  318. package/types/api/index.d.ts +1 -0
  319. package/types/api/width.d.ts +19 -0
  320. package/types/configs/blok-config.d.ts +33 -0
  321. package/types/index.d.ts +4 -0
  322. package/types/react.d.ts +58 -0
  323. package/types/utils/popover/popover.d.ts +7 -0
  324. package/dist/chunks/blok-B0pAWdVk.mjs +0 -20102
  325. package/dist/chunks/constants-DmDwNSTM.mjs +0 -5123
  326. package/dist/chunks/i18next-B47TKgbU.mjs +0 -1303
  327. package/dist/chunks/i18next-loader-v9SlYZ0i.mjs +0 -43
  328. package/dist/chunks/index-DHLWzZaA.mjs +0 -130
  329. package/dist/chunks/messages-0Pxnqd4N.mjs +0 -75
  330. package/dist/chunks/messages-0ZXYUq7S.mjs +0 -75
  331. package/dist/chunks/messages-2OD2uUDS.mjs +0 -75
  332. package/dist/chunks/messages-7cEMfYzh.mjs +0 -75
  333. package/dist/chunks/messages-8mwfda1Q.mjs +0 -75
  334. package/dist/chunks/messages-B-FqWsBM.mjs +0 -75
  335. package/dist/chunks/messages-B1jzqWiQ.mjs +0 -75
  336. package/dist/chunks/messages-B5wk4Ezz.mjs +0 -75
  337. package/dist/chunks/messages-BAZ5Ld8x.mjs +0 -75
  338. package/dist/chunks/messages-BBhGp198.mjs +0 -75
  339. package/dist/chunks/messages-BC9IjIb7.mjs +0 -75
  340. package/dist/chunks/messages-BFEmpeV-.mjs +0 -75
  341. package/dist/chunks/messages-BGqzTZy0.mjs +0 -75
  342. package/dist/chunks/messages-BICs1abK.mjs +0 -75
  343. package/dist/chunks/messages-BJX6rOnd.mjs +0 -75
  344. package/dist/chunks/messages-BL2bXRhN.mjs +0 -75
  345. package/dist/chunks/messages-BMs5qdlH.mjs +0 -75
  346. package/dist/chunks/messages-BRsjUNwB.mjs +0 -75
  347. package/dist/chunks/messages-BSqV8OUR.mjs +0 -75
  348. package/dist/chunks/messages-BTqu3DfG.mjs +0 -75
  349. package/dist/chunks/messages-BXnDEsur.mjs +0 -75
  350. package/dist/chunks/messages-BYcre4-6.mjs +0 -75
  351. package/dist/chunks/messages-BZ9LRJf-.mjs +0 -75
  352. package/dist/chunks/messages-BgypBy7y.mjs +0 -75
  353. package/dist/chunks/messages-BsuGf70G.mjs +0 -75
  354. package/dist/chunks/messages-BwaoF4lQ.mjs +0 -75
  355. package/dist/chunks/messages-C1l8_7-y.mjs +0 -75
  356. package/dist/chunks/messages-C5NA_r9v.mjs +0 -75
  357. package/dist/chunks/messages-C6zgZ5pA.mjs +0 -75
  358. package/dist/chunks/messages-CAo5ghFI.mjs +0 -75
  359. package/dist/chunks/messages-CH9qlJ9I.mjs +0 -75
  360. package/dist/chunks/messages-CI0HqAeS.mjs +0 -75
  361. package/dist/chunks/messages-CJJtms9k.mjs +0 -75
  362. package/dist/chunks/messages-CM2hJqk6.mjs +0 -75
  363. package/dist/chunks/messages-CRMiDPIQ.mjs +0 -75
  364. package/dist/chunks/messages-CWsZuBj1.mjs +0 -75
  365. package/dist/chunks/messages-C_gLHo6A.mjs +0 -75
  366. package/dist/chunks/messages-Cbu-NUDn.mjs +0 -75
  367. package/dist/chunks/messages-Cjb_MCeh.mjs +0 -75
  368. package/dist/chunks/messages-ClXYO9Wn.mjs +0 -75
  369. package/dist/chunks/messages-CsH20vhP.mjs +0 -75
  370. package/dist/chunks/messages-CsjAGhzA.mjs +0 -75
  371. package/dist/chunks/messages-Cx7VKFOE.mjs +0 -75
  372. package/dist/chunks/messages-D3JeBwxo.mjs +0 -75
  373. package/dist/chunks/messages-D541fieJ.mjs +0 -75
  374. package/dist/chunks/messages-D7XPdglc.mjs +0 -75
  375. package/dist/chunks/messages-DBhylfvt.mjs +0 -75
  376. package/dist/chunks/messages-DCA120lW.mjs +0 -75
  377. package/dist/chunks/messages-DCf_xZMN.mjs +0 -75
  378. package/dist/chunks/messages-DDwXKCpe.mjs +0 -75
  379. package/dist/chunks/messages-DNKDlxcy.mjs +0 -75
  380. package/dist/chunks/messages-DPvEjrGK.mjs +0 -75
  381. package/dist/chunks/messages-DQ-AkNxA.mjs +0 -75
  382. package/dist/chunks/messages-DVuvkNap.mjs +0 -75
  383. package/dist/chunks/messages-DaglyqUT.mjs +0 -75
  384. package/dist/chunks/messages-Di0bAfwA.mjs +0 -75
  385. package/dist/chunks/messages-DuLct0Yr.mjs +0 -75
  386. package/dist/chunks/messages-DzEYYhZh.mjs +0 -75
  387. package/dist/chunks/messages-DznNGAB2.mjs +0 -75
  388. package/dist/chunks/messages-DzoIzyu8.mjs +0 -75
  389. package/dist/chunks/messages-QYOGmket.mjs +0 -75
  390. package/dist/chunks/messages-cEjGDAgI.mjs +0 -75
  391. package/dist/chunks/messages-ddhvrdpE.mjs +0 -75
  392. package/dist/chunks/messages-mwfNK5nZ.mjs +0 -75
  393. package/dist/chunks/messages-nG_vNDte.mjs +0 -75
  394. package/dist/chunks/messages-tDq3Owh7.mjs +0 -75
  395. package/dist/chunks/messages-x6VJVZKx.mjs +0 -75
  396. package/dist/messages-0Pxnqd4N.mjs +0 -75
  397. package/dist/messages-0ZXYUq7S.mjs +0 -75
  398. package/dist/messages-2OD2uUDS.mjs +0 -75
  399. package/dist/messages-7cEMfYzh.mjs +0 -75
  400. package/dist/messages-8mwfda1Q.mjs +0 -75
  401. package/dist/messages-B-FqWsBM.mjs +0 -75
  402. package/dist/messages-B1jzqWiQ.mjs +0 -75
  403. package/dist/messages-B5wk4Ezz.mjs +0 -75
  404. package/dist/messages-BAZ5Ld8x.mjs +0 -75
  405. package/dist/messages-BBhGp198.mjs +0 -75
  406. package/dist/messages-BC9IjIb7.mjs +0 -75
  407. package/dist/messages-BFEmpeV-.mjs +0 -75
  408. package/dist/messages-BGqzTZy0.mjs +0 -75
  409. package/dist/messages-BICs1abK.mjs +0 -75
  410. package/dist/messages-BJX6rOnd.mjs +0 -75
  411. package/dist/messages-BL2bXRhN.mjs +0 -75
  412. package/dist/messages-BMs5qdlH.mjs +0 -75
  413. package/dist/messages-BRsjUNwB.mjs +0 -75
  414. package/dist/messages-BSqV8OUR.mjs +0 -75
  415. package/dist/messages-BTqu3DfG.mjs +0 -75
  416. package/dist/messages-BXnDEsur.mjs +0 -75
  417. package/dist/messages-BYcre4-6.mjs +0 -75
  418. package/dist/messages-BZ9LRJf-.mjs +0 -75
  419. package/dist/messages-BgypBy7y.mjs +0 -75
  420. package/dist/messages-BsuGf70G.mjs +0 -75
  421. package/dist/messages-BwaoF4lQ.mjs +0 -75
  422. package/dist/messages-C1l8_7-y.mjs +0 -75
  423. package/dist/messages-C5NA_r9v.mjs +0 -75
  424. package/dist/messages-C6zgZ5pA.mjs +0 -75
  425. package/dist/messages-CAo5ghFI.mjs +0 -75
  426. package/dist/messages-CH9qlJ9I.mjs +0 -75
  427. package/dist/messages-CI0HqAeS.mjs +0 -75
  428. package/dist/messages-CJJtms9k.mjs +0 -75
  429. package/dist/messages-CM2hJqk6.mjs +0 -75
  430. package/dist/messages-CRMiDPIQ.mjs +0 -75
  431. package/dist/messages-CWsZuBj1.mjs +0 -75
  432. package/dist/messages-C_gLHo6A.mjs +0 -75
  433. package/dist/messages-Cbu-NUDn.mjs +0 -75
  434. package/dist/messages-Cjb_MCeh.mjs +0 -75
  435. package/dist/messages-ClXYO9Wn.mjs +0 -75
  436. package/dist/messages-CsH20vhP.mjs +0 -75
  437. package/dist/messages-CsjAGhzA.mjs +0 -75
  438. package/dist/messages-Cx7VKFOE.mjs +0 -75
  439. package/dist/messages-D3JeBwxo.mjs +0 -75
  440. package/dist/messages-D541fieJ.mjs +0 -75
  441. package/dist/messages-D7XPdglc.mjs +0 -75
  442. package/dist/messages-DBhylfvt.mjs +0 -75
  443. package/dist/messages-DCA120lW.mjs +0 -75
  444. package/dist/messages-DCf_xZMN.mjs +0 -75
  445. package/dist/messages-DDwXKCpe.mjs +0 -75
  446. package/dist/messages-DNKDlxcy.mjs +0 -75
  447. package/dist/messages-DPvEjrGK.mjs +0 -75
  448. package/dist/messages-DQ-AkNxA.mjs +0 -75
  449. package/dist/messages-DVuvkNap.mjs +0 -75
  450. package/dist/messages-DaglyqUT.mjs +0 -75
  451. package/dist/messages-Di0bAfwA.mjs +0 -75
  452. package/dist/messages-DuLct0Yr.mjs +0 -75
  453. package/dist/messages-DzEYYhZh.mjs +0 -75
  454. package/dist/messages-DznNGAB2.mjs +0 -75
  455. package/dist/messages-DzoIzyu8.mjs +0 -75
  456. package/dist/messages-QYOGmket.mjs +0 -75
  457. package/dist/messages-cEjGDAgI.mjs +0 -75
  458. package/dist/messages-ddhvrdpE.mjs +0 -75
  459. package/dist/messages-mwfNK5nZ.mjs +0 -75
  460. package/dist/messages-nG_vNDte.mjs +0 -75
  461. package/dist/messages-tDq3Owh7.mjs +0 -75
  462. package/dist/messages-x6VJVZKx.mjs +0 -75
@@ -93,6 +93,11 @@ export class RectangleSelection extends Module {
93
93
  */
94
94
  private rectCrossesBlocks = false;
95
95
 
96
+ /**
97
+ * The block index where selection started (anchor point for geometry-based selection)
98
+ */
99
+ private anchorBlockIndex: number | null = null;
100
+
96
101
  /**
97
102
  * Selection rectangle
98
103
  */
@@ -167,8 +172,10 @@ export class RectangleSelection extends Module {
167
172
  */
168
173
  if (!startsInsideToolbar && !shiftKey) {
169
174
  this.Blok.BlockSelection.allBlocksSelected = false;
175
+ this.Blok.BlockSelection.disableNavigationMode();
170
176
  this.clearSelection();
171
177
  this.stackOfSelected = [];
178
+ this.anchorBlockIndex = null;
172
179
  }
173
180
 
174
181
  const selectorsToAvoid = [
@@ -208,6 +215,8 @@ export class RectangleSelection extends Module {
208
215
  this.mousedown = false;
209
216
  this.startX = 0;
210
217
  this.startY = 0;
218
+ this.anchorBlockIndex = null;
219
+ this.stackOfSelected = [];
211
220
  if (this.overlayRectangle !== null) {
212
221
  this.overlayRectangle.style.display = 'none';
213
222
  }
@@ -217,7 +226,7 @@ export class RectangleSelection extends Module {
217
226
  * is RectSelection Activated
218
227
  */
219
228
  public isRectActivated(): boolean {
220
- return this.isRectSelectionActivated;
229
+ return this.isRectSelectionActivated || this.mousedown;
221
230
  }
222
231
 
223
232
  /**
@@ -274,7 +283,7 @@ export class RectangleSelection extends Module {
274
283
  passive: true,
275
284
  });
276
285
 
277
- this.listeners.on(document.body, 'mouseup', () => {
286
+ this.listeners.on(document, 'mouseup', () => {
278
287
  this.processMouseUp();
279
288
  }, false);
280
289
  }
@@ -467,9 +476,12 @@ export class RectangleSelection extends Module {
467
476
  */
468
477
  this.rectCrossesBlocks = false;
469
478
  const block = index !== undefined ? this.Blok.BlockManager.getBlockByIndex(index) : undefined;
479
+ const rootBlock = block !== undefined
480
+ ? this.Blok.BlockManager.resolveToRootBlock(block)
481
+ : undefined;
470
482
 
471
- if (block) {
472
- const holderRect = block.holder.getBoundingClientRect();
483
+ if (rootBlock) {
484
+ const holderRect = rootBlock.holder.getBoundingClientRect();
473
485
  const scrollLeft = this.getScrollLeft();
474
486
 
475
487
  // Selection rectangle horizontal bounds (in page coordinates)
@@ -584,45 +596,34 @@ export class RectangleSelection extends Module {
584
596
 
585
597
  /**
586
598
  * Collects information needed to determine the behavior of the rectangle
587
- * For page-wide selection, we check blocks at the center X position but at the actual mouse Y position
588
- * @returns {object} index - index next Block, leftPos - start of left border of Block, rightPos - right border
599
+ * For page-wide selection, we check blocks at the redactor's center X position but at the actual mouse Y position
600
+ * @returns {object} index - index of the Block at the current mouse Y position
589
601
  */
590
- private genInfoForMouseSelection(): {index: number | undefined; leftPos: number; rightPos: number} {
591
- const widthOfRedactor = document.body.offsetWidth;
592
- const centerOfRedactor = widthOfRedactor / 2;
602
+ private genInfoForMouseSelection(): {index: number | undefined} {
603
+ const { UI } = this.Blok;
604
+ const redactor = UI.nodes.redactor;
605
+ const redactorRect = redactor.getBoundingClientRect();
606
+ const centerOfRedactor = redactorRect.left + redactorRect.width / 2;
593
607
  const scrollTop = this.getScrollTop();
594
608
  const y = this.mouseY - scrollTop;
595
609
 
596
610
  // For page-wide selection: check what block is at the center X, but at the mouse's Y position
597
611
  // This allows selection to work even when mouse is in the left/right margins
598
612
  const elementUnderMouse = document.elementFromPoint(centerOfRedactor, y);
599
- const lastBlockHolder = this.Blok.BlockManager.lastBlock?.holder;
600
- const contentElement = lastBlockHolder?.querySelector(createSelector(DATA_ATTR.elementContent));
601
- const contentWidth = contentElement ? Number.parseInt(window.getComputedStyle(contentElement).width, 10) : 0;
602
- const centerOfBlock = contentWidth / 2;
603
- const leftPos = centerOfRedactor - centerOfBlock;
604
- const rightPos = centerOfRedactor + centerOfBlock;
605
613
 
606
614
  if (!elementUnderMouse) {
607
615
  return {
608
616
  index: undefined,
609
- leftPos,
610
- rightPos,
611
617
  };
612
618
  }
613
619
  const blockInCurrentPos = this.Blok.BlockManager.getBlockByChildNode(elementUnderMouse);
614
- const rootBlock = blockInCurrentPos !== undefined
615
- ? this.Blok.BlockManager.resolveToRootBlock(blockInCurrentPos)
616
- : undefined;
617
620
 
618
- const index = rootBlock !== undefined
619
- ? this.Blok.BlockManager.blocks.findIndex((block) => block.holder === rootBlock.holder)
621
+ const index = blockInCurrentPos !== undefined
622
+ ? this.Blok.BlockManager.blocks.indexOf(blockInCurrentPos)
620
623
  : undefined;
621
624
 
622
625
  return {
623
626
  index,
624
- leftPos,
625
- rightPos,
626
627
  };
627
628
  }
628
629
 
@@ -660,83 +661,75 @@ export class RectangleSelection extends Module {
660
661
  }
661
662
 
662
663
  /**
663
- * Adds a block to the selection and determines which blocks should be selected
664
- * @param {object} index - index of new block in the reactor
664
+ * Adds a block to the selection and determines which blocks should be selected.
665
+ * Uses geometry-based approach: tracks an anchor block index and computes the
666
+ * expected range [min(anchor, current), max(anchor, current)] on each call.
667
+ * @param {number} index - index of new block in the reactor
665
668
  */
666
669
  private trySelectNextBlock(index: number): void {
667
- const sizeStack = this.stackOfSelected.length;
668
- const lastSelected = this.stackOfSelected[sizeStack - 1];
669
- const sameBlock = lastSelected === index;
670
-
671
- if (sameBlock) {
672
- return;
670
+ if (this.anchorBlockIndex === null) {
671
+ this.anchorBlockIndex = index;
673
672
  }
674
673
 
675
- const previousSelected = this.stackOfSelected[sizeStack - 2];
676
- const blockNumbersIncrease = previousSelected !== undefined && lastSelected !== undefined
677
- ? lastSelected - previousSelected > 0
678
- : false;
679
- const isInitialSelection = sizeStack <= 1;
680
- const selectionInDownDirection = lastSelected !== undefined && index > lastSelected && blockNumbersIncrease;
681
- const selectionInUpDirection = lastSelected !== undefined && index < lastSelected && sizeStack > 1 && !blockNumbersIncrease;
682
- const generalSelection = selectionInDownDirection || selectionInUpDirection || isInitialSelection;
683
- const reduction = !generalSelection;
684
-
685
- // When the selection is too fast, some blocks do not have time to be noticed. Fix it.
686
- if (!reduction && (lastSelected === undefined || index > lastSelected)) {
687
- const startIndex = lastSelected !== undefined ? lastSelected + 1 : index;
688
-
689
- Array.from({ length: index - startIndex + 1 }, (_unused, offset) => startIndex + offset)
690
- .forEach((ind) => {
691
- this.addBlockInSelection(ind);
692
- });
674
+ const blocks = this.Blok.BlockManager.blocks;
675
+ const anchorBlock = blocks[this.anchorBlockIndex];
676
+ const currentBlock = blocks[index];
693
677
 
678
+ if (!anchorBlock || !currentBlock) {
694
679
  return;
695
680
  }
696
681
 
697
- // for both directions
698
- if (!reduction && lastSelected !== undefined && index < lastSelected) {
699
- Array.from(
700
- { length: lastSelected - index },
701
- (_unused, offset) => lastSelected - 1 - offset
702
- ).forEach((ind) => {
703
- this.addBlockInSelection(ind);
704
- });
682
+ const anchorRect = anchorBlock.holder.getBoundingClientRect();
683
+ const currentRect = currentBlock.holder.getBoundingClientRect();
705
684
 
706
- return;
707
- }
685
+ /**
686
+ * Constrain the selection range to the actual rubber band coordinates.
687
+ * Without this, the range extends to the full bounding box of the anchor/current blocks,
688
+ * which can select blocks that are visually outside the rubber band rectangle.
689
+ */
690
+ const scrollTop = this.getScrollTop();
691
+ const rubberBandMinY = Math.min(this.startY, this.mouseY) - scrollTop;
692
+ const rubberBandMaxY = Math.max(this.startY, this.mouseY) - scrollTop;
708
693
 
709
- if (!reduction) {
710
- return;
711
- }
694
+ const minY = Math.max(Math.min(anchorRect.top, currentRect.top), rubberBandMinY);
695
+ const maxY = Math.min(Math.max(anchorRect.bottom, currentRect.bottom), rubberBandMaxY);
712
696
 
713
- const shouldRemove = (stackIndex: number): boolean => {
714
- if (lastSelected === undefined) {
715
- return false;
716
- }
697
+ const scrollLeft = this.getScrollLeft();
698
+ const rubberBandMinX = Math.min(this.startX, this.mouseX) - scrollLeft;
699
+ const rubberBandMaxX = Math.max(this.startX, this.mouseX) - scrollLeft;
717
700
 
718
- if (index > lastSelected) {
719
- return index > stackIndex;
720
- }
701
+ const expectedIndices = new Set<number>();
721
702
 
722
- return index < stackIndex;
723
- };
703
+ blocks.forEach((block, i) => {
704
+ const blockRect = block.holder.getBoundingClientRect();
705
+ const blockContentEl = block.holder.querySelector<HTMLElement>('[data-blok-element-content]');
706
+ const blockContentRect = (blockContentEl ?? block.holder).getBoundingClientRect();
724
707
 
725
- const indicesToRemove: number[] = [];
708
+ const xOverlaps = rubberBandMinX === rubberBandMaxX || (blockContentRect.right > rubberBandMinX && blockContentRect.left < rubberBandMaxX);
726
709
 
727
- for (const stackIndex of [ ...this.stackOfSelected ].reverse()) {
728
- if (!shouldRemove(stackIndex)) {
729
- break;
710
+ // Include blocks that have visual height and overlap the selection range
711
+ if (blockRect.height > 0 && blockRect.bottom > minY && blockRect.top < maxY && xOverlaps) {
712
+ expectedIndices.add(i);
730
713
  }
714
+ });
731
715
 
732
- if (this.rectCrossesBlocks) {
733
- this.Blok.BlockSelection.unSelectBlockByIndex(stackIndex);
716
+ const previousStack = new Set(this.stackOfSelected);
717
+
718
+ // Deselect blocks no longer in range
719
+ for (const prevIndex of previousStack) {
720
+ if (!expectedIndices.has(prevIndex) && this.rectCrossesBlocks) {
721
+ this.Blok.BlockSelection.unSelectBlockByIndex(prevIndex);
734
722
  }
735
- indicesToRemove.push(stackIndex);
736
723
  }
737
724
 
738
- if (indicesToRemove.length > 0) {
739
- this.stackOfSelected.splice(this.stackOfSelected.length - indicesToRemove.length, indicesToRemove.length);
725
+ // Select blocks newly in range
726
+ for (const expectedIndex of expectedIndices) {
727
+ if (!previousStack.has(expectedIndex) && this.rectCrossesBlocks) {
728
+ this.Blok.BlockSelection.selectBlockByIndex(expectedIndex);
729
+ }
740
730
  }
731
+
732
+ // Replace stack with the visually selected indices
733
+ this.stackOfSelected = Array.from(expectedIndices).sort((a, b) => a - b);
741
734
  }
742
735
  }
@@ -183,7 +183,7 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
183
183
  this.Blok.BlockSelection.clearCache();
184
184
  }
185
185
 
186
- /** Get tool's settings data - only relevant for single block selection */
186
+ /** Get tool-specific tunes and common tunes (delete, move, etc.) */
187
187
  const { toolTunes, commonTunes } = block.getTunes();
188
188
 
189
189
  const PopoverClass = isMobileScreen() ? PopoverMobile : PopoverDesktop;
@@ -196,6 +196,7 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
196
196
  nothingFound: this.Blok.I18n.t('popover.nothingFound'),
197
197
  search: this.Blok.I18n.t('popover.search'),
198
198
  },
199
+ autoFocusFirstItem: false,
199
200
  };
200
201
 
201
202
  if (PopoverClass === PopoverDesktop) {
@@ -292,18 +293,20 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
292
293
 
293
294
  /**
294
295
  * Returns list of items to be displayed in block tunes menu.
295
- * Merges tool specific tunes, conversion menu and common tunes in one list in predefined order
296
+ * Merges conversion menu, tool-specific tunes, and common tunes in one list in predefined order
296
297
  * @param currentBlock – block we are about to open block tunes for
297
298
  * @param commonTunes – common tunes
298
- * @param toolTunes - tool specific tunes
299
+ * @param toolTunes tool-specific tunes from renderSettings()
299
300
  */
300
301
  private async getTunesItems(currentBlock: Block, commonTunes: MenuConfigItem[], toolTunes?: MenuConfigItem[]): Promise<PopoverItemParams[]> {
301
302
  const items = [] as MenuConfigItem[];
302
303
  const selectedBlocks = this.Blok.BlockSelection.selectedBlocks;
303
304
  const hasMultipleBlocksSelected = selectedBlocks.length > 1;
304
305
 
306
+ const allBlockTools = Array.from(this.Blok.Tools.blockTools.values());
307
+
305
308
  /**
306
- * Only show tool-specific tunes when a single block is selected
309
+ * Tool-specific tunes come first (e.g. heading level selector)
307
310
  */
308
311
  if (!hasMultipleBlocksSelected && toolTunes !== undefined && toolTunes.length > 0) {
309
312
  items.push(...toolTunes);
@@ -312,8 +315,6 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
312
315
  });
313
316
  }
314
317
 
315
- const allBlockTools = Array.from(this.Blok.Tools.blockTools.values());
316
-
317
318
  /**
318
319
  * Get convertible tools based on selection:
319
320
  * - For single block: use existing single-block conversion logic
@@ -340,6 +341,23 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
340
341
  onActivate: async () => {
341
342
  const { Caret, Toolbar } = this.Blok;
342
343
 
344
+ // Warn before converting a block that has nested children — they will be
345
+ // promoted to sibling level (or lost if the host cannot hold children).
346
+ const childCount = currentBlock.contentIds.length;
347
+
348
+ if (childCount > 0) {
349
+ const message = this.Blok.I18n.t('blockSettings.convertWithChildrenWarning', {
350
+ count: childCount,
351
+ });
352
+ const fallback = `This block has ${childCount} nested block${childCount === 1 ? '' : 's'}. Converting it will promote them to the top level. Continue?`;
353
+ // eslint-disable-next-line no-alert
354
+ const confirmed = window.confirm(message !== 'blockSettings.convertWithChildrenWarning' ? message : fallback);
355
+
356
+ if (!confirmed) {
357
+ return;
358
+ }
359
+ }
360
+
343
361
  const newBlock = await this.convertBlock(
344
362
  currentBlock,
345
363
  selectedBlocks,
@@ -375,7 +393,7 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
375
393
  }
376
394
 
377
395
  /**
378
- * For single block selection, show all common tunes (delete, move, etc.)
396
+ * For single block selection, show common tunes (delete, move, etc.)
379
397
  * For multiple blocks, only show delete option with multi-block delete behavior
380
398
  */
381
399
  if (!hasMultipleBlocksSelected) {
@@ -586,6 +586,15 @@ export class Toolbar extends Module<ToolbarNodes> {
586
586
  // Only set explicitlyClosed if not explicitly disabled (e.g., when called from toolbox after block insertion)
587
587
  if (options?.setExplicitlyClosed !== false) {
588
588
  this.explicitlyClosed = true;
589
+
590
+ /**
591
+ * Reset the BlockHoverController's lastHoveredBlockId so that the next
592
+ * mousemove over the same block re-emits BlockHovered.
593
+ * Without this, deduplication in BlockHoverController suppresses the event
594
+ * and the toolbar can never reopen on the same block after being closed by
595
+ * a mousedown (e.g. from RectangleSelection.startSelection).
596
+ */
597
+ this.Blok.UI.resetBlockHoverState();
589
598
  }
590
599
 
591
600
  /**
@@ -761,13 +770,6 @@ export class Toolbar extends Module<ToolbarNodes> {
761
770
  const actions = $.make('div', [
762
771
  // eslint-disable-next-line @typescript-eslint/no-deprecated -- CSS getter now returns Tailwind classes
763
772
  this.CSS.actions,
764
- // Narrow mode positioning on non-mobile screens
765
- 'not-mobile:group-data-[blok-narrow=true]:right-[calc(-1*(var(--spacing-narrow-mode-right-padding))-5px)]',
766
- // RTL narrow mode: use left positioning instead
767
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:right-auto',
768
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:left-[calc(-1*(var(--spacing-narrow-mode-right-padding))-5px)]',
769
- // RTL narrow mode additional left offset
770
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:left-[-5px]',
771
773
  ]);
772
774
 
773
775
  this.nodes.content = content;
@@ -351,7 +351,12 @@ export class InlineToolbar extends Module<InlineToolbarNodes> {
351
351
  return;
352
352
  }
353
353
 
354
- const wrapperOffset = this.Blok.UI.nodes.wrapper.getBoundingClientRect();
354
+ const uiWrapper = this.Blok.UI.nodes.wrapper;
355
+ const offsetParent = this.nodes.wrapper.offsetParent as HTMLElement | null;
356
+ const isContainedByUiWrapper = offsetParent === uiWrapper;
357
+ const wrapperOffset = isContainedByUiWrapper
358
+ ? uiWrapper.getBoundingClientRect()
359
+ : new DOMRect(0, 0, 0, 0);
355
360
  const contentRect = this.Blok.UI.contentRect;
356
361
  const selectionRect = SelectionUtils.rect;
357
362
 
@@ -99,14 +99,10 @@ export class PlusButtonHandler {
99
99
  // Keep hover background when toolbox is open
100
100
  'group-data-[blok-toolbox-opened=true]:bg-bg-light',
101
101
  // Mobile styles (static positioning with overlay-pane appearance)
102
- 'mobile:bg-white mobile:border mobile:border-[#e8e8eb] mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
102
+ 'mobile:bg-popover-bg mobile:border mobile:border-mobile-border mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
103
103
  'mobile:w-toolbox-btn-mobile mobile:h-toolbox-btn-mobile',
104
104
  // RTL styles
105
- 'group-data-[blok-rtl=true]:right-[calc(-1*(var(--spacing-toolbox-btn)))] group-data-[blok-rtl=true]:left-auto',
106
- // Narrow mode (not-mobile)
107
- 'not-mobile:group-data-[blok-narrow=true]:left-[5px]',
108
- // Narrow mode RTL (not-mobile)
109
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:left-0 not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:right-[5px]'
105
+ 'group-data-[blok-rtl=true]:right-[calc(-1*(var(--spacing-toolbox-btn)))] group-data-[blok-rtl=true]:left-auto'
110
106
  ),
111
107
  ], {
112
108
  innerHTML: IconPlus,
@@ -76,7 +76,16 @@ export class ToolbarPositioner {
76
76
  * to properly center the toolbar on the text, not on the marker which may have different font-size
77
77
  */
78
78
  const textElement = listItemElement?.querySelector('[contenteditable]');
79
- const contentElement = textElement ?? listItemElement ?? targetBlock.pluginsContent;
79
+ const pluginsContent = targetBlock.pluginsContent;
80
+ /**
81
+ * If pluginsContent is a non-editable container (e.g. a toggle heading wrapper <div>),
82
+ * use its first contenteditable descendant for accurate line-height centering.
83
+ */
84
+ const editableDescendant =
85
+ !pluginsContent.matches('[contenteditable]')
86
+ ? (pluginsContent.querySelector('[contenteditable]') ?? null)
87
+ : null;
88
+ const contentElement = textElement ?? listItemElement ?? editableDescendant ?? pluginsContent;
80
89
  const contentRect = contentElement.getBoundingClientRect();
81
90
  const contentOffset = contentRect.top - holderRect.top;
82
91
 
@@ -126,7 +126,7 @@ export class SettingsTogglerHandler {
126
126
  'group-data-[blok-block-settings-opened=true]:bg-bg-light',
127
127
  'can-hover:hover:group-data-[blok-block-settings-opened=true]:cursor-pointer',
128
128
  // Mobile styles (static positioning with overlay-pane appearance)
129
- 'mobile:bg-white mobile:border mobile:border-[#e8e8eb] mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
129
+ 'mobile:bg-popover-bg mobile:border mobile:border-mobile-border mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
130
130
  'mobile:w-toolbox-btn-mobile mobile:h-toolbox-btn-mobile'
131
131
  ),
132
132
  'group-data-[blok-dragging=true]:cursor-grabbing',
@@ -40,14 +40,10 @@ export const getToolbarStyles = (): { [name: string]: string } => {
40
40
  // Keep hover background when toolbox is opened
41
41
  'group-data-[blok-toolbox-opened=true]:bg-bg-light',
42
42
  // Mobile styles (static positioning with overlay-pane appearance)
43
- 'mobile:bg-white mobile:border mobile:border-[#e8e8eb] mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
43
+ 'mobile:bg-popover-bg mobile:border mobile:border-mobile-border mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
44
44
  'mobile:w-toolbox-btn-mobile mobile:h-toolbox-btn-mobile',
45
45
  // RTL styles
46
- 'group-data-[blok-rtl=true]:right-[calc(-1*(var(--spacing-toolbox-btn)))] group-data-[blok-rtl=true]:left-auto',
47
- // Narrow mode (not-mobile)
48
- 'not-mobile:group-data-[blok-narrow=true]:left-[5px]',
49
- // Narrow mode RTL (not-mobile)
50
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:left-0 not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:right-[5px]'
46
+ 'group-data-[blok-rtl=true]:right-[calc(-1*(var(--spacing-toolbox-btn)))] group-data-[blok-rtl=true]:left-auto'
51
47
  ),
52
48
  plusButtonShortcutKey: 'text-white',
53
49
  /**
@@ -69,7 +65,7 @@ export const getToolbarStyles = (): { [name: string]: string } => {
69
65
  'group-data-[blok-block-settings-opened=true]:bg-bg-light',
70
66
  'can-hover:hover:group-data-[blok-block-settings-opened=true]:cursor-pointer',
71
67
  // Mobile styles (static positioning with overlay-pane appearance)
72
- 'mobile:bg-white mobile:border mobile:border-[#e8e8eb] mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
68
+ 'mobile:bg-popover-bg mobile:border mobile:border-mobile-border mobile:shadow-overlay-pane mobile:rounded-[6px] mobile:z-2',
73
69
  'mobile:w-toolbox-btn-mobile mobile:h-toolbox-btn-mobile',
74
70
  // Not-mobile styles
75
71
  'not-mobile:w-6'
@@ -65,6 +65,9 @@ export class UI extends Module<UINodes> {
65
65
  private documentClickedHandler: ((event: MouseEvent) => void) | null = null;
66
66
  private redactorTouchHandler: ((event: Event) => void) | null = null;
67
67
 
68
+ /** Unique style tag ID for this instance's font override, derived from the holder element */
69
+ private fontStyleTagId: string | null = null;
70
+
68
71
  /**
69
72
  * Reset the block hover state (used after drag cancellation to allow toolbar to show again)
70
73
  */
@@ -148,6 +151,7 @@ export class UI extends Module<UINodes> {
148
151
  * Load and append CSS
149
152
  */
150
153
  this.loadStyles();
154
+ this.loadFontStyles();
151
155
 
152
156
  /**
153
157
  * Register this Blok instance with the accessibility announcer
@@ -370,6 +374,14 @@ export class UI extends Module<UINodes> {
370
374
  this.unbindReadOnlyInsensitiveListeners();
371
375
  this.unbindReadOnlySensitiveListeners();
372
376
 
377
+ // Remove the per-instance font style tag to prevent leaks in SPAs
378
+ if (this.fontStyleTagId !== null) {
379
+ const fontStyleTag = $.get(this.fontStyleTagId);
380
+ if (fontStyleTag) {
381
+ fontStyleTag.remove();
382
+ }
383
+ }
384
+
373
385
  // Clean up accessibility announcer
374
386
  destroyAnnouncer();
375
387
  }
@@ -454,11 +466,11 @@ export class UI extends Module<UINodes> {
454
466
  this.nodes.wrapper.setAttribute(DATA_ATTR.rtl, 'true');
455
467
  }
456
468
  this.nodes.redactor = $.make('div', [
457
- // Narrow mode: add right margin on non-mobile screens
458
- 'not-mobile:group-data-[blok-narrow=true]:mr-(--spacing-narrow-mode-right-padding)',
459
- // RTL narrow mode: add left margin instead
460
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:ml-(--spacing-narrow-mode-right-padding)',
461
- 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:mr-0',
469
+ // Narrow mode: add left margin on non-mobile screens to make room for toolbar buttons
470
+ 'not-mobile:group-data-[blok-narrow=true]:ml-(--spacing-narrow-mode-padding)',
471
+ // RTL narrow mode: add right margin instead
472
+ 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:mr-(--spacing-narrow-mode-padding)',
473
+ 'not-mobile:group-data-[blok-rtl=true]:group-data-[blok-narrow=true]:ml-0',
462
474
  // Firefox empty contenteditable fix
463
475
  '[&_[contenteditable]:empty]:after:content-["\\feff_"]',
464
476
  ]);
@@ -527,6 +539,48 @@ export class UI extends Module<UINodes> {
527
539
  $.prepend(document.head, tag);
528
540
  }
529
541
 
542
+ /**
543
+ * Injects a font-family override stylesheet when config.style.fontFamily is set.
544
+ * Uses a separate <style> tag so it applies even when blok-styles already exists
545
+ * (multiple editor instances on the same page).
546
+ */
547
+ private loadFontStyles(): void {
548
+ const fontFamily = this.config.style?.fontFamily;
549
+
550
+ if (!fontFamily) {
551
+ return;
552
+ }
553
+
554
+ const holderId = this.nodes.holder.id !== '' ? this.nodes.holder.id : (this.nodes.wrapper.dataset['blokInterface'] ?? 'default');
555
+ const styleTagId = `blok-font-${holderId}`;
556
+
557
+ this.fontStyleTagId = styleTagId;
558
+
559
+ if ($.get(styleTagId)) {
560
+ return;
561
+ }
562
+
563
+ const css = [
564
+ `[data-blok-interface=blok], [data-blok-interface=tooltip] {`,
565
+ ` --blok-font-family: ${fontFamily};`,
566
+ `}`,
567
+ `[data-blok-popover]:not([data-blok-popover-inline]) {`,
568
+ ` --blok-font-family: ${fontFamily};`,
569
+ `}`,
570
+ ].join('\n');
571
+
572
+ const tag = $.make('style', null, {
573
+ id: styleTagId,
574
+ textContent: css,
575
+ });
576
+
577
+ if (this.config.style?.nonce) {
578
+ tag.setAttribute('nonce', this.config.style.nonce);
579
+ }
580
+
581
+ $.prepend(document.head, tag);
582
+ }
583
+
530
584
  /**
531
585
  * Adds listeners that should work both in read-only and read-write modes
532
586
  */
@@ -109,9 +109,10 @@ export const createDocumentClickedHandler = (
109
109
  /**
110
110
  * Clear Selection if user clicked somewhere
111
111
  * But preserve selection when clicking on block settings toggler or inside block settings
112
- * to allow multi-block operations like conversion
112
+ * to allow multi-block operations like conversion.
113
+ * Also preserve selection when Shift is held (additive Shift+drag rubber band selection).
113
114
  */
114
- if (!context.doNotProcess) {
115
+ if (!context.doNotProcess && !event.shiftKey) {
115
116
  Blok.BlockSelection.clearSelection(event);
116
117
  }
117
118
 
@@ -0,0 +1,69 @@
1
+ import { Module } from '../__module';
2
+
3
+ const DEFAULT_NARROW_WIDTH = '650px';
4
+ const DEFAULT_FULL_WIDTH = '100%';
5
+ const CSS_VAR = '--blok-content-width';
6
+
7
+ /**
8
+ * Manages the editor-level width mode.
9
+ *
10
+ * Applies a CSS custom property (--blok-content-width) to the editor wrapper
11
+ * element, which block content elements read via CSS cascade.
12
+ */
13
+ export class WidthManager extends Module {
14
+ private currentMode: 'narrow' | 'full' = 'narrow';
15
+
16
+ /**
17
+ * Called by Core after all modules are constructed and wired.
18
+ */
19
+ public prepare(): void {
20
+ const initialMode = this.config.defaultWidth ?? 'narrow';
21
+ this.currentMode = initialMode;
22
+ this.applyWidth(initialMode);
23
+ }
24
+
25
+ /**
26
+ * Returns the current width mode.
27
+ */
28
+ public getWidth(): 'narrow' | 'full' {
29
+ return this.currentMode;
30
+ }
31
+
32
+ /**
33
+ * Sets the editor width mode.
34
+ * No-op if already in the requested mode.
35
+ */
36
+ public setWidth(mode: 'narrow' | 'full'): void {
37
+ if (this.currentMode === mode) {
38
+ return;
39
+ }
40
+ this.currentMode = mode;
41
+ this.applyWidth(mode);
42
+
43
+ const callback = this.config.onWidthChange;
44
+ if (typeof callback === 'function') {
45
+ callback(mode, this.resolveValue(mode));
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Toggles between 'narrow' and 'full'.
51
+ */
52
+ public toggle(): void {
53
+ this.setWidth(this.currentMode === 'narrow' ? 'full' : 'narrow');
54
+ }
55
+
56
+ // ─── Private ───────────────────────────────────────────────────────────────
57
+
58
+ private applyWidth(mode: 'narrow' | 'full'): void {
59
+ const value = this.resolveValue(mode);
60
+ this.Blok.UI.nodes.wrapper.style.setProperty(CSS_VAR, value);
61
+ }
62
+
63
+ private resolveValue(mode: 'narrow' | 'full'): string {
64
+ if (mode === 'narrow') {
65
+ return this.config.narrowWidth ?? DEFAULT_NARROW_WIDTH;
66
+ }
67
+ return this.config.fullWidth ?? DEFAULT_FULL_WIDTH;
68
+ }
69
+ }
@@ -212,6 +212,17 @@ export class DocumentStore {
212
212
  this.ydoc.transact(fn, origin);
213
213
  }
214
214
 
215
+ /**
216
+ * Execute Yjs operations without adding them to the undo history.
217
+ * Uses a non-tracked origin so the UndoManager ignores these changes.
218
+ * Use this for auto-repair operations (e.g. ensuring empty cells have a block)
219
+ * that should never be undoable by the user.
220
+ * @param fn - Function containing Yjs operations to execute
221
+ */
222
+ public transactWithoutCapture(fn: () => void): void {
223
+ this.ydoc.transact(fn, 'no-capture');
224
+ }
225
+
215
226
  /**
216
227
  * Get existing tunes Y.Map or create a new one.
217
228
  * @param yblock - The block Y.Map