@jackuait/blok 0.4.1 → 0.4.3-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 (397) hide show
  1. package/README.md +136 -17
  2. package/codemod/README.md +45 -7
  3. package/codemod/migrate-editorjs-to-blok.js +951 -92
  4. package/codemod/test.js +780 -77
  5. package/dist/blok.mjs +5 -2
  6. package/dist/chunks/blok-8ptWuVZC.mjs +12838 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-bLawSYRV.mjs +43 -0
  9. package/dist/{index-CBkApZKo.mjs → chunks/index-5nYtWZD2.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-CvMDAIzb.mjs +1988 -0
  11. package/dist/chunks/messages-2434tVOK.mjs +47 -0
  12. package/dist/chunks/messages-3DcCwXMF.mjs +47 -0
  13. package/dist/chunks/messages-4kMwVAKY.mjs +47 -0
  14. package/dist/chunks/messages-57uL5htT.mjs +47 -0
  15. package/dist/chunks/messages-76-iJV9Q.mjs +47 -0
  16. package/dist/chunks/messages-8p86Eyf2.mjs +47 -0
  17. package/dist/chunks/messages-BBX0p0Pi.mjs +47 -0
  18. package/dist/chunks/messages-BCm2eudQ.mjs +47 -0
  19. package/dist/chunks/messages-BFiUomgG.mjs +47 -0
  20. package/dist/chunks/messages-BIPNHHAV.mjs +47 -0
  21. package/dist/chunks/messages-BUlwu9mo.mjs +47 -0
  22. package/dist/chunks/messages-BX-DPa-z.mjs +47 -0
  23. package/dist/chunks/messages-BextV3Qh.mjs +47 -0
  24. package/dist/chunks/messages-BiPSFlUG.mjs +47 -0
  25. package/dist/chunks/messages-BiXe9G-O.mjs +47 -0
  26. package/dist/chunks/messages-Bl5z_Igo.mjs +47 -0
  27. package/dist/chunks/messages-BnsE97ku.mjs +47 -0
  28. package/dist/chunks/messages-BoO8gsVD.mjs +47 -0
  29. package/dist/chunks/messages-BqWaOGMn.mjs +47 -0
  30. package/dist/chunks/messages-BqkL2_Ro.mjs +47 -0
  31. package/dist/chunks/messages-BvCkXKX-.mjs +47 -0
  32. package/dist/chunks/messages-C6tbPLoj.mjs +47 -0
  33. package/dist/chunks/messages-CA6T3-gQ.mjs +47 -0
  34. package/dist/chunks/messages-CFFPFdWP.mjs +47 -0
  35. package/dist/chunks/messages-CFrKE-TN.mjs +47 -0
  36. package/dist/chunks/messages-CHz8VlG-.mjs +47 -0
  37. package/dist/chunks/messages-CLixzySl.mjs +47 -0
  38. package/dist/chunks/messages-CV7OM_qk.mjs +47 -0
  39. package/dist/chunks/messages-CXHt3eCC.mjs +47 -0
  40. package/dist/chunks/messages-CbmsBrB0.mjs +47 -0
  41. package/dist/chunks/messages-Ceo1KtFx.mjs +47 -0
  42. package/dist/chunks/messages-Cm0LJLtB.mjs +47 -0
  43. package/dist/chunks/messages-CmymP_Ar.mjs +47 -0
  44. package/dist/chunks/messages-D0ohMB5H.mjs +47 -0
  45. package/dist/chunks/messages-D3GrDwXh.mjs +47 -0
  46. package/dist/chunks/messages-D3vTzIpL.mjs +47 -0
  47. package/dist/chunks/messages-D5WeksbV.mjs +47 -0
  48. package/dist/chunks/messages-DGaab4EP.mjs +47 -0
  49. package/dist/chunks/messages-DKha57ZU.mjs +47 -0
  50. package/dist/chunks/messages-DOaujgMW.mjs +47 -0
  51. package/dist/chunks/messages-DVbPLd_0.mjs +47 -0
  52. package/dist/chunks/messages-D_FCyfW6.mjs +47 -0
  53. package/dist/chunks/messages-Dd5iZN3c.mjs +47 -0
  54. package/dist/chunks/messages-DehM7135.mjs +47 -0
  55. package/dist/chunks/messages-Dg1OHftD.mjs +47 -0
  56. package/dist/chunks/messages-Di6Flq-b.mjs +47 -0
  57. package/dist/chunks/messages-Dqhhex6e.mjs +47 -0
  58. package/dist/chunks/messages-DueVe0F1.mjs +47 -0
  59. package/dist/chunks/messages-Dx3eFwI0.mjs +47 -0
  60. package/dist/chunks/messages-FOtiUoKl.mjs +47 -0
  61. package/dist/chunks/messages-FTOZNhRD.mjs +47 -0
  62. package/dist/chunks/messages-IQxGfQIV.mjs +47 -0
  63. package/dist/chunks/messages-JF2fzCkK.mjs +47 -0
  64. package/dist/chunks/messages-MOGl7I5v.mjs +47 -0
  65. package/dist/chunks/messages-QgYhPL-3.mjs +47 -0
  66. package/dist/chunks/messages-WYWIbQwo.mjs +47 -0
  67. package/dist/chunks/messages-a6A_LgDv.mjs +47 -0
  68. package/dist/chunks/messages-bSf31LJi.mjs +47 -0
  69. package/dist/chunks/messages-diGozhTn.mjs +47 -0
  70. package/dist/chunks/messages-er-kd-VO.mjs +47 -0
  71. package/dist/chunks/messages-ez3w5NBn.mjs +47 -0
  72. package/dist/chunks/messages-f3uXjegd.mjs +47 -0
  73. package/dist/chunks/messages-ohwI1UGv.mjs +47 -0
  74. package/dist/chunks/messages-p9BZJaFV.mjs +47 -0
  75. package/dist/chunks/messages-qIQ4L4rw.mjs +47 -0
  76. package/dist/chunks/messages-qWkXPggi.mjs +47 -0
  77. package/dist/chunks/messages-w5foGze_.mjs +47 -0
  78. package/dist/full.mjs +50 -0
  79. package/dist/locales.mjs +227 -0
  80. package/dist/messages-2434tVOK.mjs +47 -0
  81. package/dist/messages-3DcCwXMF.mjs +47 -0
  82. package/dist/messages-4kMwVAKY.mjs +47 -0
  83. package/dist/messages-57uL5htT.mjs +47 -0
  84. package/dist/messages-76-iJV9Q.mjs +47 -0
  85. package/dist/messages-8p86Eyf2.mjs +47 -0
  86. package/dist/messages-BBX0p0Pi.mjs +47 -0
  87. package/dist/messages-BCm2eudQ.mjs +47 -0
  88. package/dist/messages-BFiUomgG.mjs +47 -0
  89. package/dist/messages-BIPNHHAV.mjs +47 -0
  90. package/dist/messages-BUlwu9mo.mjs +47 -0
  91. package/dist/messages-BX-DPa-z.mjs +47 -0
  92. package/dist/messages-BextV3Qh.mjs +47 -0
  93. package/dist/messages-BiPSFlUG.mjs +47 -0
  94. package/dist/messages-BiXe9G-O.mjs +47 -0
  95. package/dist/messages-Bl5z_Igo.mjs +47 -0
  96. package/dist/messages-BnsE97ku.mjs +47 -0
  97. package/dist/messages-BoO8gsVD.mjs +47 -0
  98. package/dist/messages-BqWaOGMn.mjs +47 -0
  99. package/dist/messages-BqkL2_Ro.mjs +47 -0
  100. package/dist/messages-BvCkXKX-.mjs +47 -0
  101. package/dist/messages-C6tbPLoj.mjs +47 -0
  102. package/dist/messages-CA6T3-gQ.mjs +47 -0
  103. package/dist/messages-CFFPFdWP.mjs +47 -0
  104. package/dist/messages-CFrKE-TN.mjs +47 -0
  105. package/dist/messages-CHz8VlG-.mjs +47 -0
  106. package/dist/messages-CLixzySl.mjs +47 -0
  107. package/dist/messages-CV7OM_qk.mjs +47 -0
  108. package/dist/messages-CXHt3eCC.mjs +47 -0
  109. package/dist/messages-CbmsBrB0.mjs +47 -0
  110. package/dist/messages-Ceo1KtFx.mjs +47 -0
  111. package/dist/messages-Cm0LJLtB.mjs +47 -0
  112. package/dist/messages-CmymP_Ar.mjs +47 -0
  113. package/dist/messages-D0ohMB5H.mjs +47 -0
  114. package/dist/messages-D3GrDwXh.mjs +47 -0
  115. package/dist/messages-D3vTzIpL.mjs +47 -0
  116. package/dist/messages-D5WeksbV.mjs +47 -0
  117. package/dist/messages-DGaab4EP.mjs +47 -0
  118. package/dist/messages-DKha57ZU.mjs +47 -0
  119. package/dist/messages-DOaujgMW.mjs +47 -0
  120. package/dist/messages-DVbPLd_0.mjs +47 -0
  121. package/dist/messages-D_FCyfW6.mjs +47 -0
  122. package/dist/messages-Dd5iZN3c.mjs +47 -0
  123. package/dist/messages-DehM7135.mjs +47 -0
  124. package/dist/messages-Dg1OHftD.mjs +47 -0
  125. package/dist/messages-Di6Flq-b.mjs +47 -0
  126. package/dist/messages-Dqhhex6e.mjs +47 -0
  127. package/dist/messages-DueVe0F1.mjs +47 -0
  128. package/dist/messages-Dx3eFwI0.mjs +47 -0
  129. package/dist/messages-FOtiUoKl.mjs +47 -0
  130. package/dist/messages-FTOZNhRD.mjs +47 -0
  131. package/dist/messages-IQxGfQIV.mjs +47 -0
  132. package/dist/messages-JF2fzCkK.mjs +47 -0
  133. package/dist/messages-MOGl7I5v.mjs +47 -0
  134. package/dist/messages-QgYhPL-3.mjs +47 -0
  135. package/dist/messages-WYWIbQwo.mjs +47 -0
  136. package/dist/messages-a6A_LgDv.mjs +47 -0
  137. package/dist/messages-bSf31LJi.mjs +47 -0
  138. package/dist/messages-diGozhTn.mjs +47 -0
  139. package/dist/messages-er-kd-VO.mjs +47 -0
  140. package/dist/messages-ez3w5NBn.mjs +47 -0
  141. package/dist/messages-f3uXjegd.mjs +47 -0
  142. package/dist/messages-ohwI1UGv.mjs +47 -0
  143. package/dist/messages-p9BZJaFV.mjs +47 -0
  144. package/dist/messages-qIQ4L4rw.mjs +47 -0
  145. package/dist/messages-qWkXPggi.mjs +47 -0
  146. package/dist/messages-w5foGze_.mjs +47 -0
  147. package/dist/tools.mjs +3073 -0
  148. package/dist/vendor.LICENSE.txt +59 -156
  149. package/package.json +60 -15
  150. package/src/blok.ts +267 -0
  151. package/src/components/__module.ts +139 -0
  152. package/src/components/block/api.ts +155 -0
  153. package/src/components/block/index.ts +1427 -0
  154. package/src/components/block-tunes/block-tune-delete.ts +51 -0
  155. package/src/components/blocks.ts +338 -0
  156. package/src/components/constants/data-attributes.ts +342 -0
  157. package/src/components/constants.ts +76 -0
  158. package/src/components/core.ts +392 -0
  159. package/src/components/dom.ts +773 -0
  160. package/src/components/domIterator.ts +189 -0
  161. package/src/components/errors/critical.ts +5 -0
  162. package/src/components/events/BlockChanged.ts +16 -0
  163. package/src/components/events/BlockHovered.ts +21 -0
  164. package/src/components/events/BlockSettingsClosed.ts +12 -0
  165. package/src/components/events/BlockSettingsOpened.ts +12 -0
  166. package/src/components/events/BlokMobileLayoutToggled.ts +15 -0
  167. package/src/components/events/FakeCursorAboutToBeToggled.ts +17 -0
  168. package/src/components/events/FakeCursorHaveBeenSet.ts +17 -0
  169. package/src/components/events/HistoryStateChanged.ts +19 -0
  170. package/src/components/events/RedactorDomChanged.ts +14 -0
  171. package/src/components/events/index.ts +46 -0
  172. package/src/components/flipper.ts +481 -0
  173. package/src/components/i18n/i18next-loader.ts +84 -0
  174. package/src/components/i18n/lightweight-i18n.ts +86 -0
  175. package/src/components/i18n/locales/TRANSLATION_GUIDELINES.md +113 -0
  176. package/src/components/i18n/locales/am/messages.json +44 -0
  177. package/src/components/i18n/locales/ar/messages.json +44 -0
  178. package/src/components/i18n/locales/az/messages.json +44 -0
  179. package/src/components/i18n/locales/bg/messages.json +44 -0
  180. package/src/components/i18n/locales/bn/messages.json +44 -0
  181. package/src/components/i18n/locales/bs/messages.json +44 -0
  182. package/src/components/i18n/locales/cs/messages.json +44 -0
  183. package/src/components/i18n/locales/da/messages.json +44 -0
  184. package/src/components/i18n/locales/de/messages.json +44 -0
  185. package/src/components/i18n/locales/dv/messages.json +44 -0
  186. package/src/components/i18n/locales/el/messages.json +44 -0
  187. package/src/components/i18n/locales/en/messages.json +44 -0
  188. package/src/components/i18n/locales/es/messages.json +44 -0
  189. package/src/components/i18n/locales/et/messages.json +44 -0
  190. package/src/components/i18n/locales/fa/messages.json +44 -0
  191. package/src/components/i18n/locales/fi/messages.json +44 -0
  192. package/src/components/i18n/locales/fil/messages.json +44 -0
  193. package/src/components/i18n/locales/fr/messages.json +44 -0
  194. package/src/components/i18n/locales/gu/messages.json +44 -0
  195. package/src/components/i18n/locales/he/messages.json +44 -0
  196. package/src/components/i18n/locales/hi/messages.json +44 -0
  197. package/src/components/i18n/locales/hr/messages.json +44 -0
  198. package/src/components/i18n/locales/hu/messages.json +44 -0
  199. package/src/components/i18n/locales/hy/messages.json +44 -0
  200. package/src/components/i18n/locales/id/messages.json +44 -0
  201. package/src/components/i18n/locales/index.ts +225 -0
  202. package/src/components/i18n/locales/it/messages.json +44 -0
  203. package/src/components/i18n/locales/ja/messages.json +44 -0
  204. package/src/components/i18n/locales/ka/messages.json +44 -0
  205. package/src/components/i18n/locales/km/messages.json +44 -0
  206. package/src/components/i18n/locales/kn/messages.json +44 -0
  207. package/src/components/i18n/locales/ko/messages.json +44 -0
  208. package/src/components/i18n/locales/ku/messages.json +44 -0
  209. package/src/components/i18n/locales/lo/messages.json +44 -0
  210. package/src/components/i18n/locales/lt/messages.json +44 -0
  211. package/src/components/i18n/locales/lv/messages.json +44 -0
  212. package/src/components/i18n/locales/mk/messages.json +44 -0
  213. package/src/components/i18n/locales/ml/messages.json +44 -0
  214. package/src/components/i18n/locales/mn/messages.json +44 -0
  215. package/src/components/i18n/locales/mr/messages.json +44 -0
  216. package/src/components/i18n/locales/ms/messages.json +44 -0
  217. package/src/components/i18n/locales/my/messages.json +44 -0
  218. package/src/components/i18n/locales/ne/messages.json +44 -0
  219. package/src/components/i18n/locales/nl/messages.json +44 -0
  220. package/src/components/i18n/locales/no/messages.json +44 -0
  221. package/src/components/i18n/locales/pa/messages.json +44 -0
  222. package/src/components/i18n/locales/pl/messages.json +44 -0
  223. package/src/components/i18n/locales/ps/messages.json +44 -0
  224. package/src/components/i18n/locales/pt/messages.json +44 -0
  225. package/src/components/i18n/locales/ro/messages.json +44 -0
  226. package/src/components/i18n/locales/ru/messages.json +44 -0
  227. package/src/components/i18n/locales/sd/messages.json +44 -0
  228. package/src/components/i18n/locales/si/messages.json +44 -0
  229. package/src/components/i18n/locales/sk/messages.json +44 -0
  230. package/src/components/i18n/locales/sl/messages.json +44 -0
  231. package/src/components/i18n/locales/sq/messages.json +44 -0
  232. package/src/components/i18n/locales/sr/messages.json +44 -0
  233. package/src/components/i18n/locales/sv/messages.json +44 -0
  234. package/src/components/i18n/locales/sw/messages.json +44 -0
  235. package/src/components/i18n/locales/ta/messages.json +44 -0
  236. package/src/components/i18n/locales/te/messages.json +44 -0
  237. package/src/components/i18n/locales/th/messages.json +44 -0
  238. package/src/components/i18n/locales/tr/messages.json +44 -0
  239. package/src/components/i18n/locales/ug/messages.json +44 -0
  240. package/src/components/i18n/locales/uk/messages.json +44 -0
  241. package/src/components/i18n/locales/ur/messages.json +44 -0
  242. package/src/components/i18n/locales/vi/messages.json +44 -0
  243. package/src/components/i18n/locales/yi/messages.json +44 -0
  244. package/src/components/i18n/locales/zh/messages.json +44 -0
  245. package/src/components/icons/index.ts +242 -0
  246. package/src/components/inline-tools/inline-tool-bold.ts +2213 -0
  247. package/src/components/inline-tools/inline-tool-convert.ts +141 -0
  248. package/src/components/inline-tools/inline-tool-italic.ts +500 -0
  249. package/src/components/inline-tools/inline-tool-link.ts +539 -0
  250. package/src/components/modules/api/blocks.ts +363 -0
  251. package/src/components/modules/api/caret.ts +125 -0
  252. package/src/components/modules/api/events.ts +51 -0
  253. package/src/components/modules/api/history.ts +73 -0
  254. package/src/components/modules/api/i18n.ts +33 -0
  255. package/src/components/modules/api/index.ts +39 -0
  256. package/src/components/modules/api/inlineToolbar.ts +33 -0
  257. package/src/components/modules/api/listeners.ts +56 -0
  258. package/src/components/modules/api/notifier.ts +46 -0
  259. package/src/components/modules/api/readonly.ts +39 -0
  260. package/src/components/modules/api/sanitizer.ts +30 -0
  261. package/src/components/modules/api/saver.ts +52 -0
  262. package/src/components/modules/api/selection.ts +48 -0
  263. package/src/components/modules/api/styles.ts +72 -0
  264. package/src/components/modules/api/toolbar.ts +79 -0
  265. package/src/components/modules/api/tools.ts +16 -0
  266. package/src/components/modules/api/tooltip.ts +67 -0
  267. package/src/components/modules/api/ui.ts +36 -0
  268. package/src/components/modules/blockEvents.ts +1375 -0
  269. package/src/components/modules/blockManager.ts +1348 -0
  270. package/src/components/modules/blockSelection.ts +708 -0
  271. package/src/components/modules/caret.ts +853 -0
  272. package/src/components/modules/crossBlockSelection.ts +329 -0
  273. package/src/components/modules/dragManager.ts +1141 -0
  274. package/src/components/modules/history.ts +1098 -0
  275. package/src/components/modules/i18n.ts +325 -0
  276. package/src/components/modules/index.ts +139 -0
  277. package/src/components/modules/modificationsObserver.ts +147 -0
  278. package/src/components/modules/paste.ts +1092 -0
  279. package/src/components/modules/readonly.ts +136 -0
  280. package/src/components/modules/rectangleSelection.ts +668 -0
  281. package/src/components/modules/renderer.ts +155 -0
  282. package/src/components/modules/saver.ts +283 -0
  283. package/src/components/modules/toolbar/blockSettings.ts +776 -0
  284. package/src/components/modules/toolbar/index.ts +1311 -0
  285. package/src/components/modules/toolbar/inline.ts +956 -0
  286. package/src/components/modules/tools.ts +589 -0
  287. package/src/components/modules/ui.ts +1179 -0
  288. package/src/components/polyfills.ts +113 -0
  289. package/src/components/selection.ts +1189 -0
  290. package/src/components/tools/base.ts +274 -0
  291. package/src/components/tools/block.ts +291 -0
  292. package/src/components/tools/collection.ts +67 -0
  293. package/src/components/tools/factory.ts +85 -0
  294. package/src/components/tools/inline.ts +71 -0
  295. package/src/components/tools/tune.ts +33 -0
  296. package/src/components/ui/toolbox.ts +497 -0
  297. package/src/components/utils/announcer.ts +205 -0
  298. package/src/components/utils/api.ts +20 -0
  299. package/src/components/utils/bem.ts +26 -0
  300. package/src/components/utils/blocks.ts +284 -0
  301. package/src/components/utils/caret.ts +1067 -0
  302. package/src/components/utils/data-model-transform.ts +382 -0
  303. package/src/components/utils/events.ts +117 -0
  304. package/src/components/utils/keyboard.ts +60 -0
  305. package/src/components/utils/listeners.ts +296 -0
  306. package/src/components/utils/mutations.ts +39 -0
  307. package/src/components/utils/notifier/draw.ts +190 -0
  308. package/src/components/utils/notifier/index.ts +66 -0
  309. package/src/components/utils/notifier/types.ts +1 -0
  310. package/src/components/utils/notifier.ts +77 -0
  311. package/src/components/utils/placeholder.ts +140 -0
  312. package/src/components/utils/popover/components/hint/hint.const.ts +10 -0
  313. package/src/components/utils/popover/components/hint/hint.ts +46 -0
  314. package/src/components/utils/popover/components/hint/index.ts +6 -0
  315. package/src/components/utils/popover/components/popover-header/index.ts +2 -0
  316. package/src/components/utils/popover/components/popover-header/popover-header.const.ts +8 -0
  317. package/src/components/utils/popover/components/popover-header/popover-header.ts +80 -0
  318. package/src/components/utils/popover/components/popover-header/popover-header.types.ts +14 -0
  319. package/src/components/utils/popover/components/popover-item/index.ts +13 -0
  320. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +50 -0
  321. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +666 -0
  322. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.const.ts +14 -0
  323. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.ts +136 -0
  324. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +20 -0
  325. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.ts +117 -0
  326. package/src/components/utils/popover/components/popover-item/popover-item.ts +187 -0
  327. package/src/components/utils/popover/components/search-input/index.ts +2 -0
  328. package/src/components/utils/popover/components/search-input/search-input.const.ts +8 -0
  329. package/src/components/utils/popover/components/search-input/search-input.ts +181 -0
  330. package/src/components/utils/popover/components/search-input/search-input.types.ts +30 -0
  331. package/src/components/utils/popover/index.ts +13 -0
  332. package/src/components/utils/popover/popover-abstract.ts +448 -0
  333. package/src/components/utils/popover/popover-desktop.ts +643 -0
  334. package/src/components/utils/popover/popover-inline.ts +338 -0
  335. package/src/components/utils/popover/popover-mobile.ts +201 -0
  336. package/src/components/utils/popover/popover.const.ts +81 -0
  337. package/src/components/utils/popover/utils/popover-states-history.ts +72 -0
  338. package/src/components/utils/promise-queue.ts +43 -0
  339. package/src/components/utils/sanitizer.ts +537 -0
  340. package/src/components/utils/scroll-locker.ts +87 -0
  341. package/src/components/utils/shortcut.ts +231 -0
  342. package/src/components/utils/shortcuts.ts +113 -0
  343. package/src/components/utils/tools.ts +105 -0
  344. package/src/components/utils/tooltip.ts +642 -0
  345. package/src/components/utils/tw.ts +241 -0
  346. package/src/components/utils.ts +1081 -0
  347. package/src/env.d.ts +13 -0
  348. package/src/full.ts +69 -0
  349. package/src/locales.ts +51 -0
  350. package/src/stories/Block.stories.ts +498 -0
  351. package/src/stories/EditorModes.stories.ts +505 -0
  352. package/src/stories/Header.stories.ts +137 -0
  353. package/src/stories/InlineToolbar.stories.ts +498 -0
  354. package/src/stories/List.stories.ts +259 -0
  355. package/src/stories/Notifier.stories.ts +340 -0
  356. package/src/stories/Paragraph.stories.ts +112 -0
  357. package/src/stories/Placeholder.stories.ts +319 -0
  358. package/src/stories/Popover.stories.ts +844 -0
  359. package/src/stories/Selection.stories.ts +250 -0
  360. package/src/stories/StubBlock.stories.ts +156 -0
  361. package/src/stories/Toolbar.stories.ts +223 -0
  362. package/src/stories/Toolbox.stories.ts +166 -0
  363. package/src/stories/Tooltip.stories.ts +198 -0
  364. package/src/stories/helpers.ts +463 -0
  365. package/src/styles/main.css +123 -0
  366. package/src/tools/header/index.ts +570 -0
  367. package/src/tools/index.ts +38 -0
  368. package/src/tools/list/index.ts +1803 -0
  369. package/src/tools/paragraph/index.ts +411 -0
  370. package/src/tools/stub/index.ts +107 -0
  371. package/src/types-internal/blok-modules.d.ts +87 -0
  372. package/src/types-internal/html-janitor.d.ts +28 -0
  373. package/src/types-internal/module-config.d.ts +11 -0
  374. package/src/variants/all-locales.ts +155 -0
  375. package/src/variants/blok-maximum.ts +20 -0
  376. package/src/variants/blok-minimum.ts +243 -0
  377. package/types/api/blocks.d.ts +1 -1
  378. package/types/api/i18n.d.ts +5 -3
  379. package/types/api/selection.d.ts +6 -0
  380. package/types/api/styles.d.ts +0 -5
  381. package/types/configs/blok-config.d.ts +21 -0
  382. package/types/configs/i18n-config.d.ts +52 -2
  383. package/types/configs/i18n-dictionary.d.ts +16 -90
  384. package/types/data-attributes.d.ts +169 -0
  385. package/types/data-formats/output-data.d.ts +15 -0
  386. package/types/full.d.ts +80 -0
  387. package/types/index.d.ts +9 -24
  388. package/types/locales.d.ts +59 -0
  389. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  390. package/types/tools/block-tool.d.ts +9 -0
  391. package/types/tools/list.d.ts +25 -18
  392. package/types/tools/tool-settings.d.ts +8 -1
  393. package/types/tools/tool.d.ts +6 -0
  394. package/types/tools-entry.d.ts +49 -0
  395. package/types/utils/popover/popover-item.d.ts +0 -5
  396. package/dist/blok-BwPfU8ro.mjs +0 -21510
  397. package/dist/blok.umd.js +0 -198
@@ -0,0 +1,481 @@
1
+ import { DomIterator } from './domIterator';
2
+ import { isFunction, keyCodes } from './utils';
3
+
4
+ /**
5
+ * Flipper construction options
6
+ * @interface FlipperOptions
7
+ * @internal
8
+ */
9
+ export interface FlipperOptions {
10
+ /**
11
+ * CSS-modifier for focused item
12
+ */
13
+ focusedItemClass?: string;
14
+
15
+ /**
16
+ * Allow handling keyboard events dispatched from contenteditable elements
17
+ */
18
+ handleContentEditableTargets?: boolean;
19
+
20
+ /**
21
+ * If flipping items are the same for all Block (for ex. Toolbox), ypu can pass it on constructing
22
+ */
23
+ items?: HTMLElement[];
24
+
25
+ /**
26
+ * Optional callback for button click
27
+ */
28
+ activateCallback?: (item: HTMLElement) => void;
29
+
30
+ /**
31
+ * List of keys allowed for handling.
32
+ * Can include codes of the following keys:
33
+ * - Tab
34
+ * - Enter
35
+ * - Arrow up
36
+ * - Arrow down
37
+ * - Arrow right
38
+ * - Arrow left
39
+ * If not specified all keys are enabled
40
+ */
41
+ allowedKeys?: number[];
42
+
43
+ /**
44
+ * Callback fired when ArrowLeft is pressed.
45
+ * Used by nested popovers to close and return focus to parent.
46
+ */
47
+ onArrowLeft?: () => void;
48
+ }
49
+
50
+ /**
51
+ * Flipper is a component that iterates passed items array by TAB or Arrows and clicks it by ENTER
52
+ * @internal
53
+ */
54
+ export class Flipper {
55
+ /**
56
+ * True if flipper is currently activated
57
+ */
58
+ public get isActivated(): boolean {
59
+ return this.activated;
60
+ }
61
+
62
+ /**
63
+ * Instance of flipper iterator
64
+ */
65
+ private readonly iterator: DomIterator | null = null;
66
+
67
+ /**
68
+ * Flag that defines activation status
69
+ */
70
+ private activated = false;
71
+
72
+ /**
73
+ * Skip moving focus on the next Tab press when initial focus was pre-set
74
+ */
75
+ private skipNextTabFocus = false;
76
+
77
+ /**
78
+ * True if flipper should handle events coming from contenteditable elements
79
+ */
80
+ private handleContentEditableTargets: boolean;
81
+
82
+ /**
83
+ * List codes of the keys allowed for handling
84
+ */
85
+ private readonly allowedKeys: number[];
86
+
87
+ /**
88
+ * Call back for button click/enter
89
+ */
90
+ private readonly activateCallback?: (item: HTMLElement) => void;
91
+
92
+ /**
93
+ * Contains list of callbacks to be executed on each flip
94
+ */
95
+ private flipCallbacks: Array<() => void> = [];
96
+
97
+ /**
98
+ * Callback fired when ArrowLeft is pressed.
99
+ * Used by nested popovers to close and return focus to parent.
100
+ */
101
+ private readonly onArrowLeftCallback?: () => void;
102
+
103
+ /**
104
+ * @param options - different constructing settings
105
+ */
106
+ constructor(options: FlipperOptions) {
107
+ this.iterator = new DomIterator(options.items || [], options.focusedItemClass ?? '');
108
+ this.activateCallback = options.activateCallback;
109
+ this.allowedKeys = options.allowedKeys || Flipper.usedKeys;
110
+ this.handleContentEditableTargets = options.handleContentEditableTargets ?? false;
111
+ this.onArrowLeftCallback = options.onArrowLeft;
112
+ }
113
+
114
+ /**
115
+ * Array of keys (codes) that is handled by Flipper
116
+ * Used to:
117
+ * - preventDefault only for this keys, not all keydowns (@see constructor)
118
+ * - to skip external behaviours only for these keys, when filler is activated (@see BlockEvents@arrowRightAndDown)
119
+ */
120
+ public static get usedKeys(): number[] {
121
+ return [
122
+ keyCodes.TAB,
123
+ keyCodes.LEFT,
124
+ keyCodes.RIGHT,
125
+ keyCodes.ENTER,
126
+ keyCodes.UP,
127
+ keyCodes.DOWN,
128
+ ];
129
+ }
130
+
131
+ /**
132
+ * Active tab/arrows handling by flipper
133
+ * @param items - Some modules (like, InlineToolbar, BlockSettings) might refresh buttons dynamically
134
+ * @param cursorPosition - index of the item that should be focused once flipper is activated
135
+ */
136
+ public activate(items?: HTMLElement[], cursorPosition?: number): void {
137
+ this.activated = true;
138
+ if (items) {
139
+ this.iterator?.setItems(items);
140
+ }
141
+
142
+ if (cursorPosition !== undefined) {
143
+ this.iterator?.setCursor(cursorPosition);
144
+ }
145
+
146
+ /**
147
+ * Listening all keydowns on document and react on TAB/Enter press
148
+ * TAB will leaf iterator items
149
+ * ENTER will click the focused item
150
+ *
151
+ * Note: the event should be handled in capturing mode on following reasons:
152
+ * - prevents plugins inner keydown handlers from being called while keyboard navigation
153
+ * - otherwise this handler will be called at the moment it is attached which causes false flipper firing (see https://techread.me/js-addeventlistener-fires-for-past-events/)
154
+ */
155
+ document.addEventListener('keydown', this.onKeyDown, true);
156
+ window.addEventListener('keydown', this.onKeyDown, true);
157
+ }
158
+
159
+ /**
160
+ * Disable tab/arrows handling by flipper
161
+ */
162
+ public deactivate(): void {
163
+ this.activated = false;
164
+ this.dropCursor();
165
+ this.skipNextTabFocus = false;
166
+
167
+ document.removeEventListener('keydown', this.onKeyDown, true);
168
+ window.removeEventListener('keydown', this.onKeyDown, true);
169
+ }
170
+
171
+ /**
172
+ * Focus first item
173
+ */
174
+ public focusFirst(): void {
175
+ this.dropCursor();
176
+ this.flipRight();
177
+ }
178
+
179
+ /**
180
+ * Focus item at specified position without triggering flip callbacks
181
+ * @param position - index of item to focus. Negative value clears focus.
182
+ * @param options - optional settings for focus behavior
183
+ * @param options.skipNextTab - if true, skip the next Tab press (default: true for position 0 when no current item)
184
+ */
185
+ public focusItem(position: number, options?: { skipNextTab?: boolean }): void {
186
+ const iterator = this.iterator;
187
+
188
+ if (!iterator) {
189
+ return;
190
+ }
191
+
192
+ if (!iterator.hasItems()) {
193
+ return;
194
+ }
195
+
196
+ if (position < 0) {
197
+ iterator.dropCursor();
198
+
199
+ return;
200
+ }
201
+
202
+ const shouldSkipNextTab = options?.skipNextTab ?? (!iterator.currentItem && position === 0);
203
+
204
+ if (shouldSkipNextTab) {
205
+ this.skipNextTabFocus = true;
206
+ }
207
+
208
+ iterator.setCursor(position);
209
+ }
210
+
211
+ /**
212
+ * Focuses previous flipper iterator item
213
+ */
214
+ public flipLeft(): void {
215
+ this.iterator?.previous();
216
+ this.flipCallback();
217
+ }
218
+
219
+ /**
220
+ * Focuses next flipper iterator item
221
+ */
222
+ public flipRight(): void {
223
+ this.iterator?.next();
224
+ this.flipCallback();
225
+ }
226
+
227
+ /**
228
+ * Return true if some button is focused
229
+ */
230
+ public hasFocus(): boolean {
231
+ return !!this.iterator?.currentItem;
232
+ }
233
+
234
+ /**
235
+ * Checks if current focused item has children (nested menu)
236
+ * Looks for data-blok-has-children attribute on the current item
237
+ */
238
+ private currentItemHasChildren(): boolean {
239
+ const currentItem = this.iterator?.currentItem;
240
+
241
+ if (!currentItem) {
242
+ return false;
243
+ }
244
+
245
+ return currentItem.hasAttribute('data-blok-has-children');
246
+ }
247
+
248
+ /**
249
+ * Registers a function that should be executed on each navigation action
250
+ * @param cb - function to execute
251
+ */
252
+ public onFlip(cb: () => void): void {
253
+ this.flipCallbacks.push(cb);
254
+ }
255
+
256
+ /**
257
+ * Unregisters a function that is executed on each navigation action
258
+ * @param cb - function to stop executing
259
+ */
260
+ public removeOnFlip(cb: () => void): void {
261
+ this.flipCallbacks = this.flipCallbacks.filter(fn => fn !== cb);
262
+ }
263
+
264
+ /**
265
+ * Drops flipper's iterator cursor
266
+ * @see DomIterator#dropCursor
267
+ */
268
+ private dropCursor(): void {
269
+ this.iterator?.dropCursor();
270
+ }
271
+
272
+ /**
273
+ * Get numeric keyCode from KeyboardEvent.key for backward compatibility
274
+ * @param event - keyboard event
275
+ * @returns numeric keyCode or null if not recognized
276
+ */
277
+ private getKeyCode(event: KeyboardEvent): number | null {
278
+ const keyToCodeMap: Record<string, number> = {
279
+ 'Tab': keyCodes.TAB,
280
+ 'Enter': keyCodes.ENTER,
281
+ 'ArrowLeft': keyCodes.LEFT,
282
+ 'ArrowRight': keyCodes.RIGHT,
283
+ 'ArrowUp': keyCodes.UP,
284
+ 'ArrowDown': keyCodes.DOWN,
285
+ };
286
+
287
+ return keyToCodeMap[event.key] ?? null;
288
+ }
289
+
290
+ /**
291
+ * KeyDown event handler
292
+ * @param event - keydown event
293
+ */
294
+ private onKeyDown = (event: KeyboardEvent): void => {
295
+ const target = event.target as HTMLElement | null;
296
+
297
+ if (this.shouldSkipTarget(target, event)) {
298
+ return;
299
+ }
300
+
301
+ const keyCode = this.getKeyCode(event);
302
+ const isDirectionalArrow = keyCode === keyCodes.LEFT
303
+ || keyCode === keyCodes.RIGHT
304
+ || keyCode === keyCodes.UP
305
+ || keyCode === keyCodes.DOWN;
306
+
307
+ /**
308
+ * Allow selecting text with Shift combined with arrow keys by delegating handling to the browser.
309
+ * Other Shift-based combinations (for example Shift+Tab) are still handled by Flipper.
310
+ */
311
+ if (event.shiftKey && isDirectionalArrow) {
312
+ return;
313
+ }
314
+
315
+ const isReady = this.isEventReadyForHandling(event);
316
+
317
+ if (!isReady) {
318
+ return;
319
+ }
320
+
321
+ /**
322
+ * For Enter key, only handle it if there's a focused item.
323
+ * Otherwise, let the event propagate to allow block splitting etc.
324
+ */
325
+ if (keyCode === keyCodes.ENTER && !this.iterator?.currentItem) {
326
+ return;
327
+ }
328
+
329
+ /**
330
+ * Stop propagation to prevent plugin-level handlers from being called
331
+ * while Flipper manages keyboard navigation.
332
+ */
333
+ event.stopPropagation();
334
+ event.stopImmediatePropagation();
335
+
336
+
337
+ /**
338
+ * Prevent only used keys default behaviour
339
+ * (allows to navigate by ARROW DOWN, for example)
340
+ */
341
+ if (keyCode !== null && Flipper.usedKeys.includes(keyCode)) {
342
+ event.preventDefault();
343
+ }
344
+
345
+ switch (keyCode) {
346
+ case keyCodes.TAB:
347
+ this.handleTabPress(event);
348
+ break;
349
+ case keyCodes.LEFT:
350
+ // ArrowLeft triggers callback only if callback is set (for nested popovers)
351
+ if (this.onArrowLeftCallback) {
352
+ this.onArrowLeftCallback();
353
+ }
354
+ break;
355
+ case keyCodes.UP:
356
+ this.flipLeft();
357
+ break;
358
+ case keyCodes.RIGHT:
359
+ // ArrowRight clicks the focused item to open nested popover, but only if item has children
360
+ // Otherwise, do nothing (don't activate items without nested menu)
361
+ if (this.iterator?.currentItem && this.currentItemHasChildren()) {
362
+ this.handleEnterPress(event);
363
+ }
364
+ break;
365
+ case keyCodes.DOWN:
366
+ this.flipRight();
367
+ break;
368
+ case keyCodes.ENTER:
369
+ this.handleEnterPress(event);
370
+ break;
371
+ }
372
+ };
373
+
374
+ /**
375
+ * This function is fired before handling flipper keycodes
376
+ * The result of this function defines if it is need to be handled or not
377
+ * @param {KeyboardEvent} event - keydown keyboard event
378
+ * @returns {boolean}
379
+ */
380
+ private isEventReadyForHandling(event: KeyboardEvent): boolean {
381
+ const keyCode = this.getKeyCode(event);
382
+
383
+ return this.activated && keyCode !== null && this.allowedKeys.includes(keyCode);
384
+ }
385
+
386
+ /**
387
+ * Enables or disables handling events dispatched from contenteditable elements
388
+ * @param value - true if events from contenteditable elements should be handled
389
+ */
390
+ public setHandleContentEditableTargets(value: boolean): void {
391
+ this.handleContentEditableTargets = value;
392
+ }
393
+
394
+ /**
395
+ * When flipper is activated tab press will leaf the items
396
+ * @param {KeyboardEvent} event - tab keydown event
397
+ */
398
+ private handleTabPress(event: KeyboardEvent): void {
399
+ /** this property defines leaf direction */
400
+ const shiftKey = event.shiftKey;
401
+ const direction = shiftKey ? DomIterator.directions.LEFT : DomIterator.directions.RIGHT;
402
+
403
+ if (this.skipNextTabFocus) {
404
+ this.skipNextTabFocus = false;
405
+
406
+ return;
407
+ }
408
+
409
+ switch (direction) {
410
+ case DomIterator.directions.RIGHT:
411
+ this.flipRight();
412
+ break;
413
+ case DomIterator.directions.LEFT:
414
+ this.flipLeft();
415
+ break;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Delegates external keyboard events to the flipper handler.
421
+ * @param event - keydown event captured outside the flipper
422
+ */
423
+ public handleExternalKeydown(event: KeyboardEvent): void {
424
+ this.onKeyDown(event);
425
+ }
426
+
427
+ /**
428
+ * Enter press will click current item if flipper is activated
429
+ * @param {KeyboardEvent} event - enter keydown event
430
+ */
431
+ private handleEnterPress(event: KeyboardEvent): void {
432
+ if (!this.activated) {
433
+ return;
434
+ }
435
+
436
+ if (this.iterator?.currentItem) {
437
+ /**
438
+ * Stop Enter propagation only if flipper is ready to select focused item
439
+ */
440
+ event.stopPropagation();
441
+ event.preventDefault();
442
+ this.iterator.currentItem.click();
443
+ }
444
+
445
+ if (isFunction(this.activateCallback) && this.iterator?.currentItem) {
446
+ this.activateCallback(this.iterator.currentItem);
447
+ }
448
+ }
449
+
450
+ /**
451
+ * Fired after flipping in any direction
452
+ */
453
+ private flipCallback(): void {
454
+ if (this.iterator?.currentItem) {
455
+ this.iterator.currentItem.scrollIntoViewIfNeeded?.();
456
+ }
457
+
458
+ this.flipCallbacks.forEach(cb => cb());
459
+ }
460
+
461
+ /**
462
+ * Determine if keyboard events coming from a target should be skipped
463
+ * @param target - event target element
464
+ * @param event - keyboard event being handled
465
+ */
466
+ private shouldSkipTarget(target: HTMLElement | null, event: KeyboardEvent): boolean {
467
+ if (!target) {
468
+ return false;
469
+ }
470
+
471
+ const isNativeInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
472
+ const isNavigationKey = event.key === 'Tab' || event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'Enter' || event.key === 'ArrowRight' || event.key === 'ArrowLeft';
473
+ const shouldHandleNativeInput = target.getAttribute('data-blok-flipper-navigation-target') === 'true' && isNavigationKey;
474
+ const isContentEditable = target.isContentEditable;
475
+ const isInlineToolInput = target.closest('[data-blok-link-tool-input-opened="true"]') !== null;
476
+
477
+ const shouldSkipContentEditable = isContentEditable && !this.handleContentEditableTargets;
478
+
479
+ return (isNativeInput && !shouldHandleNativeInput) || shouldSkipContentEditable || isInlineToolInput;
480
+ }
481
+ }
@@ -0,0 +1,84 @@
1
+ import type { i18n as I18nextInstance, InitOptions } from 'i18next';
2
+ import type { I18nDictionary } from '../../../types/configs/i18n-dictionary';
3
+ import type { SupportedLocale } from '../../../types/configs/i18n-config';
4
+ import { englishDictionary } from './lightweight-i18n';
5
+
6
+ /**
7
+ * i18next instance type after initialization
8
+ */
9
+ export type InitializedI18next = I18nextInstance;
10
+
11
+ /**
12
+ * Result of initializing i18next
13
+ */
14
+ export interface I18nextInitResult {
15
+ instance: InitializedI18next;
16
+ t: (key: string, vars?: Record<string, string | number>) => string;
17
+ has: (key: string) => boolean;
18
+ setDictionary: (dictionary: I18nDictionary) => void;
19
+ changeLanguage: (locale: SupportedLocale) => Promise<void>;
20
+ }
21
+
22
+ /**
23
+ * Dynamically load and initialize i18next.
24
+ * This is only called when a non-English locale is needed.
25
+ *
26
+ * @param initialLocale - The locale to initialize with
27
+ * @param localeConfig - The loaded locale configuration
28
+ * @returns Initialized i18next wrapper
29
+ */
30
+ export const loadI18next = async (
31
+ initialLocale: SupportedLocale,
32
+ localeConfig: { dictionary: I18nDictionary }
33
+ ): Promise<I18nextInitResult> => {
34
+ // Dynamic import of i18next - this is the key to tree-shaking it out
35
+ const i18next = await import('i18next');
36
+
37
+ // Create a new instance (not the global one) for isolation
38
+ const instance = i18next.default.createInstance();
39
+
40
+ const initOptions: InitOptions = {
41
+ lng: initialLocale,
42
+ fallbackLng: 'en',
43
+ resources: {
44
+ en: {
45
+ translation: englishDictionary,
46
+ },
47
+ [initialLocale]: {
48
+ translation: localeConfig.dictionary,
49
+ },
50
+ },
51
+ interpolation: {
52
+ // Use single braces {var} to match existing format
53
+ prefix: '{',
54
+ suffix: '}',
55
+ escapeValue: false, // React/DOM handles escaping
56
+ },
57
+ // Return key if translation is missing (consistent behavior)
58
+ returnNull: false,
59
+ returnEmptyString: false,
60
+ // Don't parse keys as nested objects - we use flat keys with dots
61
+ keySeparator: false,
62
+ nsSeparator: false,
63
+ };
64
+
65
+ await instance.init(initOptions);
66
+
67
+ return {
68
+ instance,
69
+ t: (key: string, vars?: Record<string, string | number>): string => {
70
+ return instance.t(key, vars);
71
+ },
72
+ has: (key: string): boolean => {
73
+ return instance.exists(key);
74
+ },
75
+ setDictionary: (dictionary: I18nDictionary): void => {
76
+ const currentLang = instance.language;
77
+
78
+ instance.addResourceBundle(currentLang, 'translation', dictionary, true, true);
79
+ },
80
+ changeLanguage: async (locale: SupportedLocale): Promise<void> => {
81
+ await instance.changeLanguage(locale);
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,86 @@
1
+ import type { I18nDictionary } from '../../../types/configs/i18n-dictionary';
2
+ import enMessages from './locales/en/messages.json';
3
+
4
+ /**
5
+ * Lightweight i18n implementation for English-only usage.
6
+ * Provides simple string interpolation without the overhead of i18next.
7
+ *
8
+ * For non-English locales, the full i18next-based implementation is loaded dynamically.
9
+ *
10
+ * @internal
11
+ */
12
+ export class LightweightI18n {
13
+ /**
14
+ * Current dictionary (defaults to English)
15
+ */
16
+ private dictionary: I18nDictionary;
17
+
18
+ /**
19
+ * Custom overrides set via setDictionary
20
+ */
21
+ private overrides: I18nDictionary | null = null;
22
+
23
+ constructor() {
24
+ this.dictionary = enMessages;
25
+ }
26
+
27
+ /**
28
+ * Translate a key with optional interpolation.
29
+ *
30
+ * @param key - Translation key
31
+ * @param vars - Optional variables for interpolation
32
+ * @returns Translated string, or the key if not found
33
+ */
34
+ public t(key: string, vars?: Record<string, string | number>): string {
35
+ // Check overrides first, then fall back to base dictionary
36
+ const value = this.overrides?.[key] ?? this.dictionary[key];
37
+
38
+ if (value === undefined) {
39
+ return key;
40
+ }
41
+
42
+ if (vars === undefined) {
43
+ return value;
44
+ }
45
+
46
+ // Simple interpolation: replace {varName} with value
47
+ return value.replace(/\{(\w+)\}/g, (match, varName: string) => {
48
+ const replacement = vars[varName];
49
+
50
+ return replacement !== undefined ? String(replacement) : match;
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Check if a translation exists
56
+ */
57
+ public has(key: string): boolean {
58
+ return (this.overrides?.[key] ?? this.dictionary[key]) !== undefined;
59
+ }
60
+
61
+ /**
62
+ * Add custom dictionary overrides
63
+ */
64
+ public setDictionary(dictionary: I18nDictionary): void {
65
+ this.overrides = { ...this.overrides, ...dictionary };
66
+ }
67
+
68
+ /**
69
+ * Get the current locale
70
+ */
71
+ public getLocale(): 'en' {
72
+ return 'en';
73
+ }
74
+
75
+ /**
76
+ * Get text direction (always LTR for English)
77
+ */
78
+ public getDirection(): 'ltr' {
79
+ return 'ltr';
80
+ }
81
+ }
82
+
83
+ /**
84
+ * English dictionary for synchronous access
85
+ */
86
+ export const englishDictionary = enMessages;