@jackuait/blok 0.7.0-beta.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (462) hide show
  1. package/dist/blok.mjs +3 -7
  2. package/dist/chunks/blok-Ufr5cPq-.mjs +12435 -0
  3. package/dist/chunks/constants-DT17zmu_.mjs +2934 -0
  4. package/dist/chunks/i18next-DymC16cN.mjs +1146 -0
  5. package/dist/chunks/i18next-loader-qjweOJ-t.mjs +35 -0
  6. package/dist/chunks/lightweight-i18n-vbtPx5C4.mjs +105 -0
  7. package/dist/chunks/messages-3bOAVT3X2.mjs +80 -0
  8. package/dist/chunks/messages-43N0Vfg42.mjs +80 -0
  9. package/dist/chunks/messages-B0cg-ThO2.mjs +80 -0
  10. package/dist/chunks/messages-B3StvafX.mjs +80 -0
  11. package/dist/chunks/messages-B7LU-b6n2.mjs +80 -0
  12. package/dist/chunks/messages-B87-89os.mjs +80 -0
  13. package/dist/chunks/messages-BFiMCfDX2.mjs +80 -0
  14. package/dist/chunks/messages-BLxyso1L.mjs +80 -0
  15. package/dist/chunks/messages-BQZtOYxr2.mjs +80 -0
  16. package/dist/chunks/messages-BRrtoRdw2.mjs +80 -0
  17. package/dist/chunks/messages-BU_YdaAf.mjs +80 -0
  18. package/dist/chunks/messages-BWbZYIs12.mjs +80 -0
  19. package/dist/chunks/messages-B_Qcy8kr2.mjs +80 -0
  20. package/dist/chunks/messages-B_uTiuQ-.mjs +80 -0
  21. package/dist/chunks/messages-BdWTM73p.mjs +80 -0
  22. package/dist/chunks/messages-BhZcNoIQ.mjs +80 -0
  23. package/dist/chunks/messages-Bn6LwI4B.mjs +80 -0
  24. package/dist/chunks/messages-BoTtYEct2.mjs +80 -0
  25. package/dist/chunks/messages-BrvAiuWT.mjs +80 -0
  26. package/dist/chunks/messages-Byp0YFMg.mjs +80 -0
  27. package/dist/chunks/messages-C0ZWDShx2.mjs +80 -0
  28. package/dist/chunks/messages-CA-jms9R.mjs +80 -0
  29. package/dist/chunks/messages-CFr0Ha6p2.mjs +80 -0
  30. package/dist/chunks/messages-CG2xl0IV.mjs +80 -0
  31. package/dist/chunks/messages-CIGX0FfW.mjs +80 -0
  32. package/dist/chunks/messages-CRMdL0jG.mjs +80 -0
  33. package/dist/chunks/messages-CRdl14uE.mjs +80 -0
  34. package/dist/chunks/messages-Cimsel4e.mjs +80 -0
  35. package/dist/chunks/messages-CjcSWeud.mjs +80 -0
  36. package/dist/chunks/messages-ClDJuy8K2.mjs +80 -0
  37. package/dist/chunks/messages-Cn1AC0Qk.mjs +80 -0
  38. package/dist/chunks/messages-CpnXbVOK2.mjs +80 -0
  39. package/dist/chunks/messages-CqsES1wk2.mjs +80 -0
  40. package/dist/chunks/messages-Csq7JatN.mjs +80 -0
  41. package/dist/chunks/messages-CtufKbaD.mjs +80 -0
  42. package/dist/chunks/messages-Cuk0QaLM.mjs +80 -0
  43. package/dist/chunks/messages-CvamFN6x.mjs +80 -0
  44. package/dist/chunks/messages-CwRhVVui.mjs +80 -0
  45. package/dist/chunks/messages-CzCezryo.mjs +80 -0
  46. package/dist/chunks/messages-D0v0Xa_i2.mjs +80 -0
  47. package/dist/chunks/messages-D3JVx_CH2.mjs +80 -0
  48. package/dist/chunks/messages-D4jR5Oc-.mjs +80 -0
  49. package/dist/chunks/messages-D7fI9Pj52.mjs +80 -0
  50. package/dist/chunks/messages-DGodJU2R.mjs +80 -0
  51. package/dist/chunks/messages-DLrmLkco2.mjs +80 -0
  52. package/dist/chunks/messages-DPe7kW6J.mjs +80 -0
  53. package/dist/chunks/messages-DRYKKPk8.mjs +80 -0
  54. package/dist/chunks/messages-DV5c_ZRQ.mjs +80 -0
  55. package/dist/chunks/messages-Dg6kSnxq.mjs +80 -0
  56. package/dist/chunks/messages-Dgfbmyf-.mjs +80 -0
  57. package/dist/chunks/messages-DihczS7L.mjs +80 -0
  58. package/dist/chunks/messages-DkSwQvmi2.mjs +80 -0
  59. package/dist/chunks/messages-Doxcj7Qy.mjs +80 -0
  60. package/dist/chunks/messages-DqGQvcXv2.mjs +80 -0
  61. package/dist/chunks/messages-Dr7yA3xM.mjs +80 -0
  62. package/dist/chunks/messages-DriB5lEF.mjs +80 -0
  63. package/dist/chunks/messages-FB_MePlt.mjs +80 -0
  64. package/dist/chunks/messages-JyZvGvrN.mjs +80 -0
  65. package/dist/chunks/messages-KdvbGwLH.mjs +80 -0
  66. package/dist/chunks/messages-M0HT-kBW.mjs +80 -0
  67. package/dist/chunks/messages-M8noQ6Kp2.mjs +80 -0
  68. package/dist/chunks/messages-elZUbCrN.mjs +80 -0
  69. package/dist/chunks/messages-iWMOMK822.mjs +80 -0
  70. package/dist/chunks/messages-kC92TJI72.mjs +80 -0
  71. package/dist/chunks/messages-tfyq1JIh2.mjs +80 -0
  72. package/dist/chunks/messages-v1HkA3kF2.mjs +80 -0
  73. package/dist/chunks/messages-yuqArCc6.mjs +80 -0
  74. package/dist/chunks/notifier-BqYxvxnV.mjs +96 -0
  75. package/dist/chunks/objectSpread2-CyPxu8-u.mjs +62 -0
  76. package/dist/chunks/tools-CJIETS-H.mjs +6004 -0
  77. package/dist/chunks/tw-DmW6-pCY.mjs +237 -0
  78. package/dist/cli.mjs +36 -49
  79. package/dist/full.mjs +26 -52
  80. package/dist/locales.mjs +181 -254
  81. package/dist/messages-2iHnlF0U.mjs +80 -0
  82. package/dist/messages-49ZJ_ISf.mjs +80 -0
  83. package/dist/messages-B8jjwMLK.mjs +80 -0
  84. package/dist/messages-BEDVb3ZX.mjs +80 -0
  85. package/dist/messages-BEEr6Vh82.mjs +80 -0
  86. package/dist/messages-BFT0F9pw.mjs +80 -0
  87. package/dist/messages-BHOI7R4K.mjs +80 -0
  88. package/dist/messages-BRPH_a6a.mjs +80 -0
  89. package/dist/messages-BSlQrYwp.mjs +80 -0
  90. package/dist/messages-BTNuOkhL.mjs +80 -0
  91. package/dist/messages-BX2KVzJp2.mjs +80 -0
  92. package/dist/messages-BaGwIHPb2.mjs +80 -0
  93. package/dist/messages-BdA_xvxj.mjs +80 -0
  94. package/dist/messages-BeJaje7e2.mjs +80 -0
  95. package/dist/messages-BfgHOkAy.mjs +80 -0
  96. package/dist/messages-BflWzIcP2.mjs +80 -0
  97. package/dist/messages-BigRnQS92.mjs +80 -0
  98. package/dist/messages-BjnJajTO2.mjs +80 -0
  99. package/dist/messages-BpA30dPf.mjs +80 -0
  100. package/dist/messages-BrPEPj382.mjs +80 -0
  101. package/dist/messages-Bt_9ptDu.mjs +80 -0
  102. package/dist/messages-C0cXOCHN2.mjs +80 -0
  103. package/dist/messages-C3tLCwJp2.mjs +80 -0
  104. package/dist/messages-C45IBZtA2.mjs +80 -0
  105. package/dist/messages-CA0hwajz.mjs +80 -0
  106. package/dist/messages-CCKZS2f4.mjs +80 -0
  107. package/dist/messages-CCm71gq3.mjs +80 -0
  108. package/dist/messages-CERs9LC9.mjs +80 -0
  109. package/dist/messages-CLQvtc_8.mjs +80 -0
  110. package/dist/messages-CPx1R-PH.mjs +80 -0
  111. package/dist/messages-CYFdbooL2.mjs +80 -0
  112. package/dist/messages-CYLYnOV82.mjs +80 -0
  113. package/dist/messages-CYZVFnaF.mjs +80 -0
  114. package/dist/messages-CaAdEXoh2.mjs +80 -0
  115. package/dist/messages-CicggErN2.mjs +80 -0
  116. package/dist/messages-CkAWTSc4.mjs +80 -0
  117. package/dist/messages-CkVfziK_2.mjs +80 -0
  118. package/dist/messages-CsM2iz1H2.mjs +80 -0
  119. package/dist/messages-D-12TeCM2.mjs +80 -0
  120. package/dist/messages-D0i5Vdyy2.mjs +80 -0
  121. package/dist/messages-D5KmRsUV2.mjs +80 -0
  122. package/dist/messages-DBwaWI0X.mjs +80 -0
  123. package/dist/messages-DDGzypb4.mjs +80 -0
  124. package/dist/messages-DQGzw4IC.mjs +80 -0
  125. package/dist/messages-DWZyaZNA.mjs +80 -0
  126. package/dist/messages-DYlxQEIv.mjs +80 -0
  127. package/dist/messages-DZo0x7Bd.mjs +80 -0
  128. package/dist/messages-Dc1yFFBM.mjs +80 -0
  129. package/dist/messages-DdUpYaJ1.mjs +80 -0
  130. package/dist/messages-DgstU8GH.mjs +80 -0
  131. package/dist/messages-DhdWq5oQ2.mjs +80 -0
  132. package/dist/messages-DmX52AQr.mjs +80 -0
  133. package/dist/messages-Dr-YJYIK2.mjs +80 -0
  134. package/dist/messages-DuubRyFf.mjs +80 -0
  135. package/dist/messages-DvTVsLOK2.mjs +80 -0
  136. package/dist/messages-DwPfgL_u.mjs +80 -0
  137. package/dist/messages-DxKIxLKw.mjs +80 -0
  138. package/dist/messages-DzhR8Klk.mjs +80 -0
  139. package/dist/messages-MBBSKGjJ2.mjs +80 -0
  140. package/dist/messages-RNusm48G2.mjs +80 -0
  141. package/dist/messages-XwPD18Kk.mjs +80 -0
  142. package/dist/messages-YfjdnhUF.mjs +80 -0
  143. package/dist/messages-aNMLsF8T2.mjs +80 -0
  144. package/dist/messages-cOqXp22e.mjs +80 -0
  145. package/dist/messages-g58itYPI.mjs +80 -0
  146. package/dist/messages-vfkwiKQo.mjs +80 -0
  147. package/dist/messages-vssmW7KO.mjs +80 -0
  148. package/dist/react.mjs +108 -0
  149. package/dist/tools.mjs +3 -7485
  150. package/dist/vendor.LICENSE.txt +86 -86
  151. package/package.json +56 -29
  152. package/src/blok.ts +52 -2
  153. package/src/components/block/api.ts +8 -0
  154. package/src/components/block/mutation-handler.ts +29 -4
  155. package/src/components/block/style-manager.ts +1 -1
  156. package/src/components/block-tunes/block-tune-width.ts +39 -0
  157. package/src/components/blocks.ts +56 -2
  158. package/src/components/core.ts +1 -0
  159. package/src/components/i18n/locales/am/messages.json +6 -1
  160. package/src/components/i18n/locales/ar/messages.json +6 -1
  161. package/src/components/i18n/locales/az/messages.json +6 -1
  162. package/src/components/i18n/locales/bg/messages.json +8 -3
  163. package/src/components/i18n/locales/bn/messages.json +6 -1
  164. package/src/components/i18n/locales/bs/messages.json +6 -1
  165. package/src/components/i18n/locales/cs/messages.json +6 -1
  166. package/src/components/i18n/locales/da/messages.json +6 -1
  167. package/src/components/i18n/locales/de/messages.json +8 -3
  168. package/src/components/i18n/locales/dv/messages.json +6 -1
  169. package/src/components/i18n/locales/el/messages.json +8 -3
  170. package/src/components/i18n/locales/en/messages.json +5 -0
  171. package/src/components/i18n/locales/es/messages.json +6 -1
  172. package/src/components/i18n/locales/et/messages.json +6 -1
  173. package/src/components/i18n/locales/fa/messages.json +8 -3
  174. package/src/components/i18n/locales/fi/messages.json +6 -1
  175. package/src/components/i18n/locales/fil/messages.json +21 -16
  176. package/src/components/i18n/locales/fr/messages.json +6 -1
  177. package/src/components/i18n/locales/gu/messages.json +6 -1
  178. package/src/components/i18n/locales/he/messages.json +6 -1
  179. package/src/components/i18n/locales/hi/messages.json +6 -1
  180. package/src/components/i18n/locales/hr/messages.json +6 -1
  181. package/src/components/i18n/locales/hu/messages.json +6 -1
  182. package/src/components/i18n/locales/hy/messages.json +8 -3
  183. package/src/components/i18n/locales/id/messages.json +12 -7
  184. package/src/components/i18n/locales/it/messages.json +6 -1
  185. package/src/components/i18n/locales/ja/messages.json +6 -1
  186. package/src/components/i18n/locales/ka/messages.json +6 -1
  187. package/src/components/i18n/locales/km/messages.json +6 -1
  188. package/src/components/i18n/locales/kn/messages.json +6 -1
  189. package/src/components/i18n/locales/ko/messages.json +6 -1
  190. package/src/components/i18n/locales/ku/messages.json +7 -2
  191. package/src/components/i18n/locales/lo/messages.json +7 -2
  192. package/src/components/i18n/locales/lt/messages.json +6 -1
  193. package/src/components/i18n/locales/lv/messages.json +6 -1
  194. package/src/components/i18n/locales/mk/messages.json +6 -1
  195. package/src/components/i18n/locales/ml/messages.json +6 -1
  196. package/src/components/i18n/locales/mn/messages.json +6 -1
  197. package/src/components/i18n/locales/mr/messages.json +6 -1
  198. package/src/components/i18n/locales/ms/messages.json +6 -1
  199. package/src/components/i18n/locales/my/messages.json +6 -1
  200. package/src/components/i18n/locales/ne/messages.json +9 -4
  201. package/src/components/i18n/locales/nl/messages.json +6 -1
  202. package/src/components/i18n/locales/no/messages.json +6 -1
  203. package/src/components/i18n/locales/pa/messages.json +6 -1
  204. package/src/components/i18n/locales/pl/messages.json +6 -1
  205. package/src/components/i18n/locales/ps/messages.json +8 -3
  206. package/src/components/i18n/locales/pt/messages.json +6 -1
  207. package/src/components/i18n/locales/ro/messages.json +6 -1
  208. package/src/components/i18n/locales/ru/messages.json +10 -5
  209. package/src/components/i18n/locales/sd/messages.json +6 -1
  210. package/src/components/i18n/locales/si/messages.json +6 -1
  211. package/src/components/i18n/locales/sk/messages.json +6 -1
  212. package/src/components/i18n/locales/sl/messages.json +6 -1
  213. package/src/components/i18n/locales/sq/messages.json +6 -1
  214. package/src/components/i18n/locales/sr/messages.json +6 -1
  215. package/src/components/i18n/locales/sv/messages.json +6 -1
  216. package/src/components/i18n/locales/sw/messages.json +6 -1
  217. package/src/components/i18n/locales/ta/messages.json +6 -1
  218. package/src/components/i18n/locales/te/messages.json +9 -4
  219. package/src/components/i18n/locales/th/messages.json +6 -1
  220. package/src/components/i18n/locales/tr/messages.json +6 -1
  221. package/src/components/i18n/locales/ug/messages.json +7 -2
  222. package/src/components/i18n/locales/uk/messages.json +6 -1
  223. package/src/components/i18n/locales/ur/messages.json +6 -1
  224. package/src/components/i18n/locales/vi/messages.json +6 -1
  225. package/src/components/i18n/locales/yi/messages.json +7 -2
  226. package/src/components/i18n/locales/zh/messages.json +6 -1
  227. package/src/components/icons/index.ts +16 -0
  228. package/src/components/inline-tools/inline-tool-link.ts +1 -1
  229. package/src/components/modules/api/blocks.ts +45 -2
  230. package/src/components/modules/api/index.ts +1 -0
  231. package/src/components/modules/api/width.ts +17 -0
  232. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +99 -0
  233. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +109 -2
  234. package/src/components/modules/blockEvents/constants.ts +7 -0
  235. package/src/components/modules/blockManager/blockManager.ts +113 -9
  236. package/src/components/modules/blockManager/hierarchy.ts +61 -0
  237. package/src/components/modules/blockManager/operations.ts +133 -15
  238. package/src/components/modules/blockManager/yjs-sync.ts +112 -4
  239. package/src/components/modules/blockSelection.ts +36 -2
  240. package/src/components/modules/crossBlockSelection.ts +22 -2
  241. package/src/components/modules/drag/DragController.ts +178 -4
  242. package/src/components/modules/drag/operations/DragOperations.ts +48 -9
  243. package/src/components/modules/drag/preview/DragPreview.ts +21 -1
  244. package/src/components/modules/drag/state/DragStateMachine.ts +6 -1
  245. package/src/components/modules/drag/target/DropTargetDetector.ts +80 -4
  246. package/src/components/modules/drag/utils/ToggleSpringLoader.ts +71 -0
  247. package/src/components/modules/index.ts +7 -1
  248. package/src/components/modules/modificationsObserver.ts +19 -0
  249. package/src/components/modules/paste/constants.ts +2 -0
  250. package/src/components/modules/paste/handlers/base.ts +33 -1
  251. package/src/components/modules/paste/handlers/html-handler.ts +121 -54
  252. package/src/components/modules/paste/index.ts +5 -0
  253. package/src/components/modules/paste/types.ts +5 -0
  254. package/src/components/modules/rectangleSelection.ts +74 -81
  255. package/src/components/modules/toolbar/blockSettings.ts +25 -7
  256. package/src/components/modules/toolbar/index.ts +9 -7
  257. package/src/components/modules/toolbar/inline/index.ts +6 -1
  258. package/src/components/modules/toolbar/plus-button.ts +2 -6
  259. package/src/components/modules/toolbar/positioning.ts +10 -1
  260. package/src/components/modules/toolbar/settings-toggler.ts +1 -1
  261. package/src/components/modules/toolbar/styles.ts +3 -7
  262. package/src/components/modules/ui.ts +59 -5
  263. package/src/components/modules/uiControllers/handlers/click.ts +3 -2
  264. package/src/components/modules/widthManager.ts +69 -0
  265. package/src/components/modules/yjs/document-store.ts +11 -0
  266. package/src/components/modules/yjs/index.ts +11 -0
  267. package/src/components/shared/color-picker.ts +3 -3
  268. package/src/components/tools/block.ts +1 -11
  269. package/src/components/ui/toolbox.ts +52 -8
  270. package/src/components/utils/blocks.ts +37 -7
  271. package/src/components/utils/mutations.ts +2 -2
  272. package/src/components/utils/notifier/draw.ts +1 -1
  273. package/src/components/utils/placeholder.ts +5 -6
  274. package/src/components/utils/popover/components/popover-header/popover-header.const.ts +1 -1
  275. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +4 -4
  276. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -6
  277. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
  278. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
  279. package/src/components/utils/popover/components/search-input/search-input.ts +7 -11
  280. package/src/components/utils/popover/components/search-input/search-input.types.ts +149 -10
  281. package/src/components/utils/popover/popover-abstract.ts +3 -2
  282. package/src/components/utils/popover/popover-desktop.ts +133 -11
  283. package/src/components/utils/popover/popover-inline.ts +1 -1
  284. package/src/components/utils/popover/popover.const.ts +3 -3
  285. package/src/components/utils/shortcut.ts +2 -0
  286. package/src/components/utils/tooltip.ts +11 -1
  287. package/src/react/BlokContent.tsx +46 -0
  288. package/src/react/holder-map.ts +17 -0
  289. package/src/react/index.ts +3 -0
  290. package/src/react/types.ts +16 -0
  291. package/src/react/useBlok.ts +173 -0
  292. package/src/stories/Placeholder.stories.ts +0 -59
  293. package/src/styles/main.css +663 -52
  294. package/src/tools/header/header-toggle-keyboard.ts +115 -0
  295. package/src/tools/header/index.ts +382 -187
  296. package/src/tools/list/block-operations.ts +1 -1
  297. package/src/tools/list/caret-manager.ts +9 -12
  298. package/src/tools/list/index.ts +2 -6
  299. package/src/tools/list/list-keyboard.ts +2 -2
  300. package/src/tools/paragraph/index.ts +1 -1
  301. package/src/tools/table/index.ts +37 -3
  302. package/src/tools/table/table-add-controls.ts +97 -8
  303. package/src/tools/table/table-cell-blocks.ts +17 -8
  304. package/src/tools/table/table-cell-clipboard.ts +1 -1
  305. package/src/tools/table/table-cell-selection.ts +27 -2
  306. package/src/tools/table/table-operations.ts +3 -2
  307. package/src/tools/toggle/block-operations.ts +4 -2
  308. package/src/tools/toggle/constants.ts +26 -2
  309. package/src/tools/toggle/dom-builder.ts +90 -25
  310. package/src/tools/toggle/index.ts +112 -9
  311. package/src/tools/toggle/toggle-keyboard.ts +5 -3
  312. package/src/tools/toggle/toggle-lifecycle.ts +79 -7
  313. package/src/tools/toggle/toggle-shortcuts.ts +214 -20
  314. package/src/tools/toggle/types.ts +2 -0
  315. package/src/types-internal/blok-modules.d.ts +4 -0
  316. package/types/api/block.d.ts +5 -0
  317. package/types/api/blocks.d.ts +29 -0
  318. package/types/api/index.d.ts +1 -0
  319. package/types/api/width.d.ts +19 -0
  320. package/types/configs/blok-config.d.ts +33 -0
  321. package/types/index.d.ts +4 -0
  322. package/types/react.d.ts +58 -0
  323. package/types/utils/popover/popover.d.ts +7 -0
  324. package/dist/chunks/blok-B0pAWdVk.mjs +0 -20102
  325. package/dist/chunks/constants-DmDwNSTM.mjs +0 -5123
  326. package/dist/chunks/i18next-B47TKgbU.mjs +0 -1303
  327. package/dist/chunks/i18next-loader-v9SlYZ0i.mjs +0 -43
  328. package/dist/chunks/index-DHLWzZaA.mjs +0 -130
  329. package/dist/chunks/messages-0Pxnqd4N.mjs +0 -75
  330. package/dist/chunks/messages-0ZXYUq7S.mjs +0 -75
  331. package/dist/chunks/messages-2OD2uUDS.mjs +0 -75
  332. package/dist/chunks/messages-7cEMfYzh.mjs +0 -75
  333. package/dist/chunks/messages-8mwfda1Q.mjs +0 -75
  334. package/dist/chunks/messages-B-FqWsBM.mjs +0 -75
  335. package/dist/chunks/messages-B1jzqWiQ.mjs +0 -75
  336. package/dist/chunks/messages-B5wk4Ezz.mjs +0 -75
  337. package/dist/chunks/messages-BAZ5Ld8x.mjs +0 -75
  338. package/dist/chunks/messages-BBhGp198.mjs +0 -75
  339. package/dist/chunks/messages-BC9IjIb7.mjs +0 -75
  340. package/dist/chunks/messages-BFEmpeV-.mjs +0 -75
  341. package/dist/chunks/messages-BGqzTZy0.mjs +0 -75
  342. package/dist/chunks/messages-BICs1abK.mjs +0 -75
  343. package/dist/chunks/messages-BJX6rOnd.mjs +0 -75
  344. package/dist/chunks/messages-BL2bXRhN.mjs +0 -75
  345. package/dist/chunks/messages-BMs5qdlH.mjs +0 -75
  346. package/dist/chunks/messages-BRsjUNwB.mjs +0 -75
  347. package/dist/chunks/messages-BSqV8OUR.mjs +0 -75
  348. package/dist/chunks/messages-BTqu3DfG.mjs +0 -75
  349. package/dist/chunks/messages-BXnDEsur.mjs +0 -75
  350. package/dist/chunks/messages-BYcre4-6.mjs +0 -75
  351. package/dist/chunks/messages-BZ9LRJf-.mjs +0 -75
  352. package/dist/chunks/messages-BgypBy7y.mjs +0 -75
  353. package/dist/chunks/messages-BsuGf70G.mjs +0 -75
  354. package/dist/chunks/messages-BwaoF4lQ.mjs +0 -75
  355. package/dist/chunks/messages-C1l8_7-y.mjs +0 -75
  356. package/dist/chunks/messages-C5NA_r9v.mjs +0 -75
  357. package/dist/chunks/messages-C6zgZ5pA.mjs +0 -75
  358. package/dist/chunks/messages-CAo5ghFI.mjs +0 -75
  359. package/dist/chunks/messages-CH9qlJ9I.mjs +0 -75
  360. package/dist/chunks/messages-CI0HqAeS.mjs +0 -75
  361. package/dist/chunks/messages-CJJtms9k.mjs +0 -75
  362. package/dist/chunks/messages-CM2hJqk6.mjs +0 -75
  363. package/dist/chunks/messages-CRMiDPIQ.mjs +0 -75
  364. package/dist/chunks/messages-CWsZuBj1.mjs +0 -75
  365. package/dist/chunks/messages-C_gLHo6A.mjs +0 -75
  366. package/dist/chunks/messages-Cbu-NUDn.mjs +0 -75
  367. package/dist/chunks/messages-Cjb_MCeh.mjs +0 -75
  368. package/dist/chunks/messages-ClXYO9Wn.mjs +0 -75
  369. package/dist/chunks/messages-CsH20vhP.mjs +0 -75
  370. package/dist/chunks/messages-CsjAGhzA.mjs +0 -75
  371. package/dist/chunks/messages-Cx7VKFOE.mjs +0 -75
  372. package/dist/chunks/messages-D3JeBwxo.mjs +0 -75
  373. package/dist/chunks/messages-D541fieJ.mjs +0 -75
  374. package/dist/chunks/messages-D7XPdglc.mjs +0 -75
  375. package/dist/chunks/messages-DBhylfvt.mjs +0 -75
  376. package/dist/chunks/messages-DCA120lW.mjs +0 -75
  377. package/dist/chunks/messages-DCf_xZMN.mjs +0 -75
  378. package/dist/chunks/messages-DDwXKCpe.mjs +0 -75
  379. package/dist/chunks/messages-DNKDlxcy.mjs +0 -75
  380. package/dist/chunks/messages-DPvEjrGK.mjs +0 -75
  381. package/dist/chunks/messages-DQ-AkNxA.mjs +0 -75
  382. package/dist/chunks/messages-DVuvkNap.mjs +0 -75
  383. package/dist/chunks/messages-DaglyqUT.mjs +0 -75
  384. package/dist/chunks/messages-Di0bAfwA.mjs +0 -75
  385. package/dist/chunks/messages-DuLct0Yr.mjs +0 -75
  386. package/dist/chunks/messages-DzEYYhZh.mjs +0 -75
  387. package/dist/chunks/messages-DznNGAB2.mjs +0 -75
  388. package/dist/chunks/messages-DzoIzyu8.mjs +0 -75
  389. package/dist/chunks/messages-QYOGmket.mjs +0 -75
  390. package/dist/chunks/messages-cEjGDAgI.mjs +0 -75
  391. package/dist/chunks/messages-ddhvrdpE.mjs +0 -75
  392. package/dist/chunks/messages-mwfNK5nZ.mjs +0 -75
  393. package/dist/chunks/messages-nG_vNDte.mjs +0 -75
  394. package/dist/chunks/messages-tDq3Owh7.mjs +0 -75
  395. package/dist/chunks/messages-x6VJVZKx.mjs +0 -75
  396. package/dist/messages-0Pxnqd4N.mjs +0 -75
  397. package/dist/messages-0ZXYUq7S.mjs +0 -75
  398. package/dist/messages-2OD2uUDS.mjs +0 -75
  399. package/dist/messages-7cEMfYzh.mjs +0 -75
  400. package/dist/messages-8mwfda1Q.mjs +0 -75
  401. package/dist/messages-B-FqWsBM.mjs +0 -75
  402. package/dist/messages-B1jzqWiQ.mjs +0 -75
  403. package/dist/messages-B5wk4Ezz.mjs +0 -75
  404. package/dist/messages-BAZ5Ld8x.mjs +0 -75
  405. package/dist/messages-BBhGp198.mjs +0 -75
  406. package/dist/messages-BC9IjIb7.mjs +0 -75
  407. package/dist/messages-BFEmpeV-.mjs +0 -75
  408. package/dist/messages-BGqzTZy0.mjs +0 -75
  409. package/dist/messages-BICs1abK.mjs +0 -75
  410. package/dist/messages-BJX6rOnd.mjs +0 -75
  411. package/dist/messages-BL2bXRhN.mjs +0 -75
  412. package/dist/messages-BMs5qdlH.mjs +0 -75
  413. package/dist/messages-BRsjUNwB.mjs +0 -75
  414. package/dist/messages-BSqV8OUR.mjs +0 -75
  415. package/dist/messages-BTqu3DfG.mjs +0 -75
  416. package/dist/messages-BXnDEsur.mjs +0 -75
  417. package/dist/messages-BYcre4-6.mjs +0 -75
  418. package/dist/messages-BZ9LRJf-.mjs +0 -75
  419. package/dist/messages-BgypBy7y.mjs +0 -75
  420. package/dist/messages-BsuGf70G.mjs +0 -75
  421. package/dist/messages-BwaoF4lQ.mjs +0 -75
  422. package/dist/messages-C1l8_7-y.mjs +0 -75
  423. package/dist/messages-C5NA_r9v.mjs +0 -75
  424. package/dist/messages-C6zgZ5pA.mjs +0 -75
  425. package/dist/messages-CAo5ghFI.mjs +0 -75
  426. package/dist/messages-CH9qlJ9I.mjs +0 -75
  427. package/dist/messages-CI0HqAeS.mjs +0 -75
  428. package/dist/messages-CJJtms9k.mjs +0 -75
  429. package/dist/messages-CM2hJqk6.mjs +0 -75
  430. package/dist/messages-CRMiDPIQ.mjs +0 -75
  431. package/dist/messages-CWsZuBj1.mjs +0 -75
  432. package/dist/messages-C_gLHo6A.mjs +0 -75
  433. package/dist/messages-Cbu-NUDn.mjs +0 -75
  434. package/dist/messages-Cjb_MCeh.mjs +0 -75
  435. package/dist/messages-ClXYO9Wn.mjs +0 -75
  436. package/dist/messages-CsH20vhP.mjs +0 -75
  437. package/dist/messages-CsjAGhzA.mjs +0 -75
  438. package/dist/messages-Cx7VKFOE.mjs +0 -75
  439. package/dist/messages-D3JeBwxo.mjs +0 -75
  440. package/dist/messages-D541fieJ.mjs +0 -75
  441. package/dist/messages-D7XPdglc.mjs +0 -75
  442. package/dist/messages-DBhylfvt.mjs +0 -75
  443. package/dist/messages-DCA120lW.mjs +0 -75
  444. package/dist/messages-DCf_xZMN.mjs +0 -75
  445. package/dist/messages-DDwXKCpe.mjs +0 -75
  446. package/dist/messages-DNKDlxcy.mjs +0 -75
  447. package/dist/messages-DPvEjrGK.mjs +0 -75
  448. package/dist/messages-DQ-AkNxA.mjs +0 -75
  449. package/dist/messages-DVuvkNap.mjs +0 -75
  450. package/dist/messages-DaglyqUT.mjs +0 -75
  451. package/dist/messages-Di0bAfwA.mjs +0 -75
  452. package/dist/messages-DuLct0Yr.mjs +0 -75
  453. package/dist/messages-DzEYYhZh.mjs +0 -75
  454. package/dist/messages-DznNGAB2.mjs +0 -75
  455. package/dist/messages-DzoIzyu8.mjs +0 -75
  456. package/dist/messages-QYOGmket.mjs +0 -75
  457. package/dist/messages-cEjGDAgI.mjs +0 -75
  458. package/dist/messages-ddhvrdpE.mjs +0 -75
  459. package/dist/messages-mwfNK5nZ.mjs +0 -75
  460. package/dist/messages-nG_vNDte.mjs +0 -75
  461. package/dist/messages-tDq3Owh7.mjs +0 -75
  462. package/dist/messages-x6VJVZKx.mjs +0 -75
@@ -262,6 +262,17 @@ export class YjsManager extends Module {
262
262
  this.documentStore.transact(fn, 'local');
263
263
  }
264
264
 
265
+ /**
266
+ * Execute Yjs operations without adding them to the undo history.
267
+ * Uses a non-tracked origin so the UndoManager ignores these changes.
268
+ * Use this for auto-repair operations (e.g. ensuring empty cells have a block)
269
+ * that should never be undoable by the user.
270
+ * @param fn - Function containing Yjs operations to execute
271
+ */
272
+ public transactWithoutCapture(fn: () => void): void {
273
+ this.documentStore.transactWithoutCapture(fn);
274
+ }
275
+
265
276
  // ========== Public API: Smart Grouping ==========
266
277
 
267
278
  /**
@@ -64,7 +64,7 @@ export interface ColorPickerHandle {
64
64
  /**
65
65
  * Base Tailwind classes shared by tab buttons
66
66
  */
67
- const TAB_BASE_CLASSES = 'flex-1 py-1.5 text-xs text-center rounded-md cursor-pointer border-none transition-colors';
67
+ const TAB_BASE_CLASSES = 'flex-1 py-1.5 text-xs text-center rounded-md cursor-pointer border-none outline-hidden transition-colors';
68
68
 
69
69
  /**
70
70
  * Neutral background for text-mode swatches so they render as visible buttons
@@ -139,7 +139,7 @@ export function createColorPicker(options: ColorPickerOptions): ColorPickerHandl
139
139
 
140
140
  swatch.setAttribute('data-blok-testid', `${testIdPrefix}-swatch-${preset.name}`);
141
141
  swatch.className = twMerge(
142
- 'w-8 h-8 rounded-md cursor-pointer border-none',
142
+ 'w-8 h-8 rounded-md cursor-pointer border-none outline-hidden',
143
143
  'flex items-center justify-center text-sm font-semibold',
144
144
  'transition-shadow ring-inset hover:ring-2 hover:ring-black/10',
145
145
  isActive && 'ring-2 ring-black/30'
@@ -169,7 +169,7 @@ export function createColorPicker(options: ColorPickerOptions): ColorPickerHandl
169
169
  defaultBtn.setAttribute('data-blok-testid', `${testIdPrefix}-default-btn`);
170
170
  defaultBtn.className = twMerge(
171
171
  'w-full py-1.5 text-xs text-center rounded-md cursor-pointer',
172
- 'bg-transparent border-none hover:bg-item-hover-bg',
172
+ 'bg-transparent border-none outline-hidden hover:bg-item-hover-bg',
173
173
  'mt-0.5 transition-colors'
174
174
  );
175
175
  defaultBtn.textContent = i18n.t('tools.marker.default');
@@ -53,22 +53,12 @@ export class BlockToolAdapter extends BaseToolAdapter<ToolType.Block, IBlockTool
53
53
  * @param readOnly - True if Blok is in read-only mode
54
54
  */
55
55
  public create(data: BlockToolData, block: BlockAPI, readOnly: boolean): IBlockTool {
56
- const toolboxEntries = this.toolbox;
57
-
58
- /**
59
- * Inject merged toolbox entries into config so tools can use them in renderSettings().
60
- * This allows tools like Header to show the same options in block settings as in the toolbox.
61
- */
62
- const configWithToolbox = toolboxEntries !== undefined
63
- ? { ...this.settings, _toolboxEntries: toolboxEntries }
64
- : this.settings;
65
-
66
56
  return new this.constructable({
67
57
  data,
68
58
  block,
69
59
  readOnly,
70
60
  api: this.api,
71
- config: configWithToolbox,
61
+ config: this.settings,
72
62
  }) as IBlockTool;
73
63
  }
74
64
 
@@ -587,6 +587,8 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
587
587
  return;
588
588
  }
589
589
 
590
+ const currentBlockParentId: string | null = currentBlock.parentId ?? null;
591
+
590
592
  /**
591
593
  * Check if the block contains only slash search text (e.g., "/head").
592
594
  * If so, treat it as empty and replace it with the new block.
@@ -605,14 +607,33 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
605
607
  ? Object.assign(await this.api.blocks.composeBlockData(toolName), blockDataOverrides)
606
608
  : undefined;
607
609
 
608
- const newBlock = this.api.blocks.insert(
609
- toolName,
610
- blockData,
611
- undefined,
612
- index,
613
- undefined,
614
- shouldReplaceBlock
615
- );
610
+ /**
611
+ * When replacing a child block (e.g. inside a toggle), the parent-clear,
612
+ * insert, and parent-restore must be a single undo entry. Wrap them in
613
+ * a transaction so undo/redo treats the conversion atomically.
614
+ */
615
+ const performInsert = (): BlockAPI => {
616
+ if (shouldReplaceBlock && currentBlockParentId !== null) {
617
+ this.api.blocks.setBlockParent(currentBlock.id, null);
618
+ }
619
+
620
+ const inserted = this.api.blocks.insert(
621
+ toolName,
622
+ blockData,
623
+ undefined,
624
+ index,
625
+ undefined,
626
+ shouldReplaceBlock
627
+ );
628
+
629
+ if (currentBlockParentId !== null) {
630
+ this.api.blocks.setBlockParent(inserted.id, currentBlockParentId);
631
+ }
632
+
633
+ return inserted;
634
+ };
635
+
636
+ const newBlock = this.insertWithTransaction(performInsert, currentBlockParentId);
616
637
 
617
638
  this.api.caret.setToBlock(index);
618
639
 
@@ -627,6 +648,29 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
627
648
  this.api.toolbar.close({ setExplicitlyClosed: false });
628
649
  }
629
650
 
651
+ /**
652
+ * Runs a block-insert callback inside a transaction when the block has a parent,
653
+ * so that parent-clear + insert + parent-restore form a single undo entry.
654
+ * When there is no parent (or transact is unavailable), runs the callback directly.
655
+ *
656
+ * @param fn - synchronous callback that performs the insert and returns the new BlockAPI
657
+ * @param parentId - the current block's parentId, or null if none
658
+ * @returns the BlockAPI returned by fn
659
+ */
660
+ private insertWithTransaction(fn: () => BlockAPI, parentId: string | null): BlockAPI {
661
+ const result: { block: BlockAPI | undefined } = { block: undefined };
662
+
663
+ if (parentId !== null && this.api.blocks.transact !== undefined) {
664
+ this.api.blocks.transact(() => {
665
+ result.block = fn();
666
+ });
667
+ } else {
668
+ result.block = fn();
669
+ }
670
+
671
+ return result.block as BlockAPI;
672
+ }
673
+
630
674
  /**
631
675
  * Starts listening to input events on the current block for inline slash search.
632
676
  * When the user types after "/", the toolbox filters based on the typed text.
@@ -73,6 +73,22 @@ export const getConvertibleToolsForBlock = async (block: BlockAPI, allBlockTools
73
73
  return result;
74
74
  }
75
75
 
76
+ /**
77
+ * Collect all data property names that appear in any toolbox entry for this tool.
78
+ * This lets us compare toolbox items against the current block using ALL distinguishing
79
+ * properties, not just the ones in a single entry.
80
+ *
81
+ * Example: header tool has entries with { level } and { level, isToggleable }.
82
+ * The union of keys is { level, isToggleable }, so regular headings and toggle
83
+ * headings are correctly treated as different block variants.
84
+ */
85
+ const allToolboxDataKeys = new Set(
86
+ tool.toolbox
87
+ .map(item => item.data)
88
+ .filter((data): data is BlockToolData => data !== undefined)
89
+ .flatMap(data => Object.keys(data))
90
+ );
91
+
76
92
  /** Filter out invalid toolbox entries */
77
93
  const actualToolboxItems = tool.toolbox.filter((toolboxItem) => {
78
94
  /**
@@ -86,10 +102,22 @@ export const getConvertibleToolsForBlock = async (block: BlockAPI, allBlockTools
86
102
 
87
103
  /**
88
104
  * When a tool has several toolbox entries, we need to make sure we do not add
89
- * toolbox item with the same data to the resulting array. This helps exclude duplicates
105
+ * toolbox item with the same data to the resulting array. This helps exclude duplicates.
106
+ *
107
+ * We compare ALL distinguishing data properties (union of keys across all toolbox entries)
108
+ * to correctly differentiate variants like regular heading vs toggle heading.
90
109
  */
91
- if (hasToolboxData && toolboxItem.data !== undefined && isSameBlockData(toolboxItem.data, blockData)) {
92
- return false;
110
+ if (hasToolboxData && toolboxItem.data !== undefined) {
111
+ const wouldProduceSameBlock = [...allToolboxDataKeys].every(key => {
112
+ const toolboxValue = toolboxItem.data !== undefined ? toolboxItem.data[key] : undefined;
113
+ const blockValue = blockData[key];
114
+
115
+ return equals(toolboxValue, blockValue);
116
+ });
117
+
118
+ if (wouldProduceSameBlock) {
119
+ return false;
120
+ }
93
121
  }
94
122
 
95
123
  if (!hasToolboxData && tool.name === block.name) {
@@ -99,10 +127,12 @@ export const getConvertibleToolsForBlock = async (block: BlockAPI, allBlockTools
99
127
  return true;
100
128
  });
101
129
 
102
- result.push({
103
- ...tool,
104
- toolbox: actualToolboxItems,
105
- } as BlockToolAdapter);
130
+ if (actualToolboxItems.length > 0) {
131
+ result.push({
132
+ ...tool,
133
+ toolbox: actualToolboxItems,
134
+ } as BlockToolAdapter);
135
+ }
106
136
 
107
137
  return result;
108
138
  }, [] as BlockToolAdapter[]);
@@ -7,9 +7,9 @@ export const isMutationBelongsToElement = (mutationRecord: MutationRecord, eleme
7
7
  const { type, target, addedNodes, removedNodes } = mutationRecord;
8
8
 
9
9
  /**
10
- * Skip own technical mutations, for example, data-blok-empty attribute changes
10
+ * Skip own technical mutations, for example, data-blok-empty or data-blok-toggle-open attribute changes
11
11
  */
12
- if (mutationRecord.type === 'attributes' && mutationRecord.attributeName === 'data-blok-empty') {
12
+ if (mutationRecord.type === 'attributes' && (mutationRecord.attributeName === 'data-blok-empty' || mutationRecord.attributeName === 'data-blok-toggle-open')) {
13
13
  return false;
14
14
  }
15
15
 
@@ -38,7 +38,7 @@ export const CSS = {
38
38
  'hover:opacity-100'
39
39
  ),
40
40
  btnsWrapper: 'flex flex-row flex-nowrap mt-[5px]',
41
- btn: 'border-none rounded-[3px] text-[13px] py-[5px] px-2.5 cursor-pointer last:ml-2.5',
41
+ btn: 'border-none rounded-[3px] text-[13px] py-[5px] px-2.5 cursor-pointer outline-hidden last:ml-2.5',
42
42
  okBtn: 'bg-[#34c992] shadow-[0_1px_1px_0_rgba(18,49,35,0.05)] text-white hover:bg-[#2db583]',
43
43
  cancelBtn: 'bg-[#f2f5f7] shadow-[0_2px_1px_0_rgba(16,19,29,0)] text-[#656b7c] hover:bg-[#e9ecee]',
44
44
  input: twJoin(
@@ -119,8 +119,10 @@ const handleEmptyElement = (element: HTMLElement): void => {
119
119
 
120
120
  /**
121
121
  * Set up placeholder behavior for a contenteditable element.
122
- * Adds focus and input event listeners to handle caret positioning
123
- * when the element is empty.
122
+ * Adds a focus event listener to position the caret at the start
123
+ * when the element is empty. Does NOT handle caret positioning on
124
+ * input events — doing so would race with the browser's own editing
125
+ * model and destroy content mid-typing (e.g. "Hello world" → "He").
124
126
  *
125
127
  * @param element - The contenteditable element
126
128
  * @param placeholder - Optional placeholder text to set
@@ -134,10 +136,7 @@ export const setupPlaceholder = (
134
136
  // Always set the attribute, even if empty (for consistency and testing)
135
137
  element.setAttribute(attributeName, placeholder ?? '');
136
138
 
137
- const handler = (): void => handleEmptyElement(element);
138
-
139
- element.addEventListener('focus', handler);
140
- element.addEventListener('input', handler);
139
+ element.addEventListener('focus', () => handleEmptyElement(element));
141
140
  };
142
141
 
143
142
  /**
@@ -4,5 +4,5 @@
4
4
  export const css = {
5
5
  root: 'flex items-center mb-2 mt-1',
6
6
  text: 'text-lg font-semibold text-text-primary',
7
- backButton: 'border-0 bg-transparent w-9 h-9 text-text-primary cursor-pointer [&_svg]:block [&_svg]:w-7 [&_svg]:h-7',
7
+ backButton: 'border-0 bg-transparent w-9 h-9 text-text-primary cursor-pointer outline-hidden [&_svg]:block [&_svg]:w-7 [&_svg]:h-7',
8
8
  };
@@ -10,7 +10,7 @@ export const css = {
10
10
  * Note: noHover state is handled via [data-blok-popover-item-no-hover] which disables hover
11
11
  * Priority order: active < hover < focus (focus wins when navigating with keyboard)
12
12
  */
13
- item: 'flex items-center select-none border-none bg-transparent rounded-lg px-2 py-(--item-padding) text-text-primary mb-0.5 transition-[color,background-color,border-color,opacity,max-height,padding,margin] duration-150 max-h-10 overflow-hidden data-blok-popover-item-active:bg-icon-active-bg data-blok-popover-item-active:text-icon-active-text can-hover:hover:cursor-pointer can-hover:hover:bg-item-hover-bg data-blok-force-hover:cursor-pointer data-blok-force-hover:bg-item-hover-bg data-[blok-focused="true"]:bg-item-focus-bg data-blok-popover-item-no-hover:hover:bg-transparent data-blok-popover-item-no-hover:cursor-default can-hover:data-blok-popover-item-destructive:hover:text-item-destructive-text can-hover:data-blok-popover-item-destructive:hover:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-force-hover]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-force-hover]]:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:bg-item-destructive-hover-bg',
13
+ item: 'flex items-center select-none border-none bg-transparent rounded-lg px-2 py-1 text-text-primary mb-px outline-hidden transition-[color,background-color,border-color,opacity,max-height,padding,margin] duration-150 max-h-9 overflow-hidden data-blok-popover-item-active:bg-icon-active-bg data-blok-popover-item-active:text-icon-active-text can-hover:hover:cursor-pointer can-hover:hover:bg-item-hover-bg data-blok-force-hover:cursor-pointer data-blok-force-hover:bg-item-hover-bg data-[blok-focused="true"]:bg-item-focus-bg data-blok-popover-item-no-hover:hover:bg-transparent data-blok-popover-item-no-hover:cursor-default can-hover:data-blok-popover-item-destructive:hover:text-item-destructive-text can-hover:data-blok-popover-item-destructive:hover:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-force-hover]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-force-hover]]:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:bg-item-destructive-hover-bg',
14
14
 
15
15
  /**
16
16
  * Item disabled state
@@ -21,7 +21,7 @@ export const css = {
21
21
  /**
22
22
  * Icon container styles
23
23
  */
24
- icon: 'flex items-center justify-center w-[26px] h-[26px] shrink-0 rounded-lg [&_svg]:w-icon [&_svg]:h-icon',
24
+ icon: 'flex items-center justify-center w-7 h-7 shrink-0 rounded-lg bg-popover-icon-bg transition-colors duration-150 [&_svg]:w-icon [&_svg]:h-icon',
25
25
 
26
26
  /**
27
27
  * Focused state class for DomIterator/Flipper keyboard navigation.
@@ -37,7 +37,7 @@ export const cssInline = {
37
37
  /**
38
38
  * Item in inline context - more compact styling
39
39
  */
40
- item: 'rounded-sm p-1',
40
+ item: 'rounded p-1',
41
41
  };
42
42
 
43
43
  /**
@@ -47,5 +47,5 @@ export const cssNestedInline = {
47
47
  /**
48
48
  * Nested item - back to desktop popover styling
49
49
  */
50
- item: 'rounded-md p-[3px] mobile:p-1',
50
+ item: 'rounded p-[3px] mobile:p-1',
51
51
  };
@@ -258,8 +258,8 @@ export class PopoverItemDefault extends PopoverItem {
258
258
  const titleEl = document.createElement('div');
259
259
 
260
260
  titleEl.className = params.secondaryLabel
261
- ? 'grow whitespace-nowrap text-sm font-medium leading-5'
262
- : 'mr-auto whitespace-nowrap text-sm font-medium leading-5';
261
+ ? 'grow whitespace-nowrap text-[13px] font-medium leading-5'
262
+ : 'mr-auto whitespace-nowrap text-[13px] font-medium leading-5';
263
263
  titleEl.setAttribute(DATA_ATTR.popoverItemTitle, '');
264
264
  titleEl.setAttribute('data-blok-testid', 'popover-item-title');
265
265
  titleEl.textContent = title;
@@ -272,7 +272,7 @@ export class PopoverItemDefault extends PopoverItem {
272
272
  if (params.secondaryLabel) {
273
273
  const secondaryEl = document.createElement('div');
274
274
 
275
- secondaryEl.className = 'ml-auto shrink-0 flex items-center whitespace-nowrap pl-20 text-[11px] font-medium tracking-wide text-text-secondary/50';
275
+ secondaryEl.className = 'ml-auto shrink-0 flex items-center whitespace-nowrap pl-20 font-mono text-[13px] tracking-wide text-text-secondary/60';
276
276
  secondaryEl.setAttribute(DATA_ATTR.popoverItemSecondaryTitle, '');
277
277
  secondaryEl.setAttribute('data-blok-testid', 'popover-item-secondary-title');
278
278
  secondaryEl.textContent = params.secondaryLabel;
@@ -326,7 +326,7 @@ export class PopoverItemDefault extends PopoverItem {
326
326
 
327
327
  return twMerge(
328
328
  css.item,
329
- !isInline && !isNestedInline && 'pl-2 pr-4',
329
+ !isInline && !isNestedInline && 'pl-2 pr-3',
330
330
  isInline && cssInline.item,
331
331
  isNestedInline && cssNestedInline.item,
332
332
  this.params.isDisabled && css.itemDisabled
@@ -342,8 +342,7 @@ export class PopoverItemDefault extends PopoverItem {
342
342
  isInline && 'w-auto h-auto [&_svg]:w-icon [&_svg]:h-icon mobile:[&_svg]:w-icon-mobile mobile:[&_svg]:h-icon-mobile',
343
343
  isNestedInline && 'w-toolbox-btn h-toolbox-btn',
344
344
  iconWithGap && 'mr-3',
345
- iconWithGap && !isInline && 'bg-icon-bg',
346
- iconWithGap && isInline && 'shadow-none bg-transparent mr-0!',
345
+ iconWithGap && isInline && 'shadow-none mr-0!',
347
346
  iconWithGap && isNestedInline && 'mr-2!',
348
347
  isWobbling && 'animate-wobble'
349
348
  );
@@ -355,6 +354,7 @@ export class PopoverItemDefault extends PopoverItem {
355
354
  private getChevronClass(isInline: boolean): string {
356
355
  return twMerge(
357
356
  css.icon,
357
+ 'w-5 h-5 bg-transparent',
358
358
  isInline && 'rotate-90'
359
359
  );
360
360
  }
@@ -2,9 +2,9 @@
2
2
  * Tailwind CSS classes for popover separator component
3
3
  */
4
4
  export const css = {
5
- container: 'py-1 px-[3px] transition-[opacity,max-height,padding] duration-150 max-h-4 overflow-hidden',
5
+ container: 'py-1.5 px-2 transition-[opacity,max-height,padding] duration-150 max-h-5 overflow-hidden',
6
6
  containerHidden: 'opacity-0 max-h-0! py-0!',
7
- line: 'h-px w-full bg-popover-border',
7
+ line: 'h-px w-full bg-popover-border/60',
8
8
  };
9
9
 
10
10
  /**
@@ -2,7 +2,7 @@
2
2
  * CSS class names to be used in popover search input class
3
3
  */
4
4
  export const css = {
5
- wrapper: 'bg-[#F8F8F8] border border-[rgba(226,226,229,0.20)] rounded-lg p-0.5 grid grid-cols-[auto_auto_1fr] grid-rows-[auto] transition-colors duration-150 focus-within:bg-white focus-within:border-[rgba(56,138,229,0.3)]',
5
+ wrapper: 'bg-search-input-bg border border-search-input-border rounded-lg p-1 grid grid-cols-[auto_auto_1fr] grid-rows-[auto] transition-all duration-200 focus-within:bg-popover-bg focus-within:border-search-input-focus-border focus-within:shadow-[0_0_0_2px_rgba(35,131,226,0.08)]',
6
6
  icon: 'w-toolbox-btn h-toolbox-btn flex items-center justify-center mr-2 [&_svg]:w-icon [&_svg]:h-icon [&_svg]:text-gray-text',
7
- input: "text-sm outline-hidden font-medium font-inherit border-0 bg-transparent m-0 p-0 leading-[22px] min-w-[calc(100%-(--spacing(6))-10px)] placeholder:text-gray-text placeholder:font-medium",
7
+ input: "text-sm outline-hidden font-medium font-inherit border-0 bg-transparent m-0 p-0 leading-[22px] min-w-[calc(100%-(--spacing(6))-10px)] placeholder:text-gray-text/60 placeholder:font-normal",
8
8
  };
@@ -5,7 +5,7 @@ import { Listeners } from '../../../listeners';
5
5
 
6
6
  import { css } from './search-input.const';
7
7
  import type { SearchInputEventMap, SearchableItem } from './search-input.types';
8
- import { SearchInputEvent, matchesSearchQuery } from './search-input.types';
8
+ import { SearchInputEvent, scoreSearchMatch } from './search-input.types';
9
9
 
10
10
 
11
11
  /**
@@ -167,17 +167,13 @@ export class SearchInput extends EventsDispatcher<SearchInputEventMap> {
167
167
  }
168
168
 
169
169
  /**
170
- * Returns list of found items for the current search query
170
+ * Returns list of found items for the current search query, sorted by relevance
171
171
  */
172
172
  private get foundItems(): SearchableItem[] {
173
- return this.items.filter(item => this.checkItem(item));
174
- }
175
-
176
- /**
177
- * Contains logic for checking whether passed item conforms the search query.
178
- * @param item - item to be checked
179
- */
180
- private checkItem(item: SearchableItem): boolean {
181
- return matchesSearchQuery(item, this.searchQuery);
173
+ return this.items
174
+ .map(item => ({ item, score: scoreSearchMatch(item, this.searchQuery) }))
175
+ .filter(({ score }) => score > 0)
176
+ .sort((a, b) => b.score - a.score)
177
+ .map(({ item }) => item);
182
178
  }
183
179
  }
@@ -18,24 +18,163 @@ export interface SearchableItem {
18
18
  searchTerms?: string[];
19
19
  }
20
20
 
21
+ /**
22
+ * Standard Levenshtein distance using single-row optimization.
23
+ * @param a - first string
24
+ * @param b - second string
25
+ * @returns edit distance between a and b
26
+ */
27
+ const levenshteinDistance = (a: string, b: string): number => {
28
+ if (a.length === 0) {
29
+ return b.length;
30
+ }
31
+ if (b.length === 0) {
32
+ return a.length;
33
+ }
34
+
35
+ /**
36
+ * Two-row DP approach: prevRow holds distances for the previous character of `a`,
37
+ * currRow is computed for the current character, then they swap.
38
+ */
39
+ const prevRow = Array.from({ length: b.length + 1 }, (_, i) => i);
40
+ const currRow = new Array<number>(b.length + 1);
41
+
42
+ for (const [idx, char] of [...a].entries()) {
43
+ currRow[0] = idx + 1;
44
+
45
+ for (const [jIdx, bChar] of [...b].entries()) {
46
+ const j = jIdx + 1;
47
+ const cost = char === bChar ? 0 : 1;
48
+
49
+ currRow[j] = Math.min(
50
+ prevRow[j] + 1, // deletion
51
+ currRow[j - 1] + 1, // insertion
52
+ prevRow[j - 1] + cost // substitution
53
+ );
54
+ }
55
+
56
+ /** Copy currRow into prevRow for the next iteration */
57
+ prevRow.splice(0, prevRow.length, ...currRow);
58
+ }
59
+
60
+ return prevRow[b.length];
61
+ };
62
+
63
+ /**
64
+ * Checks if query characters appear in order in target (subsequence match).
65
+ * @param target - string to search in
66
+ * @param query - characters to find in order
67
+ * @returns true if query is a subsequence of target
68
+ */
69
+ const isSubsequence = (target: string, query: string): boolean => {
70
+ const matched = [...target].reduce(
71
+ (qi, char) => (qi < query.length && char === query[qi] ? qi + 1 : qi),
72
+ 0
73
+ );
74
+
75
+ return matched === query.length;
76
+ };
77
+
78
+ /**
79
+ * Checks if query characters match at word boundaries in target.
80
+ * Word boundaries are: start of string, after space, hyphen, or underscore.
81
+ * @param target - string to search in
82
+ * @param query - characters to match at word boundaries
83
+ * @returns true if each query char matches a word-boundary character in order
84
+ */
85
+ const matchesWordBoundaries = (target: string, query: string): boolean => {
86
+ const matched = [...target].reduce(
87
+ (qi, char, ti) => {
88
+ const isWordBoundary = ti === 0 || target[ti - 1] === ' ' || target[ti - 1] === '-' || target[ti - 1] === '_';
89
+
90
+ return qi < query.length && isWordBoundary && char === query[qi] ? qi + 1 : qi;
91
+ },
92
+ 0
93
+ );
94
+
95
+ return matched === query.length;
96
+ };
97
+
98
+ /**
99
+ * Scores how well a single string matches a lowercased query.
100
+ * @param target - string to score against (already lowercased)
101
+ * @param lowerQuery - search query (already lowercased)
102
+ * @returns score: 100 (exact) > 90 (prefix) > 75 (substring) > 55 (word-boundary) > 35 (subsequence) > 15 (typo) > 0
103
+ */
104
+ const scoreString = (target: string, lowerQuery: string): number => {
105
+ if (target === lowerQuery) {
106
+ return 100;
107
+ }
108
+ if (target.startsWith(lowerQuery)) {
109
+ return 90;
110
+ }
111
+ if (target.includes(lowerQuery)) {
112
+ return 75;
113
+ }
114
+ if (lowerQuery.length >= 2 && matchesWordBoundaries(target, lowerQuery)) {
115
+ return 55;
116
+ }
117
+ if (lowerQuery.length >= 2 && isSubsequence(target, lowerQuery)) {
118
+ return 35;
119
+ }
120
+ if (lowerQuery.length >= 3) {
121
+ const maxDist = Math.floor(lowerQuery.length / 3);
122
+ const dist = levenshteinDistance(target, lowerQuery);
123
+
124
+ if (dist <= maxDist) {
125
+ return 15;
126
+ }
127
+ }
128
+
129
+ return 0;
130
+ };
131
+
132
+ /**
133
+ * Scores how well an item matches a search query.
134
+ * Returns the best score across title, englishTitle, and searchTerms.
135
+ * @param item - item to score
136
+ * @param query - search query (case-insensitive)
137
+ * @returns score from 0 (no match) to 100 (exact match). Empty query returns 100.
138
+ */
139
+ export const scoreSearchMatch = (item: SearchableItem, query: string): number => {
140
+ if (query === '') {
141
+ return 100;
142
+ }
143
+
144
+ const lowerQuery = query.toLowerCase();
145
+ const candidates: string[] = [];
146
+
147
+ if (item.title !== undefined) {
148
+ candidates.push(item.title.toLowerCase());
149
+ }
150
+ if (item.englishTitle !== undefined) {
151
+ candidates.push(item.englishTitle.toLowerCase());
152
+ }
153
+ if (item.searchTerms !== undefined) {
154
+ for (const term of item.searchTerms) {
155
+ candidates.push(term.toLowerCase());
156
+ }
157
+ }
158
+
159
+ const best = candidates.reduce((max, candidate) => {
160
+ const score = scoreString(candidate, lowerQuery);
161
+
162
+ return score > max ? score : max;
163
+ }, 0);
164
+
165
+ return best;
166
+ };
167
+
21
168
  /**
22
169
  * Checks if an item matches a search query.
170
+ * Uses fuzzy matching: exact, prefix, substring, subsequence, and typo-tolerant (Levenshtein).
23
171
  * Matches against: displayed title, English title, and search term aliases.
24
172
  * @param item - item to check
25
173
  * @param query - search query (case-insensitive)
26
174
  * @returns true if the item matches the query
27
175
  */
28
176
  export const matchesSearchQuery = (item: SearchableItem, query: string): boolean => {
29
- const lowerQuery = query.toLowerCase();
30
- const title = item.title?.toLowerCase() ?? '';
31
- const englishTitle = item.englishTitle?.toLowerCase() ?? '';
32
- const searchTerms = item.searchTerms ?? [];
33
-
34
- return (
35
- title.includes(lowerQuery) ||
36
- englishTitle.includes(lowerQuery) ||
37
- searchTerms.some(term => term.toLowerCase().includes(lowerQuery))
38
- );
177
+ return scoreSearchMatch(item, query) > 0;
39
178
  };
40
179
 
41
180
  /**
@@ -452,7 +452,7 @@ export abstract class PopoverAbstract<Nodes extends PopoverNodes = PopoverNodes>
452
452
  // Set CSS variables
453
453
  popover.style.setProperty('--width', this.params.width ?? 'auto');
454
454
  popover.style.setProperty('--item-padding', '4px');
455
- popover.style.setProperty('--item-height', 'calc(1.25rem + 2 * var(--item-padding))');
455
+ popover.style.setProperty('--item-height', 'calc(1.75rem + 2 * var(--item-padding))');
456
456
  popover.style.setProperty('--popover-top', 'calc(100% + 0.5rem)');
457
457
  popover.style.setProperty('--popover-left', '0');
458
458
  popover.style.setProperty('--nested-popover-overlap', '0.25rem');
@@ -461,13 +461,14 @@ export abstract class PopoverAbstract<Nodes extends PopoverNodes = PopoverNodes>
461
461
  // Create popover container
462
462
  const popoverContainer = document.createElement('div');
463
463
  popoverContainer.className = css.popoverContainer;
464
+ popoverContainer.style.boxShadow = '0 0 0 1px var(--blok-popover-border), 0 4px 16px rgba(0, 0, 0, 0.1), 0 16px 40px -8px rgba(0, 0, 0, 0.08)';
464
465
  popoverContainer.setAttribute(DATA_ATTR.popoverContainer, '');
465
466
  popoverContainer.setAttribute('data-blok-testid', 'popover-container');
466
467
 
467
468
  // Create nothing found message
468
469
  const nothingFoundMessage = document.createElement('div');
469
470
  nothingFoundMessage.className = twMerge(
470
- 'cursor-default text-sm leading-5 font-medium whitespace-nowrap overflow-hidden text-ellipsis text-gray-text px-3 py-3 text-center',
471
+ 'cursor-default text-[13px] leading-5 font-normal whitespace-nowrap overflow-hidden text-ellipsis text-gray-text/70 px-3 py-4 text-center',
471
472
  'hidden'
472
473
  );
473
474
  nothingFoundMessage.setAttribute('data-blok-testid', 'popover-nothing-found');