@jackuait/blok 0.6.0-beta.9 → 0.7.0-beta.1

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 (336) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-Bn6Q_o8h.mjs → blok-ob9Fwr1L.mjs} +3414 -2975
  3. package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
  4. package/dist/chunks/{i18next-loader-DjR4d8M7.mjs → i18next-loader-Bu3vFvye.mjs} +2 -2
  5. package/dist/chunks/{index-oe38cp86.mjs → index-CZmRzRIX.mjs} +12 -12
  6. package/dist/chunks/{inline-tool-convert-SRTkyaZn.mjs → inline-tool-convert-CvFW2iie.mjs} +1579 -961
  7. package/dist/chunks/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
  8. package/dist/chunks/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
  9. package/dist/{messages-DnXLrlHh.mjs → chunks/messages-4v4MuVEc.mjs} +6 -0
  10. package/dist/chunks/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
  11. package/dist/chunks/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
  12. package/dist/chunks/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
  13. package/dist/{messages-uKX8WBaD.mjs → chunks/messages-96kNZDll.mjs} +6 -0
  14. package/dist/chunks/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
  15. package/dist/{messages-DBn76jVV.mjs → chunks/messages-B217znr-.mjs} +8 -2
  16. package/dist/{messages-DT4dP5uK.mjs → chunks/messages-B8WNljW3.mjs} +6 -0
  17. package/dist/chunks/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
  18. package/dist/{messages-CZygwLwM.mjs → chunks/messages-BI43k_BD.mjs} +6 -0
  19. package/dist/{messages-CzTufCHu.mjs → chunks/messages-BJ6zrz2j.mjs} +6 -0
  20. package/dist/{messages-BoJc_p1r.mjs → chunks/messages-BUl_Rcnj.mjs} +6 -0
  21. package/dist/chunks/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
  22. package/dist/{messages-C2htQ_3F.mjs → chunks/messages-BcpCubnC.mjs} +6 -0
  23. package/dist/{messages-D5C3J9qr.mjs → chunks/messages-Bm-E4iRC.mjs} +6 -0
  24. package/dist/chunks/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
  25. package/dist/chunks/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
  26. package/dist/chunks/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
  27. package/dist/{messages-Dz9L52ol.mjs → chunks/messages-CRJ_mchV.mjs} +6 -0
  28. package/dist/chunks/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
  29. package/dist/chunks/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
  30. package/dist/{messages-R3hUSvr3.mjs → chunks/messages-CfiyT2Wi.mjs} +6 -0
  31. package/dist/{messages-CJdUsQ-c.mjs → chunks/messages-CgTq3QhU.mjs} +6 -0
  32. package/dist/chunks/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
  33. package/dist/{messages-Q7AO_FLv.mjs → chunks/messages-Cjjo7yHR.mjs} +6 -0
  34. package/dist/{messages-C99mq906.mjs → chunks/messages-Cl6ayUaq.mjs} +6 -0
  35. package/dist/chunks/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
  36. package/dist/chunks/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
  37. package/dist/chunks/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
  38. package/dist/{messages-BWF-zUpY.mjs → chunks/messages-CrCYPCk3.mjs} +6 -0
  39. package/dist/{messages-D-ZtY5v0.mjs → chunks/messages-Cs8zmZ3L.mjs} +6 -0
  40. package/dist/{messages-DprmQg6V.mjs → chunks/messages-CzK0LEhb.mjs} +6 -0
  41. package/dist/chunks/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
  42. package/dist/chunks/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
  43. package/dist/chunks/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
  44. package/dist/{messages-kep5wtm4.mjs → chunks/messages-D4qqwVgQ.mjs} +6 -0
  45. package/dist/chunks/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
  46. package/dist/{messages-CY8_RyFE.mjs → chunks/messages-D7u2bmP2.mjs} +6 -0
  47. package/dist/chunks/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
  48. package/dist/{messages-DLfR5bMd.mjs → chunks/messages-D9ndgBnU.mjs} +6 -0
  49. package/dist/{messages-CVw84KdI.mjs → chunks/messages-DDTQgImT.mjs} +6 -0
  50. package/dist/{messages-_ErNTNhk.mjs → chunks/messages-DH_jBeED.mjs} +6 -0
  51. package/dist/chunks/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
  52. package/dist/chunks/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
  53. package/dist/chunks/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
  54. package/dist/chunks/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
  55. package/dist/chunks/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
  56. package/dist/chunks/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
  57. package/dist/{messages-Z9nEU2xK.mjs → chunks/messages-DviiFSv2.mjs} +6 -0
  58. package/dist/chunks/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
  59. package/dist/{messages-w7v1GNaE.mjs → chunks/messages-Dzzn6XoD.mjs} +6 -0
  60. package/dist/{messages-CqWJcCbY.mjs → chunks/messages-GSByFygY.mjs} +6 -0
  61. package/dist/chunks/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
  62. package/dist/chunks/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
  63. package/dist/{messages-BU2nlrLK.mjs → chunks/messages-RonBBCnh.mjs} +6 -0
  64. package/dist/{messages-Bmu_S7GM.mjs → chunks/messages-VDriF5Qy.mjs} +6 -0
  65. package/dist/{messages-CLhcMlTc.mjs → chunks/messages-ZjUAIWb1.mjs} +6 -0
  66. package/dist/{messages-9SihnaXQ.mjs → chunks/messages-b1EdvUm0.mjs} +6 -0
  67. package/dist/{messages-DvFLX36Q.mjs → chunks/messages-begYOTgC.mjs} +6 -0
  68. package/dist/{messages-BMv4xwIr.mjs → chunks/messages-jrncnb-H.mjs} +6 -0
  69. package/dist/{messages-D5iv1Kox.mjs → chunks/messages-nefz1S71.mjs} +6 -0
  70. package/dist/{messages-CQwpzUFp.mjs → chunks/messages-ucTVgS5G.mjs} +6 -0
  71. package/dist/chunks/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
  72. package/dist/{messages-C9eaarcK.mjs → chunks/messages-wmi-iFkH.mjs} +6 -0
  73. package/dist/chunks/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
  74. package/dist/full.mjs +30 -27
  75. package/dist/locales.mjs +90 -84
  76. package/dist/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
  77. package/dist/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
  78. package/dist/{chunks/messages-DnXLrlHh.mjs → messages-4v4MuVEc.mjs} +6 -0
  79. package/dist/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
  80. package/dist/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
  81. package/dist/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
  82. package/dist/{chunks/messages-uKX8WBaD.mjs → messages-96kNZDll.mjs} +6 -0
  83. package/dist/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
  84. package/dist/{chunks/messages-DBn76jVV.mjs → messages-B217znr-.mjs} +8 -2
  85. package/dist/{chunks/messages-DT4dP5uK.mjs → messages-B8WNljW3.mjs} +6 -0
  86. package/dist/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
  87. package/dist/{chunks/messages-CZygwLwM.mjs → messages-BI43k_BD.mjs} +6 -0
  88. package/dist/{chunks/messages-CzTufCHu.mjs → messages-BJ6zrz2j.mjs} +6 -0
  89. package/dist/{chunks/messages-BoJc_p1r.mjs → messages-BUl_Rcnj.mjs} +6 -0
  90. package/dist/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
  91. package/dist/{chunks/messages-C2htQ_3F.mjs → messages-BcpCubnC.mjs} +6 -0
  92. package/dist/{chunks/messages-D5C3J9qr.mjs → messages-Bm-E4iRC.mjs} +6 -0
  93. package/dist/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
  94. package/dist/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
  95. package/dist/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
  96. package/dist/{chunks/messages-Dz9L52ol.mjs → messages-CRJ_mchV.mjs} +6 -0
  97. package/dist/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
  98. package/dist/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
  99. package/dist/{chunks/messages-R3hUSvr3.mjs → messages-CfiyT2Wi.mjs} +6 -0
  100. package/dist/{chunks/messages-CJdUsQ-c.mjs → messages-CgTq3QhU.mjs} +6 -0
  101. package/dist/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
  102. package/dist/{chunks/messages-Q7AO_FLv.mjs → messages-Cjjo7yHR.mjs} +6 -0
  103. package/dist/{chunks/messages-C99mq906.mjs → messages-Cl6ayUaq.mjs} +6 -0
  104. package/dist/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
  105. package/dist/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
  106. package/dist/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
  107. package/dist/{chunks/messages-BWF-zUpY.mjs → messages-CrCYPCk3.mjs} +6 -0
  108. package/dist/{chunks/messages-D-ZtY5v0.mjs → messages-Cs8zmZ3L.mjs} +6 -0
  109. package/dist/{chunks/messages-DprmQg6V.mjs → messages-CzK0LEhb.mjs} +6 -0
  110. package/dist/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
  111. package/dist/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
  112. package/dist/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
  113. package/dist/{chunks/messages-kep5wtm4.mjs → messages-D4qqwVgQ.mjs} +6 -0
  114. package/dist/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
  115. package/dist/{chunks/messages-CY8_RyFE.mjs → messages-D7u2bmP2.mjs} +6 -0
  116. package/dist/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
  117. package/dist/{chunks/messages-DLfR5bMd.mjs → messages-D9ndgBnU.mjs} +6 -0
  118. package/dist/{chunks/messages-CVw84KdI.mjs → messages-DDTQgImT.mjs} +6 -0
  119. package/dist/{chunks/messages-_ErNTNhk.mjs → messages-DH_jBeED.mjs} +6 -0
  120. package/dist/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
  121. package/dist/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
  122. package/dist/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
  123. package/dist/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
  124. package/dist/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
  125. package/dist/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
  126. package/dist/{chunks/messages-Z9nEU2xK.mjs → messages-DviiFSv2.mjs} +6 -0
  127. package/dist/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
  128. package/dist/{chunks/messages-w7v1GNaE.mjs → messages-Dzzn6XoD.mjs} +6 -0
  129. package/dist/{chunks/messages-CqWJcCbY.mjs → messages-GSByFygY.mjs} +6 -0
  130. package/dist/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
  131. package/dist/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
  132. package/dist/{chunks/messages-BU2nlrLK.mjs → messages-RonBBCnh.mjs} +6 -0
  133. package/dist/{chunks/messages-Bmu_S7GM.mjs → messages-VDriF5Qy.mjs} +6 -0
  134. package/dist/{chunks/messages-CLhcMlTc.mjs → messages-ZjUAIWb1.mjs} +6 -0
  135. package/dist/{chunks/messages-9SihnaXQ.mjs → messages-b1EdvUm0.mjs} +6 -0
  136. package/dist/{chunks/messages-DvFLX36Q.mjs → messages-begYOTgC.mjs} +6 -0
  137. package/dist/{chunks/messages-BMv4xwIr.mjs → messages-jrncnb-H.mjs} +6 -0
  138. package/dist/{chunks/messages-D5iv1Kox.mjs → messages-nefz1S71.mjs} +6 -0
  139. package/dist/{chunks/messages-CQwpzUFp.mjs → messages-ucTVgS5G.mjs} +6 -0
  140. package/dist/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
  141. package/dist/{chunks/messages-C9eaarcK.mjs → messages-wmi-iFkH.mjs} +6 -0
  142. package/dist/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
  143. package/dist/tools.mjs +3537 -1710
  144. package/dist/vendor.LICENSE.txt +109 -109
  145. package/package.json +43 -57
  146. package/src/blok.ts +12 -0
  147. package/src/components/__module.ts +21 -0
  148. package/src/components/block/api.ts +17 -0
  149. package/src/components/block/style-manager.ts +6 -2
  150. package/src/components/block/tool-renderer.ts +33 -30
  151. package/src/components/blocks.ts +132 -15
  152. package/src/components/constants/data-attributes.ts +7 -0
  153. package/src/components/i18n/locales/am/messages.json +6 -0
  154. package/src/components/i18n/locales/ar/messages.json +6 -0
  155. package/src/components/i18n/locales/az/messages.json +6 -0
  156. package/src/components/i18n/locales/bg/messages.json +6 -0
  157. package/src/components/i18n/locales/bn/messages.json +6 -0
  158. package/src/components/i18n/locales/bs/messages.json +6 -0
  159. package/src/components/i18n/locales/cs/messages.json +6 -0
  160. package/src/components/i18n/locales/da/messages.json +6 -0
  161. package/src/components/i18n/locales/de/messages.json +6 -0
  162. package/src/components/i18n/locales/dv/messages.json +6 -0
  163. package/src/components/i18n/locales/el/messages.json +6 -0
  164. package/src/components/i18n/locales/en/messages.json +6 -0
  165. package/src/components/i18n/locales/es/messages.json +6 -0
  166. package/src/components/i18n/locales/et/messages.json +6 -0
  167. package/src/components/i18n/locales/fa/messages.json +6 -0
  168. package/src/components/i18n/locales/fi/messages.json +6 -0
  169. package/src/components/i18n/locales/fil/messages.json +6 -0
  170. package/src/components/i18n/locales/fr/messages.json +6 -0
  171. package/src/components/i18n/locales/gu/messages.json +6 -0
  172. package/src/components/i18n/locales/he/messages.json +6 -0
  173. package/src/components/i18n/locales/hi/messages.json +6 -0
  174. package/src/components/i18n/locales/hr/messages.json +6 -0
  175. package/src/components/i18n/locales/hu/messages.json +6 -0
  176. package/src/components/i18n/locales/hy/messages.json +6 -0
  177. package/src/components/i18n/locales/id/messages.json +6 -0
  178. package/src/components/i18n/locales/it/messages.json +6 -0
  179. package/src/components/i18n/locales/ja/messages.json +6 -0
  180. package/src/components/i18n/locales/ka/messages.json +6 -0
  181. package/src/components/i18n/locales/km/messages.json +6 -0
  182. package/src/components/i18n/locales/kn/messages.json +6 -0
  183. package/src/components/i18n/locales/ko/messages.json +6 -0
  184. package/src/components/i18n/locales/ku/messages.json +6 -0
  185. package/src/components/i18n/locales/lo/messages.json +6 -0
  186. package/src/components/i18n/locales/lt/messages.json +6 -0
  187. package/src/components/i18n/locales/lv/messages.json +6 -0
  188. package/src/components/i18n/locales/mk/messages.json +6 -0
  189. package/src/components/i18n/locales/ml/messages.json +6 -0
  190. package/src/components/i18n/locales/mn/messages.json +6 -0
  191. package/src/components/i18n/locales/mr/messages.json +6 -0
  192. package/src/components/i18n/locales/ms/messages.json +6 -0
  193. package/src/components/i18n/locales/my/messages.json +6 -0
  194. package/src/components/i18n/locales/ne/messages.json +6 -0
  195. package/src/components/i18n/locales/nl/messages.json +6 -0
  196. package/src/components/i18n/locales/no/messages.json +6 -0
  197. package/src/components/i18n/locales/pa/messages.json +6 -0
  198. package/src/components/i18n/locales/pl/messages.json +6 -0
  199. package/src/components/i18n/locales/ps/messages.json +6 -0
  200. package/src/components/i18n/locales/pt/messages.json +6 -0
  201. package/src/components/i18n/locales/ro/messages.json +6 -0
  202. package/src/components/i18n/locales/ru/messages.json +6 -0
  203. package/src/components/i18n/locales/sd/messages.json +6 -0
  204. package/src/components/i18n/locales/si/messages.json +6 -0
  205. package/src/components/i18n/locales/sk/messages.json +6 -0
  206. package/src/components/i18n/locales/sl/messages.json +6 -0
  207. package/src/components/i18n/locales/sq/messages.json +6 -0
  208. package/src/components/i18n/locales/sr/messages.json +6 -0
  209. package/src/components/i18n/locales/sv/messages.json +6 -0
  210. package/src/components/i18n/locales/sw/messages.json +6 -0
  211. package/src/components/i18n/locales/ta/messages.json +6 -0
  212. package/src/components/i18n/locales/te/messages.json +6 -0
  213. package/src/components/i18n/locales/th/messages.json +6 -0
  214. package/src/components/i18n/locales/tr/messages.json +6 -0
  215. package/src/components/i18n/locales/ug/messages.json +6 -0
  216. package/src/components/i18n/locales/uk/messages.json +6 -0
  217. package/src/components/i18n/locales/ur/messages.json +6 -0
  218. package/src/components/i18n/locales/vi/messages.json +6 -0
  219. package/src/components/i18n/locales/yi/messages.json +6 -0
  220. package/src/components/i18n/locales/zh/messages.json +6 -0
  221. package/src/components/icons/index.ts +61 -7
  222. package/src/components/inline-tools/inline-tool-link.ts +1 -1
  223. package/src/components/inline-tools/inline-tool-marker.ts +737 -0
  224. package/src/components/inline-tools/utils/formatting-range-utils.ts +6 -3
  225. package/src/components/inline-tools/utils/marker-dom-utils.ts +17 -0
  226. package/src/components/modules/api/blocks.ts +34 -9
  227. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +75 -29
  228. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +54 -2
  229. package/src/components/modules/blockEvents/constants.ts +12 -0
  230. package/src/components/modules/blockEvents/index.ts +13 -5
  231. package/src/components/modules/blockManager/blockManager.ts +81 -2
  232. package/src/components/modules/blockManager/hierarchy.ts +20 -2
  233. package/src/components/modules/blockManager/operations.ts +70 -35
  234. package/src/components/modules/blockManager/repository.ts +22 -0
  235. package/src/components/modules/blockManager/types.ts +3 -1
  236. package/src/components/modules/blockManager/yjs-sync.ts +173 -39
  237. package/src/components/modules/blockSelection.ts +3 -0
  238. package/src/components/modules/crossBlockSelection.ts +11 -3
  239. package/src/components/modules/drag/preview/DragPreview.ts +10 -2
  240. package/src/components/modules/drag/target/DropTargetDetector.ts +100 -11
  241. package/src/components/modules/drag/utils/drag.constants.ts +1 -1
  242. package/src/components/modules/normalizeInlineImages.ts +263 -0
  243. package/src/components/modules/paste/google-docs-preprocessor.ts +197 -0
  244. package/src/components/modules/paste/handlers/base.ts +43 -2
  245. package/src/components/modules/paste/handlers/html-handler.ts +1 -1
  246. package/src/components/modules/paste/handlers/index.ts +1 -0
  247. package/src/components/modules/paste/handlers/table-cells-handler.ts +104 -0
  248. package/src/components/modules/paste/index.ts +20 -3
  249. package/src/components/modules/readonly.ts +8 -2
  250. package/src/components/modules/rectangleSelection.ts +5 -2
  251. package/src/components/modules/renderer.ts +35 -0
  252. package/src/components/modules/saver.ts +52 -2
  253. package/src/components/modules/toolbar/blockSettings.ts +52 -44
  254. package/src/components/modules/toolbar/index.ts +124 -17
  255. package/src/components/modules/toolbar/inline/index.ts +4 -4
  256. package/src/components/modules/toolbar/plus-button.ts +3 -3
  257. package/src/components/modules/toolbar/settings-toggler.ts +3 -3
  258. package/src/components/modules/toolbar/styles.ts +7 -7
  259. package/src/components/modules/ui.ts +6 -6
  260. package/src/components/modules/uiControllers/controllers/blockHover.ts +16 -2
  261. package/src/components/modules/uiControllers/handlers/touch.ts +83 -10
  262. package/src/components/modules/yjs/block-observer.ts +9 -3
  263. package/src/components/modules/yjs/document-store.ts +10 -7
  264. package/src/components/modules/yjs/types.ts +8 -6
  265. package/src/components/modules/yjs/undo-history.ts +90 -11
  266. package/src/components/selection/fake-background/shadows.ts +1 -1
  267. package/src/components/shared/color-picker.ts +211 -0
  268. package/src/components/shared/color-presets.ts +25 -0
  269. package/src/components/ui/toolbox.ts +27 -11
  270. package/src/components/utils/color-mapping.ts +241 -0
  271. package/src/components/utils/notifier/draw.ts +9 -9
  272. package/src/components/utils/placeholder.ts +24 -8
  273. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +3 -3
  274. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +15 -12
  275. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
  276. package/src/components/utils/popover/popover-abstract.ts +30 -5
  277. package/src/components/utils/popover/popover-desktop.ts +26 -3
  278. package/src/components/utils/popover/popover-inline.ts +14 -1
  279. package/src/components/utils/popover/popover-mobile.ts +4 -4
  280. package/src/components/utils/popover/popover.const.ts +3 -3
  281. package/src/components/utils/sanitizer.ts +24 -3
  282. package/src/components/utils/tw.ts +17 -5
  283. package/src/full.ts +4 -0
  284. package/src/stories/Header.stories.ts +106 -0
  285. package/src/stories/MarkerColors.stories.ts +730 -0
  286. package/src/stories/Placeholder.stories.ts +7 -2
  287. package/src/stories/Popover.stories.ts +1 -3
  288. package/src/stories/Table.stories.ts +1662 -0
  289. package/src/stories/helpers.ts +2 -0
  290. package/src/styles/main.css +217 -39
  291. package/src/tools/header/index.ts +204 -26
  292. package/src/tools/index.ts +5 -1
  293. package/src/tools/list/caret-manager.ts +28 -10
  294. package/src/tools/list/constants.ts +2 -2
  295. package/src/tools/list/dom-builder.ts +3 -3
  296. package/src/tools/list/static-configs.ts +0 -1
  297. package/src/tools/paragraph/index.ts +9 -5
  298. package/src/tools/table/core/table-commands.ts +99 -0
  299. package/src/tools/table/core/table-controller.ts +231 -0
  300. package/src/tools/table/core/table-events.ts +102 -0
  301. package/src/tools/table/index.ts +1070 -174
  302. package/src/tools/table/ownership/table-event-broker.ts +74 -0
  303. package/src/tools/table/ownership/table-ownership-registry.ts +126 -0
  304. package/src/tools/table/table-add-controls.ts +85 -15
  305. package/src/tools/table/table-cell-blocks.ts +336 -38
  306. package/src/tools/table/table-cell-clipboard.ts +415 -0
  307. package/src/tools/table/table-cell-color-picker.ts +34 -0
  308. package/src/tools/table/table-cell-selection.ts +264 -15
  309. package/src/tools/table/table-core.ts +3 -42
  310. package/src/tools/table/table-heading-toggle.ts +2 -2
  311. package/src/tools/table/table-model.ts +623 -0
  312. package/src/tools/table/table-operations.ts +59 -78
  313. package/src/tools/table/table-resize.ts +15 -11
  314. package/src/tools/table/table-restrictions.ts +69 -3
  315. package/src/tools/table/table-row-col-action-handler.ts +22 -7
  316. package/src/tools/table/table-row-col-controls.ts +129 -12
  317. package/src/tools/table/table-row-col-drag.ts +14 -0
  318. package/src/tools/table/table-scroll-haze.ts +152 -0
  319. package/src/tools/table/types.ts +22 -1
  320. package/src/tools/table/view/table-cell-blocks-adapter.ts +47 -0
  321. package/src/tools/toggle/block-operations.ts +110 -0
  322. package/src/tools/toggle/constants.ts +49 -0
  323. package/src/tools/toggle/dom-builder.ts +125 -0
  324. package/src/tools/toggle/index.ts +280 -0
  325. package/src/tools/toggle/toggle-keyboard.ts +139 -0
  326. package/src/tools/toggle/toggle-lifecycle.ts +80 -0
  327. package/src/tools/toggle/toggle-shortcuts.ts +107 -0
  328. package/src/tools/toggle/types.ts +21 -0
  329. package/src/variants/blok-minimum.ts +13 -0
  330. package/types/api/block.d.ts +13 -0
  331. package/types/api/blocks.d.ts +16 -0
  332. package/types/full.d.ts +2 -0
  333. package/types/tools/table.d.ts +2 -0
  334. package/types/tools-entry.d.ts +2 -1
  335. package/dist/chunks/i18next-CugVlwWp.mjs +0 -1292
  336. package/src/tools/table/data-normalizer.ts +0 -32
@@ -56,6 +56,7 @@ export class TableRowColDrag {
56
56
 
57
57
  private boundDocPointerMove: (e: PointerEvent) => void;
58
58
  private boundDocPointerUp: (e: PointerEvent) => void;
59
+ private boundDocPointerCancel: () => void;
59
60
 
60
61
  /** Resolves when drag ends — set by beginTracking, consumed by caller */
61
62
  private resolveTracking: ((wasDrag: boolean) => void) | null = null;
@@ -67,6 +68,7 @@ export class TableRowColDrag {
67
68
 
68
69
  this.boundDocPointerMove = this.handleDocPointerMove.bind(this);
69
70
  this.boundDocPointerUp = this.handleDocPointerUp.bind(this);
71
+ this.boundDocPointerCancel = this.handleDocPointerCancel.bind(this);
70
72
  }
71
73
 
72
74
  /**
@@ -87,6 +89,7 @@ export class TableRowColDrag {
87
89
 
88
90
  document.addEventListener('pointermove', this.boundDocPointerMove);
89
91
  document.addEventListener('pointerup', this.boundDocPointerUp);
92
+ document.addEventListener('pointercancel', this.boundDocPointerCancel);
90
93
 
91
94
  return new Promise<boolean>(resolve => {
92
95
  this.resolveTracking = resolve;
@@ -113,6 +116,7 @@ export class TableRowColDrag {
113
116
 
114
117
  document.removeEventListener('pointermove', this.boundDocPointerMove);
115
118
  document.removeEventListener('pointerup', this.boundDocPointerUp);
119
+ document.removeEventListener('pointercancel', this.boundDocPointerCancel);
116
120
 
117
121
  this.onDragStateChange?.(false, null);
118
122
  this.isDragging = false;
@@ -139,6 +143,7 @@ export class TableRowColDrag {
139
143
  private handleDocPointerUp(e: PointerEvent): void {
140
144
  document.removeEventListener('pointermove', this.boundDocPointerMove);
141
145
  document.removeEventListener('pointerup', this.boundDocPointerUp);
146
+ document.removeEventListener('pointercancel', this.boundDocPointerCancel);
142
147
 
143
148
  if (this.isDragging) {
144
149
  this.finishDrag(e);
@@ -150,6 +155,15 @@ export class TableRowColDrag {
150
155
  this.cleanup();
151
156
  }
152
157
 
158
+ /**
159
+ * Handle pointercancel — browser aborted the pointer (touch gesture, system dialog, etc.).
160
+ * Cleans up without applying the move (treats as abort).
161
+ */
162
+ private handleDocPointerCancel(): void {
163
+ this.resolveTracking?.(this.isDragging);
164
+ this.cleanup();
165
+ }
166
+
153
167
  private startDrag(): void {
154
168
  this.grid.style.userSelect = 'none';
155
169
  document.body.style.cursor = 'grabbing';
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Scroll haze overlays for the Table tool.
3
+ *
4
+ * Adds gradient overlays on the left/right edges of the table wrapper
5
+ * to indicate that the table content is horizontally scrollable.
6
+ * Uses a passive scroll event listener with rAF throttling.
7
+ */
8
+
9
+ const HAZE_ATTR = 'data-blok-table-haze';
10
+ const HAZE_VISIBLE_ATTR = 'data-blok-table-haze-visible';
11
+
12
+ /** Minimum scrollLeft delta to consider "scrolled" (avoids sub-pixel flicker). */
13
+ const SCROLL_THRESHOLD = 1;
14
+
15
+ const HAZE_CLASSES = [
16
+ 'absolute',
17
+ 'top-0',
18
+ 'bottom-0',
19
+ 'w-12',
20
+ 'pointer-events-none',
21
+ 'opacity-0',
22
+ 'transition-opacity',
23
+ 'duration-150',
24
+ 'z-1',
25
+ ];
26
+
27
+ const LEFT_HAZE_CLASSES = [
28
+ 'left-0',
29
+ 'bg-linear-to-r',
30
+ 'from-white/80',
31
+ 'to-transparent',
32
+ ];
33
+
34
+ const RIGHT_HAZE_CLASSES = [
35
+ 'right-5',
36
+ 'bg-linear-to-l',
37
+ 'from-white/80',
38
+ 'to-transparent',
39
+ ];
40
+
41
+ /**
42
+ * Manages left/right gradient haze overlays that indicate
43
+ * the table can be scrolled horizontally.
44
+ */
45
+ export class TableScrollHaze {
46
+ private leftHaze: HTMLDivElement | null = null;
47
+ private rightHaze: HTMLDivElement | null = null;
48
+ private scrollContainer: HTMLElement | null = null;
49
+ private boundOnScroll: (() => void) | null = null;
50
+ private ticking = false;
51
+
52
+ /**
53
+ * Create haze overlay elements and attach the scroll listener.
54
+ *
55
+ * @param wrapper - The table wrapper element (position: relative)
56
+ * @param scrollContainer - The scroll container with overflow-x: auto
57
+ */
58
+ public init(wrapper: HTMLElement, scrollContainer: HTMLElement): void {
59
+ this.scrollContainer = scrollContainer;
60
+
61
+ this.leftHaze = this.createHazeElement('left');
62
+ this.rightHaze = this.createHazeElement('right');
63
+
64
+ wrapper.appendChild(this.leftHaze);
65
+ wrapper.appendChild(this.rightHaze);
66
+
67
+ this.boundOnScroll = (): void => {
68
+ if (!this.ticking) {
69
+ requestAnimationFrame(() => {
70
+ this.syncVisibility();
71
+ this.ticking = false;
72
+ });
73
+ this.ticking = true;
74
+ }
75
+ };
76
+
77
+ scrollContainer.addEventListener('scroll', this.boundOnScroll, { passive: true });
78
+
79
+ this.syncVisibility();
80
+ }
81
+
82
+ /**
83
+ * Recalculate haze visibility (e.g. after column resize or add/delete).
84
+ */
85
+ public update(): void {
86
+ this.syncVisibility();
87
+ }
88
+
89
+ /**
90
+ * Remove overlay elements and detach the scroll listener.
91
+ */
92
+ public destroy(): void {
93
+ if (this.boundOnScroll && this.scrollContainer) {
94
+ this.scrollContainer.removeEventListener('scroll', this.boundOnScroll);
95
+ }
96
+
97
+ this.leftHaze?.remove();
98
+ this.rightHaze?.remove();
99
+
100
+ this.leftHaze = null;
101
+ this.rightHaze = null;
102
+ this.scrollContainer = null;
103
+ this.boundOnScroll = null;
104
+ this.ticking = false;
105
+ }
106
+
107
+ private createHazeElement(side: 'left' | 'right'): HTMLDivElement {
108
+ const el = document.createElement('div');
109
+
110
+ el.setAttribute(HAZE_ATTR, side);
111
+ el.setAttribute('aria-hidden', 'true');
112
+ el.classList.add(...HAZE_CLASSES, ...(side === 'left' ? LEFT_HAZE_CLASSES : RIGHT_HAZE_CLASSES));
113
+
114
+ return el;
115
+ }
116
+
117
+ private syncVisibility(): void {
118
+ const sc = this.scrollContainer;
119
+
120
+ if (!sc) {
121
+ return;
122
+ }
123
+
124
+ const { overflowX } = getComputedStyle(sc);
125
+ const canScroll = overflowX === 'auto' || overflowX === 'scroll';
126
+
127
+ if (!canScroll) {
128
+ this.setVisible(this.leftHaze, false);
129
+ this.setVisible(this.rightHaze, false);
130
+
131
+ return;
132
+ }
133
+
134
+ const { scrollLeft, scrollWidth, clientWidth } = sc;
135
+ const maxScroll = scrollWidth - clientWidth;
136
+
137
+ this.setVisible(this.leftHaze, scrollLeft > SCROLL_THRESHOLD);
138
+ this.setVisible(this.rightHaze, maxScroll > SCROLL_THRESHOLD && scrollLeft < maxScroll - SCROLL_THRESHOLD);
139
+ }
140
+
141
+ private setVisible(el: HTMLElement | null, visible: boolean): void {
142
+ if (!el) {
143
+ return;
144
+ }
145
+
146
+ if (visible) {
147
+ el.setAttribute(HAZE_VISIBLE_ATTR, '');
148
+ } else {
149
+ el.removeAttribute(HAZE_VISIBLE_ATTR);
150
+ }
151
+ }
152
+ }
@@ -4,7 +4,7 @@ import type { BlockToolData } from '../../../types';
4
4
  * Cell content always contains block IDs.
5
5
  * Every cell in the table is represented as an array of block references.
6
6
  */
7
- export type CellContent = { blocks: string[] };
7
+ export type CellContent = { blocks: string[]; color?: string; textColor?: string; text?: string };
8
8
 
9
9
  /**
10
10
  * Legacy cell content type for migration from string-based cells.
@@ -53,4 +53,25 @@ export interface TableConfig {
53
53
  withHeadings?: boolean;
54
54
  /** Whether to start stretched */
55
55
  stretched?: boolean;
56
+ /** Additional tool names to restrict from being inserted into table cells */
57
+ restrictedTools?: string[];
58
+ }
59
+
60
+ /**
61
+ * Block data within a clipboard cell (no IDs — those are assigned on paste).
62
+ */
63
+ export interface ClipboardBlockData {
64
+ tool: string;
65
+ data: Record<string, unknown>;
66
+ tunes?: Record<string, unknown>;
67
+ }
68
+
69
+ /**
70
+ * Clipboard payload for copied table cells.
71
+ * Stored as JSON in a data attribute on the HTML table element.
72
+ */
73
+ export interface TableCellsClipboard {
74
+ rows: number;
75
+ cols: number;
76
+ cells: Array<Array<{ blocks: ClipboardBlockData[]; color?: string; textColor?: string }>>;
56
77
  }
@@ -0,0 +1,47 @@
1
+ import type { TableEventBroker, BlockLifecycleEvent } from '../ownership/table-event-broker';
2
+ import type { TableOwnershipRegistry } from '../ownership/table-ownership-registry';
3
+
4
+ /**
5
+ * Adapter that bridges the ownership-based event broker into the existing
6
+ * TableCellBlocks event handling.
7
+ *
8
+ * In shadow mode, this adapter subscribes the table to the broker and
9
+ * forwards routed events to the table's handler. It does NOT replace the
10
+ * existing global event listener — both paths run in parallel for validation.
11
+ *
12
+ * After cutover (Task 7), this adapter becomes the sole event path.
13
+ */
14
+ export class TableCellBlocksAdapter {
15
+ private readonly tableId: string;
16
+ private readonly broker: TableEventBroker;
17
+ private readonly registry: TableOwnershipRegistry;
18
+ private readonly onEvent: (blockId: string, event: BlockLifecycleEvent) => void;
19
+
20
+ constructor(options: {
21
+ tableId: string;
22
+ broker: TableEventBroker;
23
+ registry: TableOwnershipRegistry;
24
+ onEvent: (blockId: string, event: BlockLifecycleEvent) => void;
25
+ }) {
26
+ this.tableId = options.tableId;
27
+ this.broker = options.broker;
28
+ this.registry = options.registry;
29
+ this.onEvent = options.onEvent;
30
+
31
+ this.broker.subscribe(this.tableId, this.handleBrokerEvent);
32
+ }
33
+
34
+ /**
35
+ * Destroy the adapter — unsubscribe from the broker.
36
+ */
37
+ destroy(): void {
38
+ this.broker.unsubscribe(this.tableId);
39
+ }
40
+
41
+ /**
42
+ * Handler for events routed through the broker.
43
+ */
44
+ private handleBrokerEvent = (blockId: string, event: BlockLifecycleEvent): void => {
45
+ this.onEvent(blockId, event);
46
+ };
47
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Toggle Block Operations - Block-related operations for ToggleItem.
3
+ *
4
+ * Extracted from ToggleItem to reduce file size.
5
+ */
6
+
7
+ import { stripFakeBackgroundElements } from '../../components/utils';
8
+
9
+ import type { ToggleItemData } from './types';
10
+
11
+ /**
12
+ * Parse HTML string into a DocumentFragment.
13
+ *
14
+ * @param html - HTML string to parse
15
+ * @returns DocumentFragment with parsed nodes
16
+ */
17
+ export const parseHTML = (html: string): DocumentFragment => {
18
+ const wrapper = document.createElement('div');
19
+ wrapper.innerHTML = html.trim();
20
+
21
+ const fragment = document.createDocumentFragment();
22
+ fragment.append(...Array.from(wrapper.childNodes));
23
+
24
+ return fragment;
25
+ };
26
+
27
+ /**
28
+ * Save the toggle item data.
29
+ *
30
+ * @param data - Current toggle item data
31
+ * @param element - The toggle wrapper element (or null)
32
+ * @param getContentElement - Function to get the content element
33
+ * @returns The saved toggle item data
34
+ */
35
+ export const saveToggleItem = (
36
+ data: ToggleItemData,
37
+ element: HTMLElement | null,
38
+ getContentElement: () => HTMLElement | null
39
+ ): ToggleItemData => {
40
+ if (!element) return data;
41
+
42
+ const contentEl = getContentElement();
43
+ const text = contentEl ? stripFakeBackgroundElements(contentEl.innerHTML) : data.text;
44
+
45
+ return { text };
46
+ };
47
+
48
+ /**
49
+ * Context for merge operations
50
+ */
51
+ export interface MergeContext {
52
+ data: ToggleItemData;
53
+ getContentElement: () => HTMLElement | null;
54
+ parseHTML: (html: string) => DocumentFragment;
55
+ }
56
+
57
+ /**
58
+ * Merge incoming data into toggle item.
59
+ *
60
+ * @param context - The merge context
61
+ * @param incomingData - The incoming data to merge
62
+ */
63
+ export const mergeToggleItemData = (
64
+ context: MergeContext,
65
+ incomingData: ToggleItemData
66
+ ): void => {
67
+ const { data, getContentElement } = context;
68
+
69
+ data.text += incomingData.text;
70
+
71
+ const contentEl = getContentElement();
72
+
73
+ if (contentEl && incomingData.text) {
74
+ const fragment = context.parseHTML(incomingData.text);
75
+
76
+ contentEl.appendChild(fragment);
77
+ contentEl.normalize();
78
+ }
79
+ };
80
+
81
+ /**
82
+ * Set data on the toggle item (for undo/redo).
83
+ *
84
+ * @param currentData - The current toggle item data
85
+ * @param newData - The new data to apply
86
+ * @param getContentElement - Function to get the content element
87
+ * @returns Object with the updated data and whether the update was in-place
88
+ */
89
+ export const setToggleItemData = (
90
+ currentData: ToggleItemData,
91
+ newData: ToggleItemData,
92
+ getContentElement: () => HTMLElement | null
93
+ ): { newData: ToggleItemData; inPlace: boolean } => {
94
+ const contentEl = getContentElement();
95
+
96
+ if (!contentEl) {
97
+ return { newData: currentData, inPlace: false };
98
+ }
99
+
100
+ const updatedData: ToggleItemData = {
101
+ ...currentData,
102
+ ...newData,
103
+ };
104
+
105
+ if (typeof newData.text === 'string') {
106
+ contentEl.innerHTML = newData.text;
107
+ }
108
+
109
+ return { newData: updatedData, inPlace: true };
110
+ };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Constants for the Toggle tool
3
+ */
4
+
5
+ /**
6
+ * Tool name used when registering this tool with Blok
7
+ */
8
+ export const TOOL_NAME = 'toggle';
9
+
10
+ /**
11
+ * Placeholder translation key
12
+ */
13
+ export const PLACEHOLDER_KEY = 'tools.toggle.placeholder';
14
+
15
+ /**
16
+ * Base styles for toggle wrapper
17
+ *
18
+ * Matches paragraph spacing: py-[3px] from blok-block + mt-[2px] mb-px
19
+ */
20
+ export const BASE_STYLES = 'outline-hidden py-[3px] mt-[2px] mb-px';
21
+
22
+ /**
23
+ * Styles for toggle content area
24
+ */
25
+ export const CONTENT_STYLES = 'outline-hidden pl-0.5 leading-[1.6em] flex-1 min-w-0';
26
+
27
+ /**
28
+ * Styles for toggle wrapper (arrow + content layout)
29
+ */
30
+ export const TOGGLE_WRAPPER_STYLES = 'flex items-start';
31
+
32
+ /**
33
+ * Styles for the toggle arrow button
34
+ */
35
+ export const ARROW_STYLES = 'flex-shrink-0 w-6 h-6 flex items-center justify-center cursor-pointer select-none rounded hover:bg-black/5 transition-all duration-200 ease-in-out mt-px';
36
+
37
+ /**
38
+ * SVG icon for the toggle arrow
39
+ */
40
+ export const ARROW_ICON = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4.5 2.5L8.5 6L4.5 9.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
41
+
42
+ /**
43
+ * Data attributes specific to the toggle tool
44
+ */
45
+ export const TOGGLE_ATTR = {
46
+ toggleOpen: 'data-blok-toggle-open',
47
+ toggleArrow: 'data-blok-toggle-arrow',
48
+ toggleContent: 'data-blok-toggle-content',
49
+ } as const;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * DOM Builder - Pure functions for DOM creation.
3
+ *
4
+ * These functions are extracted from ToggleItem for testability.
5
+ * They create DOM elements without side effects.
6
+ */
7
+
8
+ import { DATA_ATTR } from '../../components/constants';
9
+ import { twMerge } from '../../components/utils/tw';
10
+
11
+ import {
12
+ ARROW_ICON,
13
+ ARROW_STYLES,
14
+ BASE_STYLES,
15
+ CONTENT_STYLES,
16
+ TOGGLE_ATTR,
17
+ TOGGLE_WRAPPER_STYLES,
18
+ TOOL_NAME,
19
+ } from './constants';
20
+ import type { ToggleItemData } from './types';
21
+
22
+ /**
23
+ * Context object for DOM building operations
24
+ */
25
+ export interface ToggleDOMBuilderContext {
26
+ /** The toggle item data */
27
+ data: ToggleItemData;
28
+ /** Whether the editor is in read-only mode */
29
+ readOnly: boolean;
30
+ /** Whether the toggle is open (expanded) */
31
+ isOpen: boolean;
32
+ /** Optional keydown event handler */
33
+ keydownHandler: ((event: KeyboardEvent) => void) | null;
34
+ /** Callback when the arrow is clicked */
35
+ onArrowClick: () => void;
36
+ }
37
+
38
+ /**
39
+ * Result of building a toggle item element
40
+ */
41
+ export interface ToggleBuildResult {
42
+ /** The wrapper element */
43
+ wrapper: HTMLElement;
44
+ /** The arrow element for expanding/collapsing */
45
+ arrowElement: HTMLElement;
46
+ /** The content element for text input */
47
+ contentElement: HTMLElement;
48
+ }
49
+
50
+ /**
51
+ * Build the complete toggle item DOM structure.
52
+ *
53
+ * @param context - The builder context
54
+ * @returns Object containing the created elements
55
+ */
56
+ export const buildToggleItem = (context: ToggleDOMBuilderContext): ToggleBuildResult => {
57
+ const { data, readOnly, isOpen, keydownHandler, onArrowClick } = context;
58
+
59
+ const wrapper = document.createElement('div');
60
+ wrapper.className = twMerge(BASE_STYLES, TOGGLE_WRAPPER_STYLES);
61
+ wrapper.setAttribute(DATA_ATTR.tool, TOOL_NAME);
62
+ wrapper.setAttribute(TOGGLE_ATTR.toggleOpen, String(isOpen));
63
+
64
+ const arrowElement = buildArrow(isOpen, onArrowClick);
65
+ const contentElement = buildContent(data, readOnly, keydownHandler);
66
+
67
+ wrapper.appendChild(arrowElement);
68
+ wrapper.appendChild(contentElement);
69
+
70
+ return { wrapper, arrowElement, contentElement };
71
+ };
72
+
73
+ /**
74
+ * Build the arrow element for toggling open/closed state.
75
+ *
76
+ * @param isOpen - Whether the toggle is currently open
77
+ * @param onArrowClick - Callback when arrow is clicked
78
+ * @returns The arrow element
79
+ */
80
+ const buildArrow = (isOpen: boolean, onArrowClick: () => void): HTMLElement => {
81
+ const arrow = document.createElement('div');
82
+ arrow.className = ARROW_STYLES;
83
+ arrow.setAttribute(TOGGLE_ATTR.toggleArrow, '');
84
+ arrow.setAttribute('role', 'button');
85
+ arrow.setAttribute('tabindex', '-1');
86
+ arrow.setAttribute('aria-label', 'Toggle');
87
+ arrow.innerHTML = ARROW_ICON;
88
+
89
+ if (isOpen) {
90
+ arrow.style.transform = 'rotate(90deg)';
91
+ }
92
+
93
+ arrow.addEventListener('click', (event: MouseEvent) => {
94
+ event.stopPropagation();
95
+ onArrowClick();
96
+ });
97
+
98
+ return arrow;
99
+ };
100
+
101
+ /**
102
+ * Build the content element for text input.
103
+ *
104
+ * @param data - The toggle item data
105
+ * @param readOnly - Whether the editor is read-only
106
+ * @param keydownHandler - Optional keydown event handler
107
+ * @returns The content element
108
+ */
109
+ const buildContent = (
110
+ data: ToggleItemData,
111
+ readOnly: boolean,
112
+ keydownHandler: ((event: KeyboardEvent) => void) | null
113
+ ): HTMLElement => {
114
+ const content = document.createElement('div');
115
+ content.className = CONTENT_STYLES;
116
+ content.setAttribute(TOGGLE_ATTR.toggleContent, '');
117
+ content.contentEditable = readOnly ? 'false' : 'true';
118
+ content.innerHTML = data.text;
119
+
120
+ if (keydownHandler) {
121
+ content.addEventListener('keydown', keydownHandler);
122
+ }
123
+
124
+ return content;
125
+ };