@jackuait/blok 0.6.0 → 0.7.0-beta.2

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 (257) hide show
  1. package/README.md +20 -4
  2. package/dist/blok.mjs +2 -2
  3. package/dist/chunks/{blok-BAh1rvUC.mjs → blok-D9Rs29Wo.mjs} +1928 -1793
  4. package/dist/chunks/{inline-tool-convert-DduRc0fF.mjs → constants-DmNIR3I8.mjs} +596 -475
  5. package/dist/chunks/{i18next-loader-CHtGO6IK.mjs → i18next-loader-C2-jYpLi.mjs} +1 -1
  6. package/dist/chunks/index-D7V1g7Oq.mjs +130 -0
  7. package/dist/chunks/{messages-D2NOpHn9.mjs → messages-0Pxnqd4N.mjs} +7 -0
  8. package/dist/chunks/{messages-GSByFygY.mjs → messages-0ZXYUq7S.mjs} +7 -0
  9. package/dist/{messages-BUl_Rcnj.mjs → chunks/messages-2OD2uUDS.mjs} +9 -2
  10. package/dist/{messages-CgTq3QhU.mjs → chunks/messages-7cEMfYzh.mjs} +7 -0
  11. package/dist/{messages-DlJbPF2T.mjs → chunks/messages-8mwfda1Q.mjs} +7 -0
  12. package/dist/{messages-D9ndgBnU.mjs → chunks/messages-B-FqWsBM.mjs} +7 -0
  13. package/dist/{messages-B217znr-.mjs → chunks/messages-B1jzqWiQ.mjs} +7 -0
  14. package/dist/{messages-BcpCubnC.mjs → chunks/messages-B5wk4Ezz.mjs} +7 -0
  15. package/dist/chunks/{messages-DRXWF0PV.mjs → messages-BAZ5Ld8x.mjs} +7 -0
  16. package/dist/{messages-CRJ_mchV.mjs → chunks/messages-BBhGp198.mjs} +7 -0
  17. package/dist/chunks/{messages-yHcs38yI.mjs → messages-BC9IjIb7.mjs} +7 -0
  18. package/dist/chunks/{messages-Cr94GzbX.mjs → messages-BFEmpeV-.mjs} +7 -0
  19. package/dist/chunks/{messages-ucTVgS5G.mjs → messages-BGqzTZy0.mjs} +7 -0
  20. package/dist/{messages-begYOTgC.mjs → chunks/messages-BICs1abK.mjs} +7 -0
  21. package/dist/chunks/{messages-DVQvl8Qj.mjs → messages-BJX6rOnd.mjs} +7 -0
  22. package/dist/chunks/{messages-Chb7k3Rg.mjs → messages-BL2bXRhN.mjs} +7 -0
  23. package/dist/{messages-Phkd7XmE.mjs → chunks/messages-BMs5qdlH.mjs} +7 -0
  24. package/dist/chunks/{messages-Cjjo7yHR.mjs → messages-BRsjUNwB.mjs} +7 -0
  25. package/dist/chunks/{messages-D4qqwVgQ.mjs → messages-BSqV8OUR.mjs} +7 -0
  26. package/dist/chunks/{messages-DviiFSv2.mjs → messages-BTqu3DfG.mjs} +7 -0
  27. package/dist/chunks/{messages-0AbcLMLm.mjs → messages-BXnDEsur.mjs} +7 -0
  28. package/dist/{messages-CmR9ftc_.mjs → chunks/messages-BYcre4-6.mjs} +7 -0
  29. package/dist/{messages-wmi-iFkH.mjs → chunks/messages-BZ9LRJf-.mjs} +7 -0
  30. package/dist/chunks/{messages-D00x4S8o.mjs → messages-BgypBy7y.mjs} +7 -0
  31. package/dist/{messages-96kNZDll.mjs → chunks/messages-BsuGf70G.mjs} +7 -0
  32. package/dist/chunks/{messages-v3GipbFl.mjs → messages-BwaoF4lQ.mjs} +7 -0
  33. package/dist/{messages-DDTQgImT.mjs → chunks/messages-C1l8_7-y.mjs} +7 -0
  34. package/dist/{messages-B1FZ8lxU.mjs → chunks/messages-C5NA_r9v.mjs} +7 -0
  35. package/dist/{messages-Cs8zmZ3L.mjs → chunks/messages-C6zgZ5pA.mjs} +7 -0
  36. package/dist/chunks/{messages-ZjUAIWb1.mjs → messages-CAo5ghFI.mjs} +7 -0
  37. package/dist/{messages-D5S1Dnpm.mjs → chunks/messages-CH9qlJ9I.mjs} +7 -0
  38. package/dist/{messages-D7u2bmP2.mjs → chunks/messages-CI0HqAeS.mjs} +7 -0
  39. package/dist/{messages-DH_jBeED.mjs → chunks/messages-CJJtms9k.mjs} +7 -0
  40. package/dist/{messages-CDBLbUOQ.mjs → chunks/messages-CM2hJqk6.mjs} +7 -0
  41. package/dist/chunks/{messages-8IPXkrDl.mjs → messages-CRMiDPIQ.mjs} +7 -0
  42. package/dist/chunks/{messages-Dzzn6XoD.mjs → messages-CWsZuBj1.mjs} +7 -0
  43. package/dist/chunks/{messages-CW4c4cRk.mjs → messages-C_gLHo6A.mjs} +7 -0
  44. package/dist/{messages-CH4hrauY.mjs → chunks/messages-Cbu-NUDn.mjs} +7 -0
  45. package/dist/{messages-RonBBCnh.mjs → chunks/messages-Cjb_MCeh.mjs} +7 -0
  46. package/dist/chunks/{messages-BJ6zrz2j.mjs → messages-ClXYO9Wn.mjs} +7 -0
  47. package/dist/chunks/{messages-CrCYPCk3.mjs → messages-CsH20vhP.mjs} +7 -0
  48. package/dist/{messages-CzK0LEhb.mjs → chunks/messages-CsjAGhzA.mjs} +7 -0
  49. package/dist/chunks/{messages-BZlmVRwn.mjs → messages-Cx7VKFOE.mjs} +7 -0
  50. package/dist/chunks/{messages-0E0AkrNu.mjs → messages-D3JeBwxo.mjs} +7 -0
  51. package/dist/chunks/{messages-D85FqxgY.mjs → messages-D541fieJ.mjs} +7 -0
  52. package/dist/{messages-4v4MuVEc.mjs → chunks/messages-D7XPdglc.mjs} +7 -0
  53. package/dist/{messages-BC8IN4Bf.mjs → chunks/messages-DBhylfvt.mjs} +7 -0
  54. package/dist/chunks/{messages-B8WNljW3.mjs → messages-DCA120lW.mjs} +7 -0
  55. package/dist/chunks/{messages-Cr49Nt3U.mjs → messages-DCf_xZMN.mjs} +7 -0
  56. package/dist/chunks/{messages-VDriF5Qy.mjs → messages-DDwXKCpe.mjs} +7 -0
  57. package/dist/{messages-b1EdvUm0.mjs → chunks/messages-DNKDlxcy.mjs} +7 -0
  58. package/dist/{messages-L_kl2Qvh.mjs → chunks/messages-DPvEjrGK.mjs} +7 -0
  59. package/dist/chunks/{messages-62v-CLC-.mjs → messages-DQ-AkNxA.mjs} +7 -0
  60. package/dist/chunks/{messages-DdK-nFGm.mjs → messages-DVuvkNap.mjs} +7 -0
  61. package/dist/{messages-DnVlmiNT.mjs → chunks/messages-DaglyqUT.mjs} +7 -0
  62. package/dist/{messages-Bm-E4iRC.mjs → chunks/messages-Di0bAfwA.mjs} +7 -0
  63. package/dist/{messages-D1mn7Zd5.mjs → chunks/messages-DuLct0Yr.mjs} +7 -0
  64. package/dist/{messages-8DeO60Oo.mjs → chunks/messages-DzEYYhZh.mjs} +7 -0
  65. package/dist/chunks/{messages-CfiyT2Wi.mjs → messages-DznNGAB2.mjs} +7 -0
  66. package/dist/chunks/{messages-DXktiao_.mjs → messages-DzoIzyu8.mjs} +7 -0
  67. package/dist/{messages-C_4otP7U.mjs → chunks/messages-QYOGmket.mjs} +7 -0
  68. package/dist/chunks/{messages-nefz1S71.mjs → messages-cEjGDAgI.mjs} +7 -0
  69. package/dist/chunks/{messages-jrncnb-H.mjs → messages-ddhvrdpE.mjs} +7 -0
  70. package/dist/chunks/{messages-DzqM3Fel.mjs → messages-mwfNK5nZ.mjs} +7 -0
  71. package/dist/chunks/{messages-Cl6ayUaq.mjs → messages-nG_vNDte.mjs} +7 -0
  72. package/dist/{messages-C4jL-90N.mjs → chunks/messages-tDq3Owh7.mjs} +7 -0
  73. package/dist/{messages-BI43k_BD.mjs → chunks/messages-x6VJVZKx.mjs} +7 -0
  74. package/dist/full.mjs +30 -27
  75. package/dist/locales.mjs +87 -80
  76. package/dist/{messages-D2NOpHn9.mjs → messages-0Pxnqd4N.mjs} +7 -0
  77. package/dist/{messages-GSByFygY.mjs → messages-0ZXYUq7S.mjs} +7 -0
  78. package/dist/{chunks/messages-BUl_Rcnj.mjs → messages-2OD2uUDS.mjs} +9 -2
  79. package/dist/{chunks/messages-CgTq3QhU.mjs → messages-7cEMfYzh.mjs} +7 -0
  80. package/dist/{chunks/messages-DlJbPF2T.mjs → messages-8mwfda1Q.mjs} +7 -0
  81. package/dist/{chunks/messages-D9ndgBnU.mjs → messages-B-FqWsBM.mjs} +7 -0
  82. package/dist/{chunks/messages-B217znr-.mjs → messages-B1jzqWiQ.mjs} +7 -0
  83. package/dist/{chunks/messages-BcpCubnC.mjs → messages-B5wk4Ezz.mjs} +7 -0
  84. package/dist/{messages-DRXWF0PV.mjs → messages-BAZ5Ld8x.mjs} +7 -0
  85. package/dist/{chunks/messages-CRJ_mchV.mjs → messages-BBhGp198.mjs} +7 -0
  86. package/dist/{messages-yHcs38yI.mjs → messages-BC9IjIb7.mjs} +7 -0
  87. package/dist/{messages-Cr94GzbX.mjs → messages-BFEmpeV-.mjs} +7 -0
  88. package/dist/{messages-ucTVgS5G.mjs → messages-BGqzTZy0.mjs} +7 -0
  89. package/dist/{chunks/messages-begYOTgC.mjs → messages-BICs1abK.mjs} +7 -0
  90. package/dist/{messages-DVQvl8Qj.mjs → messages-BJX6rOnd.mjs} +7 -0
  91. package/dist/{messages-Chb7k3Rg.mjs → messages-BL2bXRhN.mjs} +7 -0
  92. package/dist/{chunks/messages-Phkd7XmE.mjs → messages-BMs5qdlH.mjs} +7 -0
  93. package/dist/{messages-Cjjo7yHR.mjs → messages-BRsjUNwB.mjs} +7 -0
  94. package/dist/{messages-D4qqwVgQ.mjs → messages-BSqV8OUR.mjs} +7 -0
  95. package/dist/{messages-DviiFSv2.mjs → messages-BTqu3DfG.mjs} +7 -0
  96. package/dist/{messages-0AbcLMLm.mjs → messages-BXnDEsur.mjs} +7 -0
  97. package/dist/{chunks/messages-CmR9ftc_.mjs → messages-BYcre4-6.mjs} +7 -0
  98. package/dist/{chunks/messages-wmi-iFkH.mjs → messages-BZ9LRJf-.mjs} +7 -0
  99. package/dist/{messages-D00x4S8o.mjs → messages-BgypBy7y.mjs} +7 -0
  100. package/dist/{chunks/messages-96kNZDll.mjs → messages-BsuGf70G.mjs} +7 -0
  101. package/dist/{messages-v3GipbFl.mjs → messages-BwaoF4lQ.mjs} +7 -0
  102. package/dist/{chunks/messages-DDTQgImT.mjs → messages-C1l8_7-y.mjs} +7 -0
  103. package/dist/{chunks/messages-B1FZ8lxU.mjs → messages-C5NA_r9v.mjs} +7 -0
  104. package/dist/{chunks/messages-Cs8zmZ3L.mjs → messages-C6zgZ5pA.mjs} +7 -0
  105. package/dist/{messages-ZjUAIWb1.mjs → messages-CAo5ghFI.mjs} +7 -0
  106. package/dist/{chunks/messages-D5S1Dnpm.mjs → messages-CH9qlJ9I.mjs} +7 -0
  107. package/dist/{chunks/messages-D7u2bmP2.mjs → messages-CI0HqAeS.mjs} +7 -0
  108. package/dist/{chunks/messages-DH_jBeED.mjs → messages-CJJtms9k.mjs} +7 -0
  109. package/dist/{chunks/messages-CDBLbUOQ.mjs → messages-CM2hJqk6.mjs} +7 -0
  110. package/dist/{messages-8IPXkrDl.mjs → messages-CRMiDPIQ.mjs} +7 -0
  111. package/dist/{messages-Dzzn6XoD.mjs → messages-CWsZuBj1.mjs} +7 -0
  112. package/dist/{messages-CW4c4cRk.mjs → messages-C_gLHo6A.mjs} +7 -0
  113. package/dist/{chunks/messages-CH4hrauY.mjs → messages-Cbu-NUDn.mjs} +7 -0
  114. package/dist/{chunks/messages-RonBBCnh.mjs → messages-Cjb_MCeh.mjs} +7 -0
  115. package/dist/{messages-BJ6zrz2j.mjs → messages-ClXYO9Wn.mjs} +7 -0
  116. package/dist/{messages-CrCYPCk3.mjs → messages-CsH20vhP.mjs} +7 -0
  117. package/dist/{chunks/messages-CzK0LEhb.mjs → messages-CsjAGhzA.mjs} +7 -0
  118. package/dist/{messages-BZlmVRwn.mjs → messages-Cx7VKFOE.mjs} +7 -0
  119. package/dist/{messages-0E0AkrNu.mjs → messages-D3JeBwxo.mjs} +7 -0
  120. package/dist/{messages-D85FqxgY.mjs → messages-D541fieJ.mjs} +7 -0
  121. package/dist/{chunks/messages-4v4MuVEc.mjs → messages-D7XPdglc.mjs} +7 -0
  122. package/dist/{chunks/messages-BC8IN4Bf.mjs → messages-DBhylfvt.mjs} +7 -0
  123. package/dist/{messages-B8WNljW3.mjs → messages-DCA120lW.mjs} +7 -0
  124. package/dist/{messages-Cr49Nt3U.mjs → messages-DCf_xZMN.mjs} +7 -0
  125. package/dist/{messages-VDriF5Qy.mjs → messages-DDwXKCpe.mjs} +7 -0
  126. package/dist/{chunks/messages-b1EdvUm0.mjs → messages-DNKDlxcy.mjs} +7 -0
  127. package/dist/{chunks/messages-L_kl2Qvh.mjs → messages-DPvEjrGK.mjs} +7 -0
  128. package/dist/{messages-62v-CLC-.mjs → messages-DQ-AkNxA.mjs} +7 -0
  129. package/dist/{messages-DdK-nFGm.mjs → messages-DVuvkNap.mjs} +7 -0
  130. package/dist/{chunks/messages-DnVlmiNT.mjs → messages-DaglyqUT.mjs} +7 -0
  131. package/dist/{chunks/messages-Bm-E4iRC.mjs → messages-Di0bAfwA.mjs} +7 -0
  132. package/dist/{chunks/messages-D1mn7Zd5.mjs → messages-DuLct0Yr.mjs} +7 -0
  133. package/dist/{chunks/messages-8DeO60Oo.mjs → messages-DzEYYhZh.mjs} +7 -0
  134. package/dist/{messages-CfiyT2Wi.mjs → messages-DznNGAB2.mjs} +7 -0
  135. package/dist/{messages-DXktiao_.mjs → messages-DzoIzyu8.mjs} +7 -0
  136. package/dist/{chunks/messages-C_4otP7U.mjs → messages-QYOGmket.mjs} +7 -0
  137. package/dist/{messages-nefz1S71.mjs → messages-cEjGDAgI.mjs} +7 -0
  138. package/dist/{messages-jrncnb-H.mjs → messages-ddhvrdpE.mjs} +7 -0
  139. package/dist/{messages-DzqM3Fel.mjs → messages-mwfNK5nZ.mjs} +7 -0
  140. package/dist/{messages-Cl6ayUaq.mjs → messages-nG_vNDte.mjs} +7 -0
  141. package/dist/{chunks/messages-C4jL-90N.mjs → messages-tDq3Owh7.mjs} +7 -0
  142. package/dist/{chunks/messages-BI43k_BD.mjs → messages-x6VJVZKx.mjs} +7 -0
  143. package/dist/tools.mjs +1233 -801
  144. package/package.json +1 -1
  145. package/src/components/constants/data-attributes.ts +7 -0
  146. package/src/components/i18n/locales/am/messages.json +7 -0
  147. package/src/components/i18n/locales/ar/messages.json +7 -0
  148. package/src/components/i18n/locales/az/messages.json +7 -0
  149. package/src/components/i18n/locales/bg/messages.json +7 -0
  150. package/src/components/i18n/locales/bn/messages.json +7 -0
  151. package/src/components/i18n/locales/bs/messages.json +7 -0
  152. package/src/components/i18n/locales/cs/messages.json +7 -0
  153. package/src/components/i18n/locales/da/messages.json +7 -0
  154. package/src/components/i18n/locales/de/messages.json +7 -0
  155. package/src/components/i18n/locales/dv/messages.json +7 -0
  156. package/src/components/i18n/locales/el/messages.json +7 -0
  157. package/src/components/i18n/locales/en/messages.json +7 -0
  158. package/src/components/i18n/locales/es/messages.json +7 -0
  159. package/src/components/i18n/locales/et/messages.json +7 -0
  160. package/src/components/i18n/locales/fa/messages.json +7 -0
  161. package/src/components/i18n/locales/fi/messages.json +7 -0
  162. package/src/components/i18n/locales/fil/messages.json +7 -0
  163. package/src/components/i18n/locales/fr/messages.json +7 -0
  164. package/src/components/i18n/locales/gu/messages.json +7 -0
  165. package/src/components/i18n/locales/he/messages.json +7 -0
  166. package/src/components/i18n/locales/hi/messages.json +7 -0
  167. package/src/components/i18n/locales/hr/messages.json +7 -0
  168. package/src/components/i18n/locales/hu/messages.json +7 -0
  169. package/src/components/i18n/locales/hy/messages.json +7 -0
  170. package/src/components/i18n/locales/id/messages.json +7 -0
  171. package/src/components/i18n/locales/it/messages.json +7 -0
  172. package/src/components/i18n/locales/ja/messages.json +7 -0
  173. package/src/components/i18n/locales/ka/messages.json +7 -0
  174. package/src/components/i18n/locales/km/messages.json +7 -0
  175. package/src/components/i18n/locales/kn/messages.json +7 -0
  176. package/src/components/i18n/locales/ko/messages.json +7 -0
  177. package/src/components/i18n/locales/ku/messages.json +7 -0
  178. package/src/components/i18n/locales/lo/messages.json +7 -0
  179. package/src/components/i18n/locales/lt/messages.json +7 -0
  180. package/src/components/i18n/locales/lv/messages.json +7 -0
  181. package/src/components/i18n/locales/mk/messages.json +7 -0
  182. package/src/components/i18n/locales/ml/messages.json +7 -0
  183. package/src/components/i18n/locales/mn/messages.json +7 -0
  184. package/src/components/i18n/locales/mr/messages.json +7 -0
  185. package/src/components/i18n/locales/ms/messages.json +7 -0
  186. package/src/components/i18n/locales/my/messages.json +7 -0
  187. package/src/components/i18n/locales/ne/messages.json +7 -0
  188. package/src/components/i18n/locales/nl/messages.json +7 -0
  189. package/src/components/i18n/locales/no/messages.json +7 -0
  190. package/src/components/i18n/locales/pa/messages.json +7 -0
  191. package/src/components/i18n/locales/pl/messages.json +7 -0
  192. package/src/components/i18n/locales/ps/messages.json +7 -0
  193. package/src/components/i18n/locales/pt/messages.json +7 -0
  194. package/src/components/i18n/locales/ro/messages.json +7 -0
  195. package/src/components/i18n/locales/ru/messages.json +7 -0
  196. package/src/components/i18n/locales/sd/messages.json +7 -0
  197. package/src/components/i18n/locales/si/messages.json +7 -0
  198. package/src/components/i18n/locales/sk/messages.json +7 -0
  199. package/src/components/i18n/locales/sl/messages.json +7 -0
  200. package/src/components/i18n/locales/sq/messages.json +7 -0
  201. package/src/components/i18n/locales/sr/messages.json +7 -0
  202. package/src/components/i18n/locales/sv/messages.json +7 -0
  203. package/src/components/i18n/locales/sw/messages.json +7 -0
  204. package/src/components/i18n/locales/ta/messages.json +7 -0
  205. package/src/components/i18n/locales/te/messages.json +7 -0
  206. package/src/components/i18n/locales/th/messages.json +7 -0
  207. package/src/components/i18n/locales/tr/messages.json +7 -0
  208. package/src/components/i18n/locales/ug/messages.json +7 -0
  209. package/src/components/i18n/locales/uk/messages.json +7 -0
  210. package/src/components/i18n/locales/ur/messages.json +7 -0
  211. package/src/components/i18n/locales/vi/messages.json +7 -0
  212. package/src/components/i18n/locales/yi/messages.json +7 -0
  213. package/src/components/i18n/locales/zh/messages.json +7 -0
  214. package/src/components/icons/index.ts +44 -7
  215. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +44 -2
  216. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +54 -2
  217. package/src/components/modules/blockEvents/constants.ts +12 -0
  218. package/src/components/modules/blockEvents/index.ts +1 -3
  219. package/src/components/modules/blockManager/blockManager.ts +16 -0
  220. package/src/components/modules/blockManager/operations.ts +106 -9
  221. package/src/components/modules/blockSelection.ts +2 -0
  222. package/src/components/modules/caret.ts +49 -4
  223. package/src/components/modules/drag/DragController.ts +34 -2
  224. package/src/components/modules/paste/handlers/blok-data-handler.ts +50 -3
  225. package/src/components/modules/toolbar/index.ts +11 -16
  226. package/src/components/modules/ui.ts +12 -0
  227. package/src/components/ui/toolbox.ts +26 -2
  228. package/src/components/utils/notifier/draw.ts +116 -14
  229. package/src/components/utils/notifier/index.ts +31 -4
  230. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +2 -2
  231. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +7 -7
  232. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
  233. package/src/components/utils/popover/components/search-input/search-input.const.ts +1 -1
  234. package/src/components/utils/popover/popover-abstract.ts +5 -2
  235. package/src/components/utils/popover/popover-desktop.ts +39 -2
  236. package/src/components/utils/popover/popover.const.ts +3 -3
  237. package/src/full.ts +4 -0
  238. package/src/stories/Placeholder.stories.ts +7 -2
  239. package/src/stories/helpers.ts +2 -0
  240. package/src/styles/main.css +64 -10
  241. package/src/tools/header/index.ts +307 -26
  242. package/src/tools/index.ts +3 -1
  243. package/src/tools/table/index.ts +2 -3
  244. package/src/tools/table/table-add-controls.ts +29 -1
  245. package/src/tools/table/table-cell-blocks.ts +93 -0
  246. package/src/tools/toggle/block-operations.ts +110 -0
  247. package/src/tools/toggle/constants.ts +49 -0
  248. package/src/tools/toggle/dom-builder.ts +152 -0
  249. package/src/tools/toggle/index.ts +302 -0
  250. package/src/tools/toggle/toggle-keyboard.ts +156 -0
  251. package/src/tools/toggle/toggle-lifecycle.ts +81 -0
  252. package/src/tools/toggle/toggle-shortcuts.ts +113 -0
  253. package/src/tools/toggle/types.ts +21 -0
  254. package/types/full.d.ts +2 -0
  255. package/types/tools-entry.d.ts +2 -1
  256. package/types/utils/popover/popover.d.ts +8 -0
  257. package/dist/chunks/index-DBWWKrDe.mjs +0 -78
@@ -175,6 +175,35 @@ export class BlockOperations {
175
175
  return previousBlock ?? null;
176
176
  }
177
177
 
178
+ /**
179
+ * Get next visible block (skips blocks whose holder has 'hidden' class)
180
+ * Returns null when no visible block is found after the current one
181
+ */
182
+ public get nextVisibleBlock(): Block | null {
183
+ if (this.currentBlockIndex === -1) {
184
+ return null;
185
+ }
186
+
187
+ return this.repository.blocks
188
+ .slice(this.currentBlockIndex + 1)
189
+ .find(block => !block.holder.classList.contains('hidden')) ?? null;
190
+ }
191
+
192
+ /**
193
+ * Get previous visible block (skips blocks whose holder has 'hidden' class)
194
+ * Returns null when no visible block is found before the current one
195
+ */
196
+ public get previousVisibleBlock(): Block | null {
197
+ if (this.currentBlockIndex === -1) {
198
+ return null;
199
+ }
200
+
201
+ return this.repository.blocks
202
+ .slice(0, this.currentBlockIndex)
203
+ .reverse()
204
+ .find(block => !block.holder.classList.contains('hidden')) ?? null;
205
+ }
206
+
178
207
  /**
179
208
  * Insert new block
180
209
  * @param options - Insert options
@@ -256,6 +285,20 @@ export class BlockOperations {
256
285
 
257
286
  blocksStore.insert(targetIndex, block, replace, appendToWorkingArea);
258
287
 
288
+ /**
289
+ * Update the raw currentBlockIndex BEFORE firing the mutation event so
290
+ * that listeners (e.g. TableCellBlocks.handleBlockMutation) see the
291
+ * index of the newly inserted block. We bypass the setter to avoid
292
+ * triggering stopCapturing prematurely — that happens after Yjs sync.
293
+ */
294
+ const prevIndex = this.currentBlockIndex;
295
+
296
+ if (needToFocus) {
297
+ this.currentBlockIndex = targetIndex;
298
+ } else if (targetIndex <= this.currentBlockIndex) {
299
+ this.currentBlockIndex++;
300
+ }
301
+
259
302
  /**
260
303
  * Force call of didMutated event on Block insertion
261
304
  */
@@ -277,12 +320,12 @@ export class BlockOperations {
277
320
  }, targetIndex);
278
321
  }
279
322
 
280
- if (needToFocus) {
281
- this.currentBlockIndexValue = targetIndex;
282
- }
283
-
284
- if (!needToFocus && targetIndex <= this.currentBlockIndex) {
285
- this.currentBlockIndexValue++;
323
+ /**
324
+ * Trigger stopCapturing for the index change now that Yjs sync is done.
325
+ * This preserves undo group boundaries at the original timing.
326
+ */
327
+ if (this.currentBlockIndex !== prevIndex && !this.suppressStopCapturing) {
328
+ this.dependencies.YjsManager?.stopCapturing();
286
329
  }
287
330
 
288
331
  return block;
@@ -349,6 +392,18 @@ export class BlockOperations {
349
392
  parentBlock.contentIds = parentBlock.contentIds.filter(id => id !== block.id);
350
393
  }
351
394
 
395
+ // Promote children to root level when a parent block is removed
396
+ for (const childId of block.contentIds) {
397
+ const childBlock = this.repository.getBlockById(childId);
398
+
399
+ if (childBlock === undefined) {
400
+ continue;
401
+ }
402
+
403
+ childBlock.parentId = null;
404
+ childBlock.holder.classList.remove('hidden');
405
+ }
406
+
352
407
  blocksStore.remove(index);
353
408
 
354
409
  /**
@@ -416,6 +471,8 @@ export class BlockOperations {
416
471
  tool: block.name,
417
472
  data: Object.assign({}, existingData, data ?? {}),
418
473
  tunes: tunes ?? block.preservedTunes,
474
+ parentId: block.parentId ?? undefined,
475
+ contentIds: block.contentIds.length > 0 ? [...block.contentIds] : undefined,
419
476
  bindEventsImmediately: true,
420
477
  });
421
478
 
@@ -455,6 +512,10 @@ export class BlockOperations {
455
512
  const blockIndex = this.repository.getBlockIndex(block);
456
513
  const newBlockId = generateBlockId();
457
514
 
515
+ // Capture hierarchy before replacement
516
+ const oldParentId = block.parentId;
517
+ const oldContentIds = [...block.contentIds];
518
+
458
519
  // Atomic transaction: remove old block + add new block as single undo entry
459
520
  this.dependencies.YjsManager.transact(() => {
460
521
  this.dependencies.YjsManager.removeBlock(block.id);
@@ -466,7 +527,7 @@ export class BlockOperations {
466
527
  });
467
528
 
468
529
  // DOM update (skip Yjs sync — already done above)
469
- return this.insert({
530
+ const newBlock = this.insert({
470
531
  id: newBlockId,
471
532
  tool: newTool,
472
533
  data,
@@ -474,6 +535,28 @@ export class BlockOperations {
474
535
  replace: true,
475
536
  skipYjsSync: true,
476
537
  }, blocksStore);
538
+
539
+ // Transfer hierarchy to new block
540
+ if (oldParentId !== null) {
541
+ newBlock.parentId = oldParentId;
542
+
543
+ const parentBlock = this.repository.getBlockById(oldParentId);
544
+
545
+ if (parentBlock !== undefined) {
546
+ parentBlock.contentIds = parentBlock.contentIds.map(id => id === block.id ? newBlock.id : id);
547
+ }
548
+ }
549
+
550
+ for (const childId of oldContentIds) {
551
+ const childBlock = this.repository.getBlockById(childId);
552
+
553
+ if (childBlock !== undefined) {
554
+ childBlock.parentId = newBlock.id;
555
+ }
556
+ }
557
+ newBlock.contentIds = oldContentIds;
558
+
559
+ return newBlock;
477
560
  }
478
561
 
479
562
  /**
@@ -663,12 +746,19 @@ export class BlockOperations {
663
746
  });
664
747
 
665
748
  // Insert DOM block (skip Yjs sync - already done above)
666
- return this.insert({
749
+ const newBlock = this.insert({
667
750
  id: newBlockId,
668
751
  tool: currentBlock.name,
669
752
  data: { text: extractedText },
670
753
  skipYjsSync: true,
671
754
  }, blocksStore);
755
+
756
+ // Inherit parentId from the split block so nested blocks stay nested
757
+ if (currentBlock.parentId !== null) {
758
+ this.hierarchy.setBlockParent(newBlock, currentBlock.parentId);
759
+ }
760
+
761
+ return newBlock;
672
762
  });
673
763
  }
674
764
 
@@ -722,7 +812,7 @@ export class BlockOperations {
722
812
  }
723
813
 
724
814
  // Insert DOM block (skip Yjs sync - already done above)
725
- return this.insert({
815
+ const newBlock = this.insert({
726
816
  id: newBlockId,
727
817
  tool: newBlockType,
728
818
  data: newBlockData,
@@ -730,6 +820,13 @@ export class BlockOperations {
730
820
  needToFocus: true,
731
821
  skipYjsSync: true,
732
822
  }, blocksStore);
823
+
824
+ // Inherit parentId from the split block so nested blocks stay nested
825
+ if (currentBlock.parentId !== null) {
826
+ this.hierarchy.setBlockParent(newBlock, currentBlock.parentId);
827
+ }
828
+
829
+ return newBlock;
733
830
  });
734
831
  }
735
832
 
@@ -336,6 +336,8 @@ export class BlockSelection extends Module {
336
336
  tool: block.name,
337
337
  data: block.preservedData,
338
338
  tunes: block.preservedTunes,
339
+ parentId: block.parentId,
340
+ contentIds: block.contentIds,
339
341
  }));
340
342
 
341
343
  this.selectedBlocks.forEach((block) => {
@@ -499,7 +499,7 @@ export class Caret extends Module {
499
499
  */
500
500
  public navigateNext(force = false): boolean {
501
501
  const { BlockManager } = this.Blok;
502
- const { currentBlock, nextBlock } = BlockManager;
502
+ const { currentBlock, nextVisibleBlock: nextBlock } = BlockManager;
503
503
 
504
504
  if (currentBlock === undefined) {
505
505
  return false;
@@ -567,7 +567,7 @@ export class Caret extends Module {
567
567
  * @param {boolean} force - pass true to skip check for caret position
568
568
  */
569
569
  public navigatePrevious(force = false): boolean {
570
- const { currentBlock, previousBlock } = this.Blok.BlockManager;
570
+ const { currentBlock, previousVisibleBlock: previousBlock } = this.Blok.BlockManager;
571
571
 
572
572
  if (!currentBlock) {
573
573
  return false;
@@ -634,7 +634,7 @@ export class Caret extends Module {
634
634
  */
635
635
  public navigateVerticalNext(): boolean {
636
636
  const { BlockManager } = this.Blok;
637
- const { currentBlock, nextBlock } = BlockManager;
637
+ const { currentBlock, nextVisibleBlock: nextBlock } = BlockManager;
638
638
 
639
639
  if (currentBlock === undefined) {
640
640
  return false;
@@ -681,6 +681,35 @@ export class Caret extends Module {
681
681
  return true;
682
682
  }
683
683
 
684
+ /**
685
+ * If current block is inside a table cell (has parentId), check if we should
686
+ * exit the table. This handles two cases:
687
+ * 1. nextBlock is still in the same table → skip all cell paragraphs
688
+ * 2. nextBlock is null (last block in flat list) → table is at the end
689
+ */
690
+ const shouldExitParent = currentBlock.parentId !== null && (
691
+ nextBlock === null ||
692
+ nextBlock.parentId === currentBlock.parentId ||
693
+ nextBlock.id === currentBlock.parentId
694
+ );
695
+
696
+ if (shouldExitParent && currentBlock.parentId !== null) {
697
+ const blockAfterTable = this.findFirstBlockAfterParent(currentBlock.parentId);
698
+
699
+ if (blockAfterTable !== null) {
700
+ this.setToBlockAtXPosition(blockAfterTable, caretX, true);
701
+
702
+ return true;
703
+ }
704
+
705
+ // No block after table — create one
706
+ const newBlock = BlockManager.insertAtEnd();
707
+
708
+ this.setToBlock(newBlock, this.positions.START);
709
+
710
+ return true;
711
+ }
712
+
684
713
  /**
685
714
  * Navigate to next block, preserving horizontal position
686
715
  */
@@ -714,7 +743,7 @@ export class Caret extends Module {
714
743
  */
715
744
  public navigateVerticalPrevious(): boolean {
716
745
  const { BlockManager } = this.Blok;
717
- const { currentBlock, previousBlock } = BlockManager;
746
+ const { currentBlock, previousVisibleBlock: previousBlock } = BlockManager;
718
747
 
719
748
  if (currentBlock === undefined) {
720
749
  return false;
@@ -773,6 +802,22 @@ export class Caret extends Module {
773
802
  return false;
774
803
  }
775
804
 
805
+ /**
806
+ * Find the first block after a parent block (e.g., a table) by scanning the flat
807
+ * block array and skipping blocks whose parentId matches.
808
+ */
809
+ private findFirstBlockAfterParent(parentBlockId: string): Block | null {
810
+ const { BlockManager } = this.Blok;
811
+ const blocks = BlockManager.blocks;
812
+ const parentIndex = blocks.findIndex(b => b.id === parentBlockId);
813
+
814
+ if (parentIndex === -1) {
815
+ return null;
816
+ }
817
+
818
+ return blocks.slice(parentIndex + 1).find(b => b.parentId !== parentBlockId) ?? null;
819
+ }
820
+
776
821
  /**
777
822
  * Inserts shadow element after passed element where caret can be placed
778
823
  * @param {Element} element - element after which shadow caret should be inserted
@@ -110,11 +110,18 @@ export class DragController extends Module {
110
110
  ? this.Blok.BlockSelection.selectedBlocks
111
111
  : [block];
112
112
 
113
- // For single-block list item drags, include all descendants
114
- const descendants = !isBlockSelected && this.listItemDescendants
113
+ // For single-block drags, include all descendants (list items via depth, toggles via contentIds)
114
+ const listDescendants = !isBlockSelected && this.listItemDescendants
115
115
  ? this.listItemDescendants.getDescendants(block)
116
116
  : [];
117
117
 
118
+ // If no list descendants found, check for hierarchy children (toggle blocks)
119
+ const hasHierarchyChildren = !isBlockSelected && block.contentIds?.length > 0;
120
+ const hierarchyDescendants = listDescendants.length === 0 && hasHierarchyChildren
121
+ ? this.getHierarchyDescendants(block)
122
+ : [];
123
+ const descendants = listDescendants.length > 0 ? listDescendants : hierarchyDescendants;
124
+
118
125
  const blocksToMove = descendants.length > 0
119
126
  ? [block, ...descendants]
120
127
  : initialBlocks;
@@ -458,6 +465,31 @@ export class DragController extends Module {
458
465
  this.Blok.Toolbar.moveAndOpen(blockToShow);
459
466
  }
460
467
 
468
+ /**
469
+ * Recursively collects all descendants of a block via the parentId/contentIds hierarchy.
470
+ * Used for toggle blocks and other parent-child structures that don't use data-list-depth.
471
+ * @param block - Parent block to collect descendants for
472
+ * @returns Array of descendant blocks
473
+ */
474
+ private getHierarchyDescendants(block: Block): Block[] {
475
+ const descendants: Block[] = [];
476
+
477
+ const collectChildren = (parentBlock: Block): void => {
478
+ for (const childId of parentBlock.contentIds) {
479
+ const child = this.Blok.BlockManager.getBlockById(childId);
480
+
481
+ if (child !== undefined) {
482
+ descendants.push(child);
483
+ collectChildren(child);
484
+ }
485
+ }
486
+ };
487
+
488
+ collectChildren(block);
489
+
490
+ return descendants;
491
+ }
492
+
461
493
  public destroy(): void {
462
494
  this.cleanup();
463
495
  }
@@ -1,6 +1,7 @@
1
1
  import type { SanitizerConfig } from '../../../../../types/configs/sanitizer-config';
2
2
  import type { SavedData } from '../../../../../types/data-formats';
3
3
  import type { BlokModules } from '../../../../types-internal/blok-modules';
4
+ import type { Block } from '../../../block';
4
5
  import { sanitizeBlocks } from '../../../utils/sanitizer';
5
6
  import type { SanitizerConfigBuilder } from '../sanitizer-config';
6
7
  import type { ToolRegistry } from '../tool-registry';
@@ -10,6 +11,15 @@ import type { PasteHandler } from './base';
10
11
  import { BasePasteHandler } from './base';
11
12
  import { PatternHandler } from './pattern-handler';
12
13
 
14
+ /**
15
+ * Shape of a block in the Blok clipboard data.
16
+ * Extends the basic SavedData fields with optional hierarchy information.
17
+ */
18
+ interface BlokClipboardBlock extends Pick<SavedData, 'id' | 'data' | 'tool'> {
19
+ parentId?: string | null;
20
+ contentIds?: string[];
21
+ }
22
+
13
23
 
14
24
  /**
15
25
  * Blok Data Handler Priority.
@@ -45,7 +55,7 @@ export class BlokDataHandler extends BasePasteHandler implements PasteHandler {
45
55
  return false;
46
56
  }
47
57
 
48
- const parsedBlokData = JSON.parse(data) as Pick<SavedData, 'id' | 'data' | 'tool'>[];
58
+ const parsedBlokData = JSON.parse(data) as BlokClipboardBlock[];
49
59
 
50
60
  // Check if we should try pattern matching first (for URL pasting within editor)
51
61
  const hasPatterns = this.toolRegistry.toolsPatterns.length > 0;
@@ -118,9 +128,11 @@ export class BlokDataHandler extends BasePasteHandler implements PasteHandler {
118
128
 
119
129
  /**
120
130
  * Insert Blok JSON blocks.
131
+ * After inserting all blocks, restores parent-child hierarchy using an ID mapping
132
+ * (pasted blocks receive new IDs, so original IDs are mapped to new block instances).
121
133
  */
122
134
  private insertBlokBlocks(
123
- blocks: Pick<SavedData, 'id' | 'data' | 'tool'>[],
135
+ blocks: BlokClipboardBlock[],
124
136
  canReplace: boolean
125
137
  ): void {
126
138
  const { BlockManager, Caret, Tools } = this.Blok;
@@ -130,7 +142,14 @@ export class BlokDataHandler extends BasePasteHandler implements PasteHandler {
130
142
  this.config.sanitizer
131
143
  );
132
144
 
133
- sanitizedBlocks.forEach(({ tool, data }, i) => {
145
+ /**
146
+ * Map from original (old) block ID to the newly inserted Block instance.
147
+ * Used after insertion to re-establish parent-child relationships.
148
+ */
149
+ const oldIdToEntry = new Map<string, { newBlock: Block; original: BlokClipboardBlock }>();
150
+
151
+ sanitizedBlocks.forEach((sanitizedBlock, i) => {
152
+ const { tool, data } = sanitizedBlock;
134
153
  const needToReplaceCurrentBlock = i === 0 &&
135
154
  canReplace &&
136
155
  Boolean(BlockManager.currentBlock?.tool.isDefault) &&
@@ -142,7 +161,35 @@ export class BlokDataHandler extends BasePasteHandler implements PasteHandler {
142
161
  replace: needToReplaceCurrentBlock,
143
162
  });
144
163
 
164
+ const originalBlock = blocks[i];
165
+
166
+ if (originalBlock !== undefined) {
167
+ oldIdToEntry.set(originalBlock.id, { newBlock: block, original: originalBlock });
168
+ }
169
+
145
170
  Caret.setToBlock(block, Caret.positions.END);
146
171
  });
172
+
173
+ /**
174
+ * Restore parent-child hierarchy using the old-to-new ID mapping.
175
+ * Only restores relationships where both parent and child are in the pasted set.
176
+ */
177
+ for (const [, { newBlock, original }] of oldIdToEntry) {
178
+ if (original.parentId === undefined || original.parentId === null) {
179
+ continue;
180
+ }
181
+
182
+ const parentEntry = oldIdToEntry.get(original.parentId);
183
+
184
+ if (parentEntry === undefined) {
185
+ continue;
186
+ }
187
+
188
+ newBlock.parentId = parentEntry.newBlock.id;
189
+
190
+ if (!parentEntry.newBlock.contentIds.includes(newBlock.id)) {
191
+ parentEntry.newBlock.contentIds = [...parentEntry.newBlock.contentIds, newBlock.id];
192
+ }
193
+ }
147
194
  }
148
195
  }
@@ -393,22 +393,16 @@ export class Toolbar extends Module<ToolbarNodes> {
393
393
  }
394
394
 
395
395
  /**
396
- * Suppress toolbar buttons when the focused element is inside a table cell.
397
- * The toolbar still positions itself for toolbox/slash-search purposes,
398
- * but plus button and settings toggler remain hidden while a cell has focus.
399
- *
400
- * Note: we check focus (activeElement) not hover. On hover alone, the plus
401
- * button should remain visible so the user can click it to add blocks
402
- * below the table. Only when the user actually clicks/focuses inside a cell
403
- * should the buttons be suppressed.
396
+ * Adjust toolbar button visibility when focus is inside a table cell.
397
+ * The plus button always stays visible so users can add blocks below the table.
398
+ * The settings toggler is hidden because drag/settings don't apply to individual cells.
404
399
  */
405
400
  const focusIsInsideCell = this.isFocusInsideTableCell();
406
- const displayValue = focusIsInsideCell ? 'none' : '';
407
401
 
408
- plusButton.style.display = displayValue;
402
+ plusButton.style.display = '';
409
403
 
410
404
  if (settingsToggler) {
411
- settingsToggler.style.display = displayValue;
405
+ settingsToggler.style.display = focusIsInsideCell ? 'none' : '';
412
406
  }
413
407
 
414
408
  const targetBlockHolder = targetBlock.holder;
@@ -662,8 +656,8 @@ export class Toolbar extends Module<ToolbarNodes> {
662
656
 
663
657
  /**
664
658
  * Updates toolbar button visibility based on whether a table cell has focus.
665
- * Hides plus button and settings toggler when focus is inside a cell;
666
- * restores them when focus moves to a regular block.
659
+ * The plus button always stays visible; the settings toggler is hidden when
660
+ * focus is inside a cell and restored when focus moves to a regular block.
667
661
  *
668
662
  * Called from the focusin listener so button state is updated immediately
669
663
  * on click, without waiting for the next hover/moveAndOpen cycle.
@@ -676,12 +670,11 @@ export class Toolbar extends Module<ToolbarNodes> {
676
670
  }
677
671
 
678
672
  const focusIsInsideCell = this.isFocusInsideTableCell();
679
- const displayValue = focusIsInsideCell ? 'none' : '';
680
673
 
681
- plusButton.style.display = displayValue;
674
+ plusButton.style.display = '';
682
675
 
683
676
  if (settingsToggler) {
684
- settingsToggler.style.display = displayValue;
677
+ settingsToggler.style.display = focusIsInsideCell ? 'none' : '';
685
678
  }
686
679
  }
687
680
 
@@ -837,9 +830,11 @@ export class Toolbar extends Module<ToolbarNodes> {
837
830
  i18nLabels: {
838
831
  filter: this.Blok.I18n.t('popover.search'),
839
832
  nothingFound: this.Blok.I18n.t('popover.nothingFound'),
833
+ slashSearchPlaceholder: this.Blok.I18n.t('toolbox.typeToSearch'),
840
834
  },
841
835
  i18n: this.Blok.I18n,
842
836
  triggerElement: this.nodes.plusButton,
837
+ leftAlignElement: this.nodes.content,
843
838
  });
844
839
 
845
840
  this.toolboxInstance.on(ToolboxEvent.Opened, () => {
@@ -22,6 +22,7 @@ import { KeyboardController } from './uiControllers/controllers/keyboard';
22
22
  import { SelectionController } from './uiControllers/controllers/selection';
23
23
  import { createDocumentClickedHandler } from './uiControllers/handlers/click';
24
24
  import { createRedactorTouchHandler } from './uiControllers/handlers/touch';
25
+ import { ToggleShortcuts } from '../../tools/toggle/toggle-shortcuts';
25
26
 
26
27
  /**
27
28
  * HTML Elements used for UI
@@ -56,6 +57,7 @@ export class UI extends Module<UINodes> {
56
57
  private keyboardController: KeyboardController | null = null;
57
58
  private selectionController: SelectionController | null = null;
58
59
  private blockHoverController: BlockHoverController | null = null;
60
+ private toggleShortcuts: ToggleShortcuts | null = null;
59
61
 
60
62
  /**
61
63
  * Handlers for simple event behaviors
@@ -158,6 +160,15 @@ export class UI extends Module<UINodes> {
158
160
  */
159
161
  this.initializeControllers();
160
162
 
163
+ /**
164
+ * Register toggle shortcuts (CMD+ALT+T) for collapsing/expanding all toggle blocks
165
+ */
166
+ this.toggleShortcuts = new ToggleShortcuts(
167
+ this.Blok.API.methods,
168
+ this.nodes.wrapper
169
+ );
170
+ this.toggleShortcuts.register();
171
+
161
172
  /**
162
173
  * Enable selection controller after initialization.
163
174
  * This is needed because bindReadOnlyInsensitiveListeners() is called in make()
@@ -343,6 +354,7 @@ export class UI extends Module<UINodes> {
343
354
  * Clean blok`s UI
344
355
  */
345
356
  public destroy(): void {
357
+ this.toggleShortcuts?.unregister();
346
358
  this.nodes.holder.innerHTML = '';
347
359
 
348
360
  this.unbindReadOnlyInsensitiveListeners();
@@ -14,6 +14,7 @@ import { translateToolTitle, type I18nInstance } from '../utils/tools';
14
14
 
15
15
  import type { API, BlockToolData, ToolboxConfigEntry, PopoverItemParams, BlockAPI } from '@/types';
16
16
  import { PopoverEvent } from '@/types/utils/popover/popover-event';
17
+ import { DATA_ATTR } from '../constants';
17
18
 
18
19
 
19
20
  /**
@@ -56,7 +57,7 @@ export interface ToolboxEventMap {
56
57
  /**
57
58
  * Available i18n dict keys that should be passed to the constructor
58
59
  */
59
- type ToolboxTextLabelsKeys = 'filter' | 'nothingFound';
60
+ type ToolboxTextLabelsKeys = 'filter' | 'nothingFound' | 'slashSearchPlaceholder';
60
61
 
61
62
  /**
62
63
  * Toolbox
@@ -144,6 +145,11 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
144
145
  */
145
146
  private triggerElement?: HTMLElement;
146
147
 
148
+ /**
149
+ * Optional element whose left edge is used for horizontal popover alignment.
150
+ */
151
+ private leftAlignElement?: HTMLElement;
152
+
147
153
  /**
148
154
  * The block element currently being listened to for inline slash search
149
155
  */
@@ -168,13 +174,15 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
168
174
  * @param options.tools - Tools available to check whether some of them should be displayed at the Toolbox or not
169
175
  * @param options.i18n - I18n instance for translations
170
176
  * @param options.triggerElement - Element relative to which the popover should be positioned
177
+ * @param options.leftAlignElement - Element whose left edge is used for horizontal popover alignment
171
178
  */
172
- constructor({ api, tools, i18nLabels, i18n, triggerElement }: {
179
+ constructor({ api, tools, i18nLabels, i18n, triggerElement, leftAlignElement }: {
173
180
  api: API;
174
181
  tools: ToolsCollection<BlockToolAdapter>;
175
182
  i18nLabels: Record<ToolboxTextLabelsKeys, string>;
176
183
  i18n: I18nInstance;
177
184
  triggerElement?: HTMLElement;
185
+ leftAlignElement?: HTMLElement;
178
186
  }) {
179
187
  super();
180
188
 
@@ -183,6 +191,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
183
191
  this.i18nLabels = i18nLabels;
184
192
  this.i18n = i18n;
185
193
  this.triggerElement = triggerElement;
194
+ this.leftAlignElement = leftAlignElement;
186
195
 
187
196
  this.enableShortcuts();
188
197
 
@@ -311,6 +320,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
311
320
  this.isInsideTableCell = false;
312
321
  }
313
322
 
323
+ this.stopListeningToBlockInput();
314
324
  this.popover?.hide();
315
325
  this.opened = false;
316
326
  this.emit(ToolboxEvent.Closed);
@@ -344,6 +354,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
344
354
  this.popover = new PopoverClass({
345
355
  scopeElement: this.api.ui.nodes.redactor,
346
356
  trigger: this.triggerElement || this.nodes.toolbox,
357
+ leftAlignElement: this.leftAlignElement,
347
358
  messages: {
348
359
  nothingFound: this.i18nLabels.nothingFound,
349
360
  search: this.i18nLabels.filter,
@@ -630,6 +641,9 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
630
641
 
631
642
  this.currentBlockForSearch = currentBlock.holder;
632
643
  this.currentContentEditable = this.currentBlockForSearch.querySelector('[contenteditable="true"]');
644
+ if (this.currentContentEditable instanceof HTMLElement) {
645
+ this.currentContentEditable.setAttribute(DATA_ATTR.slashSearch, this.i18nLabels.slashSearchPlaceholder);
646
+ }
633
647
  this.listeners.on(this.currentBlockForSearch, 'input', this.handleBlockInput);
634
648
  }
635
649
 
@@ -639,6 +653,9 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
639
653
  private stopListeningToBlockInput(): void {
640
654
  if (this.currentBlockForSearch !== null) {
641
655
  this.listeners.off(this.currentBlockForSearch, 'input', this.handleBlockInput);
656
+ if (this.currentContentEditable instanceof HTMLElement) {
657
+ this.currentContentEditable.removeAttribute(DATA_ATTR.slashSearch);
658
+ }
642
659
  this.currentBlockForSearch = null;
643
660
  this.currentContentEditable = null;
644
661
  }
@@ -666,6 +683,13 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
666
683
 
667
684
  const query = text.slice(slashIndex + 1);
668
685
 
686
+ if (this.currentContentEditable instanceof HTMLElement) {
687
+ this.currentContentEditable.setAttribute(
688
+ DATA_ATTR.slashSearch,
689
+ query.length === 0 ? this.i18nLabels.slashSearchPlaceholder : ''
690
+ );
691
+ }
692
+
669
693
  this.popover?.filterItems(query);
670
694
  };
671
695