@jackuait/blok 0.4.1-beta.0 → 0.4.1-beta.11

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 (402) hide show
  1. package/README.md +138 -17
  2. package/codemod/README.md +45 -7
  3. package/codemod/migrate-editorjs-to-blok.js +960 -92
  4. package/codemod/test.js +780 -77
  5. package/dist/blok.mjs +5 -2
  6. package/dist/chunks/blok-oNSQ3HA6.mjs +13217 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-BdNRw4n4.mjs +43 -0
  9. package/dist/{index-OwEtDFlk.mjs → chunks/index-DHgXmfki.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-CRqgjRim.mjs +1989 -0
  11. package/dist/chunks/messages-0tDXLuyH.mjs +48 -0
  12. package/dist/chunks/messages-2_xedlYw.mjs +48 -0
  13. package/dist/chunks/messages-AHESHJm_.mjs +48 -0
  14. package/dist/chunks/messages-B5hdXZwA.mjs +48 -0
  15. package/dist/chunks/messages-B5jGUnOy.mjs +48 -0
  16. package/dist/chunks/messages-B5puUm7R.mjs +48 -0
  17. package/dist/chunks/messages-B66ZSDCJ.mjs +48 -0
  18. package/dist/chunks/messages-B9Oba7sq.mjs +48 -0
  19. package/dist/chunks/messages-BA0rcTCY.mjs +48 -0
  20. package/dist/chunks/messages-BBJgd5jG.mjs +48 -0
  21. package/dist/chunks/messages-BPqWKx5Z.mjs +48 -0
  22. package/dist/chunks/messages-Bdv-IkfG.mjs +48 -0
  23. package/dist/chunks/messages-BeUhMpsr.mjs +48 -0
  24. package/dist/chunks/messages-Bf6Y3_GI.mjs +48 -0
  25. package/dist/chunks/messages-BiExzWJv.mjs +48 -0
  26. package/dist/chunks/messages-BlpqL8vG.mjs +48 -0
  27. package/dist/chunks/messages-BmKCChWZ.mjs +48 -0
  28. package/dist/chunks/messages-Bn253WWC.mjs +48 -0
  29. package/dist/chunks/messages-BrJHUxQL.mjs +48 -0
  30. package/dist/chunks/messages-C5b7hr_E.mjs +48 -0
  31. package/dist/chunks/messages-C7I_AVH2.mjs +48 -0
  32. package/dist/chunks/messages-CJoBtXU6.mjs +48 -0
  33. package/dist/chunks/messages-CQj2JU2j.mjs +48 -0
  34. package/dist/chunks/messages-CUZ1x1QD.mjs +48 -0
  35. package/dist/chunks/messages-CUy1vn-b.mjs +48 -0
  36. package/dist/chunks/messages-CVeWVKsV.mjs +48 -0
  37. package/dist/chunks/messages-CXHd9SUK.mjs +48 -0
  38. package/dist/chunks/messages-CbMyJSzS.mjs +48 -0
  39. package/dist/chunks/messages-CbhuIWRJ.mjs +48 -0
  40. package/dist/chunks/messages-CeCjVKMW.mjs +48 -0
  41. package/dist/chunks/messages-Cj-t1bdy.mjs +48 -0
  42. package/dist/chunks/messages-CkFT2gle.mjs +48 -0
  43. package/dist/chunks/messages-Cm9aLHeX.mjs +48 -0
  44. package/dist/chunks/messages-CnvW8Slp.mjs +48 -0
  45. package/dist/chunks/messages-Cr-RJ7YB.mjs +48 -0
  46. package/dist/chunks/messages-CrsJ1TEJ.mjs +48 -0
  47. package/dist/chunks/messages-Cu08aLS3.mjs +48 -0
  48. package/dist/chunks/messages-CvaqJFN-.mjs +48 -0
  49. package/dist/chunks/messages-CyDU5lz9.mjs +48 -0
  50. package/dist/chunks/messages-CySyfkMU.mjs +48 -0
  51. package/dist/chunks/messages-Cyi2AMmz.mjs +48 -0
  52. package/dist/chunks/messages-D00OjS2n.mjs +48 -0
  53. package/dist/chunks/messages-DDLgIPDF.mjs +48 -0
  54. package/dist/chunks/messages-DMQIHGRj.mjs +48 -0
  55. package/dist/chunks/messages-DOlC_Tty.mjs +48 -0
  56. package/dist/chunks/messages-DV6shA9b.mjs +48 -0
  57. package/dist/chunks/messages-DY94ykcE.mjs +48 -0
  58. package/dist/chunks/messages-DbVquYKN.mjs +48 -0
  59. package/dist/chunks/messages-DcKOuncK.mjs +48 -0
  60. package/dist/chunks/messages-Dg92dXZ5.mjs +48 -0
  61. package/dist/chunks/messages-DnbbyJT3.mjs +48 -0
  62. package/dist/chunks/messages-DteYq0rv.mjs +48 -0
  63. package/dist/chunks/messages-GC2PhgV3.mjs +48 -0
  64. package/dist/chunks/messages-JGsXAReJ.mjs +48 -0
  65. package/dist/chunks/messages-JZUhXTuV.mjs +48 -0
  66. package/dist/chunks/messages-LvFKBBPa.mjs +48 -0
  67. package/dist/chunks/messages-NP1myMGI.mjs +48 -0
  68. package/dist/chunks/messages-Q4kc_ZtL.mjs +48 -0
  69. package/dist/chunks/messages-RvMHb2Ht.mjs +48 -0
  70. package/dist/chunks/messages-ftMcCEuO.mjs +48 -0
  71. package/dist/chunks/messages-o24dK6CU.mjs +48 -0
  72. package/dist/chunks/messages-pA5TvcAj.mjs +48 -0
  73. package/dist/chunks/messages-rRSHQDCX.mjs +48 -0
  74. package/dist/chunks/messages-srxrv8Yh.mjs +48 -0
  75. package/dist/chunks/messages-wdqp4610.mjs +48 -0
  76. package/dist/chunks/messages-zS1AXZ0y.mjs +48 -0
  77. package/dist/chunks/messages-zSzDzXej.mjs +48 -0
  78. package/dist/full.mjs +50 -0
  79. package/dist/locales.mjs +228 -0
  80. package/dist/messages-0tDXLuyH.mjs +48 -0
  81. package/dist/messages-2_xedlYw.mjs +48 -0
  82. package/dist/messages-AHESHJm_.mjs +48 -0
  83. package/dist/messages-B5hdXZwA.mjs +48 -0
  84. package/dist/messages-B5jGUnOy.mjs +48 -0
  85. package/dist/messages-B5puUm7R.mjs +48 -0
  86. package/dist/messages-B66ZSDCJ.mjs +48 -0
  87. package/dist/messages-B9Oba7sq.mjs +48 -0
  88. package/dist/messages-BA0rcTCY.mjs +48 -0
  89. package/dist/messages-BBJgd5jG.mjs +48 -0
  90. package/dist/messages-BPqWKx5Z.mjs +48 -0
  91. package/dist/messages-Bdv-IkfG.mjs +48 -0
  92. package/dist/messages-BeUhMpsr.mjs +48 -0
  93. package/dist/messages-Bf6Y3_GI.mjs +48 -0
  94. package/dist/messages-BiExzWJv.mjs +48 -0
  95. package/dist/messages-BlpqL8vG.mjs +48 -0
  96. package/dist/messages-BmKCChWZ.mjs +48 -0
  97. package/dist/messages-Bn253WWC.mjs +48 -0
  98. package/dist/messages-BrJHUxQL.mjs +48 -0
  99. package/dist/messages-C5b7hr_E.mjs +48 -0
  100. package/dist/messages-C7I_AVH2.mjs +48 -0
  101. package/dist/messages-CJoBtXU6.mjs +48 -0
  102. package/dist/messages-CQj2JU2j.mjs +48 -0
  103. package/dist/messages-CUZ1x1QD.mjs +48 -0
  104. package/dist/messages-CUy1vn-b.mjs +48 -0
  105. package/dist/messages-CVeWVKsV.mjs +48 -0
  106. package/dist/messages-CXHd9SUK.mjs +48 -0
  107. package/dist/messages-CbMyJSzS.mjs +48 -0
  108. package/dist/messages-CbhuIWRJ.mjs +48 -0
  109. package/dist/messages-CeCjVKMW.mjs +48 -0
  110. package/dist/messages-Cj-t1bdy.mjs +48 -0
  111. package/dist/messages-CkFT2gle.mjs +48 -0
  112. package/dist/messages-Cm9aLHeX.mjs +48 -0
  113. package/dist/messages-CnvW8Slp.mjs +48 -0
  114. package/dist/messages-Cr-RJ7YB.mjs +48 -0
  115. package/dist/messages-CrsJ1TEJ.mjs +48 -0
  116. package/dist/messages-Cu08aLS3.mjs +48 -0
  117. package/dist/messages-CvaqJFN-.mjs +48 -0
  118. package/dist/messages-CyDU5lz9.mjs +48 -0
  119. package/dist/messages-CySyfkMU.mjs +48 -0
  120. package/dist/messages-Cyi2AMmz.mjs +48 -0
  121. package/dist/messages-D00OjS2n.mjs +48 -0
  122. package/dist/messages-DDLgIPDF.mjs +48 -0
  123. package/dist/messages-DMQIHGRj.mjs +48 -0
  124. package/dist/messages-DOlC_Tty.mjs +48 -0
  125. package/dist/messages-DV6shA9b.mjs +48 -0
  126. package/dist/messages-DY94ykcE.mjs +48 -0
  127. package/dist/messages-DbVquYKN.mjs +48 -0
  128. package/dist/messages-DcKOuncK.mjs +48 -0
  129. package/dist/messages-Dg92dXZ5.mjs +48 -0
  130. package/dist/messages-DnbbyJT3.mjs +48 -0
  131. package/dist/messages-DteYq0rv.mjs +48 -0
  132. package/dist/messages-GC2PhgV3.mjs +48 -0
  133. package/dist/messages-JGsXAReJ.mjs +48 -0
  134. package/dist/messages-JZUhXTuV.mjs +48 -0
  135. package/dist/messages-LvFKBBPa.mjs +48 -0
  136. package/dist/messages-NP1myMGI.mjs +48 -0
  137. package/dist/messages-Q4kc_ZtL.mjs +48 -0
  138. package/dist/messages-RvMHb2Ht.mjs +48 -0
  139. package/dist/messages-ftMcCEuO.mjs +48 -0
  140. package/dist/messages-o24dK6CU.mjs +48 -0
  141. package/dist/messages-pA5TvcAj.mjs +48 -0
  142. package/dist/messages-rRSHQDCX.mjs +48 -0
  143. package/dist/messages-srxrv8Yh.mjs +48 -0
  144. package/dist/messages-wdqp4610.mjs +48 -0
  145. package/dist/messages-zS1AXZ0y.mjs +48 -0
  146. package/dist/messages-zSzDzXej.mjs +48 -0
  147. package/dist/tools.mjs +3117 -0
  148. package/dist/vendor.LICENSE.txt +26 -225
  149. package/package.json +63 -24
  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 +1428 -0
  154. package/src/components/block-tunes/block-tune-delete.ts +51 -0
  155. package/src/components/blocks.ts +352 -0
  156. package/src/components/constants/data-attributes.ts +344 -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 +497 -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 +45 -0
  177. package/src/components/i18n/locales/ar/messages.json +45 -0
  178. package/src/components/i18n/locales/az/messages.json +45 -0
  179. package/src/components/i18n/locales/bg/messages.json +45 -0
  180. package/src/components/i18n/locales/bn/messages.json +45 -0
  181. package/src/components/i18n/locales/bs/messages.json +45 -0
  182. package/src/components/i18n/locales/cs/messages.json +45 -0
  183. package/src/components/i18n/locales/da/messages.json +45 -0
  184. package/src/components/i18n/locales/de/messages.json +45 -0
  185. package/src/components/i18n/locales/dv/messages.json +45 -0
  186. package/src/components/i18n/locales/el/messages.json +45 -0
  187. package/src/components/i18n/locales/en/messages.json +45 -0
  188. package/src/components/i18n/locales/es/messages.json +45 -0
  189. package/src/components/i18n/locales/et/messages.json +45 -0
  190. package/src/components/i18n/locales/fa/messages.json +45 -0
  191. package/src/components/i18n/locales/fi/messages.json +45 -0
  192. package/src/components/i18n/locales/fil/messages.json +45 -0
  193. package/src/components/i18n/locales/fr/messages.json +45 -0
  194. package/src/components/i18n/locales/gu/messages.json +45 -0
  195. package/src/components/i18n/locales/he/messages.json +45 -0
  196. package/src/components/i18n/locales/hi/messages.json +45 -0
  197. package/src/components/i18n/locales/hr/messages.json +45 -0
  198. package/src/components/i18n/locales/hu/messages.json +45 -0
  199. package/src/components/i18n/locales/hy/messages.json +45 -0
  200. package/src/components/i18n/locales/id/messages.json +45 -0
  201. package/src/components/i18n/locales/index.ts +231 -0
  202. package/src/components/i18n/locales/it/messages.json +45 -0
  203. package/src/components/i18n/locales/ja/messages.json +45 -0
  204. package/src/components/i18n/locales/ka/messages.json +45 -0
  205. package/src/components/i18n/locales/km/messages.json +45 -0
  206. package/src/components/i18n/locales/kn/messages.json +45 -0
  207. package/src/components/i18n/locales/ko/messages.json +45 -0
  208. package/src/components/i18n/locales/ku/messages.json +45 -0
  209. package/src/components/i18n/locales/lo/messages.json +45 -0
  210. package/src/components/i18n/locales/lt/messages.json +45 -0
  211. package/src/components/i18n/locales/lv/messages.json +45 -0
  212. package/src/components/i18n/locales/mk/messages.json +45 -0
  213. package/src/components/i18n/locales/ml/messages.json +45 -0
  214. package/src/components/i18n/locales/mn/messages.json +45 -0
  215. package/src/components/i18n/locales/mr/messages.json +45 -0
  216. package/src/components/i18n/locales/ms/messages.json +45 -0
  217. package/src/components/i18n/locales/my/messages.json +45 -0
  218. package/src/components/i18n/locales/ne/messages.json +45 -0
  219. package/src/components/i18n/locales/nl/messages.json +45 -0
  220. package/src/components/i18n/locales/no/messages.json +45 -0
  221. package/src/components/i18n/locales/pa/messages.json +45 -0
  222. package/src/components/i18n/locales/pl/messages.json +45 -0
  223. package/src/components/i18n/locales/ps/messages.json +45 -0
  224. package/src/components/i18n/locales/pt/messages.json +45 -0
  225. package/src/components/i18n/locales/ro/messages.json +45 -0
  226. package/src/components/i18n/locales/ru/messages.json +45 -0
  227. package/src/components/i18n/locales/sd/messages.json +45 -0
  228. package/src/components/i18n/locales/si/messages.json +45 -0
  229. package/src/components/i18n/locales/sk/messages.json +45 -0
  230. package/src/components/i18n/locales/sl/messages.json +45 -0
  231. package/src/components/i18n/locales/sq/messages.json +45 -0
  232. package/src/components/i18n/locales/sr/messages.json +45 -0
  233. package/src/components/i18n/locales/sv/messages.json +45 -0
  234. package/src/components/i18n/locales/sw/messages.json +45 -0
  235. package/src/components/i18n/locales/ta/messages.json +45 -0
  236. package/src/components/i18n/locales/te/messages.json +45 -0
  237. package/src/components/i18n/locales/th/messages.json +45 -0
  238. package/src/components/i18n/locales/tr/messages.json +45 -0
  239. package/src/components/i18n/locales/ug/messages.json +45 -0
  240. package/src/components/i18n/locales/uk/messages.json +45 -0
  241. package/src/components/i18n/locales/ur/messages.json +45 -0
  242. package/src/components/i18n/locales/vi/messages.json +45 -0
  243. package/src/components/i18n/locales/yi/messages.json +45 -0
  244. package/src/components/i18n/locales/zh/messages.json +45 -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 +377 -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 +35 -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 +1591 -0
  269. package/src/components/modules/blockManager.ts +1356 -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 +1204 -0
  274. package/src/components/modules/history.ts +1098 -0
  275. package/src/components/modules/i18n.ts +332 -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 +711 -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 +781 -0
  284. package/src/components/modules/toolbar/index.ts +1315 -0
  285. package/src/components/modules/toolbar/inline.ts +956 -0
  286. package/src/components/modules/tools.ts +625 -0
  287. package/src/components/modules/ui.ts +1283 -0
  288. package/src/components/polyfills.ts +113 -0
  289. package/src/components/selection.ts +1179 -0
  290. package/src/components/tools/base.ts +301 -0
  291. package/src/components/tools/block.ts +339 -0
  292. package/src/components/tools/collection.ts +67 -0
  293. package/src/components/tools/factory.ts +138 -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 +601 -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 +680 -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 +186 -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 +178 -0
  330. package/src/components/utils/popover/components/search-input/search-input.types.ts +59 -0
  331. package/src/components/utils/popover/index.ts +13 -0
  332. package/src/components/utils/popover/popover-abstract.ts +457 -0
  333. package/src/components/utils/popover/popover-desktop.ts +676 -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 +110 -0
  344. package/src/components/utils/tooltip.ts +591 -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 +646 -0
  367. package/src/tools/index.ts +45 -0
  368. package/src/tools/list/index.ts +1819 -0
  369. package/src/tools/paragraph/index.ts +412 -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 +9 -1
  378. package/types/api/history.d.ts +7 -0
  379. package/types/api/i18n.d.ts +22 -3
  380. package/types/api/selection.d.ts +6 -0
  381. package/types/api/styles.d.ts +23 -10
  382. package/types/configs/blok-config.d.ts +29 -0
  383. package/types/configs/i18n-config.d.ts +52 -2
  384. package/types/configs/i18n-dictionary.d.ts +16 -90
  385. package/types/data-attributes.d.ts +170 -0
  386. package/types/data-formats/output-data.d.ts +15 -0
  387. package/types/full.d.ts +80 -0
  388. package/types/index.d.ts +30 -13
  389. package/types/locales.d.ts +59 -0
  390. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  391. package/types/tools/block-tool.d.ts +9 -0
  392. package/types/tools/header.d.ts +18 -0
  393. package/types/tools/index.d.ts +1 -0
  394. package/types/tools/list.d.ts +91 -0
  395. package/types/tools/paragraph.d.ts +71 -0
  396. package/types/tools/tool-settings.d.ts +92 -6
  397. package/types/tools/tool.d.ts +6 -0
  398. package/types/tools-entry.d.ts +49 -0
  399. package/types/utils/popover/popover-item.d.ts +18 -5
  400. package/types/utils/popover/popover.d.ts +7 -0
  401. package/dist/blok-D_baBvTG.mjs +0 -25795
  402. package/dist/blok.umd.js +0 -181
@@ -0,0 +1,676 @@
1
+ import { Flipper } from '../../flipper';
2
+ import { PopoverAbstract } from './popover-abstract';
3
+ import type { PopoverItem, PopoverItemRenderParamsMap } from './components/popover-item';
4
+ import { PopoverItemSeparator, css as popoverItemCls } from './components/popover-item';
5
+ import type { PopoverParams } from '@/types/utils/popover/popover';
6
+ import { PopoverEvent } from '@/types/utils/popover/popover-event';
7
+ import { keyCodes } from '../../utils';
8
+ import { CSSVariables } from './popover.const';
9
+ import { DATA_ATTR } from '../../constants/data-attributes';
10
+ import type { SearchableItem } from './components/search-input';
11
+ import { SearchInput, SearchInputEvent, matchesSearchQuery } from './components/search-input';
12
+ import { PopoverItemDefault } from './components/popover-item';
13
+ import { PopoverItemHtml } from './components/popover-item/popover-item-html/popover-item-html';
14
+
15
+ /**
16
+ * Desktop popover.
17
+ * On desktop devices popover behaves like a floating element. Nested popover appears at right or left side.
18
+ * @internal
19
+ * @todo support rtl for nested popovers and search
20
+ */
21
+ export class PopoverDesktop extends PopoverAbstract {
22
+ /**
23
+ * Flipper - module for keyboard iteration between elements
24
+ */
25
+ public flipper: Flipper | undefined;
26
+
27
+ /**
28
+ * Popover nesting level. 0 value means that it is a root popover
29
+ */
30
+ public nestingLevel = 0;
31
+
32
+ /**
33
+ * Reference to nested popover if exists.
34
+ * Undefined by default, PopoverDesktop when exists and null after destroyed.
35
+ */
36
+ protected nestedPopover: PopoverDesktop | undefined | null;
37
+
38
+ /**
39
+ * Item nested popover is displayed for
40
+ */
41
+ protected nestedPopoverTriggerItem: PopoverItem | null = null;
42
+
43
+ /**
44
+ * Last hovered item inside popover.
45
+ * Is used to determine if cursor is moving inside one item or already moved away to another one.
46
+ * Helps prevent reopening nested popover while cursor is moving inside one item area.
47
+ */
48
+ private previouslyHoveredItem: PopoverItem | null = null;
49
+
50
+ /**
51
+ * Element of the page that creates 'scope' of the popover.
52
+ * If possible, popover will not cross specified element's borders when opening.
53
+ */
54
+ private scopeElement: HTMLElement = document.body;
55
+
56
+ /**
57
+ * Element relative to which the popover should be positioned
58
+ */
59
+ private trigger: HTMLElement | undefined;
60
+
61
+ /**
62
+ * Popover size cache
63
+ */
64
+ private _size: { height: number; width: number } | undefined;
65
+
66
+ /**
67
+ * Construct the instance
68
+ * @param params - popover params
69
+ * @param itemsRenderParams – popover item render params.
70
+ * The parameters that are not set by user via popover api but rather depend on technical implementation
71
+ */
72
+ constructor(params: PopoverParams, itemsRenderParams?: PopoverItemRenderParamsMap) {
73
+ super(params, itemsRenderParams);
74
+
75
+ if (params.trigger) {
76
+ this.trigger = params.trigger;
77
+ }
78
+
79
+ if (params.nestingLevel !== undefined) {
80
+ this.nestingLevel = params.nestingLevel;
81
+ }
82
+
83
+ if (this.nestingLevel > 0) {
84
+ this.nodes.popover.setAttribute(DATA_ATTR.nested, 'true');
85
+ }
86
+
87
+ if (params.scopeElement !== undefined) {
88
+ this.scopeElement = params.scopeElement;
89
+ }
90
+
91
+ if (this.nodes.popoverContainer !== null) {
92
+ this.listeners.on(this.nodes.popoverContainer, 'mouseover', (event: Event) => this.handleHover(event));
93
+ }
94
+
95
+ if (params.searchable) {
96
+ this.addSearch();
97
+ }
98
+
99
+ if (params.flippable === false) {
100
+ return;
101
+ }
102
+
103
+ if (params.flipper !== undefined) {
104
+ params.flipper.deactivate();
105
+ params.flipper.removeOnFlip(this.onFlip);
106
+ this.flipper = params.flipper;
107
+ } else {
108
+ this.flipper = new Flipper({
109
+ items: this.flippableElements,
110
+ focusedItemClass: popoverItemCls.focused,
111
+ allowedKeys: [
112
+ keyCodes.TAB,
113
+ keyCodes.UP,
114
+ keyCodes.DOWN,
115
+ keyCodes.ENTER,
116
+ keyCodes.RIGHT,
117
+ keyCodes.LEFT,
118
+ ],
119
+ onArrowLeft: params.onNavigateBack,
120
+ handleContentEditableTargets: params.handleContentEditableNavigation,
121
+ });
122
+ }
123
+
124
+ this.flipper?.onFlip(this.onFlip);
125
+ }
126
+
127
+ /**
128
+ * Returns true if some item inside popover is focused
129
+ */
130
+ public hasFocus(): boolean {
131
+ if (this.flipper === undefined) {
132
+ return false;
133
+ }
134
+
135
+ return this.flipper.hasFocus();
136
+ }
137
+
138
+ /**
139
+ * Scroll position inside items container of the popover
140
+ */
141
+ public get scrollTop(): number {
142
+ if (this.nodes.items === null) {
143
+ return 0;
144
+ }
145
+
146
+ return this.nodes.items.scrollTop;
147
+ }
148
+
149
+ /**
150
+ * Returns visible element offset top
151
+ */
152
+ public get offsetTop(): number {
153
+ if (this.nodes.popoverContainer === null) {
154
+ return 0;
155
+ }
156
+
157
+ return this.nodes.popoverContainer.offsetTop;
158
+ }
159
+
160
+ /**
161
+ * Open popover
162
+ */
163
+ public show(): void {
164
+ const mountTarget = this.getMountElement();
165
+
166
+ if (this.trigger && mountTarget) {
167
+ document.body.appendChild(mountTarget);
168
+ }
169
+
170
+ if (this.trigger) {
171
+ const { top, left } = this.calculatePosition();
172
+ this.nodes.popover.style.position = 'absolute';
173
+ this.nodes.popover.style.top = `${top}px`;
174
+ this.nodes.popover.style.left = `${left}px`;
175
+ this.nodes.popover.style.setProperty(CSSVariables.PopoverTop, '0px');
176
+ this.nodes.popover.style.setProperty(CSSVariables.PopoverLeft, '0px');
177
+ }
178
+
179
+ this.nodes.popover.style.setProperty(CSSVariables.PopoverHeight, this.size.height + 'px');
180
+
181
+ if (!this.trigger && !this.shouldOpenBottom) {
182
+ this.setOpenTop(true);
183
+ // Apply open-top positioning (moved from popover.css)
184
+ this.nodes.popover.style.setProperty(CSSVariables.PopoverTop, 'calc(-1 * (0.5rem + var(--popover-height)))');
185
+ }
186
+
187
+ if (!this.trigger && !this.shouldOpenRight) {
188
+ this.setOpenLeft(true);
189
+ // Apply open-left positioning (moved from popover.css)
190
+ this.nodes.popover.style.setProperty(CSSVariables.PopoverLeft, 'calc(-1 * var(--width) + 100%)');
191
+ }
192
+
193
+ super.show();
194
+ this.flipper?.activate(this.flippableElements);
195
+
196
+ // Focus the first item: search field if present, otherwise first menu item
197
+ requestAnimationFrame(() => {
198
+ this.focusInitialElement();
199
+ });
200
+ }
201
+
202
+ /**
203
+ * Focuses the initial element when popover is shown.
204
+ * Focuses search field if present, otherwise first menu item.
205
+ * Skips the first Tab press so it just "enters" the menu rather than advancing.
206
+ */
207
+ private focusInitialElement(): void {
208
+ if (this.search) {
209
+ this.search.focus();
210
+
211
+ return;
212
+ }
213
+
214
+ this.flipper?.focusItem(0, { skipNextTab: true });
215
+ }
216
+
217
+ /**
218
+ * Calculates position for the popover
219
+ */
220
+ private calculatePosition(): { top: number; left: number } {
221
+ if (!this.trigger) {
222
+ return {
223
+ top: 0,
224
+ left: 0,
225
+ };
226
+ }
227
+
228
+ const triggerRect = this.trigger.getBoundingClientRect();
229
+ const popoverRect = this.size;
230
+ const windowWidth = window.innerWidth;
231
+ const windowHeight = window.innerHeight;
232
+ const offset = 8;
233
+
234
+ const initialTop = triggerRect.bottom + offset + window.scrollY;
235
+ const shouldFlipTop = (triggerRect.bottom + offset + popoverRect.height > windowHeight + window.scrollY) &&
236
+ (triggerRect.top - offset - popoverRect.height > window.scrollY);
237
+ const top = shouldFlipTop ? triggerRect.top - offset - popoverRect.height + window.scrollY : initialTop;
238
+
239
+ const initialLeft = triggerRect.left + window.scrollX;
240
+ const shouldFlipLeft = initialLeft + popoverRect.width > windowWidth + window.scrollX;
241
+ const left = shouldFlipLeft ? Math.max(0, triggerRect.right - popoverRect.width + window.scrollX) : initialLeft;
242
+
243
+ return {
244
+ top,
245
+ left,
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Closes popover
251
+ */
252
+ public hide = (): void => {
253
+ super.hide();
254
+
255
+ this.destroyNestedPopoverIfExists();
256
+
257
+ this.flipper?.deactivate();
258
+
259
+ this.previouslyHoveredItem = null;
260
+ };
261
+
262
+ /**
263
+ * Clears memory
264
+ */
265
+ public destroy(): void {
266
+ this.hide();
267
+ super.destroy();
268
+ }
269
+
270
+ /**
271
+ * Checks if popover contains the node.
272
+ * Overridden to check nested popover as well.
273
+ * @param node - node to check
274
+ */
275
+ public override hasNode(node: Node): boolean {
276
+ if (super.hasNode(node)) {
277
+ return true;
278
+ }
279
+
280
+ if (this.nestedPopover !== undefined && this.nestedPopover !== null) {
281
+ return this.nestedPopover.hasNode(node);
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ /**
288
+ * Handles displaying nested items for the item.
289
+ * @param item – item to show nested popover for
290
+ */
291
+ protected override showNestedItems(item: PopoverItem): void {
292
+ if (this.nestedPopover !== null && this.nestedPopover !== undefined) {
293
+ return;
294
+ }
295
+
296
+ this.nestedPopoverTriggerItem = item;
297
+
298
+ this.showNestedPopoverForItem(item);
299
+ }
300
+
301
+ /**
302
+ * Handles hover events inside popover items container
303
+ * @param event - hover event data
304
+ */
305
+ protected handleHover(event: Event): void {
306
+ const item = this.getTargetItem(event);
307
+
308
+ if (item === undefined) {
309
+ return;
310
+ }
311
+
312
+ if (this.previouslyHoveredItem === item) {
313
+ return;
314
+ }
315
+
316
+ this.destroyNestedPopoverIfExists();
317
+
318
+ this.previouslyHoveredItem = item;
319
+
320
+ if (!item.hasChildren) {
321
+ return;
322
+ }
323
+
324
+ this.showNestedPopoverForItem(item);
325
+ }
326
+
327
+ /**
328
+ * Sets CSS variable with position of item near which nested popover should be displayed.
329
+ * Is used for correct positioning of the nested popover
330
+ * @param nestedPopoverEl - nested popover element
331
+ * @param item – item near which nested popover should be displayed
332
+ */
333
+ protected setTriggerItemPosition(nestedPopoverEl: HTMLElement, item: PopoverItem): void {
334
+ const itemEl = item.getElement();
335
+ const itemOffsetTop = (itemEl ? itemEl.offsetTop : 0) - this.scrollTop;
336
+ const topOffset = this.offsetTop + itemOffsetTop;
337
+
338
+ const actualPopoverEl = nestedPopoverEl.querySelector(`[${DATA_ATTR.popover}]`) as HTMLElement | null ?? nestedPopoverEl;
339
+
340
+ actualPopoverEl.style.setProperty(CSSVariables.TriggerItemTop, topOffset + 'px');
341
+ }
342
+
343
+ /**
344
+ * Destroys existing nested popover
345
+ */
346
+ protected destroyNestedPopoverIfExists(): void {
347
+ if (this.nestedPopover === undefined || this.nestedPopover === null) {
348
+ return;
349
+ }
350
+
351
+ const triggerItemElement = this.nestedPopoverTriggerItem?.getElement();
352
+
353
+ this.nestedPopover.off(PopoverEvent.ClosedOnActivate, this.hide);
354
+ this.nestedPopover.hide();
355
+ this.nestedPopover.destroy();
356
+ this.nestedPopover.getElement().remove();
357
+ this.nestedPopover = null;
358
+ this.flipper?.activate(this.flippableElements);
359
+ // Focus the trigger item synchronously to ensure keyboard events work immediately
360
+ this.focusAfterNestedPopoverClose(triggerItemElement);
361
+
362
+ this.nestedPopoverTriggerItem?.onChildrenClose();
363
+ // Reset trigger item so clicking the same item again will open the nested popover
364
+ this.nestedPopoverTriggerItem = null;
365
+ }
366
+
367
+ /**
368
+ * Focuses the appropriate item after nested popover closes.
369
+ * Focuses the item that opened the nested popover, or falls back to first item.
370
+ * @param triggerItemElement - element that triggered the nested popover
371
+ */
372
+ private focusAfterNestedPopoverClose(triggerItemElement: HTMLElement | null | undefined): void {
373
+ if (!triggerItemElement || !this.flipper) {
374
+ this.flipper?.focusFirst();
375
+
376
+ return;
377
+ }
378
+
379
+ const triggerIndex = this.flippableElements.indexOf(triggerItemElement);
380
+
381
+ if (triggerIndex !== -1) {
382
+ // Don't skip next Tab - user expects Tab to move to next item after closing nested popover
383
+ this.flipper.focusItem(triggerIndex, { skipNextTab: false });
384
+
385
+ return;
386
+ }
387
+
388
+ this.flipper.focusFirst();
389
+ }
390
+
391
+ /**
392
+ * Creates and displays nested popover for specified item.
393
+ * Is used only on desktop
394
+ * @param item - item to display nested popover by
395
+ */
396
+ protected showNestedPopoverForItem(item: PopoverItem): PopoverDesktop {
397
+ this.nestedPopover = new PopoverDesktop({
398
+ searchable: item.isChildrenSearchable,
399
+ items: item.children,
400
+ nestingLevel: this.nestingLevel + 1,
401
+ flippable: item.isChildrenFlippable,
402
+ messages: this.messages,
403
+ onNavigateBack: this.destroyNestedPopoverIfExists.bind(this),
404
+ });
405
+
406
+ item.onChildrenOpen();
407
+
408
+ /**
409
+ * Close nested popover when item with 'closeOnActivate' property set was clicked
410
+ * parent popover should also be closed
411
+ */
412
+ this.nestedPopover.on(PopoverEvent.ClosedOnActivate, this.hide);
413
+
414
+ const nestedPopoverEl = this.nestedPopover.getMountElement();
415
+ const actualNestedPopoverEl = this.nestedPopover.getElement();
416
+
417
+ this.nodes.popover.appendChild(nestedPopoverEl);
418
+
419
+ this.setTriggerItemPosition(nestedPopoverEl, item);
420
+
421
+ /* We need nesting level value in CSS to calculate offset left for nested popover */
422
+ /* Set on the actual popover element so it's available for --popover-left calculation */
423
+ actualNestedPopoverEl.style.setProperty(CSSVariables.NestingLevel, this.nestedPopover.nestingLevel.toString());
424
+
425
+ // Apply nested popover positioning (moved from popover.css)
426
+ this.applyNestedPopoverPositioning(nestedPopoverEl);
427
+
428
+ this.nestedPopover.show();
429
+ this.flipper?.deactivate();
430
+
431
+ return this.nestedPopover;
432
+ }
433
+
434
+ /**
435
+ * Applies positioning styles to nested popover container.
436
+ * This replaces CSS selectors like [data-blok-nested] [data-blok-popover-container]
437
+ * @param nestedPopoverEl - the nested popover element (mount element)
438
+ */
439
+ private applyNestedPopoverPositioning(nestedPopoverEl: HTMLElement): void {
440
+ const nestedContainer = nestedPopoverEl.querySelector(`[${DATA_ATTR.popoverContainer}]`) as HTMLElement | null;
441
+
442
+ if (!nestedContainer) {
443
+ return;
444
+ }
445
+
446
+ const actualPopoverEl = nestedPopoverEl.querySelector(`[${DATA_ATTR.popover}]`) as HTMLElement | null ?? nestedPopoverEl;
447
+
448
+ // Check if parent popover has openTop or openLeft state
449
+ const isParentOpenTop = this.nodes.popover.hasAttribute(DATA_ATTR.popoverOpenTop);
450
+ const isParentOpenLeft = this.nodes.popover.hasAttribute(DATA_ATTR.popoverOpenLeft);
451
+
452
+ // Apply position: absolute for nested container
453
+ nestedContainer.style.position = 'absolute';
454
+
455
+ // Calculate --popover-left based on nesting level and parent open direction
456
+ // Set on the actual popover element to override its default value
457
+ if (isParentOpenLeft) {
458
+ // Position to the left
459
+ actualPopoverEl.style.setProperty(CSSVariables.PopoverLeft, 'calc(-1 * (var(--nesting-level) + 1) * var(--width) + 100%)');
460
+ } else {
461
+ // Position to the right
462
+ actualPopoverEl.style.setProperty(CSSVariables.PopoverLeft, 'calc(var(--nesting-level) * (var(--width) - var(--nested-popover-overlap)))');
463
+ }
464
+
465
+ // Calculate top position based on parent open direction
466
+ if (isParentOpenTop) {
467
+ // Open upward
468
+ nestedContainer.style.top = 'calc(var(--trigger-item-top) - var(--popover-height) + var(--item-height) + 0.5rem + var(--nested-popover-overlap))';
469
+ } else {
470
+ // Open downward
471
+ nestedContainer.style.top = 'calc(var(--trigger-item-top) - var(--nested-popover-overlap))';
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Checks if popover should be opened bottom.
477
+ * It should happen when there is enough space below or not enough space above
478
+ */
479
+ private get shouldOpenBottom(): boolean {
480
+ if (this.nodes.popover === undefined || this.nodes.popover === null) {
481
+ return false;
482
+ }
483
+ const popoverRect = this.nodes.popoverContainer.getBoundingClientRect();
484
+ const scopeElementRect = this.scopeElement.getBoundingClientRect();
485
+ const popoverHeight = this.size.height;
486
+ const popoverPotentialBottomEdge = popoverRect.top + popoverHeight;
487
+ const popoverPotentialTopEdge = popoverRect.top - popoverHeight;
488
+ const bottomEdgeForComparison = Math.min(window.innerHeight, scopeElementRect.bottom);
489
+
490
+ return popoverPotentialTopEdge < scopeElementRect.top || popoverPotentialBottomEdge <= bottomEdgeForComparison;
491
+ }
492
+
493
+ /**
494
+ * Checks if popover should be opened left.
495
+ * It should happen when there is enough space in the right or not enough space in the left
496
+ */
497
+ private get shouldOpenRight(): boolean {
498
+ if (this.nodes.popover === undefined || this.nodes.popover === null) {
499
+ return false;
500
+ }
501
+
502
+ const popoverRect = this.nodes.popover.getBoundingClientRect();
503
+ const scopeElementRect = this.scopeElement.getBoundingClientRect();
504
+ const popoverWidth = this.size.width;
505
+ const popoverPotentialRightEdge = popoverRect.right + popoverWidth;
506
+ const popoverPotentialLeftEdge = popoverRect.left - popoverWidth;
507
+ const rightEdgeForComparison = Math.min(window.innerWidth, scopeElementRect.right);
508
+
509
+ return popoverPotentialLeftEdge < scopeElementRect.left || popoverPotentialRightEdge <= rightEdgeForComparison;
510
+ }
511
+
512
+ /**
513
+ * Helps to calculate size of popover that is only resolved when popover is displayed on screen.
514
+ * Renders invisible clone of popover to get actual values.
515
+ */
516
+ public get size(): { height: number; width: number } {
517
+ if (this._size) {
518
+ return this._size;
519
+ }
520
+
521
+ const size = {
522
+ height: 0,
523
+ width: 0,
524
+ };
525
+
526
+ if (this.nodes.popover === null) {
527
+ return size;
528
+ }
529
+
530
+ const popoverClone = this.nodes.popover.cloneNode(true) as HTMLElement;
531
+
532
+ popoverClone.style.visibility = 'hidden';
533
+ popoverClone.style.position = 'absolute';
534
+ popoverClone.style.top = '-1000px';
535
+
536
+ popoverClone.setAttribute(DATA_ATTR.popoverOpened, 'true');
537
+ popoverClone.querySelector(`[${DATA_ATTR.nested}]`)?.remove();
538
+ document.body.appendChild(popoverClone);
539
+
540
+ const container = popoverClone.querySelector(`[${DATA_ATTR.popoverContainer}]`) as HTMLElement;
541
+
542
+ size.height = container.offsetHeight;
543
+ size.width = container.offsetWidth;
544
+ popoverClone.remove();
545
+
546
+ this._size = size;
547
+
548
+ return size;
549
+ }
550
+
551
+ /**
552
+ * Returns list of elements available for keyboard navigation.
553
+ */
554
+ protected get flippableElements(): HTMLElement[] {
555
+ const result = this.items.flatMap(item => {
556
+ return this.getFlippableElementsForItem(item);
557
+ }).filter((item): item is HTMLElement => item !== undefined && item !== null);
558
+
559
+ return result;
560
+ }
561
+
562
+ /**
563
+ * Gets flippable elements for a single item.
564
+ * @param item - popover item to get elements from
565
+ * @returns array of HTML elements for keyboard navigation
566
+ */
567
+ private getFlippableElementsForItem(item: PopoverItem): HTMLElement[] {
568
+ if (item instanceof PopoverItemHtml) {
569
+ const element = item.getElement();
570
+
571
+ return element ? [element] : [];
572
+ }
573
+
574
+ if (!(item instanceof PopoverItemDefault)) {
575
+ return [];
576
+ }
577
+
578
+ if (item.isDisabled) {
579
+ return [];
580
+ }
581
+
582
+ const element = item.getElement();
583
+
584
+ return element ? [ element ] : [];
585
+ }
586
+
587
+ /**
588
+ * Called on flipper navigation
589
+ */
590
+ private onFlip = (): void => {
591
+ const focusedItem = this.itemsDefault.find(item => item.isFocused);
592
+
593
+ focusedItem?.onFocus();
594
+ };
595
+
596
+ /**
597
+ * Adds search to the popover
598
+ */
599
+ private addSearch(): void {
600
+ this.search = new SearchInput({
601
+ items: this.itemsDefault,
602
+ placeholder: this.messages.search,
603
+ });
604
+
605
+ this.search.on(SearchInputEvent.Search, this.onSearch);
606
+
607
+ const searchElement = this.search.getElement();
608
+
609
+ searchElement.classList.add('mb-1.5');
610
+
611
+ this.nodes.popoverContainer.insertBefore(searchElement, this.nodes.popoverContainer.firstChild);
612
+ }
613
+
614
+ /**
615
+ * Filters popover items by query string.
616
+ * Used for inline slash search where typing happens in the block, not in a search input.
617
+ * @param query - search query text
618
+ */
619
+ public override filterItems(query: string): void {
620
+ const matchingItems = this.itemsDefault.filter(item => matchesSearchQuery(item, query));
621
+
622
+ this.onSearch({
623
+ query,
624
+ items: matchingItems as unknown as SearchableItem[],
625
+ });
626
+ }
627
+
628
+ /**
629
+ * Handles input inside search field
630
+ * @param data - search input event data
631
+ * @param data.query - search query text
632
+ * @param data.items - search results
633
+ */
634
+ private onSearch = (data: { query: string, items: SearchableItem[] }): void => {
635
+ const isEmptyQuery = data.query === '';
636
+ const isNothingFound = data.items.length === 0;
637
+
638
+ // Cast data.items to PopoverItemDefault[] since we know that's what filterItems passes
639
+ const matchingItems = data.items as unknown as PopoverItemDefault[];
640
+
641
+ this.items
642
+ .forEach((item) => {
643
+ const isDefaultItem = item instanceof PopoverItemDefault;
644
+ const isSeparatorOrHtml = item instanceof PopoverItemSeparator || item instanceof PopoverItemHtml;
645
+ const isHidden = isDefaultItem
646
+ ? !matchingItems.includes(item as PopoverItemDefault)
647
+ : isSeparatorOrHtml && (isNothingFound || !isEmptyQuery);
648
+
649
+ item.toggleHidden(isHidden);
650
+ });
651
+ this.toggleNothingFoundMessage(isNothingFound);
652
+
653
+ /** List of elements available for keyboard navigation considering search query applied */
654
+ const flippableElements = isEmptyQuery ? this.flippableElements : data.items.map(item => (item as PopoverItem).getElement());
655
+
656
+ if (!this.flipper?.isActivated) {
657
+ return;
658
+ }
659
+
660
+ /** Update flipper items with only visible */
661
+ this.flipper.deactivate();
662
+ this.flipper.activate(flippableElements as HTMLElement[]);
663
+
664
+ /**
665
+ * Focus first item after filtering.
666
+ * Always skip the first Tab press so it just "enters" the menu rather than
667
+ * advancing to second item. This applies regardless of whether the query is
668
+ * empty (initial "/" open) or non-empty (user is typing to filter), because
669
+ * the user's keyboard focus is still in the search input - pressing Tab
670
+ * should enter the list at item 0, not advance from 0 to 1.
671
+ */
672
+ if (flippableElements.length > 0) {
673
+ this.flipper.focusItem(0, { skipNextTab: true });
674
+ }
675
+ };
676
+ }