@vonage/vivid 5.23.1-preview.0 → 5.24.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 (746) hide show
  1. package/accordion/index.cjs +1 -1
  2. package/accordion/index.js +1 -1
  3. package/accordion-item/index.cjs +1 -1
  4. package/accordion-item/index.js +1 -1
  5. package/action-group/index.cjs +1 -1
  6. package/action-group/index.js +1 -1
  7. package/alert/definition.cjs +1 -1
  8. package/alert/definition.js +1 -1
  9. package/alert/index.cjs +7 -7
  10. package/alert/index.js +13 -14
  11. package/audio-player/definition.cjs +1 -1
  12. package/audio-player/definition.js +1 -1
  13. package/audio-player/index.cjs +19 -17
  14. package/audio-player/index.js +24 -22
  15. package/avatar/definition.cjs +1 -1
  16. package/avatar/definition.js +1 -1
  17. package/avatar/index.cjs +4 -4
  18. package/avatar/index.js +6 -6
  19. package/badge/definition.cjs +1 -1
  20. package/badge/definition.js +1 -1
  21. package/badge/index.cjs +1 -1
  22. package/badge/index.js +1 -1
  23. package/banner/definition.cjs +1 -1
  24. package/banner/definition.js +1 -1
  25. package/banner/index.cjs +3 -3
  26. package/banner/index.js +8 -8
  27. package/breadcrumb/definition.cjs +1 -1
  28. package/breadcrumb/definition.js +1 -1
  29. package/breadcrumb-item/definition.cjs +1 -1
  30. package/breadcrumb-item/definition.js +1 -1
  31. package/breadcrumb-item/index.cjs +2 -2
  32. package/breadcrumb-item/index.js +5 -5
  33. package/bundled/affix.cjs +1 -1
  34. package/bundled/affix.js +1 -1
  35. package/bundled/base-color-picker.cjs +2 -2
  36. package/bundled/base-color-picker.js +5 -5
  37. package/bundled/calendar-picker.template.cjs +1 -1
  38. package/bundled/calendar-picker.template.js +1 -1
  39. package/bundled/definition11.cjs +4 -4
  40. package/bundled/definition11.js +5 -5
  41. package/bundled/definition12.cjs +9 -7
  42. package/bundled/definition12.js +28 -26
  43. package/bundled/definition13.cjs +9 -7
  44. package/bundled/definition13.js +16 -15
  45. package/bundled/definition15.cjs +8 -7
  46. package/bundled/definition15.js +26 -24
  47. package/bundled/definition16.cjs +4 -2
  48. package/bundled/definition16.js +8 -6
  49. package/bundled/definition17.cjs +8 -6
  50. package/bundled/definition17.js +15 -14
  51. package/bundled/definition18.cjs +12 -83
  52. package/bundled/definition18.js +35 -420
  53. package/bundled/definition19.cjs +87 -5
  54. package/bundled/definition19.js +432 -14
  55. package/bundled/definition2.cjs +1 -13
  56. package/bundled/definition2.js +181 -48
  57. package/bundled/definition20.cjs +7 -35
  58. package/bundled/definition20.js +17 -170
  59. package/bundled/definition21.cjs +35 -27
  60. package/bundled/definition21.js +154 -155
  61. package/bundled/definition22.cjs +29 -4
  62. package/bundled/definition22.js +171 -17
  63. package/bundled/definition23.cjs +6 -12
  64. package/bundled/definition23.js +17 -32
  65. package/bundled/definition24.cjs +12 -39
  66. package/bundled/definition24.js +32 -67
  67. package/bundled/definition25.cjs +44 -0
  68. package/bundled/definition25.js +77 -0
  69. package/bundled/definition3.cjs +13 -1
  70. package/bundled/definition3.js +48 -181
  71. package/bundled/definition4.cjs +9 -7
  72. package/bundled/definition4.js +18 -16
  73. package/bundled/definition5.cjs +5 -5
  74. package/bundled/definition5.js +9 -9
  75. package/bundled/definition6.cjs +3 -3
  76. package/bundled/definition6.js +16 -16
  77. package/bundled/definition7.cjs +1 -1
  78. package/bundled/definition7.js +1 -1
  79. package/bundled/definition8.cjs +7 -7
  80. package/bundled/definition8.js +9 -7
  81. package/bundled/definition9.cjs +4 -4
  82. package/bundled/definition9.js +12 -12
  83. package/bundled/extractOptions.cjs +1 -0
  84. package/bundled/extractOptions.js +11 -0
  85. package/bundled/listbox.cjs +1 -1
  86. package/bundled/listbox.js +24 -11
  87. package/bundled/mixins.cjs +3 -3
  88. package/bundled/mixins.js +5 -5
  89. package/bundled/numberConverter.cjs +1 -1
  90. package/bundled/numberConverter.js +36 -1
  91. package/bundled/picker-field.template.cjs +13 -13
  92. package/bundled/picker-field.template.js +16 -16
  93. package/bundled/render-in-light-dom.cjs +1 -1
  94. package/bundled/render-in-light-dom.js +16 -19
  95. package/bundled/slider.template.cjs +8 -8
  96. package/bundled/slider.template.js +9 -9
  97. package/bundled/text-field.cjs +1 -1
  98. package/bundled/text-field.js +1 -1
  99. package/bundled/time-selection-picker.template.cjs +3 -3
  100. package/bundled/time-selection-picker.template.js +9 -9
  101. package/bundled/vivid-element.cjs +1 -1
  102. package/bundled/vivid-element.js +9 -1
  103. package/button/definition.cjs +1 -1
  104. package/button/definition.js +1 -1
  105. package/calendar/definition.cjs +1 -1
  106. package/calendar/definition.js +1 -1
  107. package/calendar/index.cjs +9 -9
  108. package/calendar/index.js +7 -7
  109. package/calendar-event/definition.cjs +1 -1
  110. package/calendar-event/definition.js +1 -1
  111. package/calendar-event/index.cjs +2 -2
  112. package/calendar-event/index.js +2 -2
  113. package/card/definition.cjs +1 -1
  114. package/card/definition.js +1 -1
  115. package/card/index.cjs +3 -3
  116. package/card/index.js +6 -6
  117. package/color-picker/index.cjs +10 -10
  118. package/color-picker/index.js +52 -52
  119. package/combobox/definition.cjs +1 -1
  120. package/combobox/definition.js +1 -1
  121. package/combobox/index.cjs +11 -8
  122. package/combobox/index.js +59 -49
  123. package/country/definition.cjs +1 -1
  124. package/country/definition.js +1 -1
  125. package/country/index.cjs +1 -1
  126. package/country/index.js +1 -1
  127. package/country-group/definition.cjs +1 -1
  128. package/country-group/definition.js +1 -1
  129. package/country-group/index.cjs +1 -1
  130. package/country-group/index.js +2 -2
  131. package/custom-elements.json +837 -1225
  132. package/data-grid/definition.cjs +1 -1
  133. package/data-grid/definition.js +1 -1
  134. package/data-grid/index.cjs +8 -6
  135. package/data-grid/index.js +22 -20
  136. package/date-picker/definition.cjs +1 -1
  137. package/date-picker/definition.js +1 -1
  138. package/date-picker/index.cjs +1 -1
  139. package/date-picker/index.js +1 -1
  140. package/date-range-picker/definition.cjs +1 -1
  141. package/date-range-picker/definition.js +1 -1
  142. package/date-range-picker/index.cjs +1 -1
  143. package/date-range-picker/index.js +1 -1
  144. package/date-time-picker/definition.cjs +1 -1
  145. package/date-time-picker/definition.js +1 -1
  146. package/date-time-picker/index.cjs +1 -1
  147. package/date-time-picker/index.js +1 -1
  148. package/dial-pad/definition.cjs +1 -1
  149. package/dial-pad/definition.js +1 -1
  150. package/dial-pad/index.cjs +25 -23
  151. package/dial-pad/index.js +127 -56
  152. package/dialog/definition.cjs +1 -1
  153. package/dialog/definition.js +1 -1
  154. package/dialog/index.cjs +14 -14
  155. package/dialog/index.js +17 -18
  156. package/divider/definition.cjs +1 -1
  157. package/divider/definition.js +1 -1
  158. package/divider/index.cjs +1 -1
  159. package/divider/index.js +1 -1
  160. package/elevation/definition.cjs +1 -1
  161. package/elevation/definition.js +1 -1
  162. package/empty-state/definition.cjs +1 -1
  163. package/empty-state/definition.js +1 -1
  164. package/empty-state/index.cjs +4 -4
  165. package/empty-state/index.js +7 -11
  166. package/fab/definition.cjs +1 -1
  167. package/fab/definition.js +1 -1
  168. package/fab/index.cjs +4 -4
  169. package/fab/index.js +9 -13
  170. package/file-picker/definition.cjs +1 -1
  171. package/file-picker/definition.js +1 -1
  172. package/file-picker/index.cjs +8 -8
  173. package/file-picker/index.js +19 -19
  174. package/flag/definition.cjs +1 -1
  175. package/flag/definition.js +1 -1
  176. package/flag/index.cjs +5 -5
  177. package/flag/index.js +8 -12
  178. package/header/definition.cjs +1 -1
  179. package/header/definition.js +1 -1
  180. package/header/index.cjs +7 -7
  181. package/header/index.js +6 -10
  182. package/icon/index.cjs +1 -1
  183. package/icon/index.js +1 -1
  184. package/index.cjs +214 -209
  185. package/index.js +67 -66
  186. package/kbd-key/definition.cjs +1 -1
  187. package/kbd-key/definition.js +1 -1
  188. package/kbd-key/index.cjs +3 -3
  189. package/kbd-key/index.js +2 -6
  190. package/kbd-shortcut/definition.cjs +1 -1
  191. package/kbd-shortcut/definition.js +1 -1
  192. package/layout/definition.cjs +1 -1
  193. package/layout/definition.js +1 -1
  194. package/layout/index.cjs +3 -1
  195. package/layout/index.js +3 -1
  196. package/lib/accordion/variations.browser-spec.d.ts +1 -0
  197. package/lib/accordion-item/accordion-item.d.ts +2 -1
  198. package/lib/accordion-item/variations.browser-spec.d.ts +1 -0
  199. package/lib/action-group/action-group.d.ts +1 -1
  200. package/lib/action-group/variations.browser-spec.d.ts +1 -0
  201. package/lib/alert/alert.d.ts +2 -2
  202. package/lib/alert/variations.browser-spec.d.ts +1 -0
  203. package/lib/audio-player/audio-player.d.ts +1 -1
  204. package/lib/audio-player/variations.browser-spec.d.ts +1 -0
  205. package/lib/avatar/avatar.d.ts +1 -1
  206. package/lib/avatar/variations.browser-spec.d.ts +1 -0
  207. package/lib/badge/badge.d.ts +5 -5
  208. package/lib/badge/badge.template.d.ts +1 -2
  209. package/lib/badge/variations.browser-spec.d.ts +1 -0
  210. package/lib/banner/banner.d.ts +3 -3
  211. package/lib/banner/variations.browser-spec.d.ts +1 -0
  212. package/lib/breadcrumb/breadcrumb.d.ts +1 -1
  213. package/lib/breadcrumb-item/breadcrumb-item.d.ts +1 -1
  214. package/lib/breadcrumb-item/variations.browser-spec.d.ts +1 -0
  215. package/lib/button/button.d.ts +3 -3
  216. package/lib/button/variations.browser-spec.d.ts +1 -0
  217. package/lib/calendar/variations.browser-spec.d.ts +1 -0
  218. package/lib/calendar-event/calendar-event.d.ts +1 -1
  219. package/lib/calendar-event/variations.browser-spec.d.ts +1 -0
  220. package/lib/card/card.d.ts +5 -5
  221. package/lib/card/variations.browser-spec.d.ts +1 -0
  222. package/lib/checkbox/checkbox.d.ts +6 -6
  223. package/lib/checkbox/variations.browser-spec.d.ts +1 -0
  224. package/lib/color-picker/color-picker.d.ts +8 -8
  225. package/lib/color-picker/variations.browser-spec.d.ts +1 -0
  226. package/lib/combobox/combobox.d.ts +7 -7
  227. package/lib/combobox/variations.browser-spec.d.ts +1 -0
  228. package/lib/components.d.ts +1 -0
  229. package/lib/contextual-help/variations.browser-spec.d.ts +1 -0
  230. package/lib/country/variations.browser-spec.d.ts +1 -0
  231. package/lib/country-group/country-group.d.ts +2 -2
  232. package/lib/data-grid/data-grid-cell.d.ts +4 -3
  233. package/lib/data-grid/data-grid-row.d.ts +3 -2
  234. package/lib/data-grid/data-grid.options.d.ts +5 -0
  235. package/lib/data-grid/variations.browser-spec.d.ts +1 -0
  236. package/lib/date-picker/date-picker.d.ts +8 -8
  237. package/lib/date-picker/variations.browser-spec.d.ts +1 -0
  238. package/lib/date-range-picker/date-range-picker.d.ts +4 -4
  239. package/lib/date-range-picker/variations.browser-spec.d.ts +1 -0
  240. package/lib/date-time-picker/date-time-picker.d.ts +8 -8
  241. package/lib/date-time-picker/variations.browser-spec.d.ts +1 -0
  242. package/lib/dial-pad/dial-pad.d.ts +2 -1
  243. package/lib/dial-pad/variations.browser-spec.d.ts +1 -0
  244. package/lib/dialog/dialog.d.ts +2 -2
  245. package/lib/dialog/variations.browser-spec.d.ts +1 -0
  246. package/lib/divider/divider.d.ts +1 -1
  247. package/lib/divider/variations.browser-spec.d.ts +1 -0
  248. package/lib/empty-state/variations.browser-spec.d.ts +1 -0
  249. package/lib/fab/fab.d.ts +6 -6
  250. package/lib/fab/variations.browser-spec.d.ts +1 -0
  251. package/lib/file-picker/file-picker.d.ts +7 -7
  252. package/lib/file-picker/variations.browser-spec.d.ts +1 -0
  253. package/lib/flag/variations.browser-spec.d.ts +1 -0
  254. package/lib/header/header.d.ts +1 -1
  255. package/lib/header/variations.browser-spec.d.ts +1 -0
  256. package/lib/icon/variations.browser-spec.d.ts +1 -0
  257. package/lib/kbd-key/variations.browser-spec.d.ts +1 -0
  258. package/lib/kbd-shortcut/variations.browser-spec.d.ts +1 -0
  259. package/lib/layout/variations.browser-spec.d.ts +1 -0
  260. package/lib/menu/menu.d.ts +2 -2
  261. package/lib/menu/variations.browser-spec.d.ts +1 -0
  262. package/lib/menu-item/menu-item.d.ts +3 -3
  263. package/lib/menu-item/variations.browser-spec.d.ts +1 -0
  264. package/lib/nav/nav.d.ts +1 -1
  265. package/lib/nav/variations.browser-spec.d.ts +1 -0
  266. package/lib/nav-disclosure/nav-disclosure.d.ts +2 -2
  267. package/lib/nav-disclosure/variations.browser-spec.d.ts +1 -0
  268. package/lib/nav-item/nav-item.d.ts +2 -2
  269. package/lib/nav-item/variations.browser-spec.d.ts +1 -0
  270. package/lib/note/note.d.ts +1 -1
  271. package/lib/note/variations.browser-spec.d.ts +1 -0
  272. package/lib/number-field/number-field.d.ts +9 -9
  273. package/lib/number-field/variations.browser-spec.d.ts +1 -0
  274. package/lib/optgroup/definition.d.ts +3 -0
  275. package/lib/optgroup/index.d.ts +1 -0
  276. package/lib/optgroup/optgroup.d.ts +430 -0
  277. package/lib/optgroup/optgroup.template.d.ts +2 -0
  278. package/lib/optgroup/variations.browser-spec.d.ts +1 -0
  279. package/lib/option/option.d.ts +2 -2
  280. package/lib/option/variations.browser-spec.d.ts +1 -0
  281. package/lib/pagination/pagination.d.ts +1 -1
  282. package/lib/pagination/variations.browser-spec.d.ts +1 -0
  283. package/lib/popover/popover.d.ts +2 -2
  284. package/lib/popover/variations.browser-spec.d.ts +1 -0
  285. package/lib/progress/progress.d.ts +1 -1
  286. package/lib/progress/variations.browser-spec.d.ts +1 -0
  287. package/lib/progress-ring/progress-ring.d.ts +1 -1
  288. package/lib/progress-ring/variations.browser-spec.d.ts +1 -0
  289. package/lib/radio/radio.d.ts +3 -3
  290. package/lib/radio/variations.browser-spec.d.ts +1 -0
  291. package/lib/radio-group/radio-group.d.ts +1 -1
  292. package/lib/radio-group/variations.browser-spec.d.ts +1 -0
  293. package/lib/range-slider/range-slider.d.ts +3 -3
  294. package/lib/range-slider/variations.browser-spec.d.ts +1 -0
  295. package/lib/rich-text-editor/rich-text-editor.d.ts +1 -1
  296. package/lib/rich-text-editor/rte/features/internal/cursor-fix.d.ts +6 -1
  297. package/lib/rich-text-editor/variations.browser-spec.d.ts +1 -0
  298. package/lib/rich-text-view/variations.browser-spec.d.ts +1 -0
  299. package/lib/searchable-select/option-tag.d.ts +1 -1
  300. package/lib/searchable-select/searchable-select.d.ts +47 -47
  301. package/lib/searchable-select/variations.browser-spec.d.ts +1 -0
  302. package/lib/select/select.d.ts +9 -9
  303. package/lib/select/variations.browser-spec.d.ts +1 -0
  304. package/lib/selectable-box/selectable-box.d.ts +1 -1
  305. package/lib/selectable-box/variations.browser-spec.d.ts +1 -0
  306. package/lib/side-drawer/variations.browser-spec.d.ts +1 -0
  307. package/lib/simple-color-picker/simple-color-picker.d.ts +4 -4
  308. package/lib/simple-color-picker/variations.browser-spec.d.ts +1 -0
  309. package/lib/slider/slider.d.ts +3 -3
  310. package/lib/slider/variations.browser-spec.d.ts +1 -0
  311. package/lib/split-button/split-button.d.ts +3 -3
  312. package/lib/split-button/variations.browser-spec.d.ts +1 -0
  313. package/lib/status/status.d.ts +1 -1
  314. package/lib/status/variations.browser-spec.d.ts +1 -0
  315. package/lib/switch/switch.d.ts +2 -2
  316. package/lib/switch/variations.browser-spec.d.ts +1 -0
  317. package/lib/tab/tab.d.ts +15 -15
  318. package/lib/tab-panel/tab-panel.d.ts +1 -1
  319. package/lib/table/table-cell.d.ts +1 -1
  320. package/lib/table/table-header-cell.d.ts +1 -1
  321. package/lib/table/table-row.d.ts +1 -1
  322. package/lib/table/table-sorting-button.d.ts +1 -1
  323. package/lib/table/variations.browser-spec.d.ts +1 -0
  324. package/lib/tabs/variations.browser-spec.d.ts +1 -0
  325. package/lib/tag/tag.d.ts +15 -15
  326. package/lib/tag/variations.browser-spec.d.ts +1 -0
  327. package/lib/tag-group/tag-group.d.ts +1 -1
  328. package/lib/tag-name-map.d.ts +2 -1
  329. package/lib/text-area/text-area.d.ts +8 -8
  330. package/lib/text-area/text-area.template.d.ts +1 -2
  331. package/lib/text-area/variations.browser-spec.d.ts +1 -0
  332. package/lib/text-field/text-field.d.ts +9 -9
  333. package/lib/text-field/variations.browser-spec.d.ts +1 -0
  334. package/lib/time-picker/time-picker.d.ts +4 -4
  335. package/lib/time-picker/variations.browser-spec.d.ts +1 -0
  336. package/lib/toggletip/toggletip.d.ts +2 -2
  337. package/lib/toggletip/variations.browser-spec.d.ts +1 -0
  338. package/lib/tooltip/tooltip.d.ts +2 -2
  339. package/lib/tooltip/variations.browser-spec.d.ts +1 -0
  340. package/lib/tree-item/tree-item.d.ts +2 -2
  341. package/lib/tree-item/variations.browser-spec.d.ts +1 -0
  342. package/lib/tree-view/tree-view.d.ts +1 -1
  343. package/lib/video-player/variations.browser-spec.d.ts +1 -0
  344. package/lib/video-player/video-player.d.ts +1 -1
  345. package/menu/definition.cjs +1 -1
  346. package/menu/definition.js +1 -1
  347. package/menu/index.cjs +1 -1
  348. package/menu/index.js +1 -1
  349. package/menu-item/definition.cjs +1 -1
  350. package/menu-item/definition.js +1 -1
  351. package/menu-item/index.cjs +1 -1
  352. package/menu-item/index.js +1 -1
  353. package/nav/definition.cjs +1 -1
  354. package/nav/definition.js +1 -1
  355. package/nav-disclosure/definition.cjs +1 -1
  356. package/nav-disclosure/definition.js +1 -1
  357. package/nav-disclosure/index.cjs +6 -6
  358. package/nav-disclosure/index.js +11 -15
  359. package/nav-item/definition.cjs +1 -1
  360. package/nav-item/definition.js +1 -1
  361. package/nav-item/index.cjs +2 -2
  362. package/nav-item/index.js +11 -15
  363. package/note/definition.cjs +1 -1
  364. package/note/definition.js +1 -1
  365. package/note/index.cjs +5 -5
  366. package/note/index.js +10 -11
  367. package/number-field/definition.cjs +1 -1
  368. package/number-field/definition.js +1 -1
  369. package/number-field/index.cjs +12 -12
  370. package/number-field/index.js +35 -36
  371. package/optgroup/definition.cjs +5 -0
  372. package/optgroup/definition.js +2 -0
  373. package/optgroup/index.cjs +1 -0
  374. package/optgroup/index.js +4 -0
  375. package/package.json +15 -6
  376. package/pagination/definition.cjs +1 -1
  377. package/pagination/definition.js +1 -1
  378. package/platform-switch/definition.cjs +1 -1
  379. package/platform-switch/definition.js +1 -1
  380. package/popover/definition.cjs +1 -1
  381. package/popover/definition.js +1 -1
  382. package/popover/index.cjs +8 -8
  383. package/popover/index.js +11 -15
  384. package/popup/definition.cjs +1 -1
  385. package/popup/definition.js +1 -1
  386. package/progress/definition.cjs +1 -1
  387. package/progress/definition.js +1 -1
  388. package/progress/index.cjs +8 -8
  389. package/progress/index.js +9 -10
  390. package/radio/definition.cjs +1 -1
  391. package/radio/definition.js +1 -1
  392. package/radio-group/definition.cjs +1 -1
  393. package/radio-group/definition.js +1 -1
  394. package/range-slider/definition.cjs +1 -1
  395. package/range-slider/definition.js +1 -1
  396. package/range-slider/index.cjs +10 -8
  397. package/range-slider/index.js +26 -24
  398. package/rich-text-editor/definition.cjs +1 -1
  399. package/rich-text-editor/definition.js +1 -1
  400. package/rich-text-editor/index.cjs +3 -3
  401. package/rich-text-editor/index.js +762 -751
  402. package/rich-text-view/definition.cjs +1 -1
  403. package/rich-text-view/definition.js +1 -1
  404. package/searchable-select/definition.cjs +2 -1
  405. package/searchable-select/definition.js +2 -2
  406. package/searchable-select/index.cjs +30 -27
  407. package/searchable-select/index.js +104 -85
  408. package/select/definition.cjs +1 -1
  409. package/select/definition.js +1 -1
  410. package/select/index.cjs +1 -1
  411. package/select/index.js +1 -1
  412. package/selectable-box/definition.cjs +1 -1
  413. package/selectable-box/definition.js +1 -1
  414. package/selectable-box/index.cjs +8 -8
  415. package/selectable-box/index.js +8 -9
  416. package/shared/aria/delegates-aria.d.ts +1 -1
  417. package/shared/aria/host-semantics.d.ts +1 -1
  418. package/shared/color-picker/base-color-picker.d.ts +1 -1
  419. package/shared/feedback/feedback-message.d.ts +1 -1
  420. package/shared/feedback/mixins.d.ts +2 -2
  421. package/shared/foundation/button/button.d.ts +2 -2
  422. package/shared/foundation/form-associated/form-associated.d.ts +2 -2
  423. package/shared/foundation/listbox/extractOptions.d.ts +2 -0
  424. package/shared/foundation/listbox/listbox.d.ts +2 -0
  425. package/shared/patterns/affix.d.ts +2 -2
  426. package/shared/patterns/anchored.d.ts +2 -2
  427. package/shared/patterns/char-count/char-count.d.ts +1 -1
  428. package/shared/patterns/form-elements/form-element.d.ts +1 -1
  429. package/shared/patterns/form-elements/with-contextual-help.d.ts +1 -1
  430. package/shared/patterns/form-elements/with-error-text.d.ts +1 -1
  431. package/shared/patterns/form-elements/with-success-text.d.ts +1 -1
  432. package/shared/patterns/kbd-shortcut.d.ts +1 -1
  433. package/shared/patterns/linkable.d.ts +1 -1
  434. package/shared/patterns/localized.d.ts +2 -2
  435. package/shared/patterns/trapped-focus.d.ts +1 -1
  436. package/shared/picker-field/mixins/calendar-picker.d.ts +2 -2
  437. package/shared/picker-field/mixins/calendar-picker.template.d.ts +2 -2
  438. package/shared/picker-field/mixins/inline-time-picker/inline-time-picker.d.ts +1 -1
  439. package/shared/picker-field/mixins/min-max-calendar-picker.d.ts +2 -2
  440. package/shared/picker-field/mixins/single-date-picker.d.ts +2 -2
  441. package/shared/picker-field/mixins/single-value-picker.d.ts +2 -2
  442. package/shared/picker-field/mixins/time-selection-picker.d.ts +2 -2
  443. package/shared/picker-field/mixins/time-selection-picker.template.d.ts +4 -4
  444. package/shared/picker-field/picker-field.d.ts +7 -7
  445. package/side-drawer/definition.cjs +1 -1
  446. package/side-drawer/definition.js +1 -1
  447. package/side-drawer/index.cjs +3 -3
  448. package/side-drawer/index.js +3 -3
  449. package/simple-color-picker/definition.cjs +1 -1
  450. package/simple-color-picker/definition.js +1 -1
  451. package/simple-color-picker/index.cjs +4 -4
  452. package/simple-color-picker/index.js +6 -6
  453. package/slider/definition.cjs +1 -1
  454. package/slider/definition.js +1 -1
  455. package/slider/index.cjs +1 -1
  456. package/slider/index.js +1 -1
  457. package/split-button/definition.cjs +1 -1
  458. package/split-button/definition.js +1 -1
  459. package/split-button/index.cjs +5 -4
  460. package/split-button/index.js +10 -9
  461. package/status/definition.cjs +1 -1
  462. package/status/definition.js +1 -1
  463. package/status/index.cjs +7 -5
  464. package/status/index.js +14 -12
  465. package/styles/core/all.css +5 -7
  466. package/styles/core/theme.css +5 -7
  467. package/styles/core/typography.css +0 -3
  468. package/styles/tokens/vivid-2-compat.css +1 -6
  469. package/switch/definition.cjs +1 -1
  470. package/switch/definition.js +1 -1
  471. package/switch/index.cjs +5 -4
  472. package/switch/index.js +14 -12
  473. package/tab/definition.cjs +1 -1
  474. package/tab/definition.js +1 -1
  475. package/tab-panel/definition.cjs +1 -1
  476. package/tab-panel/definition.js +1 -1
  477. package/table/definition.cjs +1 -1
  478. package/table/definition.js +1 -1
  479. package/table/index.cjs +10 -10
  480. package/table/index.js +12 -12
  481. package/tabs/definition.cjs +1 -1
  482. package/tabs/definition.js +1 -1
  483. package/tabs/index.cjs +6 -4
  484. package/tabs/index.js +10 -9
  485. package/tag/definition.cjs +1 -1
  486. package/tag/definition.js +1 -1
  487. package/tag/index.cjs +6 -6
  488. package/tag/index.js +8 -8
  489. package/tag-group/definition.cjs +1 -1
  490. package/tag-group/definition.js +1 -1
  491. package/text-area/definition.cjs +1 -1
  492. package/text-area/definition.js +1 -1
  493. package/text-area/index.cjs +8 -6
  494. package/text-area/index.js +20 -19
  495. package/time-picker/definition.cjs +1 -1
  496. package/time-picker/definition.js +1 -1
  497. package/tree-item/definition.cjs +1 -1
  498. package/tree-item/definition.js +1 -1
  499. package/tree-view/definition.cjs +1 -1
  500. package/tree-view/definition.js +1 -1
  501. package/unbundled/affix.cjs +2 -7
  502. package/unbundled/affix.js +2 -7
  503. package/unbundled/anchored.cjs +2 -6
  504. package/unbundled/anchored.js +2 -6
  505. package/unbundled/aria-binding-directive.cjs +1 -3
  506. package/unbundled/aria-binding-directive.js +1 -3
  507. package/unbundled/base-color-picker.cjs +18 -52
  508. package/unbundled/base-color-picker.js +18 -52
  509. package/unbundled/base-progress.cjs +4 -14
  510. package/unbundled/base-progress.js +4 -14
  511. package/unbundled/button.cjs +2 -8
  512. package/unbundled/button.js +2 -8
  513. package/unbundled/calendar-picker.template.cjs +31 -85
  514. package/unbundled/calendar-picker.template.js +30 -84
  515. package/unbundled/char-count.cjs +2 -4
  516. package/unbundled/char-count.js +2 -4
  517. package/unbundled/data-grid.options.cjs +3 -19
  518. package/unbundled/data-grid.options.js +3 -19
  519. package/unbundled/definition.cjs +3 -8
  520. package/unbundled/definition.js +3 -8
  521. package/unbundled/definition10.cjs +316 -211
  522. package/unbundled/definition10.js +313 -202
  523. package/unbundled/definition11.cjs +262 -356
  524. package/unbundled/definition11.js +248 -354
  525. package/unbundled/definition12.cjs +243 -274
  526. package/unbundled/definition12.js +241 -260
  527. package/unbundled/definition13.cjs +341 -255
  528. package/unbundled/definition13.js +338 -252
  529. package/unbundled/definition14.cjs +61 -371
  530. package/unbundled/definition14.js +57 -367
  531. package/unbundled/definition15.cjs +32 -77
  532. package/unbundled/definition15.js +28 -73
  533. package/unbundled/definition16.cjs +120 -32
  534. package/unbundled/definition16.js +117 -29
  535. package/unbundled/definition17.cjs +24 -132
  536. package/unbundled/definition17.js +24 -126
  537. package/unbundled/definition18.cjs +74 -26
  538. package/unbundled/definition18.js +67 -25
  539. package/unbundled/definition19.cjs +33 -79
  540. package/unbundled/definition19.js +32 -73
  541. package/unbundled/definition2.cjs +11 -8
  542. package/unbundled/definition2.js +11 -8
  543. package/unbundled/definition20.cjs +272 -29
  544. package/unbundled/definition20.js +264 -27
  545. package/unbundled/definition21.cjs +135 -263
  546. package/unbundled/definition21.js +133 -260
  547. package/unbundled/definition22.cjs +17 -155
  548. package/unbundled/definition22.js +13 -151
  549. package/unbundled/definition23.cjs +9 -17
  550. package/unbundled/definition23.js +10 -18
  551. package/unbundled/definition24.cjs +4 -10
  552. package/unbundled/definition24.js +4 -10
  553. package/unbundled/definition25.cjs +2 -10
  554. package/unbundled/definition25.js +2 -10
  555. package/unbundled/definition26.cjs +28 -70
  556. package/unbundled/definition26.js +28 -70
  557. package/unbundled/definition27.cjs +6 -13
  558. package/unbundled/definition27.js +6 -13
  559. package/unbundled/definition28.cjs +30 -77
  560. package/unbundled/definition28.js +30 -77
  561. package/unbundled/definition29.cjs +7 -14
  562. package/unbundled/definition29.js +7 -14
  563. package/unbundled/definition3.cjs +5 -16
  564. package/unbundled/definition3.js +5 -16
  565. package/unbundled/definition30.cjs +66 -516
  566. package/unbundled/definition30.js +58 -514
  567. package/unbundled/definition31.cjs +502 -42
  568. package/unbundled/definition31.js +500 -40
  569. package/unbundled/definition32.cjs +42 -253
  570. package/unbundled/definition32.js +39 -250
  571. package/unbundled/definition33.cjs +238 -81
  572. package/unbundled/definition33.js +235 -78
  573. package/unbundled/definition34.cjs +75 -2059
  574. package/unbundled/definition34.js +72 -2032
  575. package/unbundled/definition35.cjs +1990 -25
  576. package/unbundled/definition35.js +1960 -24
  577. package/unbundled/definition36.cjs +27 -134
  578. package/unbundled/definition36.js +24 -126
  579. package/unbundled/definition37.cjs +71 -368
  580. package/unbundled/definition37.js +66 -363
  581. package/unbundled/definition38.cjs +300 -176
  582. package/unbundled/definition38.js +295 -171
  583. package/unbundled/definition39.cjs +184 -374
  584. package/unbundled/definition39.js +180 -370
  585. package/unbundled/definition4.cjs +2 -11
  586. package/unbundled/definition4.js +2 -7
  587. package/unbundled/definition40.cjs +392 -237
  588. package/unbundled/definition40.js +389 -234
  589. package/unbundled/definition41.cjs +264 -50
  590. package/unbundled/definition41.js +259 -45
  591. package/unbundled/definition42.cjs +48 -71
  592. package/unbundled/definition42.js +46 -69
  593. package/unbundled/definition43.cjs +56 -426
  594. package/unbundled/definition43.js +55 -425
  595. package/unbundled/definition44.cjs +387 -48
  596. package/unbundled/definition44.js +383 -44
  597. package/unbundled/definition45.cjs +54 -48
  598. package/unbundled/definition45.js +50 -44
  599. package/unbundled/definition46.cjs +40 -173
  600. package/unbundled/definition46.js +36 -169
  601. package/unbundled/definition47.cjs +172 -33
  602. package/unbundled/definition47.js +168 -28
  603. package/unbundled/definition48.cjs +31 -97
  604. package/unbundled/definition48.js +23 -95
  605. package/unbundled/definition49.cjs +71 -38
  606. package/unbundled/definition49.js +68 -35
  607. package/unbundled/definition5.cjs +2 -5
  608. package/unbundled/definition5.js +2 -5
  609. package/unbundled/definition50.cjs +55 -26
  610. package/unbundled/definition50.js +53 -21
  611. package/unbundled/definition51.cjs +24 -43
  612. package/unbundled/definition51.js +18 -40
  613. package/unbundled/definition52.cjs +30 -340
  614. package/unbundled/definition52.js +28 -338
  615. package/unbundled/definition53.cjs +295 -197
  616. package/unbundled/definition53.js +292 -194
  617. package/unbundled/definition54.cjs +211 -45
  618. package/unbundled/definition54.js +207 -41
  619. package/unbundled/definition55.cjs +42 -308
  620. package/unbundled/definition55.js +38 -304
  621. package/unbundled/definition56.cjs +266 -53
  622. package/unbundled/definition56.js +263 -49
  623. package/unbundled/definition57.cjs +51 -162
  624. package/unbundled/definition57.js +49 -160
  625. package/unbundled/definition58.cjs +135 -253
  626. package/unbundled/definition58.js +130 -251
  627. package/unbundled/definition59.cjs +209 -457
  628. package/unbundled/definition59.js +206 -454
  629. package/unbundled/definition6.cjs +179 -17
  630. package/unbundled/definition6.js +170 -14
  631. package/unbundled/definition60.cjs +441 -3722
  632. package/unbundled/definition60.js +435 -3553
  633. package/unbundled/definition61.cjs +3713 -761
  634. package/unbundled/definition61.js +3540 -751
  635. package/unbundled/definition62.cjs +761 -95
  636. package/unbundled/definition62.js +758 -92
  637. package/unbundled/definition63.cjs +106 -1055
  638. package/unbundled/definition63.js +98 -1047
  639. package/unbundled/definition64.cjs +991 -103
  640. package/unbundled/definition64.js +986 -101
  641. package/unbundled/definition65.cjs +111 -83
  642. package/unbundled/definition65.js +106 -77
  643. package/unbundled/definition66.cjs +71 -179
  644. package/unbundled/definition66.js +62 -176
  645. package/unbundled/definition67.cjs +154 -120
  646. package/unbundled/definition67.js +151 -117
  647. package/unbundled/definition68.cjs +126 -52
  648. package/unbundled/definition68.js +122 -48
  649. package/unbundled/definition69.cjs +52 -94
  650. package/unbundled/definition69.js +50 -91
  651. package/unbundled/definition7.cjs +31 -177
  652. package/unbundled/definition7.js +24 -170
  653. package/unbundled/definition70.cjs +92 -22
  654. package/unbundled/definition70.js +87 -17
  655. package/unbundled/definition71.cjs +21 -93
  656. package/unbundled/definition71.js +15 -90
  657. package/unbundled/definition72.cjs +77 -309
  658. package/unbundled/definition72.js +72 -232
  659. package/unbundled/definition73.cjs +288 -335
  660. package/unbundled/definition73.js +217 -329
  661. package/unbundled/definition74.cjs +327 -29
  662. package/unbundled/definition74.js +318 -26
  663. package/unbundled/definition75.cjs +28 -129
  664. package/unbundled/definition75.js +23 -125
  665. package/unbundled/definition76.cjs +107 -271
  666. package/unbundled/definition76.js +103 -267
  667. package/unbundled/definition77.cjs +258 -27
  668. package/unbundled/definition77.js +249 -25
  669. package/unbundled/definition78.cjs +30 -155
  670. package/unbundled/definition78.js +28 -140
  671. package/unbundled/definition79.cjs +117 -183
  672. package/unbundled/definition79.js +108 -179
  673. package/unbundled/definition8.cjs +152 -36
  674. package/unbundled/definition8.js +148 -31
  675. package/unbundled/definition80.cjs +180 -492
  676. package/unbundled/definition80.js +175 -486
  677. package/unbundled/definition81.cjs +517 -0
  678. package/unbundled/definition81.js +497 -0
  679. package/unbundled/definition9.cjs +200 -135
  680. package/unbundled/definition9.js +189 -130
  681. package/unbundled/delegates-aria.cjs +1 -3
  682. package/unbundled/delegates-aria.js +1 -3
  683. package/unbundled/divider.cjs +2 -7
  684. package/unbundled/divider.js +2 -7
  685. package/unbundled/extractOptions.cjs +21 -0
  686. package/unbundled/extractOptions.js +16 -0
  687. package/unbundled/form-associated.cjs +20 -60
  688. package/unbundled/form-associated.js +20 -60
  689. package/unbundled/form-element.cjs +5 -15
  690. package/unbundled/form-element.js +5 -15
  691. package/unbundled/host-semantics.cjs +1 -3
  692. package/unbundled/host-semantics.js +1 -3
  693. package/unbundled/kbd-shortcut.cjs +1 -3
  694. package/unbundled/kbd-shortcut.js +1 -3
  695. package/unbundled/linkable.cjs +1 -3
  696. package/unbundled/linkable.js +1 -3
  697. package/unbundled/listbox.cjs +29 -26
  698. package/unbundled/listbox.js +29 -26
  699. package/unbundled/localized.cjs +3 -9
  700. package/unbundled/localized.js +3 -9
  701. package/unbundled/mixins.cjs +9 -25
  702. package/unbundled/mixins.js +9 -25
  703. package/unbundled/numberConverter.cjs +39 -9
  704. package/unbundled/numberConverter.js +39 -9
  705. package/unbundled/picker-field.template.cjs +16 -36
  706. package/unbundled/picker-field.template.js +16 -36
  707. package/unbundled/platform.cjs +1 -3
  708. package/unbundled/platform.js +1 -3
  709. package/unbundled/playbackRates.cjs +1 -3
  710. package/unbundled/playbackRates.js +1 -3
  711. package/unbundled/randomId.cjs +1 -3
  712. package/unbundled/randomId.js +1 -3
  713. package/unbundled/single-date-picker.cjs +6 -18
  714. package/unbundled/single-date-picker.js +6 -18
  715. package/unbundled/single-value-picker.cjs +7 -21
  716. package/unbundled/single-value-picker.js +7 -21
  717. package/unbundled/slider.template.cjs +6 -14
  718. package/unbundled/slider.template.js +6 -14
  719. package/unbundled/slottable-request.cjs +2 -6
  720. package/unbundled/slottable-request.js +2 -6
  721. package/unbundled/text-field.cjs +1 -1
  722. package/unbundled/text-field.js +1 -1
  723. package/unbundled/time-selection-picker.template.cjs +27 -79
  724. package/unbundled/time-selection-picker.template.js +27 -79
  725. package/unbundled/trapped-focus.cjs +1 -3
  726. package/unbundled/trapped-focus.js +1 -3
  727. package/unbundled/vivid-element.cjs +16 -19
  728. package/unbundled/vivid-element.js +16 -19
  729. package/unbundled/with-contextual-help.cjs +4 -13
  730. package/unbundled/with-contextual-help.js +4 -13
  731. package/unbundled/with-error-text.cjs +2 -6
  732. package/unbundled/with-error-text.js +2 -6
  733. package/unbundled/with-success-text.cjs +1 -3
  734. package/unbundled/with-success-text.js +1 -3
  735. package/video-player/definition.cjs +1 -1
  736. package/video-player/definition.js +1 -1
  737. package/video-player/index.cjs +3 -3
  738. package/video-player/index.js +5 -5
  739. package/visually-hidden/definition.cjs +1 -1
  740. package/visually-hidden/definition.js +1 -1
  741. package/vivid.api.json +194 -0
  742. package/shared/color-picker/index.d.ts +0 -3
  743. package/shared/foundation/button/index.d.ts +0 -2
  744. package/shared/patterns/char-count/index.d.ts +0 -1
  745. package/shared/patterns/form-elements/index.d.ts +0 -4
  746. package/shared/patterns/index.d.ts +0 -7
@@ -1,825 +1,3614 @@
1
- import { d as createRegisterFunction, u as defineVividComponent } from "./vivid-element.js";
2
- import { t as iconDefinition } from "./definition.js";
1
+ import { d as createRegisterFunction, t as VividElement, u as defineVividComponent } from "./vivid-element.js";
3
2
  import { t as __decorate } from "./decorate.js";
4
- import { a as affixIconTemplateFactory, i as IconWrapper, n as AffixIconWithTrailing } from "./affix.js";
5
- import { n as FormAssociated } from "./form-associated.js";
6
- import { t as FormElement } from "./form-element.js";
7
- import { t as WithSuccessText } from "./with-success-text.js";
8
- import { t as WithErrorText } from "./with-error-text.js";
9
- import { t as WithContextualHelp } from "./with-contextual-help.js";
10
- import { t as Localized } from "./localized.js";
11
- import { i as Button, r as chevronTemplateFactory, t as buttonDefinition } from "./definition7.js";
12
- import { t as handleEscapeKeyAndStopPropogation } from "./dialog.js";
13
- import { i as Popup, t as popupDefinition } from "./definition10.js";
14
- import { n as applyHostSemantics, t as HostSemantics } from "./host-semantics.js";
15
- import { n as WithLightDOMFeedback, r as feedbackMessageDefinition } from "./mixins.js";
3
+ import { r as ProgressRing, t as progressRingDefinition } from "./definition5.js";
4
+ import { n as WithObservableLocale } from "./localized.js";
5
+ import { i as Button, t as buttonDefinition } from "./definition6.js";
6
+ import { i as Popup, r as PlacementStrategy, t as popupDefinition } from "./definition9.js";
7
+ import { i as MenuItem, t as menuItemDefinition } from "./definition11.js";
8
+ import { r as Menu, t as menuDefinition } from "./definition12.js";
9
+ import { t as Divider } from "./divider.js";
10
+ import { t as generateRandomId } from "./randomId.js";
11
+ import { n as textFieldDefinition, r as TextField } from "./definition26.js";
12
+ import { n as tooltipDefinition, r as Tooltip } from "./definition27.js";
16
13
  import { r as ListboxOption, t as listboxOptionDefinition } from "./definition29.js";
17
- import { t as Listbox } from "./listbox.js";
18
- import { Observable, Updates, attr, html, observable, ref, slotted, volatile, when } from "@microsoft/fast-element";
19
- import { classNames, inRange, keyArrowDown, keyArrowUp, keyEnd, keyEnter, keyEscape, keyHome, keySpace, keyTab, uniqueId } from "@microsoft/fast-web-utilities";
20
- //#region src/lib/select/select.scss?inline
21
- var select_default = ".label-wrapper{align-items:center;gap:var(--label-wrapper-gap,4px);flex-direction:row;display:flex}.label-wrapper[hidden]{display:none}.label:not(slot),.label::slotted(label){flex:0 auto}.chevron{font:var(--vvd-typography-base-extended);flex-shrink:0;display:flex;transform:rotate(0)}@media (prefers-reduced-motion:no-preference){.chevron{transition:transform .2s}}:host([data-expanded=true]) .chevron,:host([open]) .chevron{transform:rotate(180deg)}:host(:focus-visible){outline:none}:host{--_low-ink-color:var(--vvd-color-neutral-600);--focus-stroke-gap-color:transparent;flex-direction:column;gap:4px;display:inline-flex}:host([disabled]){--_low-ink-color:var(--vvd-color-neutral-600);cursor:not-allowed}.label{color:var(--vvd-color-canvas-text);font:var(--vvd-typography-base)}.control{--_appearance-color-text:var(--vvd-color-canvas-text);--_appearance-color-fill:var(--vvd-color-canvas);--_appearance-color-outline:var(--vvd-color-neutral-500)}.control.appearance-ghost{--_appearance-color-text:var(--_connotation-color-firm);--_appearance-color-fill:transparent;--_appearance-color-outline:transparent}@media (hover:hover){.control:hover:where(:not(.disabled,:disabled,.readonly)){--_appearance-color-text:var(--vvd-color-canvas-text);--_appearance-color-fill:var(--vvd-color-canvas);--_appearance-color-outline:var(--vvd-color-neutral-700)}.control:hover:where(:not(.disabled,:disabled,.readonly)).appearance-ghost{--_appearance-color-text:var(--_connotation-color-firm);--_appearance-color-fill:var(--_connotation-color-faint);--_appearance-color-outline:transparent}}.control.hover:where(:not(.disabled,:disabled,.readonly)){--_appearance-color-text:var(--vvd-color-canvas-text);--_appearance-color-fill:var(--vvd-color-canvas);--_appearance-color-outline:var(--vvd-color-neutral-700)}.control.hover:where(:not(.disabled,:disabled,.readonly)).appearance-ghost{--_appearance-color-text:var(--_connotation-color-firm);--_appearance-color-fill:var(--_connotation-color-faint);--_appearance-color-outline:transparent}.control:disabled{--_appearance-color-text:var(--vvd-color-neutral-600);--_appearance-color-fill:var(--vvd-color-neutral-100);--_appearance-color-outline:var(--vvd-color-neutral-300)}.control:disabled.appearance-ghost{--_appearance-color-text:var(--vvd-color-neutral-300);--_appearance-color-fill:transparent;--_appearance-color-outline:transparent}.control.disabled{--_appearance-color-text:var(--vvd-color-neutral-600);--_appearance-color-fill:var(--vvd-color-neutral-100);--_appearance-color-outline:var(--vvd-color-neutral-300)}.control.disabled.appearance-ghost{--_appearance-color-text:var(--vvd-color-neutral-300);--_appearance-color-fill:transparent;--_appearance-color-outline:transparent}.control.readonly:where(:not(.disabled,:disabled)){--_appearance-color-text:var(--vvd-color-canvas-text);--_appearance-color-fill:var(--vvd-color-neutral-200);--_appearance-color-outline:var(--vvd-color-neutral-400)}.control.readonly:where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text:var(--vvd-color-neutral-600);--_appearance-color-fill:transparent;--_appearance-color-outline:transparent}.control.error:where(:not(.disabled,:disabled)){--_appearance-color-text:notSet;--_appearance-color-fill:var(--vvd-color-alert-50);--_appearance-color-outline:var(--vvd-color-alert-500)}.control.error:where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text:notSet;--_appearance-color-fill:var(--vvd-color-alert-50);--_appearance-color-outline:transparent}.control.success:where(:not(.disabled,:disabled)){--_appearance-color-text:notSet;--_appearance-color-fill:var(--vvd-color-success-50);--_appearance-color-outline:var(--vvd-color-success-500)}.control.success:where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text:notSet;--_appearance-color-fill:var(--vvd-color-success-50);--_appearance-color-outline:transparent}.control{--_connotation-color-primary:var(--vvd-select-accent-primary,var(--vvd-color-canvas-text));--_connotation-color-primary-text:var(--vvd-select-accent-primary-text,var(--vvd-color-canvas));--_connotation-color-primary-increment:var(--vvd-select-accent-primary-increment,var(--vvd-color-neutral-800));--_connotation-color-intermediate:var(--vvd-select-accent-intermediate,var(--vvd-color-neutral-500));--_connotation-color-faint:var(--vvd-select-accent-faint,var(--vvd-color-neutral-50));--_connotation-color-soft:var(--vvd-select-accent-soft,var(--vvd-color-neutral-100));--_connotation-color-firm:var(--vvd-select-accent-firm,var(--vvd-color-canvas-text));--_connotation-color-fierce:var(--vvd-select-accent-fierce,var(--vvd-color-neutral-700));border-radius:var(--_select-control-border-radius);block-size:var(--_select-block-size);padding-inline:var(--_select-padding-inline);--_select-icon-size:calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2))) / 2);--_select-block-size:calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2)));--_select-padding-inline:calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2))) / 2.5);background-color:var(--_appearance-color-fill);box-shadow:inset 0 0 0 1px var(--_appearance-color-outline);color:var(--_appearance-color-text);font:var(--vvd-typography-base);justify-content:space-between;align-items:center;gap:8px;transition:box-shadow .2s,background-color .2s;display:flex}.control.size-condensed{--_select-icon-size:calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2))) / 2.5);--_select-block-size:calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2) - 8));--_select-padding-inline:calc(calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2) - 16)) / 2)}.control.size-condensed:not(.shape-pill){--_select-control-border-radius:4px}.control-wrapper{position:relative}.control:not(.disabled){cursor:pointer}.control.disabled{pointer-events:none}.control:not(.shape-pill){--_select-control-border-radius:8px}.control.shape-pill{--_select-control-border-radius:24px}.listbox{max-height:var(--select-height,408px);flex-direction:column;gap:2px;padding:4px;display:flex;overflow-y:auto}:host([multiple]:focus-visible) .listbox{box-shadow:0 0 0 4px color-mix(in srgb, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px));border-radius:8px}.selected-value{white-space:nowrap;flex-grow:1;align-items:center;column-gap:12px;display:flex;overflow:hidden}.selected-value .text{text-overflow:ellipsis;max-inline-size:100%;overflow:hidden}.control.shows-placeholder .selected-value .text{color:var(--vvd-color-neutral-600)}.selected-value slot[name=icon]{flex:0 0 var(--_select-icon-size);font-size:var(--_select-icon-size);line-height:1}.control.has-meta .selected-value{padding-inline-end:8px}.feedback-wrapper{display:contents}::part(popup-base){inline-size:max-content;min-inline-size:var(--_select-fixed-width,100%)}:host([multiple]) ::part(popup-base){position:static}@supports selector(:has(*)){:host(:focus-within) .control:not(.has-activedescendant,:has(.clear-button:focus)){--focus-stroke-gap-color:transparent;box-shadow:0 0 0 4px color-mix(in srgb, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px))}}@supports not selector(:has(*)){:host(:focus-within) .control:not(.has-activedescendant){--focus-stroke-gap-color:transparent;box-shadow:0 0 0 4px color-mix(in srgb, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px))}}:host(:not([multiple]):focus-visible) ::slotted([data-vvd-component=option][current-selected]){box-shadow:0 0 0 4px color-mix(in srgb, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px));--focus-stroke-gap-color:transparent;border-radius:8px}:host([multiple]) .clear-button{margin-inline-start:auto}:host([multiple][clearable]) .label-wrapper{min-block-size:calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density,0), 2) - 16))}";
14
+ import { t as dividerDefinition } from "./definition36.js";
15
+ import { a as featureFacade, c as impl, i as contributionPriority, n as removeSymbol, o as getFeatureImpl, r as RteFeatureImpl, s as sortedContributions, t as dispatchSlottableRequest } from "./slottable-request.js";
16
+ import { n as selectDefinition, r as Select } from "./definition62.js";
17
+ import { ElementStyles, html, observable, ref, volatile } from "@microsoft/fast-element";
18
+ import { DOMParser, DOMSerializer, Fragment, NodeRange, Schema, Slice } from "prosemirror-model";
19
+ import { AllSelection, EditorState, NodeSelection, Plugin, PluginKey, TextSelection } from "prosemirror-state";
20
+ import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
21
+ import { keymap } from "prosemirror-keymap";
22
+ import { autoJoin, baseKeymap, chainCommands, createParagraphNear, liftEmptyBlock, newlineInCode, splitBlockAs, toggleMark } from "prosemirror-commands";
23
+ import { dropCursor } from "prosemirror-dropcursor";
24
+ import { gapCursor } from "prosemirror-gapcursor";
25
+ import DOMPurify from "dompurify";
26
+ import { closeHistory, history, redo, undo } from "prosemirror-history";
27
+ import { InputRule, inputRules, undoInputRule } from "prosemirror-inputrules";
28
+ import { RemoveMarkStep, ReplaceAroundStep, dropPoint } from "prosemirror-transform";
29
+ import { marks } from "prosemirror-schema-basic";
30
+ //#region src/lib/rich-text-editor/rich-text-editor.scss?inline
31
+ var rich_text_editor_default = ":host{display:block}.rte{--editor-padding-inline:var(--rich-text-editor-padding-inline,16px);--editor-padding-block:var(--rich-text-editor-padding-block,8px);block-size:100%;max-block-size:inherit;min-block-size:inherit;flex-direction:column;display:flex}.editor{display:contents}.editor-viewport{contain:layout;flex-direction:column;flex:1;min-block-size:0;display:flex;position:relative;overflow:hidden}.editor-scroll-area{background-color:var(--vvd-color-canvas);color:var(--vvd-color-canvas-text);font:var(--vvd-typography-base);--scrollbar-track-color:transparent;--scrollbar-thumb-color:color-mix(in sRGB, var(--vvd-color-neutral-950), transparent 70%);scrollbar-color:var(--scrollbar-thumb-color) var(--scrollbar-track-color);scrollbar-width:thin;flex-direction:column;flex:1;min-block-size:0;display:flex;overflow-y:auto}.editor-scroll-area ::-webkit-scrollbar{width:4px}.editor-scroll-area ::-webkit-scrollbar-track{background:var(--scrollbar-track-color)}.editor-scroll-area ::-webkit-scrollbar-thumb{background-color:var(--scrollbar-fallback-track-color,var(--scrollbar-thumb-color));border:0;border-radius:4px}.popovers--disabled>*{display:none!important}";
22
32
  //#endregion
23
- //#region src/lib/select/select.ts
33
+ //#region src/lib/rich-text-editor/rich-text-editor.ts
24
34
  /**
25
35
  * @public
26
- * @component select
27
- * @slot - Default slot.
28
- * @slot icon - The preferred way to add an icon to the select control.
29
- * @slot meta - Slot to add meta content to the select control.
30
- * @slot helper-text - Describes how to use the select. Alternative to the `helper-text` attribute.
31
- * @event {CustomEvent<undefined>} input - Fires a custom 'input' event when the value updates
32
- * @event {CustomEvent<HTMLElement>} change - Fires a custom 'change' event when the value updates
33
- * @vueModel modelValue value input,@lazy:change `event.currentTarget.value`
34
- * @testAction selectOptionByValue selectOptionByValue
35
- * @testAction selectOptionByText selectOptionByText
36
+ * @component rich-text-editor
37
+ * @slot editor-before - Displayed before the scrollable editor area.
38
+ * @slot editor-start - Displayed at the start of the scrollable editor area.
39
+ * @slot editor-end - Displayed at the end of the scrollable editor area.
40
+ * @slot editor-after - Displayed after the scrollable editor area.
41
+ * @slot status - Displayed between the editor viewport and the toolbar.
42
+ * @slot text-color-picker - Color picker for the RteTextColorFeature.
43
+ * @dynamicSlot `{ url: string }` inline-image-placeholder - Placeholder content for inline images.
44
+ * @dynamicSlot `{ id: string }` suggestions-empty - Empty state if no suggestions are found.
36
45
  */
37
- var Select = class extends WithLightDOMFeedback(WithContextualHelp(WithErrorText(WithSuccessText(Localized(FormElement(HostSemantics(AffixIconWithTrailing(FormAssociated(Listbox))))))))) {
46
+ var RichTextEditor = class extends WithObservableLocale(VividElement) {
47
+ /** @internal */
48
+ instanceChanged(prevInstance) {
49
+ prevInstance?.[impl].destroyViewIfNeeded();
50
+ this._initViewIfNeeded();
51
+ prevInstance?.[impl].styles.removeStylesFrom(this.shadowRoot);
52
+ this.instance?.[impl].styles.addStylesTo(this.shadowRoot);
53
+ }
54
+ _initViewIfNeeded() {
55
+ const instance = this.instance?.[impl];
56
+ if (instance && this.$fastController.isConnected && !instance.view) {
57
+ this._syncStateIfNeeded();
58
+ instance.createView(this._editorEl);
59
+ }
60
+ }
61
+ _destroyViewIfNeeded() {
62
+ this.instance?.[impl].destroyViewIfNeeded();
63
+ }
64
+ connectedCallback() {
65
+ super.connectedCallback();
66
+ this._initViewIfNeeded();
67
+ }
68
+ disconnectedCallback() {
69
+ super.disconnectedCallback();
70
+ this._destroyViewIfNeeded();
71
+ }
72
+ /** @internal */
73
+ localeChanged() {
74
+ this._syncStateIfNeeded();
75
+ }
76
+ _syncStateIfNeeded() {
77
+ this.instance?.[impl].updateHostState({
78
+ locale: this.locale,
79
+ ctx: this._ctx
80
+ });
81
+ }
82
+ };
83
+ __decorate([observable], RichTextEditor.prototype, "instance", void 0);
84
+ //#endregion
85
+ //#region src/lib/rich-text-editor/rich-text-editor.template.ts
86
+ var RichTextEditorTemplate = (ctx) => {
87
+ return html`<template :_ctx="${() => ctx}">
88
+ <div class="rte">
89
+ <slot name="editor-before"></slot>
90
+ <div class="editor-viewport" ${ref("editorViewportElement")}>
91
+ <div class="editor-scroll-area" part="editor-scrollable-area">
92
+ <slot name="editor-start"></slot>
93
+ <div class="editor rich-text" ${ref("_editorEl")}></div>
94
+ <div class="popovers"></div>
95
+ <slot name="editor-end"></slot>
96
+ </div>
97
+ </div>
98
+ <slot name="editor-after"></slot>
99
+ <slot name="status"></slot>
100
+ <div class="toolbar"></div>
101
+ </div>
102
+ </template>`;
103
+ };
104
+ //#endregion
105
+ //#region src/lib/rich-text-editor/popover.ts
106
+ var Kind = {
107
+ default: {
108
+ placement: void 0,
109
+ placementStrategy: PlacementStrategy.AutoPlacementHorizontal,
110
+ shiftCrossAxis: false,
111
+ strategy: "absolute"
112
+ },
113
+ autocomplete: {
114
+ placement: "bottom-start",
115
+ placementStrategy: PlacementStrategy.Flip,
116
+ shiftCrossAxis: false,
117
+ strategy: "fixed"
118
+ },
119
+ imageOptions: {
120
+ placement: "bottom",
121
+ placementStrategy: PlacementStrategy.Flip,
122
+ shiftCrossAxis: true,
123
+ strategy: "absolute"
124
+ }
125
+ };
126
+ var popoverTemplate = (context) => {
127
+ const popup = context.tagFor(Popup);
128
+ return html`<${popup}
129
+ :anchor="${(x) => x.anchorEl}"
130
+ :placement="${(x) => Kind[x.kind].placement}"
131
+ :placementStrategy="${(x) => Kind[x.kind].placementStrategy}"
132
+ :shiftCrossAxis="${(x) => Kind[x.kind].shiftCrossAxis}"
133
+ :open="${(x) => x.open}"
134
+ :offset="${(x) => x.offset}"
135
+ :strategy="${(x) => Kind[x.kind].strategy}"
136
+ exportparts="vvd-theme-alternate"
137
+ >
138
+ <slot></slot>
139
+ </${popup}>`;
140
+ };
141
+ var Popover = class extends VividElement {
38
142
  constructor(..._args) {
39
143
  super(..._args);
40
- this.proxy = document.createElement("select");
41
- this.activeIndex = -1;
42
- this.rangeStartIndex = -1;
43
- this.open = false;
44
- this.listboxId = uniqueId("listbox-");
45
- this.maxHeight = 0;
46
- this.fixedDropdown = false;
47
- this._feedbackWrapper = null;
48
- this._isResetting = false;
49
- this.clearable = false;
50
- this._isClearButtonFocused = false;
144
+ this.kind = "default";
145
+ this.anchorBlocksPopover = false;
146
+ this.onAnchorBlockPopoverChanged = () => {
147
+ this.anchorBlocksPopover = this.anchorEl?.dataset.blockPopover === "true" || false;
148
+ };
149
+ this.requestedOpenState = false;
51
150
  }
52
- /**
53
- * Returns the last checked option.
54
- *
55
- * @internal
56
- */
57
- get activeOption() {
58
- return this.options[this.activeIndex];
151
+ static setBlockPopover(onElement, block) {
152
+ onElement.dataset.blockPopover = block ? "true" : "false";
153
+ const event = new CustomEvent("block-popover-changed", {
154
+ bubbles: false,
155
+ composed: false
156
+ });
157
+ onElement.dispatchEvent(event);
59
158
  }
60
- /**
61
- * Returns the list of checked options.
62
- *
63
- * @internal
64
- */
65
- get checkedOptions() {
66
- return this.options.filter((o) => o.checked);
159
+ /** Closes the popover. It reopens when anchorEl changes to a new element that does not block it. */
160
+ dismiss() {
161
+ this.anchorBlocksPopover = true;
67
162
  }
68
- /**
69
- * Returns the index of the first selected option.
70
- *
71
- * @internal
72
- */
73
- get firstSelectedOptionIndex() {
74
- return this.options.indexOf(this.firstSelectedOption);
163
+ anchorElChanged(prev, next) {
164
+ prev?.removeEventListener("block-popover-changed", this.onAnchorBlockPopoverChanged);
165
+ next?.addEventListener("block-popover-changed", this.onAnchorBlockPopoverChanged);
166
+ this.onAnchorBlockPopoverChanged();
75
167
  }
76
- /**
77
- * Updates the `ariaActiveDescendant` property when the active index changes.
78
- *
79
- * @internal
80
- */
81
- activeIndexChanged(_, next) {
82
- this._activeDescendant = this.options[next]?.id ?? "";
83
- this.focusAndScrollOptionIntoView();
168
+ anchorIdChanged() {
169
+ this.updateAnchor();
84
170
  }
85
- /**
86
- * Toggles the checked state for the currently active option.
87
- *
88
- * @remarks
89
- * Multiple-selection mode only.
90
- *
91
- * @internal
92
- */
93
- checkActiveIndex() {
94
- const activeItem = this.activeOption;
95
- /* v8 ignore else -- @preserve */
96
- if (activeItem) activeItem.checked = true;
171
+ updateAnchor() {
172
+ if (this.anchorId && this.isConnected) this.anchorEl = this.getRootNode().getElementById(this.anchorId) || void 0;
173
+ else this.anchorEl = void 0;
97
174
  }
98
- /**
99
- * Sets the active index to the first option and marks it as checked.
100
- *
101
- * @remarks
102
- * Multi-selection mode only.
103
- *
104
- * @param preserveChecked - mark all options unchecked before changing the active index
105
- *
106
- * @internal
107
- */
108
- checkFirstOption(preserveChecked) {
109
- const firstSelectableIndex = this.getNextSelectableIndex(0);
110
- if (firstSelectableIndex === -1) return;
111
- if (preserveChecked) {
112
- if (this.rangeStartIndex === -1) this.rangeStartIndex = this.activeIndex;
113
- this.options.forEach((o, i) => {
114
- o.checked = inRange(i, firstSelectableIndex, this.rangeStartIndex + 1) && !o.disabled;
115
- });
116
- } else this.uncheckAllOptions();
117
- this.activeIndex = firstSelectableIndex;
118
- this.checkActiveIndex();
175
+ requestOpenState(open) {
176
+ this.requestedOpenState = open;
119
177
  }
120
- /**
121
- * Decrements the active index and sets the matching option as checked.
122
- *
123
- * @remarks
124
- * Multi-selection mode only.
125
- *
126
- * @param preserveChecked - mark all options unchecked before changing the active index
127
- *
128
- * @internal
129
- */
130
- checkLastOption(preserveChecked) {
131
- const lastSelectableIndex = this.getPreviousSelectableIndex(this.length - 1);
132
- if (lastSelectableIndex === -1) return;
133
- if (preserveChecked) {
134
- if (this.rangeStartIndex === -1) this.rangeStartIndex = this.activeIndex;
135
- this.options.forEach((o, i) => {
136
- o.checked = inRange(i, this.rangeStartIndex, lastSelectableIndex + 1) && !o.disabled;
137
- });
138
- } else this.uncheckAllOptions();
139
- this.activeIndex = lastSelectableIndex;
140
- this.checkActiveIndex();
178
+ get open() {
179
+ return this.requestedOpenState && !!this.anchorEl && !this.anchorBlocksPopover;
141
180
  }
142
- /**
143
- * Increments the active index and marks the matching option as checked.
144
- *
145
- * @remarks
146
- * Multiple-selection mode only.
147
- *
148
- * @param preserveChecked - mark all options unchecked before changing the active index
149
- *
150
- * @internal
151
- */
152
- checkNextOption(preserveChecked) {
153
- const nextIndex = this.getNextSelectableIndex(this.activeIndex + 1);
154
- if (nextIndex === -1) return;
155
- if (preserveChecked) {
156
- if (this.rangeStartIndex === -1) this.rangeStartIndex = this.activeIndex;
157
- this.options.forEach((o, i) => {
158
- o.checked = inRange(i, this.rangeStartIndex, nextIndex + 1) && !o.disabled;
159
- });
160
- } else this.uncheckAllOptions();
161
- this.activeIndex = nextIndex;
162
- this.checkActiveIndex();
181
+ #observer;
182
+ connectedCallback() {
183
+ super.connectedCallback();
184
+ this.updateAnchor();
185
+ this.#observer = new MutationObserver((records) => {
186
+ if (records.some((r) => Array.from(r.addedNodes).some((n) => n instanceof HTMLElement && n.id === this.anchorId))) this.updateAnchor();
187
+ });
188
+ this.#observer.observe(this.getRootNode(), {
189
+ childList: true,
190
+ subtree: true
191
+ });
163
192
  }
164
- /**
165
- * Decrements the active index and marks the matching option as checked.
166
- *
167
- * @remarks
168
- * Multiple-selection mode only.
169
- *
170
- * @param preserveChecked - mark all options unchecked before changing the active index
171
- *
172
- * @internal
173
- */
174
- checkPreviousOption(preserveChecked) {
175
- const previousIndex = this.getPreviousSelectableIndex(this.activeIndex - 1);
176
- if (previousIndex === -1) return;
177
- if (preserveChecked) {
178
- if (this.rangeStartIndex === -1) this.rangeStartIndex = this.activeIndex;
179
- if (this.checkedOptions.length === 1) this.rangeStartIndex += 1;
180
- this.options.forEach((o, i) => {
181
- o.checked = inRange(i, previousIndex, this.rangeStartIndex + 1) && !o.disabled;
182
- });
183
- } else this.uncheckAllOptions();
184
- this.activeIndex = previousIndex;
185
- this.checkActiveIndex();
193
+ disconnectedCallback() {
194
+ super.disconnectedCallback();
195
+ this.#observer.disconnect();
186
196
  }
187
- /**
188
- * @internal
189
- */
190
- focusAndScrollOptionIntoView() {
191
- super.focusAndScrollOptionIntoView(this.activeOption);
197
+ };
198
+ __decorate([observable], Popover.prototype, "kind", void 0);
199
+ __decorate([observable], Popover.prototype, "offset", void 0);
200
+ __decorate([observable], Popover.prototype, "anchorBlocksPopover", void 0);
201
+ __decorate([observable], Popover.prototype, "anchorEl", void 0);
202
+ __decorate([observable], Popover.prototype, "anchorId", void 0);
203
+ __decorate([observable], Popover.prototype, "requestedOpenState", void 0);
204
+ __decorate([volatile], Popover.prototype, "open", null);
205
+ var popoverDefinition = defineVividComponent("rich-text-editor-popover", Popover, popoverTemplate, [popupDefinition], {});
206
+ //#endregion
207
+ //#region ../../node_modules/.pnpm/prosemirror-view@1.41.8/node_modules/prosemirror-view/style/prosemirror.css?inline
208
+ var prosemirror_default = ".ProseMirror{word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:\"liga\" 0;position:relative}.ProseMirror pre{white-space:pre-wrap}.ProseMirror li{position:relative}.ProseMirror-hideselection ::selection{background:0 0}.ProseMirror-hideselection ::selection{background:0 0}.ProseMirror-hideselection{caret-color:#0000}.ProseMirror [draggable][contenteditable=false]{user-select:text}.ProseMirror-selectednode{outline:2px solid #8cf}li.ProseMirror-selectednode{outline:none}li.ProseMirror-selectednode:after{content:\"\";pointer-events:none;border:2px solid #8cf;position:absolute;inset:-2px -2px -2px -32px}img.ProseMirror-separator{border:none!important;margin:0!important;display:inline!important}";
209
+ //#endregion
210
+ //#region src/lib/rich-text-editor/rte/utils/default-textblock.ts
211
+ function defaultTextblockForMatch(match) {
212
+ for (let i = 0; i < match.edgeCount; i++) {
213
+ const { type } = match.edge(i);
214
+ /* v8 ignore if -- @preserve It's currently not possible to exercise this code in our RTE */
215
+ if (type.isTextblock && !type.hasRequiredAttrs()) return type;
192
216
  }
193
- /**
194
- * In multiple-selection mode:
195
- * If any options are selected, the first selected option is checked when
196
- * the listbox receives focus. If no options are selected, the first
197
- * selectable option is checked.
198
- *
199
- * @internal
200
- */
201
- focusinHandler(e) {
202
- if (!this.multiple) {
203
- super.focusinHandler(e);
204
- return;
205
- }
206
- /* v8 ignore else -- @preserve */
207
- if (!this.shouldSkipFocus && e.target === e.currentTarget) {
208
- this.uncheckAllOptions();
209
- if (this.activeIndex === -1) this.activeIndex = this.firstSelectedOptionIndex !== -1 ? this.firstSelectedOptionIndex : 0;
210
- this.checkActiveIndex();
211
- this.setSelectedOptions();
212
- this.focusAndScrollOptionIntoView();
213
- }
214
- this.shouldSkipFocus = false;
217
+ /* v8 ignore next 1 -- @preserve*/
218
+ throw new Error("No default textblock found.");
219
+ }
220
+ //#endregion
221
+ //#region src/lib/rich-text-editor/rte/utils/ui.style.scss?inline
222
+ var ui_style_default = "[data-class=ui-select]{min-inline-size:120px;margin-block:-4px}.ui-divider{block-size:20px}.ui-button-group{gap:4px;display:flex}.ui-tooltip,.ui-menu{--_popup-display:contents;display:contents}.ui-tooltip-wrapper{display:contents}";
223
+ //#endregion
224
+ //#region src/lib/rich-text-editor/rte/utils/feature-state.ts
225
+ var FeatureState = class {
226
+ constructor(initialValue) {
227
+ this.plugin = new Plugin({ state: {
228
+ init: () => initialValue,
229
+ apply: (tr, value) => {
230
+ const meta = tr.getMeta(this.plugin);
231
+ return meta !== void 0 ? meta : value;
232
+ }
233
+ } });
215
234
  }
216
- /**
217
- * Sets an option as selected and gives it focus.
218
- *
219
- * @public
220
- */
221
- setSelectedOptions() {
222
- if (!this.multiple) {
223
- super.setSelectedOptions();
224
- return;
225
- }
226
- /* v8 ignore else -- @preserve */
227
- if (this.$fastController.isConnected && this.options) {
228
- this.selectedOptions = this.options.filter((o) => o.selected);
229
- this.focusAndScrollOptionIntoView();
230
- }
235
+ getValue(rte) {
236
+ return this.plugin.getState(rte.state);
231
237
  }
232
- /**
233
- * Toggles the selected state of the provided options. If any provided items
234
- * are in an unselected state, all items are set to selected. If every
235
- * provided item is selected, they are all unselected.
236
- *
237
- * @internal
238
- */
239
- toggleSelectedForAllCheckedOptions() {
240
- const enabledCheckedOptions = this.checkedOptions.filter((o) => !o.disabled);
241
- const force = !enabledCheckedOptions.every((o) => o.selected);
242
- enabledCheckedOptions.forEach((o) => o.selected = force);
243
- this.selectedIndex = this.options.indexOf(enabledCheckedOptions[enabledCheckedOptions.length - 1]);
244
- this.setSelectedOptions();
245
- this.updateValue(true);
238
+ setValue(rte, newValue) {
239
+ rte.dispatchTransaction(rte.tr.setMeta(this.plugin, newValue));
246
240
  }
247
- /**
248
- * @internal
249
- */
250
- typeaheadBufferChanged(prev, next) {
251
- if (!this.multiple) {
252
- super.typeaheadBufferChanged(prev, next);
253
- return;
254
- }
255
- /* v8 ignore if -- @preserve */
256
- if (this.$fastController.isConnected) {
257
- const typeaheadMatches = this.getTypeaheadMatches();
258
- const activeIndex = this.options.indexOf(typeaheadMatches[0]);
259
- if (activeIndex > -1) {
260
- this.activeIndex = activeIndex;
261
- this.uncheckAllOptions();
262
- this.checkActiveIndex();
263
- }
264
- this.typeaheadExpired = false;
265
- }
241
+ };
242
+ //#endregion
243
+ //#region src/lib/rich-text-editor/rte/features/internal/core.style.scss?inline
244
+ var core_style_default = ".ProseMirror{box-sizing:border-box;padding:var(--editor-padding-block) var(--editor-padding-inline);outline:none;flex:1 0 0}.ProseMirror-selectednode{--focus-stroke-gap-color:transparent;--focus-border-radius:2px;outline:none;position:relative}.ProseMirror-selectednode:after{box-shadow:0 0 0 4px color-mix(in sRGB, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px));border-radius:var(--focus-border-radius,inherit);block-size:calc(100% + var(--focus-block-size-addition,4px));content:\"\";inline-size:calc(100% + var(--focus-block-size-addition,4px));display:block;position:absolute;inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}.editor--disabled .ProseMirror{color:var(--vvd-color-neutral-300);cursor:not-allowed}";
245
+ //#endregion
246
+ //#region src/lib/rich-text-editor/rte/features/internal/foreign-html.ts
247
+ var RteForeignHtmlFeatureImpl = class extends RteFeatureImpl {
248
+ constructor(..._args) {
249
+ super(..._args);
250
+ this.name = "RteForeignHtmlFeature";
266
251
  }
267
- /**
268
- * Unchecks all options.
269
- *
270
- * @remarks
271
- * Multiple-selection mode only.
272
- *
273
- * @param preserveChecked - reset the rangeStartIndex
274
- *
275
- * @internal
276
- */
277
- uncheckAllOptions(preserveChecked = false) {
278
- this.options.forEach((o) => o.checked = false);
279
- /* v8 ignore else -- @preserve */
280
- if (!preserveChecked) this.rangeStartIndex = -1;
252
+ getPlugins(rte) {
253
+ return [this.contribution(new Plugin({ props: {
254
+ transformPastedHTML: (html) => rte.foreignHtmlParser[impl].transform(html),
255
+ clipboardParser: rte.foreignHtmlParser[impl].parser,
256
+ clipboardSerializer: rte.foreignHtmlSerializer[impl].serializer
257
+ } }))];
281
258
  }
282
- /**
283
- * Sets focus when the open property changes.
284
- *
285
- * @internal
286
- */
287
- openChanged(prev, next) {
288
- if (!this.collapsible) return;
289
- if (this.open) {
290
- this.focusAndScrollOptionIntoView();
291
- this.indexWhenOpened = this.selectedIndex;
292
- Updates.enqueue(() => this.focus());
293
- return;
259
+ };
260
+ //#endregion
261
+ //#region src/lib/rich-text-editor/rte/features/internal/cursor-fix.ts
262
+ /**
263
+ * When the cursor is positioned after an inline atom node at the end of a line,
264
+ * browsers may display the cursor inside the atom.
265
+ */
266
+ var atomCursorFix = ($cursor) => {
267
+ if (!($cursor.parentOffset === $cursor.parent.content.size)) return null;
268
+ const nodeBefore = $cursor.nodeBefore;
269
+ if (nodeBefore && nodeBefore.isInline && nodeBefore.isAtom && !nodeBefore.isText) return {};
270
+ return null;
271
+ };
272
+ /**
273
+ * When the cursor is positioned directly before an inline atom node (e.g. an image)
274
+ * that wraps to the next line, browsers may display the cursor on the next line even
275
+ * though typing inserts text on the previous line. A ZWSP between cursor and atom will be
276
+ * layouted to the previous line and therefore fix the cursor position.
277
+ */
278
+ var beforeAtomCursorFix = ($cursor) => {
279
+ const nodeAfter = $cursor.nodeAfter;
280
+ if (nodeAfter && nodeAfter.isInline && nodeAfter.isAtom && !nodeAfter.isText) return { afterCursor: true };
281
+ return null;
282
+ };
283
+ function createZwspWidget(style) {
284
+ const span = document.createElement("span");
285
+ span.textContent = "​";
286
+ for (const [prop, value] of Object.entries(style)) span.style.setProperty(prop, value);
287
+ return span;
288
+ }
289
+ var RteCursorFixFeatureImpl = class extends RteFeatureImpl {
290
+ constructor(..._args) {
291
+ super(..._args);
292
+ this.name = "RteCursorFix";
293
+ }
294
+ getPlugins(rte) {
295
+ const cursorFixes = [atomCursorFix, beforeAtomCursorFix];
296
+ for (const markType of Object.values(rte.schema.marks)) {
297
+ const spec = markType.spec;
298
+ if (spec.cursorFix) cursorFixes.push(spec.cursorFix);
294
299
  }
295
- const didClose = prev && !next;
296
- const selectionChangedWhileOpen = this.indexWhenOpened !== this.selectedIndex;
297
- if (didClose && selectionChangedWhileOpen) this.updateValue(true);
300
+ return [this.contribution(new Plugin({ props: { decorations: (state) => {
301
+ const { $cursor } = state.selection;
302
+ if (!$cursor) return null;
303
+ const decorations = [];
304
+ const cursorFixStyles = {};
305
+ let before = false;
306
+ let after = false;
307
+ for (const fn of cursorFixes) {
308
+ const result = fn($cursor, state);
309
+ if (!result) continue;
310
+ if (result.style) Object.assign(cursorFixStyles, result.style);
311
+ if (result.afterCursor) after = true;
312
+ else before = true;
313
+ }
314
+ if (before) decorations.push(Decoration.widget($cursor.pos, () => createZwspWidget(cursorFixStyles), { side: -1 }));
315
+ if (after) decorations.push(Decoration.widget($cursor.pos, () => createZwspWidget(cursorFixStyles), { side: 1 }));
316
+ if (decorations.length === 0) return null;
317
+ return DecorationSet.create(state.doc, decorations);
318
+ } } }))];
298
319
  }
299
- /**
300
- * The component is collapsible when in single-selection mode.
301
- *
302
- * @internal
303
- */
304
- get collapsible() {
305
- return !this.multiple;
320
+ };
321
+ featureFacade(RteCursorFixFeatureImpl);
322
+ //#endregion
323
+ //#region src/lib/rich-text-editor/rte/features/internal/core.ts
324
+ /** Plugin to bring state from the host web component into ProseMirror. */
325
+ var hostBridgePlugin = new Plugin({ state: {
326
+ init() {
327
+ return null;
328
+ },
329
+ apply(tr, value) {
330
+ const meta = tr.getMeta(hostBridgePlugin);
331
+ if (meta) return meta;
332
+ else return value;
306
333
  }
307
- /**
308
- * @internal
309
- */
310
- valueChanged(prev, next) {
311
- const nextSelectedIndex = this.options.findIndex((el) => el.value === next);
312
- const validNextSelectedIndex = this._validSelectedIndex(nextSelectedIndex);
313
- const nextValue = this.options[validNextSelectedIndex]?.value ?? "";
314
- if (this.selectedIndex !== validNextSelectedIndex) this.selectedIndex = validNextSelectedIndex;
315
- if (next !== nextValue) return;
316
- super.valueChanged(prev, next);
317
- this.updateDisplayValue();
334
+ } });
335
+ var RteCoreImpl = class extends RteFeatureImpl {
336
+ constructor(..._args) {
337
+ super(..._args);
338
+ this.name = "RteCore";
339
+ this.disabled = new FeatureState(false);
340
+ this.scrollThreshold = void 0;
341
+ this.scrollMargin = void 0;
318
342
  }
319
- /**
320
- * Sets the value and display value to match the first selected option.
321
- *
322
- * @param shouldEmit - if true, the input and change events will be emitted
323
- *
324
- * @internal
325
- */
326
- updateValue(shouldEmit) {
327
- if (this.$fastController.isConnected) this.value = this.firstSelectedOption?.value ?? "";
328
- if (shouldEmit) {
329
- this.$emit("input");
330
- this.$emit("change", this, {
331
- bubbles: true,
332
- composed: void 0
333
- });
343
+ getStyles() {
344
+ return [
345
+ this.contribution(prosemirror_default),
346
+ this.contribution(core_style_default),
347
+ this.contribution(ui_style_default)
348
+ ];
349
+ }
350
+ getPlugins(rte) {
351
+ const splitFn = splitBlockAs((node, atEnd, $from) => {
352
+ if (!atEnd) return {
353
+ type: node.type,
354
+ attrs: node.attrs
355
+ };
356
+ return {
357
+ type: defaultTextblockForMatch($from.node($from.depth - 1).contentMatchAt($from.indexAfter($from.depth - 1))),
358
+ attrs: rte.textblockAttrs.extractFromNode(node)
359
+ };
360
+ });
361
+ const splitFnKeepMarks = (state, dispatch) => splitFn(state, dispatch && ((tr) => {
362
+ const marks = state.storedMarks || state.selection.$to.parentOffset && state.selection.$from.marks();
363
+ if (marks) tr.ensureMarks(marks);
364
+ dispatch(tr);
365
+ }));
366
+ const enterKeyChainCommands = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitFnKeepMarks);
367
+ return [
368
+ this.contribution(this.disabled.plugin),
369
+ this.contribution(new Plugin({
370
+ props: {
371
+ editable: () => !this.disabled.getValue(rte),
372
+ handleDOMEvents: { click: (_view, event) => {
373
+ if (this.disabled.getValue(rte)) {
374
+ event.preventDefault();
375
+ return true;
376
+ }
377
+ return false;
378
+ } }
379
+ },
380
+ view: (view) => {
381
+ const popovers = view.dom.getRootNode().querySelector(".popovers");
382
+ const updateDisabled = () => {
383
+ const disabled = this.disabled.getValue(rte);
384
+ popovers.classList.toggle("popovers--disabled", disabled);
385
+ view.dom.parentElement.classList.toggle("editor--disabled", disabled);
386
+ };
387
+ updateDisabled();
388
+ return { update: () => {
389
+ updateDisabled();
390
+ } };
391
+ }
392
+ })),
393
+ this.contribution(keymap({
394
+ ...baseKeymap,
395
+ Enter: enterKeyChainCommands,
396
+ "Shift-Enter": enterKeyChainCommands
397
+ })),
398
+ this.contribution(dropCursor()),
399
+ this.contribution(gapCursor()),
400
+ this.contribution(hostBridgePlugin)
401
+ ];
402
+ }
403
+ getFeatures() {
404
+ return [
405
+ this,
406
+ new RteForeignHtmlFeatureImpl(),
407
+ new RteCursorFixFeatureImpl()
408
+ ];
409
+ }
410
+ };
411
+ featureFacade(RteCoreImpl);
412
+ //#endregion
413
+ //#region src/lib/rich-text-editor/rte/utils/sanitization.ts
414
+ var DEFAULT_ALLOWED_URI_REGEXP = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
415
+ var ALLOWED_URI_REGEXP_WITH_BLOB = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|blob):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
416
+ var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
417
+ var domPurifyConfig = { ALLOWED_URI_REGEXP: ALLOWED_URI_REGEXP_WITH_BLOB };
418
+ /**
419
+ * Sanitize potentially dangerous URLs, like "javascript:", in anchor href attributes.
420
+ * Returns empty string if the URL is unsafe.
421
+ */
422
+ var sanitizeLinkHref = (url) => {
423
+ if (!DEFAULT_ALLOWED_URI_REGEXP.test(url.replace(ATTR_WHITESPACE, ""))) return "";
424
+ const anchor = document.createElement("a");
425
+ anchor.setAttribute("href", url);
426
+ /* v8 ignore next -- since href is already validated it's probably always present @preserve */
427
+ return DOMPurify.sanitize(anchor, {
428
+ RETURN_DOM: true,
429
+ ...domPurifyConfig
430
+ }).querySelector("a").getAttribute("href") ?? "";
431
+ };
432
+ /**
433
+ * Sanitize potentially dangerous URLs, like "javascript:", in image src attributes.
434
+ * Returns empty string if the URL is unsafe.
435
+ */
436
+ var sanitizeImageSrc = (url) => {
437
+ const img = document.createElement("img");
438
+ img.setAttribute("src", url);
439
+ return DOMPurify.sanitize(img, {
440
+ RETURN_DOM: true,
441
+ ...domPurifyConfig
442
+ }).querySelector("img").getAttribute("src") ?? "";
443
+ };
444
+ /**
445
+ * Escapes a CSS value for insertion into style attribute.
446
+ * E.g. "15px; background: red" => "15px"
447
+ */
448
+ var escapeCssProperty = (value) => value.replace(/[;!].*/, "");
449
+ //#endregion
450
+ //#region src/lib/rich-text-editor/rte/html-parser.ts
451
+ var copy = (obj) => ({ ...obj });
452
+ var parseRulesFromSchema = (schema) => ({
453
+ nodes: Object.fromEntries(Object.keys(schema.nodes).map((name) => [name, (schema.nodes[name].spec.parseDOM ?? []).map(copy)])),
454
+ marks: Object.fromEntries(Object.keys(schema.marks).map((name) => [name, (schema.marks[name].spec.parseDOM ?? []).map(copy)]))
455
+ });
456
+ var RteHtmlParser = class {
457
+ constructor(config, options) {
458
+ this[impl] = new RteHtmlParserImpl(config[impl], options);
459
+ }
460
+ /** Converts an HTML string to an RteDocument. */
461
+ parseDocument(html, options) {
462
+ return this[impl].parser.parse(this.parseHtml(html, options), { preserveWhitespace: true }).toJSON();
463
+ }
464
+ /** Converts an HTML string to an RteFragment. */
465
+ parseFragment(html, options) {
466
+ return this[impl].parser.parseSlice(this.parseHtml(html, options), { preserveWhitespace: true }).content.toJSON() ?? [];
467
+ }
468
+ parseHtml(html, options) {
469
+ const dom = DOMPurify.sanitize(html, {
470
+ RETURN_DOM: true,
471
+ ...domPurifyConfig
472
+ });
473
+ const container = document.createDocumentFragment();
474
+ container.appendChild(dom);
475
+ options?.modifyDom?.(container);
476
+ return container;
477
+ }
478
+ };
479
+ var RteHtmlParserImpl = class {
480
+ constructor(config, options) {
481
+ const rules = parseRulesFromSchema(config.schema);
482
+ options?.modifyParseRules?.(rules);
483
+ this.parser = buildDomParser(config.schema, rules);
484
+ }
485
+ /** Used by the editor when foreign HTML is pasted or dropped */
486
+ transform(html) {
487
+ return DOMPurify.sanitize(html);
488
+ }
489
+ };
490
+ var buildDomParser = (schema, { marks, nodes }) => {
491
+ const parserRules = [];
492
+ const priority = (rule) => rule.priority ?? 50;
493
+ function insert(rule) {
494
+ let i = 0;
495
+ for (; i < parserRules.length; i++) {
496
+ const next = parserRules[i];
497
+ if (priority(next) < priority(rule)) break;
334
498
  }
499
+ parserRules.splice(i, 0, rule);
335
500
  }
336
- /**
337
- * Updates the proxy value when the selected index changes.
338
- *
339
- * @param prev - the previous selected index
340
- * @param next - the next selected index
341
- *
342
- * @internal
343
- */
344
- selectedIndexChanged(prev, next) {
345
- super.selectedIndexChanged(prev, next);
346
- this.updateValue();
501
+ for (const name in marks) marks[name]?.forEach((rule) => {
502
+ insert(rule = copy(rule));
503
+ if (!(rule.mark || rule.ignore || rule.clearMark)) rule.mark = name;
504
+ });
505
+ for (const name in nodes) nodes[name]?.forEach((rule) => {
506
+ insert(rule = copy(rule));
507
+ if (!(rule.node || rule.ignore || rule.mark)) rule.node = name;
508
+ });
509
+ parserRules.push({
510
+ tag: "br",
511
+ closeParent: true
512
+ });
513
+ return new DOMParser(schema, parserRules);
514
+ };
515
+ //#endregion
516
+ //#region src/lib/rich-text-editor/rte/html-serializer.ts
517
+ var RteHtmlSerializer = class {
518
+ constructor(config, options) {
519
+ this[impl] = new RteHtmlSerializerImpl(config[impl], options);
347
520
  }
348
- /**
349
- * Handle opening and closing the listbox when the select is clicked.
350
- *
351
- * @param e - the mouse event
352
- * @internal
353
- */
354
- clickHandler(e) {
355
- if (this.disabled || this._isFromContextualHelp(e)) return;
356
- const clickedOption = e.target.closest(`option,[role=option],[data-vvd-component=option]`);
357
- if (clickedOption && clickedOption.disabled) return;
358
- if (this.multiple) {
359
- this.uncheckAllOptions();
360
- this.activeIndex = this.options.indexOf(clickedOption);
361
- this.checkActiveIndex();
362
- this.toggleSelectedForAllCheckedOptions();
363
- } else super.clickHandler(e);
364
- if (this.collapsible) this.open = !this.open;
365
- return true;
521
+ /** Converts an RteDocument to an HTML string. */
522
+ serializeDocument(doc, options) {
523
+ return this[impl].serializeFragment(doc.content, options);
366
524
  }
367
- /**
368
- * Handles focus state when the element or its children lose focus.
369
- *
370
- * @param e - The focus event
371
- * @internal
372
- */
373
- focusoutHandler(e) {
374
- if (this.multiple) this.uncheckAllOptions();
375
- if (!this.open) return true;
376
- const focusTarget = e.relatedTarget;
377
- if (this.isSameNode(focusTarget)) {
378
- this.focus();
379
- return;
525
+ /** Converts an RteFragment to an HTML string. */
526
+ serializeFragment(fragment, options) {
527
+ return this[impl].serializeFragment(fragment, options);
528
+ }
529
+ };
530
+ var RteHtmlSerializerImpl = class RteHtmlSerializerImpl {
531
+ constructor(config, options) {
532
+ this.config = config;
533
+ const serializers = RteHtmlSerializerImpl.domSerializersFromSchema(config.schema);
534
+ Object.assign(serializers.nodes, options?.serializers?.nodes ?? {});
535
+ Object.assign(serializers.marks, options?.serializers?.marks ?? {});
536
+ this.serializer = new DOMSerializer(serializers.nodes, serializers.marks);
537
+ }
538
+ static domSerializersFromSchema(schema) {
539
+ const result = {
540
+ nodes: {},
541
+ marks: {}
542
+ };
543
+ for (const name in schema.marks) {
544
+ const toDOM = schema.marks[name].spec.toDOM;
545
+ if (toDOM) result.marks[name] = toDOM;
380
546
  }
381
- /* v8 ignore else -- @preserve */
382
- if (!this.options.includes(focusTarget)) {
383
- this.open = false;
384
- if (this.indexWhenOpened !== this.selectedIndex) this.updateValue(true);
547
+ for (const name in schema.nodes) {
548
+ const toDOM = schema.nodes[name].spec.serializeToDOM ?? schema.nodes[name].spec.toDOM;
549
+ if (toDOM) result.nodes[name] = toDOM;
385
550
  }
551
+ result.nodes.text = (node) => document.createTextNode(node.text);
552
+ return result;
553
+ }
554
+ serializeFragment(fragment, options) {
555
+ const parsedFragment = Fragment.fromJSON(this.config.schema, fragment);
556
+ const serializedFragment = this.serializer.serializeFragment(parsedFragment);
557
+ const container = document.createDocumentFragment();
558
+ container.appendChild(serializedFragment);
559
+ options?.modifyDom?.(container);
560
+ const output = document.createElement("div");
561
+ output.appendChild(container);
562
+ return output.innerHTML;
563
+ }
564
+ };
565
+ //#endregion
566
+ //#region src/lib/rich-text-editor/rte/instance.ts
567
+ var parseDocument = (schema, doc) => {
568
+ const node = schema.topNodeType.createAndFill(null, doc ? Fragment.fromJSON(schema, doc.content) : null);
569
+ if (!node) throw new Error("Document could not be parsed");
570
+ node.check();
571
+ return node;
572
+ };
573
+ var RteInstance = class {
574
+ constructor(config, options) {
575
+ this.options = options;
576
+ this.feature = (Feature, featureId) => {
577
+ return this[impl].getPublicInterface(Feature, featureId);
578
+ };
579
+ this[impl] = new RteInstanceImpl(this, config, options);
580
+ }
581
+ /** Returns the current document state. */
582
+ getDocument() {
583
+ return this[impl].state.doc.toJSON();
584
+ }
585
+ /** Reset the editor to its initial state. Optionally, an initial document can be provided. */
586
+ reset(initialDocument) {
587
+ this[impl].reset(initialDocument);
386
588
  }
387
589
  /**
388
- * Updates the value when an option's value changes.
389
- *
390
- * @param source - the source object
391
- * @param propertyName - the property to evaluate
392
- *
393
- * @internal
590
+ * Replaces the current selection with the given content.
591
+ * If no text is selected, this inserts the content at the cursor position.
394
592
  */
395
- handleChange(source, propertyName) {
396
- super.handleChange(source, propertyName);
397
- if (propertyName === "value") this.updateValue();
593
+ replaceSelection(content, options) {
594
+ const { state, tr, schema, dispatchTransaction } = this[impl];
595
+ tr.replaceSelection(new Slice(Fragment.fromJSON(schema, content), 0, 0));
596
+ tr.doc.check();
597
+ const $from = tr.doc.resolve(tr.mapping.map(state.selection.from));
598
+ const $to = tr.doc.resolve(tr.selection.to);
599
+ const [$head, $anchor] = options?.cursorPlacement === "start" ? [$from, $to] : [$to, $from];
600
+ if (options?.selectContent) tr.setSelection(state.selection instanceof AllSelection ? new AllSelection(tr.doc) : TextSelection.between($anchor, $head));
601
+ else tr.setSelection(TextSelection.between($head, $head));
602
+ dispatchTransaction(tr);
398
603
  }
399
604
  /**
400
- * Prevents focus when a scrollbar is clicked.
401
- *
402
- * @param e - the mouse event object
403
- *
404
- * @internal
605
+ * Replaces the entire document with the given new document.
606
+ * Unlike reset, this preserves the rest of the editor state. The undo history is preserved, so the user can undo the replacement.
405
607
  */
406
- mousedownHandler(e) {
407
- if (e.offsetX >= 0 && e.offsetX <= this.listbox.scrollWidth) return super.mousedownHandler(e);
408
- return this.collapsible;
608
+ replaceDocument(newDocument, options) {
609
+ const { state, tr, schema, dispatchTransaction } = this[impl];
610
+ tr.replaceWith(0, state.doc.content.size, parseDocument(schema, newDocument));
611
+ if (options?.selectContent) tr.setSelection(new AllSelection(tr.doc));
612
+ else if (options?.cursorPlacement === "end") tr.setSelection(TextSelection.atEnd(tr.doc));
613
+ else tr.setSelection(TextSelection.atStart(tr.doc));
614
+ dispatchTransaction(tr);
409
615
  }
410
616
  /**
411
- * @internal
617
+ * Scrolls the cursor into view.
618
+ * Has no effect if the editor is not currently mounted.
412
619
  */
413
- multipleChanged(_, next) {
414
- this.options.forEach((o) => {
415
- o.checked = next ? false : void 0;
620
+ scrollIntoView() {
621
+ const instance = this[impl];
622
+ if (!instance.view) return;
623
+ instance.dispatchTransaction(instance.tr.scrollIntoView());
624
+ }
625
+ };
626
+ var RteInstanceImpl = class {
627
+ getFeature(name) {
628
+ const f = this.config.featureMap.get(name);
629
+ if (!f) throw new Error(`Feature not found: ${name}`);
630
+ return f;
631
+ }
632
+ getPublicInterface(Feature, featureId) {
633
+ const instances = this.config.featureFacadesMap.get(Feature);
634
+ if (!instances || instances.length === 0) throw new Error(`Feature not found`);
635
+ if (instances[0].featureId !== void 0) {
636
+ if (featureId === void 0) throw new Error(`No featureId provided for multi-instance feature.`);
637
+ const instance = instances.find((f) => f.featureId === featureId);
638
+ if (!instance) throw new Error(`Feature with id "${featureId}" not found`);
639
+ return instance.getPublicInterface(this);
640
+ }
641
+ if (featureId !== void 0) throw new Error(`Feature does not support featureId`);
642
+ return instances[0].getPublicInterface(this);
643
+ }
644
+ constructor(instanceFacade, configFacade, options) {
645
+ this.options = options;
646
+ this.view = null;
647
+ this.dispatchTransaction = (tr) => {
648
+ const prevState = this.state;
649
+ this.state = this.state.apply(tr);
650
+ this.view?.updateState(this.state);
651
+ if (prevState.doc !== this.state.doc) this.options?.onChange?.();
652
+ return this.state;
653
+ };
654
+ this.facade = instanceFacade;
655
+ const config = configFacade[impl];
656
+ this.config = config;
657
+ this.schema = config.schema;
658
+ this.textblockAttrs = config.textblockAttrs;
659
+ this.features = config.features;
660
+ this.foreignHtmlParser = options?.foreignHtmlParser ?? new RteHtmlParser(configFacade);
661
+ this.foreignHtmlSerializer = options?.foreignHtmlSerializer ?? new RteHtmlSerializer(configFacade);
662
+ this.styles = new ElementStyles(sortedContributions(config.features.flatMap((f) => f.getStyles())));
663
+ this.initState(options?.initialDocument);
664
+ }
665
+ initState(initialDoc) {
666
+ this.state = EditorState.create({
667
+ doc: parseDocument(this.schema, initialDoc),
668
+ schema: this.config.schema,
669
+ plugins: sortedContributions(this.config.features.flatMap((feature) => feature.getPlugins(this)))
416
670
  });
417
- this.setSelectedOptions();
418
- /* v8 ignore if -- @preserve */
419
- if (this.proxy) this.proxy.multiple = next;
420
671
  }
421
- /**
422
- * Updates the selectedness of each option when the list of selected options changes.
423
- *
424
- * @param prev - the previous list of selected options
425
- * @param next - the current list of selected options
426
- *
427
- * @internal
428
- */
429
- selectedOptionsChanged(prev, next) {
430
- super.selectedOptionsChanged(prev, next);
431
- this.options.forEach((o, i) => {
432
- const proxyOption = this.proxy.options.item(i);
433
- if (proxyOption) proxyOption.selected = o.selected;
672
+ reset(initialDocument) {
673
+ const currentHostState = hostBridgePlugin.getState(this.state);
674
+ this.initState(initialDocument);
675
+ this.updateHostState(currentHostState);
676
+ this.view?.updateState(this.state);
677
+ }
678
+ createView(target) {
679
+ const core = this.config.featureMap.get("RteCore");
680
+ this.view = new EditorView((editor) => {
681
+ editor.part = "editor";
682
+ target.appendChild(editor);
683
+ }, {
684
+ state: this.state,
685
+ dispatchTransaction: this.dispatchTransaction,
686
+ ...core?.scrollThreshold !== void 0 && { scrollThreshold: core.scrollThreshold },
687
+ ...core?.scrollMargin !== void 0 && { scrollMargin: core.scrollMargin }
434
688
  });
435
689
  }
436
- /**
437
- * Resets and fills the proxy to match the component's options.
438
- *
439
- * @internal
440
- */
441
- setProxyOptions() {
442
- /* v8 ignore else -- @preserve */
443
- if (this.proxy instanceof HTMLSelectElement && this.options) {
444
- this.proxy.length = 0;
445
- this.options.forEach((option) => {
446
- const proxyOption = option.proxy || (option instanceof HTMLOptionElement ? option.cloneNode() : null);
447
- if (proxyOption) this.proxy.options.add(proxyOption);
448
- });
690
+ destroyViewIfNeeded() {
691
+ if (this.view) {
692
+ this.view.destroy();
693
+ this.view = null;
449
694
  }
450
695
  }
451
- /**
452
- * Handles keydown actions when the select is in multiple selection mode.
453
- *
454
- * @internal
455
- */
456
- multipleKeydownHandler(e) {
457
- if (this.disabled) return;
458
- const { key, shiftKey } = e;
459
- this.shouldSkipFocus = false;
460
- switch (key) {
461
- case keyHome:
462
- this.checkFirstOption(shiftKey);
463
- return;
464
- case keyArrowDown:
465
- this.checkNextOption(shiftKey);
466
- return;
467
- case keyArrowUp:
468
- this.checkPreviousOption(shiftKey);
469
- return;
470
- case keyEnd:
471
- this.checkLastOption(shiftKey);
472
- return;
473
- case keyTab:
474
- this.focusAndScrollOptionIntoView();
475
- return;
476
- case keyEscape:
477
- this.uncheckAllOptions();
478
- this.checkActiveIndex();
479
- return;
480
- case keySpace:
481
- e.preventDefault();
482
- /* v8 ignore else -- @preserve */
483
- if (this.typeaheadExpired) {
484
- this.toggleSelectedForAllCheckedOptions();
485
- return;
486
- }
487
- default:
488
- /* v8 ignore else -- @preserve */
489
- if (key.length === 1) this.handleTypeAhead(key);
490
- return;
491
- }
696
+ createComponent(type) {
697
+ return document.createElement(this.hostState().ctx.tagFor(type, true));
492
698
  }
493
- /**
494
- * Handle keyboard interaction for the select.
495
- *
496
- * @param e - the keyboard event
497
- * @internal
498
- */
499
- keydownHandler(e) {
500
- const selectedIndexBefore = this.selectedIndex;
501
- if (this.multiple) this.multipleKeydownHandler(e);
502
- else super.keydownHandler(e);
503
- switch (e.key) {
504
- case keySpace:
505
- e.preventDefault();
506
- if (this.collapsible && this.typeaheadExpired) this.open = !this.open;
507
- break;
508
- case keyHome:
509
- case keyEnd:
510
- e.preventDefault();
511
- break;
512
- case keyEnter:
513
- e.preventDefault();
514
- this.open = !this.open;
515
- break;
516
- case keyEscape:
517
- if (this.collapsible && this.open) {
518
- e.preventDefault();
519
- this.open = false;
520
- }
521
- break;
522
- case keyTab:
523
- if (this.collapsible && this.open) {
524
- e.preventDefault();
525
- this.open = false;
526
- }
527
- return true;
528
- }
529
- if (this.collapsible && !this.open && this.selectedIndex !== selectedIndexBefore) this.updateValue(true);
530
- return !(e.key === keyArrowDown || e.key === keyArrowUp);
699
+ getLocale() {
700
+ return this.hostState().locale;
531
701
  }
532
- connectedCallback() {
533
- super.connectedCallback();
534
- this.addEventListener("focusout", this.focusoutHandler);
535
- this.addEventListener("contentchange", this.updateDisplayValue);
702
+ get tr() {
703
+ return this.state.tr;
536
704
  }
537
- disconnectedCallback() {
538
- this.removeEventListener("focusout", this.focusoutHandler);
539
- this.removeEventListener("contentchange", this.updateDisplayValue);
540
- super.disconnectedCallback();
705
+ hostState() {
706
+ const state = hostBridgePlugin.getState(this.state);
707
+ if (!state) throw new Error("No host state available");
708
+ return state;
541
709
  }
542
- /**
543
- *
544
- * @internal
545
- */
546
- updateDisplayValue() {
547
- if (this.collapsible) Observable.notify(this, "displayValue");
548
- }
549
- get displayValue() {
550
- Observable.track(this, "displayValue");
551
- return this.firstSelectedOption?.getAttribute("label") ?? this.firstSelectedOption?.text ?? this.placeholder ?? "";
552
- }
553
- _newDefaultSelectedIndex(prev, next, currentSelectIndex) {
554
- const defaultSelectedIndex = super._newDefaultSelectedIndex(prev, next, currentSelectIndex);
555
- if (defaultSelectedIndex === null && currentSelectIndex === -1 && !this.placeholder) {
556
- const firstSelectableIndex = this.getNextSelectableIndex(0);
557
- if (firstSelectableIndex !== -1) return firstSelectableIndex;
558
- }
559
- return defaultSelectedIndex;
710
+ updateHostState(hostState) {
711
+ this.dispatchTransaction(this.tr.setMeta(hostBridgePlugin, hostState));
560
712
  }
561
- _isDefaultSelected(option) {
562
- return super._isDefaultSelected(option) || option.value === this.initialValue || !this._isResetting && option.value === this.value;
713
+ };
714
+ //#endregion
715
+ //#region src/lib/rich-text-editor/rte/utils/textblock-attrs.ts
716
+ var TextblockAttrs = class {
717
+ constructor(specs) {
718
+ this.specs = specs;
719
+ this.attrs = {};
720
+ for (const spec of specs) this.attrs[spec.name] = { default: spec.default };
563
721
  }
564
- slottedOptionsChanged(prev, next) {
565
- this.options.forEach((o) => {
566
- Observable.getNotifier(o).unsubscribe(this, "value");
567
- });
568
- super.slottedOptionsChanged(prev, next);
569
- this.options.forEach((o) => {
570
- Observable.getNotifier(o).subscribe(this, "value");
571
- });
572
- this.setProxyOptions();
573
- this.updateValue();
574
- const scale = this.getAttribute("scale") || this.scale;
575
- next.forEach((element) => {
576
- if (scale) {
577
- element.setAttribute("scale", scale);
578
- element.scale = scale;
579
- }
580
- });
581
- this.proxy.value = this.value;
582
- this.validate();
722
+ fromDOM(dom) {
723
+ return Object.assign({}, ...this.specs.map((s) => ({ [s.name]: s.fromDOM(dom) })));
583
724
  }
584
- formResetCallback() {
585
- this.setProxyOptions();
586
- this._isResetting = true;
587
- this.selectedIndex = this._newDefaultSelectedIndex([], this.options, -1) ?? -1;
588
- this._isResetting = false;
725
+ getStyle(node) {
726
+ return this.specs.flatMap((s) => s.toStyles(node)).join("; ");
589
727
  }
590
- /**
591
- * @internal
592
- */
593
- get _shouldShowClearButton() {
594
- if (!this.clearable) return false;
595
- if (this.multiple) return this.selectedOptions?.length > 0;
596
- return this.value !== "";
728
+ getDOMAttrsProperties(node) {
729
+ if (!this.specs.length) return {};
730
+ return { style: this.getStyle(node) };
597
731
  }
598
- /**
599
- * @internal
600
- */
601
- _onClearButtonFocus() {
602
- this._isClearButtonFocused = true;
603
- this.activeIndex = -1;
604
- this.uncheckAllOptions();
732
+ getDOMAttrs(node) {
733
+ if (!this.specs.length) return [];
734
+ return [this.getDOMAttrsProperties(node)];
605
735
  }
606
- /**
607
- * @internal
608
- */
609
- _onClearButtonBlur() {
610
- this._isClearButtonFocused = false;
736
+ extractFromNode(node) {
737
+ return Object.assign({}, ...Object.keys(this.attrs).map((attr) => ({ [attr]: node.attrs[attr] })));
611
738
  }
612
- /**
613
- * @internal
614
- */
615
- get _shouldShowLabelWrapper() {
616
- return Boolean(this.label || this._hasContextualHelp || this.multiple && this._shouldShowClearButton);
739
+ };
740
+ //#endregion
741
+ //#region src/lib/rich-text-editor/rte/utils/textblock-marks.ts
742
+ var TextblockMarks = class {
743
+ constructor(specs) {
744
+ this.specs = specs;
617
745
  }
618
- /**
619
- * @internal
620
- */
621
- _onClearButtonClick() {
622
- if (this.multiple) this.selectedOptions.forEach((o) => {
623
- /* v8 ignore else -- @preserve */
624
- if (!o.disabled) o.selected = false;
625
- });
626
- else this.selectedIndex = -1;
627
- this.updateValue(true);
628
- }
629
- };
630
- __decorate([observable], Select.prototype, "activeIndex", void 0);
631
- __decorate([attr({ mode: "boolean" })], Select.prototype, "multiple", void 0);
632
- __decorate([attr({
633
- attribute: "open",
634
- mode: "boolean"
635
- })], Select.prototype, "open", void 0);
636
- __decorate([volatile], Select.prototype, "collapsible", null);
637
- __decorate([observable], Select.prototype, "control", void 0);
638
- __decorate([observable], Select.prototype, "maxHeight", void 0);
639
- __decorate([observable], Select.prototype, "_anchor", void 0);
640
- __decorate([attr()], Select.prototype, "scale", void 0);
641
- __decorate([attr], Select.prototype, "appearance", void 0);
642
- __decorate([attr], Select.prototype, "shape", void 0);
643
- __decorate([attr({
644
- mode: "boolean",
645
- attribute: "fixed-dropdown"
646
- })], Select.prototype, "fixedDropdown", void 0);
647
- __decorate([attr], Select.prototype, "placeholder", void 0);
648
- __decorate([observable], Select.prototype, "_feedbackWrapper", void 0);
649
- __decorate([observable], Select.prototype, "metaSlottedContent", void 0);
650
- __decorate([attr({ mode: "boolean" })], Select.prototype, "clearable", void 0);
651
- __decorate([observable], Select.prototype, "_isClearButtonFocused", void 0);
652
- //#endregion
653
- //#region src/lib/select/select.template.ts
654
- var getStateClasses = ({ shape, disabled, appearance, metaSlottedContent, errorValidationMessage, successText, placeholder, value, scale, _activeDescendant, open }) => classNames(["has-activedescendant", Boolean(_activeDescendant) && open], ["disabled", disabled], [`appearance-${appearance}`, Boolean(appearance)], [`shape-${shape}`, Boolean(shape)], ["has-meta", Boolean(metaSlottedContent?.length)], ["error", Boolean(errorValidationMessage)], ["success", !!successText], ["shows-placeholder", Boolean(placeholder) && !value], [`size-${scale}`, Boolean(scale)]);
655
- function renderLabel() {
656
- return html` <label
657
- for="${(x) => x.multiple ? null : "control"}"
658
- class="label"
659
- id="label"
660
- >
661
- ${(x) => x.label}
662
- </label>`;
663
- }
664
- function renderPlaceholder(context) {
665
- const optionTag = context.tagFor(ListboxOption);
666
- return html`
667
- <${optionTag} text="${(x) => x.placeholder}" hidden disabled>
668
- </${optionTag}>`;
669
- }
670
- function renderClearButton(context) {
671
- const buttonTag = context.tagFor(Button);
672
- return html`
673
- <${buttonTag}
674
- aria-label="${(x) => x.locale.select.clearButtonLabel}"
675
- aria-hidden="${(x) => x._isClearButtonFocused ? "false" : "true"}"
676
- @click="${(x, c) => {
677
- x._onClearButtonClick();
678
- c.event.stopPropagation();
679
- }}"
680
- @mousedown="${() => false}"
681
- @keydown="${(x, c) => {
682
- /* v8 ignore next -- @preserve */
683
- if (c.event.key === "Tab") x._onClearButtonBlur();
684
- c.event.stopPropagation();
685
- return true;
686
- }}"
687
- @focusin="${(x, c) => {
688
- c.event.stopPropagation();
689
- x._onClearButtonFocus();
690
- }}"
691
- @focusout="${(x) => x._onClearButtonBlur()}"
692
- ?disabled="${(x) => x.disabled}"
693
- :shape="${(x) => x.shape}"
694
- size="super-condensed"
695
- icon="close-line"
696
- appearance="ghost-light"
697
- class="clear-button"
698
- tabindex="0"
699
- ></${buttonTag}>
700
- `;
701
- }
702
- function selectValue(context) {
703
- const affixIconTemplate = affixIconTemplateFactory(context);
704
- const chevronTemplate = chevronTemplateFactory(context);
705
- return html` <div
706
- class="control ${getStateClasses}"
707
- ${ref("_anchor")}
708
- id="control"
709
- ?disabled="${(x) => x.disabled}"
710
- >
711
- <div class="selected-value">
712
- ${(x) => affixIconTemplate(x.icon, IconWrapper.Slot)}
713
- <span class="text">${(x) => x.displayValue}</span>
714
- <slot name="meta" ${slotted("metaSlottedContent")}></slot>
715
- </div>
716
- ${when((x) => x._shouldShowClearButton, renderClearButton(context))}
717
- ${chevronTemplate}
718
- </div>`;
719
- }
720
- function setFixedDropdownVarWidth(x) {
721
- return x.open && x.fixedDropdown ? `--_select-fixed-width: ${Math.round(x.getBoundingClientRect().width)}px` : null;
722
- }
723
- /**
724
- * @param context - element definition context
725
- */
726
- function renderControl(context) {
727
- const popupTag = context.tagFor(Popup);
728
- return html`
729
- <div class="label-wrapper" ?hidden=${(x) => !x._shouldShowLabelWrapper}>
730
- ${when((x) => x.label, renderLabel())}
731
- ${when((x) => x.multiple && x._shouldShowClearButton, renderClearButton(context))}
732
- <slot name="contextual-help" ${slotted("_contextualHelpSlottedContent")}></slot>
733
- </div>
734
- <div class="control-wrapper">
735
- ${when((x) => !x.multiple, selectValue(context))}
736
- <${popupTag} class="popup"
737
- style="${setFixedDropdownVarWidth}"
738
- ?open="${(x) => x.collapsible ? x.open : true}"
739
- :anchor="${(x) => x._anchor}"
740
- placement="bottom-start"
741
- strategy="${(x) => x.fixedDropdown ? null : "absolute"}">
742
- <div class="listbox"
743
- id="${(x) => x.listboxId}"
744
- role="listbox"
745
- aria-multiselectable="${(x) => x.multiple}"
746
- aria-label="${(x) => x.multiple && !x.label && x.ariaLabel ? x.ariaLabel : null}"
747
- aria-labelledby="${(x) => x.multiple && x.label ? "label" : null}"
748
- ?disabled="${(x) => x.disabled}"
749
- ?hidden="${(x) => x.collapsible ? !x.open : false}"
750
- ${ref("listbox")}>
751
- ${when((x) => x.placeholder, renderPlaceholder(context))}
752
- <slot
753
- ${slotted({
754
- filter: Listbox.slottedOptionFilter,
755
- flatten: true,
756
- property: "slottedOptions"
757
- })}>
758
- </slot>
759
- </div>
760
- </${popupTag}>
761
- </div>
762
- `;
763
- }
746
+ getAllowedMarksForNode(nodeName) {
747
+ return this.specs.filter((spec) => !spec.onNodeName || spec.onNodeName === nodeName).map((spec) => spec.markName);
748
+ }
749
+ getReferencedNodeNames() {
750
+ return new Set(this.specs.map((spec) => spec.onNodeName).filter(Boolean));
751
+ }
752
+ };
753
+ //#endregion
754
+ //#region src/lib/rich-text-editor/rte/view.ts
764
755
  /**
765
- * Ignore events that originate from feedback, e.g. a click on link
756
+ * Converts an RteDocument to an RteView tree for rendering outside the editor.
757
+ * The logic is adapted from ProseMirror's DOM serialization to ensure the resulting structure
758
+ * matches the editor's HTML structure.
766
759
  */
767
- function ifNotFromFeedback(handler) {
768
- return (x, c) => {
769
- if (!c.event.composedPath().includes(x._feedbackWrapper)) {
770
- handler(x, c.event);
771
- return;
772
- }
760
+ var convertToView = (doc, ctx) => {
761
+ const schema = ctx.config[impl].schema;
762
+ const getMarkRank = (mark) => schema.marks[mark.type].rank;
763
+ const marksEqual = (a, b) => {
764
+ if (a.type !== b.type) return false;
765
+ const attrsA = a.attrs;
766
+ const attrsB = b.attrs;
767
+ if (attrsA === attrsB) return true;
768
+ /* v8 ignore next -- not currently reachable since all attrs are required @preserve */
769
+ if (!attrsA || !attrsB) return false;
770
+ const keysA = Object.keys(attrsA);
771
+ const keysB = Object.keys(attrsB);
772
+ /* v8 ignore next -- not currently reachable since all attrs are required @preserve */
773
+ if (keysA.length !== keysB.length) return false;
774
+ for (const key of keysA) if (attrsA[key] !== attrsB[key]) return false;
773
775
  return true;
774
776
  };
775
- }
776
- var SelectTemplate = (context) => {
777
- return html`
778
- <template
779
- ${applyHostSemantics({
780
- role: "combobox",
781
- ariaLabel: (x) => x.ariaLabel ?? x.label,
782
- ariaHasPopup: (x) => x.collapsible ? "listbox" : "false",
783
- ariaExpanded: (x) => x.open,
784
- ariaDisabled: (x) => x.disabled
785
- })}
786
- aria-controls="${(x) => x.listboxId}"
787
- aria-activedescendant="${(x) => x.open ? x._activeDescendant : null}"
788
- aria-describedby="${(x) => x._feedbackDescribedBy}"
789
- tabindex="${(x) => !x.disabled ? "0" : null}"
790
- @click="${ifNotFromFeedback((x, e) => x.clickHandler(e))}"
791
- @focusin="${ifNotFromFeedback((x, e) => x.focusinHandler(e))}"
792
- @focusout="${ifNotFromFeedback((x, e) => x.focusoutHandler(e))}"
793
- @keydown="${ifNotFromFeedback((x, e) => {
794
- if (x.open) handleEscapeKeyAndStopPropogation(e);
795
- return x.keydownHandler(e);
796
- })}"
797
- @mousedown="${ifNotFromFeedback((x, e) => x.mousedownHandler(e))}"
798
- >
799
- ${renderControl(context)}
800
- <div class="feedback-wrapper" ${ref("_feedbackWrapper")}>
801
- ${(x) => x._getFeedbackTemplate(context)}
802
- </div>
803
- </template>
804
- `;
777
+ const convertFragment = (nodes) => {
778
+ const result = [];
779
+ const active = [];
780
+ const activeContents = [result];
781
+ for (const node of nodes) {
782
+ const nodeMarks = [...node.marks ?? []].sort((a, b) => getMarkRank(a) - getMarkRank(b));
783
+ let keep = 0;
784
+ let rendered = 0;
785
+ while (keep < active.length && rendered < nodeMarks.length) {
786
+ if (!marksEqual(active[keep], nodeMarks[rendered])) break;
787
+ keep++;
788
+ rendered++;
789
+ }
790
+ while (active.length > keep) {
791
+ active.pop();
792
+ activeContents.pop();
793
+ }
794
+ while (rendered < nodeMarks.length) {
795
+ const mark = nodeMarks[rendered];
796
+ const markContent = [];
797
+ activeContents[activeContents.length - 1].push({
798
+ type: "mark",
799
+ mark,
800
+ children: {
801
+ type: "fragment",
802
+ content: markContent,
803
+ [impl]: ctx
804
+ },
805
+ [impl]: ctx
806
+ });
807
+ active.push(mark);
808
+ activeContents.push(markContent);
809
+ rendered++;
810
+ }
811
+ activeContents[activeContents.length - 1].push({
812
+ type: "node",
813
+ node,
814
+ children: convertFragment(node.content ?? []),
815
+ [impl]: ctx
816
+ });
817
+ }
818
+ return {
819
+ type: "fragment",
820
+ content: result,
821
+ [impl]: ctx
822
+ };
823
+ };
824
+ return {
825
+ type: "node",
826
+ node: doc,
827
+ children: convertFragment(doc.content),
828
+ [impl]: ctx
829
+ };
805
830
  };
806
831
  //#endregion
807
- //#region src/lib/select/definition.ts
808
- /**
809
- * @internal
810
- */
811
- var selectDefinition = defineVividComponent("select", Select, SelectTemplate, [
812
- popupDefinition,
813
- iconDefinition,
832
+ //#region src/lib/rich-text-editor/rte/config.ts
833
+ var RteConfig = class {
834
+ constructor(features) {
835
+ this[impl] = new RteConfigImpl(features);
836
+ }
837
+ instantiateEditor(options) {
838
+ return new RteInstance(this, options);
839
+ }
840
+ instantiateView(document, options) {
841
+ return convertToView(document, {
842
+ config: this,
843
+ options: { ...options }
844
+ });
845
+ }
846
+ };
847
+ var RteConfigImpl = class {
848
+ constructor(featuresFacades) {
849
+ const resolveFeatures = (features) => features.flatMap((f) => f.getFeatures().flatMap((subFeature) => subFeature === f ? f : resolveFeatures([subFeature])));
850
+ this.features = resolveFeatures(featuresFacades.map(getFeatureImpl));
851
+ this.featureMap = /* @__PURE__ */ new Map();
852
+ for (const f of this.features) {
853
+ if (this.featureMap.has(f.name)) throw new Error(`Duplicate feature: ${f.name}`);
854
+ this.featureMap.set(f.name, f);
855
+ }
856
+ this.featureFacadesMap = /* @__PURE__ */ new Map();
857
+ for (const facade of featuresFacades) {
858
+ const FacadeClass = facade.constructor;
859
+ const feature = getFeatureImpl(facade);
860
+ const instances = this.featureFacadesMap.get(FacadeClass);
861
+ if (instances) instances.push(feature);
862
+ else this.featureFacadesMap.set(FacadeClass, [feature]);
863
+ }
864
+ if (!this.featureMap.has("RteBase")) throw new Error("RteBase feature is required");
865
+ if (this.featureMap.has("RteLinkFeature") && !this.featureMap.has("RteToolbarFeature")) throw new Error("RteToolbarFeature is required for RteLinkFeature");
866
+ this.textblockAttrs = new TextblockAttrs(sortedContributions(this.features.flatMap((f) => f.getTextblockAttrs())));
867
+ this.textblockMarks = new TextblockMarks(sortedContributions(this.features.flatMap((f) => f.getTextblockMarks())));
868
+ const schemaContributions = sortedContributions(this.features.flatMap((f) => f.getSchema(this.textblockAttrs, this.textblockMarks)));
869
+ const schemaSpec = {
870
+ nodes: {},
871
+ marks: {}
872
+ };
873
+ for (const schema of schemaContributions) {
874
+ Object.assign(schemaSpec.nodes, schema.nodes ?? {});
875
+ Object.assign(schemaSpec.marks, schema.marks ?? {});
876
+ }
877
+ for (const referencedNodeName of this.textblockMarks.getReferencedNodeNames()) if (!(referencedNodeName in schemaSpec.nodes)) throw new Error(`Unknown node "${referencedNodeName}"`);
878
+ this.schema = new Schema(schemaSpec);
879
+ }
880
+ };
881
+ //#endregion
882
+ //#region src/lib/rich-text-editor/rte/utils/ui.ts
883
+ var isPropBinding = (prop) => typeof prop === "function";
884
+ var on = (event, prop, handler) => [
885
+ event,
886
+ prop,
887
+ handler
888
+ ];
889
+ var UiCtx = class {
890
+ constructor(view, rte, props) {
891
+ this.view = view;
892
+ this.rte = rte;
893
+ this.props = props;
894
+ this.bindings = [];
895
+ }
896
+ /** Evaluates a prop, returning its current value. */
897
+ evalProp(prop) {
898
+ return isPropBinding(prop) ? prop(this) : prop;
899
+ }
900
+ /** On every state change, prop is re-evaluated and passed to bindFn. */
901
+ bindProp(prop, bindFn) {
902
+ if (prop === void 0) return;
903
+ else if (isPropBinding(prop)) {
904
+ const binding = () => bindFn(prop(this));
905
+ this.bindings.push(binding);
906
+ binding();
907
+ } else bindFn(prop);
908
+ }
909
+ /** To be called on each state update to refresh all bindings. */
910
+ updateBindings() {
911
+ for (const binding of this.bindings) binding();
912
+ }
913
+ /** Whether to return focus to the editor after a toolbar action */
914
+ shouldReturnFocusToEditor() {
915
+ return this.evalProp(this.props.shouldReturnFocusToEditor);
916
+ }
917
+ /** Utility to more conveniently bind props to elements */
918
+ bindToEl(target, props = {}, events = [], children = []) {
919
+ for (const name in props) this.bindProp(props[name], (value) => {
920
+ target[name] = value;
921
+ });
922
+ for (const [name, value, bindFn] of events) if (value) target.addEventListener(name, bindFn(value));
923
+ for (const child of children) target.appendChild(child);
924
+ }
925
+ };
926
+ var createDiv = (ctx, props) => {
927
+ const div = document.createElement("div");
928
+ ctx.bindToEl(div, {
929
+ className: props.className,
930
+ slot: props.slot
931
+ }, [], props.children);
932
+ return div;
933
+ };
934
+ var createAnchor = (ctx, props) => {
935
+ const anchor = document.createElement("a");
936
+ ctx.bindToEl(anchor, {
937
+ href: props.href,
938
+ target: props.target,
939
+ rel: props.rel,
940
+ className: props.className
941
+ }, [], props.children);
942
+ return anchor;
943
+ };
944
+ var wrapperTargets = /* @__PURE__ */ new WeakMap();
945
+ var createOptionalTooltip = (ctx, props) => {
946
+ const tooltip = ctx.rte.createComponent(Tooltip);
947
+ tooltip.setAttribute("exportparts", "vvd-theme-alternate");
948
+ ctx.bindToEl(tooltip, {
949
+ className: "ui-tooltip",
950
+ text: props.label,
951
+ placement: ctx.props.popupPlacement
952
+ });
953
+ ctx.bindProp(props.enabled, (enabled) => {
954
+ if (!enabled) tooltip.open = false;
955
+ tooltip.anchor = enabled ? props.anchor : void 0;
956
+ });
957
+ const wrapper = createDiv(ctx, {
958
+ className: "ui-tooltip-wrapper",
959
+ slot: props.slot,
960
+ children: [props.anchor, tooltip]
961
+ });
962
+ wrapperTargets.set(wrapper, props.anchor);
963
+ return wrapper;
964
+ };
965
+ var createButton = (ctx, props) => {
966
+ const variant = () => ctx.evalProp(props.variant) ?? "toolbar";
967
+ const size = () => variant() === "toolbar" ? "super-condensed" : "condensed";
968
+ const appearanceInactive = () => variant() === "popover-primary" ? "outlined" : "ghost-light";
969
+ const appearanceActive = () => variant() === "toolbar-menu" || variant() === "popover" ? "filled" : appearanceInactive();
970
+ const appearance = () => ctx.evalProp(props.active) ? appearanceActive() : appearanceInactive();
971
+ const connotation = () => ctx.evalProp(props.connotation) ?? (variant() === "toolbar-menu" && ctx.evalProp(props.active) ? "cta" : void 0);
972
+ const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
973
+ const button = ctx.rte.createComponent(Button);
974
+ ctx.bindToEl(button, {
975
+ size,
976
+ appearance,
977
+ disabled,
978
+ icon: props.icon,
979
+ autofocus: props.autofocus,
980
+ connotation,
981
+ [props.icon ? "ariaLabel" : "label"]: props.label,
982
+ pressed: () => Boolean(ctx.evalProp(props.active)),
983
+ ariaPressed: props.active !== void 0 ? () => ctx.evalProp(props.active) ? "true" : "false" : void 0
984
+ }, [on("click", props.onClick, (onClick) => () => {
985
+ if (!onClick() && ctx.shouldReturnFocusToEditor()) ctx.view.focus();
986
+ })]);
987
+ return createOptionalTooltip(ctx, {
988
+ enabled: () => Boolean(ctx.evalProp(props.icon) && !ctx.evalProp(props.noTooltip) && !disabled()),
989
+ label: props.label,
990
+ anchor: button,
991
+ slot: props.slot
992
+ });
993
+ };
994
+ var createMenu = (ctx, props) => {
995
+ const menu = ctx.rte.createComponent(Menu);
996
+ ctx.bindToEl(menu, {
997
+ className: "ui-menu",
998
+ autoDismiss: true,
999
+ ariaLabel: props.label,
1000
+ anchor: wrapperTargets.get(props.trigger) ?? props.trigger,
1001
+ placement: ctx.props.popupPlacement,
1002
+ offset: () => ctx.evalProp(ctx.props.menuOffset) ?? null
1003
+ }, [], props.children);
1004
+ const fragment = document.createDocumentFragment();
1005
+ fragment.appendChild(props.trigger);
1006
+ fragment.appendChild(menu);
1007
+ return fragment;
1008
+ };
1009
+ var createMenuItem = (ctx, props) => {
1010
+ const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
1011
+ const item = ctx.rte.createComponent(MenuItem);
1012
+ ctx.bindToEl(item, {
1013
+ text: props.text,
1014
+ checked: props.checked,
1015
+ disabled,
1016
+ controlType: "radio",
1017
+ checkedAppearance: "tick-only"
1018
+ }, [on("change", props.onSelect, (onSelect) => () => {
1019
+ if (item.checked && !item.disabled) {
1020
+ if (ctx.evalProp(props.checked) !== item.checked) {
1021
+ onSelect();
1022
+ if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
1023
+ }
1024
+ }
1025
+ })]);
1026
+ return item;
1027
+ };
1028
+ var createButtonGroup = (ctx, props) => createDiv(ctx, {
1029
+ slot: props.slot,
1030
+ className: "ui-button-group",
1031
+ children: props.children
1032
+ });
1033
+ function markActive(state, type) {
1034
+ const { from, $from, to, empty } = state.selection;
1035
+ if (empty) return !!type.isInSet(state.storedMarks || $from.marks());
1036
+ else return state.doc.rangeHasMark(from, to, type);
1037
+ }
1038
+ var createMarkToggle = (ctx, props) => createButton(ctx, {
1039
+ label: props.label,
1040
+ icon: props.icon,
1041
+ active: () => markActive(ctx.view.state, props.markType),
1042
+ disabled: () => !toggleMark(props.markType)(ctx.view.state),
1043
+ onClick: () => {
1044
+ toggleMark(props.markType)(ctx.view.state, ctx.view.dispatch);
1045
+ }
1046
+ });
1047
+ var createOption = (ctx, props) => {
1048
+ const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled) || ctx.evalProp(props.disabled));
1049
+ const option = ctx.rte.createComponent(ListboxOption);
1050
+ ctx.bindToEl(option, {
1051
+ value: props.value,
1052
+ text: props.text,
1053
+ disabled
1054
+ });
1055
+ return option;
1056
+ };
1057
+ var createSelect = (ctx, props) => {
1058
+ const disabled = () => Boolean(ctx.evalProp(ctx.props.disabled));
1059
+ const select = ctx.rte.createComponent(Select);
1060
+ select.setAttribute("data-class", "ui-select");
1061
+ ctx.bindToEl(select, {
1062
+ placeholder: " ",
1063
+ ariaLabel: props.label,
1064
+ appearance: "ghost",
1065
+ disabled
1066
+ }, [on("change", props.onSelect, (onSelect) => () => {
1067
+ const value = select.value;
1068
+ if (value) {
1069
+ onSelect(value);
1070
+ if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
1071
+ }
1072
+ })], props.children);
1073
+ queueMicrotask(() => {
1074
+ ctx.bindProp(props.value, (value) => select.value = value);
1075
+ });
1076
+ let hideTooltip = false;
1077
+ select.addEventListener("vwc-popup:open", () => {
1078
+ hideTooltip = true;
1079
+ ctx.updateBindings();
1080
+ });
1081
+ select.addEventListener("vwc-popup:close", () => {
1082
+ hideTooltip = false;
1083
+ ctx.updateBindings();
1084
+ });
1085
+ return createOptionalTooltip(ctx, {
1086
+ enabled: () => !hideTooltip && !disabled(),
1087
+ label: props.label,
1088
+ anchor: select
1089
+ });
1090
+ };
1091
+ var createDivider = (ctx) => {
1092
+ const divider = ctx.rte.createComponent(Divider);
1093
+ ctx.bindToEl(divider, {
1094
+ className: "ui-divider",
1095
+ orientation: "vertical"
1096
+ });
1097
+ return divider;
1098
+ };
1099
+ var createTextField = (ctx, props) => {
1100
+ const textField = ctx.rte.createComponent(TextField);
1101
+ ctx.bindToEl(textField, {
1102
+ label: props.label,
1103
+ value: props.value,
1104
+ placeholder: props.placeholder,
1105
+ slot: props.slot,
1106
+ autofocus: props.autofocus,
1107
+ type: props.type,
1108
+ helperText: props.helperText
1109
+ }, [on("input", props.onInput, (onInput) => () => {
1110
+ onInput(textField.value);
1111
+ })]);
1112
+ return textField;
1113
+ };
1114
+ var createText = (ctx, props) => {
1115
+ const textNode = document.createTextNode("");
1116
+ ctx.bindToEl(textNode, { textContent: props.text });
1117
+ return textNode;
1118
+ };
1119
+ var createSingleSlot = (ctx, props) => {
1120
+ const slot = document.createElement("slot");
1121
+ slot.name = props.name;
1122
+ let currentEl = null;
1123
+ const listeners = [];
1124
+ function cleanup() {
1125
+ for (const { el, type, handler } of listeners) el.removeEventListener(type, handler);
1126
+ listeners.length = 0;
1127
+ currentEl = null;
1128
+ }
1129
+ for (const [key, prop] of Object.entries(props.assignedProps)) ctx.bindProp(prop, (value) => {
1130
+ if (currentEl) currentEl[key] = value;
1131
+ });
1132
+ function applyPropsAndEvents(el) {
1133
+ for (const [key, prop] of Object.entries(props.assignedProps)) el[key] = ctx.evalProp(prop);
1134
+ for (const [type, handler] of Object.entries(props.assignedEvents)) {
1135
+ const listener = (e) => {
1136
+ handler(e);
1137
+ if (ctx.shouldReturnFocusToEditor()) ctx.view.focus();
1138
+ };
1139
+ el.addEventListener(type, listener);
1140
+ listeners.push({
1141
+ el,
1142
+ type,
1143
+ handler: listener
1144
+ });
1145
+ }
1146
+ }
1147
+ const processSlot = () => {
1148
+ const first = slot.assignedElements({ flatten: true })[0];
1149
+ if (first === currentEl) return;
1150
+ cleanup();
1151
+ if (first) {
1152
+ currentEl = first;
1153
+ applyPropsAndEvents(first);
1154
+ }
1155
+ };
1156
+ slot.addEventListener("slotchange", processSlot);
1157
+ queueMicrotask(processSlot);
1158
+ return slot;
1159
+ };
1160
+ //#endregion
1161
+ //#region src/lib/rich-text-editor/rte/features/internal/history.ts
1162
+ var RteHistoryFeatureImpl = class extends RteFeatureImpl {
1163
+ constructor(config) {
1164
+ super();
1165
+ this.config = config;
1166
+ this.name = "RteHistoryFeature";
1167
+ }
1168
+ getPlugins() {
1169
+ return [this.contribution(history()), this.contribution(keymap({
1170
+ "Mod-z": undo,
1171
+ "Ctrl-y": redo,
1172
+ "Cmd-Z": redo
1173
+ }))];
1174
+ }
1175
+ getToolbarItems() {
1176
+ if (!this.config.showToolbarButtons) return [];
1177
+ return [this.contribution({
1178
+ section: "history",
1179
+ render: (ctx) => createButton(ctx, {
1180
+ label: (ctx) => ctx.rte.getLocale().richTextEditor.undo,
1181
+ icon: "undo-line",
1182
+ disabled: (ctx) => !undo(ctx.view.state),
1183
+ onClick: () => {
1184
+ const { state, dispatch } = ctx.view;
1185
+ undo(state, dispatch);
1186
+ }
1187
+ })
1188
+ }, 1), this.contribution({
1189
+ section: "history",
1190
+ render: (ctx) => createButton(ctx, {
1191
+ label: (ctx) => ctx.rte.getLocale().richTextEditor.redo,
1192
+ icon: "redo-line",
1193
+ disabled: (ctx) => !redo(ctx.view.state),
1194
+ onClick: () => {
1195
+ const { state, dispatch } = ctx.view;
1196
+ redo(state, dispatch);
1197
+ }
1198
+ })
1199
+ }, 2)];
1200
+ }
1201
+ };
1202
+ //#endregion
1203
+ //#region src/lib/rich-text-editor/rte/features/internal/basic-text-blocks.style.scss?inline
1204
+ var basic_text_blocks_style_default = "h1,h2,h3,p{all:unset;display:block}h1:first-child,h2:first-child,h3:first-child,p:first-child{margin-block-start:0}h1:last-child,h2:last-child,h3:last-child,p:last-child{margin-block-end:0}p{font:var(--vvd-typography-base);font-variant-ligatures:unset;font-feature-settings:unset;margin-block:16px;line-height:20px}.heading-step-1{font:var(--vvd-typography-heading-4);font-variant-ligatures:unset;font-feature-settings:unset;margin-block:24px 12px;line-height:28px}.heading-step-2{font:var(--vvd-typography-heading-3);font-variant-ligatures:unset;font-feature-settings:unset;margin-block:24px 12px;line-height:36px}.heading-step-3{font:var(--vvd-typography-heading-2);font-variant-ligatures:unset;font-feature-settings:unset;margin-block:32px 16px;line-height:42px}";
1205
+ //#endregion
1206
+ //#region src/lib/rich-text-editor/rte/features/internal/basic-text-blocks.ts
1207
+ var RteBasicTextBlocksImpl = class extends RteFeatureImpl {
1208
+ constructor(enabledBlocks) {
1209
+ super();
1210
+ this.enabledBlocks = enabledBlocks;
1211
+ this.name = "RteBasicTextBlocks";
1212
+ }
1213
+ getStyles() {
1214
+ return [this.contribution(basic_text_blocks_style_default)];
1215
+ }
1216
+ getSchema(textblockAttrs, textblockMarks) {
1217
+ const nodes = {};
1218
+ if (this.enabledBlocks.paragraph) nodes["paragraph"] = {
1219
+ group: "block",
1220
+ content: "inline*",
1221
+ attrs: { ...textblockAttrs.attrs },
1222
+ parseDOM: [{
1223
+ tag: "p",
1224
+ getAttrs: (dom) => textblockAttrs.fromDOM(dom)
1225
+ }],
1226
+ marks: textblockMarks.getAllowedMarksForNode("paragraph").join(" "),
1227
+ toDOM(node) {
1228
+ return [
1229
+ "p",
1230
+ {
1231
+ part: `node--paragraph`,
1232
+ ...textblockAttrs.getDOMAttrsProperties(node)
1233
+ },
1234
+ 0
1235
+ ];
1236
+ },
1237
+ serializeToDOM(node) {
1238
+ return [
1239
+ "p",
1240
+ ...textblockAttrs.getDOMAttrs(node),
1241
+ 0
1242
+ ];
1243
+ }
1244
+ };
1245
+ let headingCount = 0;
1246
+ for (const level of [
1247
+ 3,
1248
+ 2,
1249
+ 1
1250
+ ]) {
1251
+ const nodeName = `heading${level}`;
1252
+ const tag = `h${level}`;
1253
+ if (!this.enabledBlocks[nodeName]) continue;
1254
+ headingCount++;
1255
+ const visualLevel = headingCount;
1256
+ nodes[nodeName] = {
1257
+ group: "block",
1258
+ content: "inline*",
1259
+ attrs: { ...textblockAttrs.attrs },
1260
+ parseDOM: [{
1261
+ tag,
1262
+ getAttrs: (dom) => textblockAttrs.fromDOM(dom)
1263
+ }],
1264
+ marks: textblockMarks.getAllowedMarksForNode(nodeName).join(" "),
1265
+ defining: true,
1266
+ toDOM(node) {
1267
+ return [
1268
+ tag,
1269
+ {
1270
+ class: `heading-step-${visualLevel}`,
1271
+ part: `node--${nodeName}`,
1272
+ ...textblockAttrs.getDOMAttrsProperties(node)
1273
+ },
1274
+ 0
1275
+ ];
1276
+ },
1277
+ serializeToDOM(node) {
1278
+ return [
1279
+ tag,
1280
+ ...textblockAttrs.getDOMAttrs(node),
1281
+ 0
1282
+ ];
1283
+ }
1284
+ };
1285
+ }
1286
+ return [this.contribution({ nodes })];
1287
+ }
1288
+ getPlugins(rte) {
1289
+ const keyBindings = {};
1290
+ if (this.enabledBlocks.paragraph) keyBindings["Mod-Alt-0"] = this.setBlockType(rte, "paragraph");
1291
+ for (const level of [
1292
+ 1,
1293
+ 2,
1294
+ 3
1295
+ ]) {
1296
+ const nodeName = `heading${level}`;
1297
+ if (this.enabledBlocks[nodeName]) keyBindings[`Mod-Alt-${level}`] = this.setBlockType(rte, nodeName);
1298
+ }
1299
+ return [this.contribution(keymap(keyBindings))];
1300
+ }
1301
+ getCurrentBlockType(state) {
1302
+ const { $from, $to } = state.selection;
1303
+ const fromTopBlock = $from.depth === 0 ? state.doc.childAfter($from.pos).node : $from.node(1);
1304
+ if (fromTopBlock !== ($to.depth === 0 ? state.doc.childBefore($to.pos).node : $to.node(1))) return null;
1305
+ if (!(fromTopBlock.type.name in this.enabledBlocks)) return null;
1306
+ return fromTopBlock.type.name;
1307
+ }
1308
+ setBlockType(rte, name) {
1309
+ return (state, dispatch) => {
1310
+ const { from, to } = state.selection;
1311
+ const tr = state.tr;
1312
+ let supportedNodeFound = false;
1313
+ state.doc.nodesBetween(from, to, (node, pos) => {
1314
+ if (node.type.name in this.enabledBlocks) {
1315
+ supportedNodeFound = true;
1316
+ tr.setBlockType(pos, pos + node.nodeSize, state.schema.nodes[name], (oldNode) => rte.textblockAttrs.extractFromNode(oldNode));
1317
+ }
1318
+ return false;
1319
+ });
1320
+ if (!supportedNodeFound) return false;
1321
+ dispatch?.(tr);
1322
+ return true;
1323
+ };
1324
+ }
1325
+ };
1326
+ //#endregion
1327
+ //#region src/lib/rich-text-editor/rte/utils/text-before-cursor.ts
1328
+ /** Get the text content before the cursor position in the current text block. */
1329
+ var textBeforeCursor = ($cursor) => $cursor.parent.textBetween(0, $cursor.parentOffset, void 0, "");
1330
+ //#endregion
1331
+ //#region src/lib/rich-text-editor/rte/features/internal/input-rules.ts
1332
+ /** Aggregates all input rules from other features. */
1333
+ var RteInputRulesFeatureImpl = class extends RteFeatureImpl {
1334
+ constructor(..._args) {
1335
+ super(..._args);
1336
+ this.name = "RteInputRulesFeature";
1337
+ }
1338
+ getPlugins(rte) {
1339
+ const ruleSpecs = sortedContributions(rte.config.features.flatMap((f) => f.getInputRules(rte)));
1340
+ if (ruleSpecs.length === 0) return [];
1341
+ const plugins = [];
1342
+ const rules = ruleSpecs.map((spec) => spec.rule);
1343
+ plugins.push(this.contribution(inputRules({ rules })));
1344
+ plugins.push(this.contribution(keymap({ Backspace: undoInputRule }), contributionPriority.high));
1345
+ const enterHandlers = ruleSpecs.filter((spec) => spec.enterHandler).map((spec) => spec.enterHandler);
1346
+ if (enterHandlers.length > 0) plugins.push(this.contribution(keymap({ Enter: (state, dispatch) => {
1347
+ const { $cursor } = state.selection;
1348
+ if (!$cursor) return false;
1349
+ const textBefore = textBeforeCursor($cursor);
1350
+ for (const { regex, handler } of enterHandlers) {
1351
+ const match = regex.exec(textBefore);
1352
+ if (!match) continue;
1353
+ const matchStart = $cursor.pos - $cursor.parentOffset + match.index;
1354
+ const tr = handler(state, match, matchStart, matchStart + match[0].length);
1355
+ if (tr) dispatch?.(tr);
1356
+ break;
1357
+ }
1358
+ return false;
1359
+ } }), contributionPriority.highest));
1360
+ return plugins;
1361
+ }
1362
+ };
1363
+ //#endregion
1364
+ //#region src/lib/rich-text-editor/rte/features/base.ts
1365
+ var RteBaseImpl = class extends RteFeatureImpl {
1366
+ constructor(config) {
1367
+ super();
1368
+ this.config = config;
1369
+ this.name = "RteBase";
1370
+ }
1371
+ getSchema() {
1372
+ return [this.contribution({ nodes: {
1373
+ doc: { content: "block+" },
1374
+ text: { group: "inline" }
1375
+ } })];
1376
+ }
1377
+ getFeatures() {
1378
+ return [
1379
+ this,
1380
+ new RteCoreImpl(),
1381
+ new RteHistoryFeatureImpl({ showToolbarButtons: this.config?.historyToolbarButtons ?? true }),
1382
+ new RteBasicTextBlocksImpl({
1383
+ heading1: this.config?.heading1 ?? false,
1384
+ heading2: this.config?.heading2 ?? false,
1385
+ heading3: this.config?.heading3 ?? false,
1386
+ paragraph: this.config?.paragraph ?? true
1387
+ }),
1388
+ new RteInputRulesFeatureImpl()
1389
+ ];
1390
+ }
1391
+ getPublicInterface(rte) {
1392
+ const core = rte.getFeature("RteCore");
1393
+ return {
1394
+ get disabled() {
1395
+ return core.disabled.getValue(rte);
1396
+ },
1397
+ set disabled(value) {
1398
+ core.disabled.setValue(rte, value);
1399
+ },
1400
+ get scrollThreshold() {
1401
+ return core.scrollThreshold;
1402
+ },
1403
+ set scrollThreshold(value) {
1404
+ core.scrollThreshold = value;
1405
+ rte.view?.setProps({ scrollThreshold: value });
1406
+ },
1407
+ get scrollMargin() {
1408
+ return core.scrollMargin;
1409
+ },
1410
+ set scrollMargin(value) {
1411
+ core.scrollMargin = value;
1412
+ rte.view?.setProps({ scrollMargin: value });
1413
+ }
1414
+ };
1415
+ }
1416
+ };
1417
+ var RteBase = featureFacade(RteBaseImpl);
1418
+ //#endregion
1419
+ //#region src/lib/rich-text-editor/rte/features/text-block-picker.ts
1420
+ var RteTextBlockPickerFeatureImpl = class extends RteFeatureImpl {
1421
+ constructor(config) {
1422
+ super();
1423
+ this.config = config;
1424
+ this.name = "RteTextBlockPickerFeature";
1425
+ }
1426
+ getToolbarItems(rte) {
1427
+ const blocks = rte.getFeature("RteBasicTextBlocks");
1428
+ return [this.contribution({
1429
+ section: "font",
1430
+ render: (ctx) => {
1431
+ return createSelect(ctx, {
1432
+ label: () => ctx.rte.getLocale().richTextEditor.paragraphStyles,
1433
+ value: (ctx) => blocks.getCurrentBlockType(ctx.view.state) ?? "",
1434
+ onSelect: (value) => {
1435
+ const { state, dispatch } = ctx.view;
1436
+ blocks.setBlockType(rte, value)(state, dispatch);
1437
+ },
1438
+ children: this.config.options.map((opt) => createOption(ctx, {
1439
+ text: opt.label,
1440
+ value: opt.node,
1441
+ disabled: () => !blocks.setBlockType(rte, opt.node)(ctx.view.state)
1442
+ }))
1443
+ });
1444
+ }
1445
+ }, 1)];
1446
+ }
1447
+ };
1448
+ var RteTextBlockPickerFeature = featureFacade(RteTextBlockPickerFeatureImpl);
1449
+ //#endregion
1450
+ //#region src/lib/rich-text-editor/rte/features/toolbar.style.scss?inline
1451
+ var toolbar_style_default = ".toolbar{background-color:var(--vvd-color-neutral-50);flex-wrap:wrap;align-items:center;gap:8px;padding:4px;display:flex}.toolbar--hidden{display:none}";
1452
+ //#endregion
1453
+ //#region src/lib/rich-text-editor/rte/features/toolbar.ts
1454
+ var RteToolbarFeatureImpl = class extends RteFeatureImpl {
1455
+ constructor(config) {
1456
+ super();
1457
+ this.config = config;
1458
+ this.name = "RteToolbarFeature";
1459
+ this.hidden = new FeatureState(false);
1460
+ }
1461
+ getStyles() {
1462
+ return [this.contribution(toolbar_style_default)];
1463
+ }
1464
+ getPlugins(rte) {
1465
+ const sections = [
1466
+ "history",
1467
+ "font",
1468
+ "text-style",
1469
+ "textblock",
1470
+ "insert"
1471
+ ];
1472
+ const itemsBySection = new Map(sections.map((section) => [section, []]));
1473
+ for (const toolbarItem of sortedContributions(rte.features.flatMap((f) => f.getToolbarItems(rte)))) itemsBySection.get(toolbarItem.section).push(toolbarItem);
1474
+ const core = rte.getFeature("RteCore");
1475
+ return [this.contribution(this.hidden.plugin), this.contribution(new Plugin({ view: (view) => {
1476
+ let focusCameFromEditorWithMouse = false;
1477
+ const ctx = new UiCtx(view, rte, {
1478
+ popupPlacement: this.config?.popupDirection === "outward" ? "bottom" : "top",
1479
+ menuOffset: 8,
1480
+ disabled: () => core.disabled.getValue(rte),
1481
+ shouldReturnFocusToEditor: () => focusCameFromEditorWithMouse
1482
+ });
1483
+ const toolbar = view.dom.getRootNode().querySelector(".toolbar");
1484
+ let mouseDownTime = -Infinity;
1485
+ const onMouseDown = () => {
1486
+ if (view.hasFocus()) focusCameFromEditorWithMouse = true;
1487
+ mouseDownTime = Date.now();
1488
+ };
1489
+ const onFocusIn = () => {
1490
+ if (Date.now() - mouseDownTime > 250) focusCameFromEditorWithMouse = false;
1491
+ };
1492
+ const onFocusOut = (e) => {
1493
+ if (!toolbar.contains(e.relatedTarget)) focusCameFromEditorWithMouse = false;
1494
+ };
1495
+ toolbar.addEventListener("mousedown", onMouseDown, { capture: true });
1496
+ toolbar.addEventListener("focusin", onFocusIn);
1497
+ toolbar.addEventListener("focusout", onFocusOut);
1498
+ ctx.bindProp(() => this.hidden.getValue(rte), (hidden) => {
1499
+ toolbar.classList.toggle("toolbar--hidden", hidden);
1500
+ });
1501
+ let openSection = false;
1502
+ for (const section of sections) {
1503
+ const items = itemsBySection.get(section);
1504
+ if (items.length && openSection) {
1505
+ toolbar.appendChild(createDivider(ctx));
1506
+ openSection = false;
1507
+ }
1508
+ for (const toolbarItemSpec of items) {
1509
+ toolbar.appendChild(toolbarItemSpec.render(ctx));
1510
+ openSection = true;
1511
+ }
1512
+ }
1513
+ return {
1514
+ update() {
1515
+ ctx.updateBindings();
1516
+ },
1517
+ destroy() {
1518
+ toolbar.innerHTML = "";
1519
+ toolbar.removeEventListener("mousedown", onMouseDown, { capture: true });
1520
+ toolbar.removeEventListener("focusin", onFocusIn);
1521
+ toolbar.removeEventListener("focusout", onFocusOut);
1522
+ focusCameFromEditorWithMouse = false;
1523
+ }
1524
+ };
1525
+ } }))];
1526
+ }
1527
+ getPublicInterface(rte) {
1528
+ const hidden = this.hidden;
1529
+ return {
1530
+ get hidden() {
1531
+ return hidden.getValue(rte);
1532
+ },
1533
+ set hidden(value) {
1534
+ hidden.setValue(rte, value);
1535
+ }
1536
+ };
1537
+ }
1538
+ };
1539
+ var RteToolbarFeature = featureFacade(RteToolbarFeatureImpl);
1540
+ //#endregion
1541
+ //#region src/lib/rich-text-editor/rte/features/placeholder.style.scss?inline
1542
+ var placeholder_style_default = ".placeholder{display:contents}.placeholder:before{color:var(--vvd-color-neutral-600);content:attr(data-placeholder);font-size:var(--placeholder-font-size,inherit);inset-inline:var(--editor-padding-inline);line-height:inherit;pointer-events:none;position:absolute}.editor--disabled .placeholder:before{color:var(--vvd-color-neutral-300)}";
1543
+ //#endregion
1544
+ //#region src/lib/rich-text-editor/rte/features/placeholder.ts
1545
+ var RtePlaceholderFeatureImpl = class extends RteFeatureImpl {
1546
+ constructor(config) {
1547
+ super();
1548
+ this.config = config;
1549
+ this.name = "RtePlaceholderFeature";
1550
+ }
1551
+ getStyles() {
1552
+ return [this.contribution(placeholder_style_default)];
1553
+ }
1554
+ getPlugins() {
1555
+ const placeholderPlugin = new Plugin({ props: { decorations: (state) => {
1556
+ if (state.doc.nodeSize === 4) {
1557
+ const storedSize = state.schema.marks.fontSize?.isInSet(state.storedMarks ?? [])?.attrs.size;
1558
+ return DecorationSet.create(state.doc, [Decoration.widget(1, () => {
1559
+ const placeholder = document.createElement("span");
1560
+ placeholder.className = "placeholder";
1561
+ placeholder.dataset.placeholder = this.config.text;
1562
+ if (storedSize) placeholder.style.setProperty("--placeholder-font-size", storedSize);
1563
+ return placeholder;
1564
+ })]);
1565
+ }
1566
+ return null;
1567
+ } } });
1568
+ return [this.contribution(placeholderPlugin)];
1569
+ }
1570
+ };
1571
+ var RtePlaceholderFeature = featureFacade(RtePlaceholderFeatureImpl);
1572
+ //#endregion
1573
+ //#region src/lib/rich-text-editor/rte/features/hard-break.ts
1574
+ var RteHardBreakFeatureImpl = class extends RteFeatureImpl {
1575
+ constructor(..._args) {
1576
+ super(..._args);
1577
+ this.name = "RteHardBreakFeature";
1578
+ }
1579
+ getSchema() {
1580
+ return [this.contribution({ nodes: { hardBreak: {
1581
+ inline: true,
1582
+ group: "inline",
1583
+ selectable: false,
1584
+ parseDOM: [{ tag: "br" }],
1585
+ toDOM() {
1586
+ return ["br"];
1587
+ }
1588
+ } } })];
1589
+ }
1590
+ getPlugins(_rte) {
1591
+ const forceBreak = (state, dispatch) => {
1592
+ const marks = state.storedMarks || state.selection.$from.marks();
1593
+ const tr = state.tr.replaceSelectionWith(state.schema.nodes.hardBreak.create(), true).scrollIntoView();
1594
+ if (marks.length) tr.setStoredMarks(marks);
1595
+ dispatch?.(tr);
1596
+ return true;
1597
+ };
1598
+ const keyBindings = { "Shift-Enter": forceBreak };
1599
+ return [this.contribution(keymap(keyBindings), contributionPriority.high)];
1600
+ }
1601
+ };
1602
+ var RteHardBreakFeature = featureFacade(RteHardBreakFeatureImpl);
1603
+ //#endregion
1604
+ //#region src/lib/rich-text-editor/rte/features/font-size-picker.ts
1605
+ var mixedFontSize = Symbol("mixedFontSize");
1606
+ var RteFontSizePickerFeatureImpl = class extends RteFeatureImpl {
1607
+ constructor(config) {
1608
+ super();
1609
+ this.config = config;
1610
+ this.name = "RteFontSizePickerFeature";
1611
+ this.fontSizes = config.options;
1612
+ if (config.onBlocks) {
1613
+ this.defaultFontSizeForNode = {};
1614
+ for (const block of config.onBlocks) this.defaultFontSizeForNode[block.node] = block.defaultSize ?? null;
1615
+ }
1616
+ }
1617
+ getTextblockMarks() {
1618
+ if (this.config?.onBlocks) return this.config.onBlocks.map((block) => this.contribution({
1619
+ markName: "fontSize",
1620
+ onNodeName: block.node
1621
+ }));
1622
+ return [this.contribution({ markName: "fontSize" })];
1623
+ }
1624
+ getSchema() {
1625
+ return [this.contribution({ marks: { fontSize: {
1626
+ attrs: { size: { validate: "string" } },
1627
+ parseDOM: [{
1628
+ tag: "span[style*='font-size']",
1629
+ getAttrs: (node) => {
1630
+ const size = node.getAttribute("style").match(/font-size:\s*([^;]+)/)?.[1]?.trim();
1631
+ if (size) return { size };
1632
+ return false;
1633
+ }
1634
+ }],
1635
+ toDOM: (mark) => {
1636
+ return [
1637
+ "span",
1638
+ { style: `font-size: ${escapeCssProperty(mark.attrs.size)};` },
1639
+ 0
1640
+ ];
1641
+ },
1642
+ cursorFix: ($cursor, state) => {
1643
+ const storedMarks = state.storedMarks;
1644
+ if (!storedMarks) return null;
1645
+ const fontSizeMark = storedMarks.find((m) => m.type.name === "fontSize");
1646
+ if (fontSizeMark) return { style: { "font-size": fontSizeMark.attrs.size } };
1647
+ if (storedMarks.length === 0) {
1648
+ const defaultSize = this.defaultFontSizeForNode?.[$cursor.parent.type.name];
1649
+ if (defaultSize) return { style: { "font-size": defaultSize } };
1650
+ }
1651
+ return null;
1652
+ }
1653
+ } } })];
1654
+ }
1655
+ getPlugins() {
1656
+ return [this.contribution(keymap({
1657
+ "Mod-Shift-.": this.adjustFontSize(-1),
1658
+ "Mod-Shift-,": this.adjustFontSize(1)
1659
+ }))];
1660
+ }
1661
+ getToolbarItems(rte) {
1662
+ return [this.contribution({
1663
+ section: "font",
1664
+ render: (ctx) => createMenu(ctx, {
1665
+ label: () => rte.getLocale().richTextEditor.textSize,
1666
+ trigger: createButton(ctx, {
1667
+ label: () => rte.getLocale().richTextEditor.textSize,
1668
+ icon: "text-size-line"
1669
+ }),
1670
+ children: this.fontSizes.map((fs) => createMenuItem(ctx, {
1671
+ text: fs.label,
1672
+ checked: () => this.getFontSizeFromSelection(ctx.view.state) === fs.size,
1673
+ disabled: () => !this.setFontSize(fs.size)(ctx.view.state),
1674
+ onSelect: () => {
1675
+ const { state, dispatch } = ctx.view;
1676
+ this.setFontSize(fs.size)(state, dispatch);
1677
+ }
1678
+ }))
1679
+ })
1680
+ }, 2)];
1681
+ }
1682
+ getFontSizeFromSelection(state) {
1683
+ const { from, to, $from, empty } = state.selection;
1684
+ const { fontSize } = state.schema.marks;
1685
+ if (empty) {
1686
+ const defaultSize = this.defaultFontSizeForNode?.[$from.parent.type.name] ?? null;
1687
+ return fontSize.isInSet(state.storedMarks || $from.marks())?.attrs.size ?? defaultSize;
1688
+ }
1689
+ let size = null;
1690
+ const observeSize = (observedSize) => {
1691
+ if (size === null) size = observedSize ?? null;
1692
+ else if (observedSize !== size) size = mixedFontSize;
1693
+ };
1694
+ state.doc.nodesBetween(from, to, (node, _, parent) => {
1695
+ if (size === mixedFontSize) return false;
1696
+ if (!node.isLeaf) {
1697
+ if (node.type.allowsMarkType(fontSize) && node.childCount === 0) observeSize(this.defaultFontSizeForNode?.[node.type.name]);
1698
+ return true;
1699
+ }
1700
+ observeSize(fontSize.isInSet(node.marks)?.attrs.size ?? (parent && this.defaultFontSizeForNode?.[parent.type.name]));
1701
+ return true;
1702
+ });
1703
+ return size;
1704
+ }
1705
+ setFontSize(size) {
1706
+ return (state, dispatch) => {
1707
+ const { from, to, empty, $from } = state.selection;
1708
+ const { fontSize } = state.schema.marks;
1709
+ if (!toggleMark(fontSize, { size })(state)) return false;
1710
+ const tr = state.tr;
1711
+ if (empty) {
1712
+ const newStoredMarks = (state.storedMarks || []).filter((m) => m.type !== fontSize);
1713
+ if (size !== this.defaultFontSizeForNode?.[$from.parent.type.name]) newStoredMarks.push(fontSize.create({ size }));
1714
+ tr.setStoredMarks(newStoredMarks);
1715
+ } else {
1716
+ tr.addMark(from, to, fontSize.create({ size }));
1717
+ tr.doc.nodesBetween(from, to, (node, pos, parent) => {
1718
+ if (!node.isInline) return;
1719
+ const mark = fontSize.isInSet(node.marks);
1720
+ const defaultSize = this.defaultFontSizeForNode?.[parent.type.name];
1721
+ if (mark && mark.attrs.size === defaultSize) tr.step(new RemoveMarkStep(pos, pos + node.nodeSize, mark));
1722
+ });
1723
+ }
1724
+ dispatch?.(tr.scrollIntoView());
1725
+ return true;
1726
+ };
1727
+ }
1728
+ adjustFontSize(adjustment) {
1729
+ return (state, dispatch) => {
1730
+ const currentSize = this.getFontSizeFromSelection(state);
1731
+ if (currentSize === null || currentSize === mixedFontSize) return false;
1732
+ const nextIndex = this.fontSizes.findIndex((fs) => fs.size === currentSize) + adjustment;
1733
+ if (nextIndex < 0 || nextIndex >= this.fontSizes.length) return false;
1734
+ return this.setFontSize(this.fontSizes[nextIndex].size)(state, dispatch);
1735
+ };
1736
+ }
1737
+ };
1738
+ var RteFontSizePickerFeature = featureFacade(RteFontSizePickerFeatureImpl);
1739
+ //#endregion
1740
+ //#region src/lib/rich-text-editor/rte/features/internal/text-style.ts
1741
+ var RteTextStyleFeatureImpl = class extends RteFeatureImpl {
1742
+ constructor(config) {
1743
+ super();
1744
+ this.config = config;
1745
+ }
1746
+ getTextblockMarks() {
1747
+ if (this.config?.onBlocks) return this.config.onBlocks.map((block) => this.contribution({
1748
+ markName: this.markName,
1749
+ onNodeName: block.node
1750
+ }));
1751
+ return [this.contribution({ markName: this.markName })];
1752
+ }
1753
+ };
1754
+ //#endregion
1755
+ //#region src/lib/rich-text-editor/rte/features/bold.ts
1756
+ var RteBoldFeatureImpl = class extends RteTextStyleFeatureImpl {
1757
+ constructor(..._args) {
1758
+ super(..._args);
1759
+ this.name = "RteBoldFeature";
1760
+ this.markName = "bold";
1761
+ }
1762
+ getSchema() {
1763
+ return [this.contribution({ marks: { bold: marks.strong } })];
1764
+ }
1765
+ getPlugins(rte) {
1766
+ return [this.contribution(keymap({ "Mod-b": toggleMark(rte.schema.marks.bold) }))];
1767
+ }
1768
+ getToolbarItems(rte) {
1769
+ return [this.contribution({
1770
+ section: "text-style",
1771
+ render: (ctx) => createMarkToggle(ctx, {
1772
+ label: () => ctx.rte.getLocale().richTextEditor.bold,
1773
+ icon: "bold-line",
1774
+ markType: rte.schema.marks.bold
1775
+ })
1776
+ }, 1)];
1777
+ }
1778
+ };
1779
+ var RteBoldFeature = featureFacade(RteBoldFeatureImpl);
1780
+ //#endregion
1781
+ //#region src/lib/rich-text-editor/rte/features/italic.ts
1782
+ var RteItalicFeatureImpl = class extends RteTextStyleFeatureImpl {
1783
+ constructor(..._args) {
1784
+ super(..._args);
1785
+ this.name = "RteItalicFeature";
1786
+ this.markName = "italic";
1787
+ }
1788
+ getSchema() {
1789
+ return [this.contribution({ marks: { italic: marks.em } })];
1790
+ }
1791
+ getPlugins(rte) {
1792
+ return [this.contribution(keymap({ "Mod-i": toggleMark(rte.schema.marks.italic) }))];
1793
+ }
1794
+ getToolbarItems(rte) {
1795
+ return [this.contribution({
1796
+ section: "text-style",
1797
+ render: (ctx) => createMarkToggle(ctx, {
1798
+ label: () => ctx.rte.getLocale().richTextEditor.italic,
1799
+ icon: "italic-line",
1800
+ markType: rte.schema.marks.italic
1801
+ })
1802
+ }, 2)];
1803
+ }
1804
+ };
1805
+ var RteItalicFeature = featureFacade(RteItalicFeatureImpl);
1806
+ //#endregion
1807
+ //#region src/lib/rich-text-editor/rte/features/underline.ts
1808
+ var RteUnderlineFeatureImpl = class extends RteTextStyleFeatureImpl {
1809
+ constructor(..._args) {
1810
+ super(..._args);
1811
+ this.name = "RteUnderlineFeature";
1812
+ this.markName = "underline";
1813
+ }
1814
+ getSchema() {
1815
+ return [this.contribution({ marks: { underline: {
1816
+ parseDOM: [{ tag: "u" }],
1817
+ toDOM() {
1818
+ return ["u", 0];
1819
+ }
1820
+ } } })];
1821
+ }
1822
+ getPlugins(rte) {
1823
+ return [this.contribution(keymap({ "Mod-u": toggleMark(rte.schema.marks.underline) }))];
1824
+ }
1825
+ getToolbarItems(rte) {
1826
+ return [this.contribution({
1827
+ section: "text-style",
1828
+ render: (ctx) => createMarkToggle(ctx, {
1829
+ label: () => ctx.rte.getLocale().richTextEditor.underline,
1830
+ icon: "underline-line",
1831
+ markType: rte.schema.marks.underline
1832
+ })
1833
+ }, 3)];
1834
+ }
1835
+ };
1836
+ var RteUnderlineFeature = featureFacade(RteUnderlineFeatureImpl);
1837
+ //#endregion
1838
+ //#region src/lib/rich-text-editor/rte/features/strikethrough.ts
1839
+ var RteStrikethroughFeatureImpl = class extends RteTextStyleFeatureImpl {
1840
+ constructor(..._args) {
1841
+ super(..._args);
1842
+ this.name = "RteStrikethroughFeature";
1843
+ this.markName = "strikethrough";
1844
+ }
1845
+ getSchema() {
1846
+ return [this.contribution({ marks: { strikethrough: {
1847
+ parseDOM: [{ tag: "s" }, { tag: "del" }],
1848
+ toDOM() {
1849
+ return ["s", 0];
1850
+ }
1851
+ } } })];
1852
+ }
1853
+ getPlugins(rte) {
1854
+ return [this.contribution(keymap({
1855
+ "Alt-Shift-5": toggleMark(rte.schema.marks.strikethrough),
1856
+ "Cmd-Shift-X": toggleMark(rte.schema.marks.strikethrough)
1857
+ }))];
1858
+ }
1859
+ getToolbarItems(rte) {
1860
+ return [this.contribution({
1861
+ section: "text-style",
1862
+ render: (ctx) => createMarkToggle(ctx, {
1863
+ label: () => ctx.rte.getLocale().richTextEditor.strikethrough,
1864
+ icon: "strikethrough-line",
1865
+ markType: rte.schema.marks.strikethrough
1866
+ })
1867
+ }, 4)];
1868
+ }
1869
+ };
1870
+ var RteStrikethroughFeature = featureFacade(RteStrikethroughFeatureImpl);
1871
+ //#endregion
1872
+ //#region src/lib/rich-text-editor/rte/features/monospace.style.scss?inline
1873
+ var monospace_style_default = "tt{font:var(--vvd-typography-base-code);font-variant-ligatures:unset;font-feature-settings:unset;font-size:unset;font-weight:unset;line-height:unset}";
1874
+ //#endregion
1875
+ //#region src/lib/rich-text-editor/rte/features/monospace.ts
1876
+ var RteMonospaceFeatureImpl = class extends RteTextStyleFeatureImpl {
1877
+ constructor(..._args) {
1878
+ super(..._args);
1879
+ this.name = "RteMonospaceFeature";
1880
+ this.markName = "monospace";
1881
+ }
1882
+ getStyles() {
1883
+ return [this.contribution(monospace_style_default)];
1884
+ }
1885
+ getSchema() {
1886
+ return [this.contribution({ marks: { monospace: {
1887
+ parseDOM: [{ tag: "tt" }, { tag: "code" }],
1888
+ toDOM() {
1889
+ return ["tt", 0];
1890
+ }
1891
+ } } })];
1892
+ }
1893
+ getPlugins(rte) {
1894
+ return [this.contribution(keymap({ "Mod-M": toggleMark(rte.schema.marks.monospace) }))];
1895
+ }
1896
+ getToolbarItems(rte) {
1897
+ return [this.contribution({
1898
+ section: "text-style",
1899
+ render: (ctx) => createMarkToggle(ctx, {
1900
+ label: () => ctx.rte.getLocale().richTextEditor.monospace,
1901
+ icon: "monospace-line",
1902
+ markType: rte.schema.marks.monospace
1903
+ })
1904
+ }, 5)];
1905
+ }
1906
+ };
1907
+ var RteMonospaceFeature = featureFacade(RteMonospaceFeatureImpl);
1908
+ //#endregion
1909
+ //#region src/lib/rich-text-editor/rte/features/text-color-picker.ts
1910
+ function markApplies(doc, ranges, type) {
1911
+ for (let i = 0; i < ranges.length; i++) {
1912
+ const { $from, $to } = ranges[i];
1913
+ let can = $from.depth == 0 ? doc.type.allowsMarkType(type) : false;
1914
+ doc.nodesBetween($from.pos, $to.pos, (node) => {
1915
+ if (can) return false;
1916
+ can = node.inlineContent && node.type.allowsMarkType(type);
1917
+ return true;
1918
+ });
1919
+ if (can) return true;
1920
+ }
1921
+ return false;
1922
+ }
1923
+ var mixedColor = Symbol("mixedColor");
1924
+ var RteTextColorPickerFeatureImpl = class extends RteFeatureImpl {
1925
+ constructor(config) {
1926
+ super();
1927
+ this.config = config;
1928
+ this.name = "RteTextColorPicker";
1929
+ if (config?.onBlocks) {
1930
+ this.defaultColorForNode = {};
1931
+ for (const block of config.onBlocks) this.defaultColorForNode[block.node] = block.defaultColor ?? null;
1932
+ }
1933
+ }
1934
+ getTextblockMarks() {
1935
+ if (this.config?.onBlocks) return this.config.onBlocks.map((block) => this.contribution({
1936
+ markName: "textColor",
1937
+ onNodeName: block.node
1938
+ }));
1939
+ return [this.contribution({ markName: "textColor" })];
1940
+ }
1941
+ getSchema() {
1942
+ return [this.contribution({ marks: { textColor: {
1943
+ attrs: { color: { validate: "string" } },
1944
+ parseDOM: [{
1945
+ tag: "span[data-text-color]",
1946
+ getAttrs: (dom) => {
1947
+ return { color: dom.getAttribute("data-text-color") };
1948
+ }
1949
+ }, {
1950
+ style: "color",
1951
+ getAttrs: (value) => {
1952
+ return { color: value };
1953
+ }
1954
+ }],
1955
+ toDOM(node) {
1956
+ const { color } = node.attrs;
1957
+ return [
1958
+ "span",
1959
+ {
1960
+ style: `color: ${escapeCssProperty(color)};`,
1961
+ "data-text-color": color
1962
+ },
1963
+ 0
1964
+ ];
1965
+ },
1966
+ inclusive: true
1967
+ } } })];
1968
+ }
1969
+ getToolbarItems() {
1970
+ return [this.contribution({
1971
+ section: "text-style",
1972
+ render: (ctx) => {
1973
+ const tooltipButton = createButton(ctx, {
1974
+ label: () => ctx.rte.getLocale().richTextEditor.textColor,
1975
+ disabled: () => !this.setColor("any")(ctx.view.state),
1976
+ icon: "textcolor-line"
1977
+ });
1978
+ const button = tooltipButton.firstElementChild;
1979
+ return createDiv(ctx, { children: [tooltipButton, createSingleSlot(ctx, {
1980
+ name: "text-color-picker",
1981
+ assignedProps: {
1982
+ anchor: button,
1983
+ value: () => this.getSelectionColor(ctx.view.state) || ""
1984
+ },
1985
+ assignedEvents: { change: (e) => {
1986
+ const value = e.currentTarget.value;
1987
+ this.setColor(value)(ctx.view.state, ctx.view.dispatch);
1988
+ } }
1989
+ })] });
1990
+ }
1991
+ }, 6)];
1992
+ }
1993
+ /** Determine the color of the current selection or null if colors are mixed */
1994
+ getSelectionColor(state) {
1995
+ const { selection } = state;
1996
+ const { textColor } = state.schema.marks;
1997
+ const { from, to, $from, empty } = selection;
1998
+ if (empty) {
1999
+ const defaultColor = this.defaultColorForNode?.[$from.parent.type.name] ?? null;
2000
+ return textColor.isInSet(state.storedMarks || $from.marks())?.attrs.color ?? defaultColor;
2001
+ }
2002
+ let selectionColor = null;
2003
+ const observeColor = (observedColor) => {
2004
+ if (selectionColor === null) selectionColor = observedColor ?? null;
2005
+ else if (observedColor !== selectionColor) selectionColor = mixedColor;
2006
+ };
2007
+ state.doc.nodesBetween(from, to, (node, _pos, parent) => {
2008
+ if (selectionColor === mixedColor) return false;
2009
+ if (!node.isLeaf) {
2010
+ if (node.type.allowsMarkType(textColor) && node.childCount === 0) observeColor(this.defaultColorForNode?.[node.type.name]);
2011
+ return true;
2012
+ }
2013
+ observeColor(textColor.isInSet(node.marks)?.attrs.color ?? (parent && this.defaultColorForNode?.[parent.type.name]));
2014
+ return true;
2015
+ });
2016
+ return selectionColor === mixedColor ? null : selectionColor;
2017
+ }
2018
+ setColor(color) {
2019
+ return (state, dispatch) => {
2020
+ const { textColor } = state.schema.marks;
2021
+ const { from, to, empty, $from } = state.selection;
2022
+ if (!markApplies(state.doc, state.selection.ranges, textColor)) return false;
2023
+ const tr = state.tr;
2024
+ if (empty) {
2025
+ const newStoredMarks = (state.storedMarks || []).filter((m) => m.type !== textColor);
2026
+ if (color !== this.defaultColorForNode?.[$from.parent.type.name]) newStoredMarks.push(textColor.create({ color }));
2027
+ tr.setStoredMarks(newStoredMarks);
2028
+ } else {
2029
+ tr.addMark(from, to, textColor.create({ color }));
2030
+ tr.doc.nodesBetween(from, to, (node, pos, parent) => {
2031
+ if (!node.isInline) return;
2032
+ const mark = textColor.isInSet(node.marks);
2033
+ const defaultColor = this.defaultColorForNode?.[parent.type.name];
2034
+ if (mark && mark.attrs.color === defaultColor) tr.step(new RemoveMarkStep(pos, pos + node.nodeSize, mark));
2035
+ });
2036
+ }
2037
+ dispatch?.(tr.scrollIntoView());
2038
+ return true;
2039
+ };
2040
+ }
2041
+ };
2042
+ var RteTextColorPickerFeature = featureFacade(RteTextColorPickerFeatureImpl);
2043
+ //#endregion
2044
+ //#region src/lib/rich-text-editor/rte/features/list.style.scss?inline
2045
+ var list_style_default = ".rich-text ul,.rich-text ol{padding-inline-start:1.5em}.rich-text li{list-style-position:inside}";
2046
+ //#endregion
2047
+ //#region src/lib/rich-text-editor/rte/features/list.ts
2048
+ var atStartOfNode = ($cursor) => $cursor.parentOffset === 0;
2049
+ var isEmpty = (node) => node.nodeSize === 2;
2050
+ var listDepth = ($li) => $li.depth - 1;
2051
+ var outOfListDepth = ($li) => $li.depth - 2;
2052
+ var getLi = ($li) => $li.parent;
2053
+ var getList = ($li) => $li.node(listDepth($li));
2054
+ var isNested = ($li) => $li.depth > 2;
2055
+ var isFirstChild = ($pos, depth) => $pos.index(depth) === 0;
2056
+ var isLastChild = ($pos, depth) => $pos.index(depth) === $pos.node(depth).childCount - 1;
2057
+ var prevSibling = ($pos, depth) => {
2058
+ const parent = $pos.node(depth);
2059
+ const index = $pos.index(depth);
2060
+ return parent.maybeChild(index - 1);
2061
+ };
2062
+ var nextSibling = ($pos, depth) => {
2063
+ const parent = $pos.node(depth);
2064
+ const index = $pos.index(depth);
2065
+ return parent.maybeChild(index + 1);
2066
+ };
2067
+ var asTextSelection = (selection) => {
2068
+ let { $from, $to } = selection;
2069
+ if (selection instanceof AllSelection) {
2070
+ const textSelection = TextSelection.between(selection.$from, selection.$to);
2071
+ $from = textSelection.$from;
2072
+ $to = textSelection.$to;
2073
+ }
2074
+ return {
2075
+ $from,
2076
+ $to
2077
+ };
2078
+ };
2079
+ var getSharedAncestor = ($from, $to) => $from.sameParent($to) ? $from.node(-1) : $from.node($from.sharedDepth($to.pos));
2080
+ var cursorInListItem = (state) => {
2081
+ const { $cursor } = state.selection;
2082
+ if ($cursor?.parent.type === state.schema.nodes.listItem) return $cursor;
2083
+ return null;
2084
+ };
2085
+ var allListItemsAreOfType = (state, $from, $to, type) => {
2086
+ let currentListType;
2087
+ let allLisAreOurType = true;
2088
+ state.doc.nodesBetween($from.pos, $to.pos, (node) => {
2089
+ if (node.type.isInGroup("list")) currentListType = node.type;
2090
+ if (node.type === state.schema.nodes.listItem && currentListType !== type) allLisAreOurType = false;
2091
+ });
2092
+ return allLisAreOurType;
2093
+ };
2094
+ var lift = (rte, $li, tr) => {
2095
+ if (isNested($li)) liftToOuterList($li, tr);
2096
+ else liftOutOfList(rte, $li, tr);
2097
+ };
2098
+ var liftToOuterList = ($li, tr) => {
2099
+ const liRange = new NodeRange($li.doc.resolve($li.before()), $li.doc.resolve($li.after()), $li.depth - 1);
2100
+ tr.lift(liRange, $li.depth - 2);
2101
+ };
2102
+ var liftOutOfList = (rte, $li, tr) => {
2103
+ const list = getList($li);
2104
+ const listIndex = $li.index(outOfListDepth($li));
2105
+ const defaultTextblock = defaultTextblockForMatch($li.node(outOfListDepth($li)).contentMatchAt(listIndex + 1));
2106
+ const atStart = isFirstChild($li, listDepth($li));
2107
+ const atEnd = isLastChild($li, listDepth($li));
2108
+ tr.step(new ReplaceAroundStep($li.before() - (atStart ? 1 : 0), $li.after() + (atEnd ? 1 : 0), $li.start(), $li.end(), new Slice((atStart ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))).append(Fragment.from(defaultTextblock.create(rte.textblockAttrs.extractFromNode(getLi($li))))).append(atEnd ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))), atStart ? 0 : 1, atEnd ? 0 : 1), (atStart ? 0 : 1) + 1));
2109
+ };
2110
+ var sink = (rte, listType, $node, tr) => {
2111
+ if ($node.parent.type === rte.schema.nodes.listItem) sinkLi(listType, $node, tr);
2112
+ else sinkNode(rte, listType, $node, tr);
2113
+ };
2114
+ var sinkLi = (listType, $li, tr) => {
2115
+ const canJoinWithPrev = prevSibling($li, listDepth($li))?.type === listType;
2116
+ const canJoinWithNext = nextSibling($li, listDepth($li))?.type === listType;
2117
+ const openStart = canJoinWithPrev ? 1 : 0;
2118
+ const openEnd = canJoinWithNext ? 1 : 0;
2119
+ tr.step(new ReplaceAroundStep($li.before() - (canJoinWithPrev ? 1 : 0), $li.after() + (canJoinWithNext ? 1 : 0), $li.before(), $li.after(), new Slice(Fragment.from(listType.create(null, [])), openStart, openEnd), 1 - openStart));
2120
+ };
2121
+ var sinkNode = (rte, listType, $node, tr) => {
2122
+ tr.step(new ReplaceAroundStep($node.before(), $node.after(), $node.start(), $node.end(), new Slice(Fragment.from(listType.create(null, [rte.schema.nodes.listItem.create(rte.textblockAttrs.extractFromNode($node.parent))])), 0, 0), 2));
2123
+ };
2124
+ var RteListFeatureImpl = class extends RteFeatureImpl {
2125
+ constructor(config) {
2126
+ super();
2127
+ this.config = config;
2128
+ this.name = "RteListFeature";
2129
+ if (!config.bulletList && !config.numberedList) throw new Error("RteListFeature requires at least one of bulletList or numberedList to be enabled");
2130
+ }
2131
+ getStyles() {
2132
+ return [this.contribution(list_style_default)];
2133
+ }
2134
+ getSchema(textblockAttrs) {
2135
+ return [this.contribution({ nodes: {
2136
+ listItem: {
2137
+ content: "inline*",
2138
+ attrs: textblockAttrs.attrs,
2139
+ defining: true,
2140
+ parseDOM: [{
2141
+ tag: "li",
2142
+ getAttrs: (dom) => textblockAttrs.fromDOM(dom)
2143
+ }],
2144
+ toDOM(node) {
2145
+ return [
2146
+ "li",
2147
+ ...textblockAttrs.getDOMAttrs(node),
2148
+ 0
2149
+ ];
2150
+ }
2151
+ },
2152
+ ...this.config.bulletList ? { bulletList: {
2153
+ group: "block list",
2154
+ content: "(listItem | list)+",
2155
+ parseDOM: [{ tag: "ul" }],
2156
+ toDOM() {
2157
+ return ["ul", 0];
2158
+ }
2159
+ } } : {},
2160
+ ...this.config.numberedList ? { numberedList: {
2161
+ group: "block list",
2162
+ content: "(listItem | list)+",
2163
+ parseDOM: [{ tag: "ol" }],
2164
+ toDOM() {
2165
+ return ["ol", 0];
2166
+ }
2167
+ } } : {}
2168
+ } })];
2169
+ }
2170
+ getPlugins(rte) {
2171
+ this.rte = rte;
2172
+ const tabCommand = (state, dispatch) => {
2173
+ const $liCursor = cursorInListItem(state);
2174
+ if ($liCursor && atStartOfNode($liCursor)) {
2175
+ const tr = state.tr;
2176
+ sinkLi(getList($liCursor).type, $liCursor, tr);
2177
+ dispatch?.(tr.scrollIntoView());
2178
+ return true;
2179
+ }
2180
+ return false;
2181
+ };
2182
+ const shiftTabCommand = (state, dispatch) => {
2183
+ const $liCursor = cursorInListItem(state);
2184
+ if ($liCursor && atStartOfNode($liCursor) && isNested($liCursor)) {
2185
+ const tr = state.tr;
2186
+ liftToOuterList($liCursor, tr);
2187
+ dispatch?.(tr.scrollIntoView());
2188
+ return true;
2189
+ }
2190
+ return false;
2191
+ };
2192
+ const enterCommand = (state, dispatch) => {
2193
+ const $liCursor = cursorInListItem(state);
2194
+ if ($liCursor && isEmpty(getLi($liCursor))) {
2195
+ const tr = state.tr;
2196
+ lift(this.rte, $liCursor, tr);
2197
+ dispatch?.(tr.scrollIntoView());
2198
+ return true;
2199
+ }
2200
+ return false;
2201
+ };
2202
+ const backspaceCommand = (state, dispatch) => {
2203
+ const $liCursor = cursorInListItem(state);
2204
+ if ($liCursor && atStartOfNode($liCursor)) {
2205
+ if (isFirstChild($liCursor, listDepth($liCursor)) && prevSibling($liCursor, outOfListDepth($liCursor))?.type === getList($liCursor).type) return false;
2206
+ const tr = state.tr;
2207
+ lift(this.rte, $liCursor, tr);
2208
+ dispatch?.(tr.scrollIntoView());
2209
+ return true;
2210
+ }
2211
+ return false;
2212
+ };
2213
+ return [this.contribution(keymap({
2214
+ Enter: enterCommand,
2215
+ Backspace: backspaceCommand,
2216
+ Tab: tabCommand,
2217
+ "Shift-Tab": shiftTabCommand,
2218
+ ...this.config.bulletList ? { "Mod-Shift-8": this.toggleList(rte.schema.nodes.bulletList) } : {},
2219
+ ...this.config.numberedList ? { "Mod-Shift-7": this.toggleList(rte.schema.nodes.numberedList) } : {}
2220
+ }), contributionPriority.high)];
2221
+ }
2222
+ getToolbarItems(rte) {
2223
+ const toolbarItems = [];
2224
+ if (this.config.bulletList) toolbarItems.push(this.contribution({
2225
+ section: "textblock",
2226
+ render: (ctx) => createButton(ctx, {
2227
+ label: () => ctx.rte.getLocale().richTextEditor.bulletList,
2228
+ icon: "bullet-list-2-line",
2229
+ active: () => this.isSelectionInList(rte.schema.nodes.bulletList, ctx.rte.state),
2230
+ onClick: () => {
2231
+ const { state, dispatch } = ctx.view;
2232
+ this.toggleList(rte.schema.nodes.bulletList)(state, dispatch);
2233
+ }
2234
+ })
2235
+ }, 1));
2236
+ if (this.config.numberedList) toolbarItems.push(this.contribution({
2237
+ section: "textblock",
2238
+ render: (ctx) => createButton(ctx, {
2239
+ label: () => ctx.rte.getLocale().richTextEditor.numberedList,
2240
+ icon: "list-numbered-line",
2241
+ active: () => this.isSelectionInList(rte.schema.nodes.numberedList, ctx.rte.state),
2242
+ onClick: () => {
2243
+ const { state, dispatch } = ctx.view;
2244
+ this.toggleList(rte.schema.nodes.numberedList)(state, dispatch);
2245
+ }
2246
+ })
2247
+ }, 2));
2248
+ return toolbarItems;
2249
+ }
2250
+ toggleList(type) {
2251
+ return autoJoin((state, dispatch) => {
2252
+ const { $from, $to } = asTextSelection(state.selection);
2253
+ if (getSharedAncestor($from, $to).type.isInGroup("list")) if (allListItemsAreOfType(state, $from, $to, type)) {
2254
+ const tr = state.tr;
2255
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
2256
+ if (node.type === state.schema.nodes.listItem) {
2257
+ const $li = tr.doc.resolve(tr.mapping.map(pos + 1));
2258
+ lift(this.rte, $li, tr);
2259
+ }
2260
+ });
2261
+ dispatch?.(tr.scrollIntoView());
2262
+ return true;
2263
+ } else {
2264
+ const tr = state.tr;
2265
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
2266
+ if (node.type.isInGroup("list") && node.type !== type) tr.setNodeMarkup(pos, type, node.attrs);
2267
+ });
2268
+ dispatch?.(tr.scrollIntoView());
2269
+ return true;
2270
+ }
2271
+ else {
2272
+ const tr = state.tr;
2273
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
2274
+ if (!node.isTextblock) return;
2275
+ const $node = tr.doc.resolve(tr.mapping.map(pos + 1));
2276
+ sink(this.rte, type, $node, tr);
2277
+ });
2278
+ dispatch?.(tr.scrollIntoView());
2279
+ return true;
2280
+ }
2281
+ }, (before, after) => before.type === type && after.type === type);
2282
+ }
2283
+ isSelectionInList(type, state) {
2284
+ const { $from, $to } = asTextSelection(state.selection);
2285
+ if (getSharedAncestor($from, $to).type.isInGroup("list")) return allListItemsAreOfType(state, $from, $to, type);
2286
+ else return false;
2287
+ }
2288
+ };
2289
+ var RteListFeature = featureFacade(RteListFeatureImpl);
2290
+ //#endregion
2291
+ //#region src/lib/rich-text-editor/rte/features/alignment.ts
2292
+ var alignments = [
2293
+ {
2294
+ value: "left",
2295
+ icon: "align-left-line",
2296
+ label: "left"
2297
+ },
2298
+ {
2299
+ value: "center",
2300
+ icon: "align-center-line",
2301
+ label: "center"
2302
+ },
2303
+ {
2304
+ value: "right",
2305
+ icon: "align-right-line",
2306
+ label: "right"
2307
+ }
2308
+ ];
2309
+ var validTextAlign = (value) => alignments.find((a) => a.value === value)?.value ?? "left";
2310
+ var RteAlignmentFeatureImpl = class extends RteFeatureImpl {
2311
+ constructor(..._args) {
2312
+ super(..._args);
2313
+ this.name = "RteAlignmentFeature";
2314
+ }
2315
+ getTextblockAttrs() {
2316
+ return [this.contribution({
2317
+ name: "textAlign",
2318
+ default: "left",
2319
+ fromDOM(dom) {
2320
+ return validTextAlign(dom.style.textAlign);
2321
+ },
2322
+ toStyles(node) {
2323
+ return [`text-align: ${validTextAlign(node.attrs.textAlign)}`];
2324
+ }
2325
+ })];
2326
+ }
2327
+ getPlugins() {
2328
+ return [this.contribution(keymap({
2329
+ "Mod-L": this.setAlignment("left"),
2330
+ "Mod-E": this.setAlignment("center"),
2331
+ "Mod-R": this.setAlignment("right")
2332
+ }))];
2333
+ }
2334
+ getToolbarItems() {
2335
+ return [this.contribution({
2336
+ section: "textblock",
2337
+ render: (ctx) => createMenu(ctx, {
2338
+ label: () => ctx.rte.getLocale().richTextEditor.alignment,
2339
+ trigger: createButton(ctx, {
2340
+ label: () => ctx.rte.getLocale().richTextEditor.alignment,
2341
+ icon: () => {
2342
+ const currentAlign = this.getAlignmentFromSelection(ctx.view.state);
2343
+ return alignments.find((a) => a.value === currentAlign)?.icon ?? "align-left-line";
2344
+ }
2345
+ }),
2346
+ children: [createButtonGroup(ctx, {
2347
+ slot: "header",
2348
+ children: alignments.map((align, index) => createButton(ctx, {
2349
+ icon: align.icon,
2350
+ label: () => ctx.rte.getLocale().richTextEditor.alignments[align.label],
2351
+ noTooltip: true,
2352
+ variant: "toolbar-menu",
2353
+ autofocus: () => {
2354
+ const currentAlign = this.getAlignmentFromSelection(ctx.view.state);
2355
+ if ((currentAlign === "mixed" || currentAlign === null) && index === 0) return true;
2356
+ return align.value === currentAlign;
2357
+ },
2358
+ active: () => this.getAlignmentFromSelection(ctx.view.state) === align.value,
2359
+ disabled: () => this.getAlignmentFromSelection(ctx.view.state) === null,
2360
+ onClick: () => {
2361
+ const { state, dispatch } = ctx.view;
2362
+ this.setAlignment(align.value)(state, dispatch);
2363
+ }
2364
+ }))
2365
+ })]
2366
+ })
2367
+ }, 3)];
2368
+ }
2369
+ getAlignmentFromSelection(state) {
2370
+ const { selection } = state;
2371
+ const { from, to } = selection;
2372
+ let align = null;
2373
+ state.doc.nodesBetween(from, to, (node) => {
2374
+ if (align === "mixed") return;
2375
+ if (node.type.isTextblock) {
2376
+ if (!align) align = node.attrs.textAlign;
2377
+ else if (align !== node.attrs.textAlign) align = "mixed";
2378
+ }
2379
+ });
2380
+ return align;
2381
+ }
2382
+ setAlignment(align) {
2383
+ return (state, dispatch) => {
2384
+ const { tr, selection } = state;
2385
+ const { from, to } = selection;
2386
+ state.doc.nodesBetween(from, to, (node, pos) => {
2387
+ if (node.type.isTextblock) tr.setNodeMarkup(pos, node.type, {
2388
+ ...node.attrs,
2389
+ textAlign: align
2390
+ });
2391
+ });
2392
+ dispatch?.(tr.scrollIntoView());
2393
+ return true;
2394
+ };
2395
+ }
2396
+ };
2397
+ var RteAlignmentFeature = featureFacade(RteAlignmentFeatureImpl);
2398
+ //#endregion
2399
+ //#region src/lib/rich-text-editor/rte/features/link.style.scss?inline
2400
+ var link_style_default = ".link-popover{flex-direction:column;gap:8px;inline-size:450px;padding:16px;display:flex}.link-popover-header{justify-content:space-between;align-items:center;display:flex}.link-popover-label{color:var(--vvd-color-neutral-600);font:var(--vvd-typography-base-condensed)}.link-popover-content{flex-direction:column;gap:16px;display:flex}.link,.rich-text a[href],.link:visited,.rich-text a[href]:visited{color:var(--vvd-color-cta-600)}.link:hover,.rich-text a[href]:hover{color:var(--vvd-color-cta-500)}.link:active,.rich-text a[href]:active{color:var(--vvd-color-cta-400)}.link-action-bar{justify-content:end;gap:8px;display:flex}.link-toolbar-menu{flex-direction:column;gap:16px;inline-size:368px;padding:8px;display:flex}";
2401
+ //#endregion
2402
+ //#region src/lib/rich-text-editor/rte/features/link.ts
2403
+ var linkPattern = "(?:https?://|www\\.)[^\\s<]+";
2404
+ function convertToLink(state, matchedText, start, end) {
2405
+ if (state.doc.rangeHasMark(start, start + 1, state.schema.marks.link)) return null;
2406
+ const link = matchedText.replace(/[.,;:!?) ]+$/, "");
2407
+ const href = link.startsWith("www.") ? `https://${link}` : link;
2408
+ const linkMark = state.schema.marks.link.create({ href });
2409
+ const linkEnd = start + link.length;
2410
+ const trailingChars = matchedText.slice(link.length);
2411
+ const tr = state.tr.addMark(start, linkEnd, linkMark);
2412
+ if (trailingChars) tr.replaceWith(linkEnd, end, state.schema.text(trailingChars));
2413
+ return tr;
2414
+ }
2415
+ var RteLinkFeatureImpl = class extends RteFeatureImpl {
2416
+ constructor(..._args) {
2417
+ super(..._args);
2418
+ this.name = "RteLinkFeature";
2419
+ this.removeLink = (state, dispatch) => {
2420
+ const tr = state.tr;
2421
+ const existingLink = this.getCurrentLink(state);
2422
+ tr.removeMark(existingLink.start, existingLink.end, state.schema.marks.link);
2423
+ dispatch?.(tr.scrollIntoView());
2424
+ return true;
2425
+ };
2426
+ }
2427
+ getStyles() {
2428
+ return [this.contribution(link_style_default)];
2429
+ }
2430
+ getSchema() {
2431
+ return [this.contribution({ marks: { link: {
2432
+ attrs: { href: { validate: "string" } },
2433
+ inclusive: false,
2434
+ parseDOM: [{
2435
+ tag: "a[href]",
2436
+ getAttrs(dom) {
2437
+ return { href: dom.getAttribute("href") };
2438
+ }
2439
+ }],
2440
+ toDOM(node) {
2441
+ const { href } = node.attrs;
2442
+ return [
2443
+ "a",
2444
+ { href: sanitizeLinkHref(href) },
2445
+ 0
2446
+ ];
2447
+ }
2448
+ } } }, contributionPriority.high)];
2449
+ }
2450
+ getTextblockMarks() {
2451
+ return [this.contribution({ markName: "link" })];
2452
+ }
2453
+ getInputRules() {
2454
+ const linkRegex = new RegExp(`${linkPattern}$`);
2455
+ return [this.contribution({
2456
+ rule: new InputRule(new RegExp(`${linkPattern} $`), (state, match, start, end) => convertToLink(state, match[0], start, end)),
2457
+ enterHandler: {
2458
+ regex: linkRegex,
2459
+ handler: (state, match, start, end) => convertToLink(state, match[0], start, end)
2460
+ }
2461
+ })];
2462
+ }
2463
+ getPlugins(rte) {
2464
+ const insertLinkCommand = () => {
2465
+ this.toolbarMenu.open = true;
2466
+ return true;
2467
+ };
2468
+ let popup;
2469
+ return [this.contribution(new Plugin({
2470
+ props: { decorations: (state) => {
2471
+ const link = this.getCurrentLink(state);
2472
+ if (link) {
2473
+ const deco = Decoration.inline(link.start, link.end, { id: "current-link" });
2474
+ return DecorationSet.create(state.doc, [deco]);
2475
+ }
2476
+ return null;
2477
+ } },
2478
+ view: (view) => {
2479
+ const ctx = new UiCtx(view, rte, {
2480
+ popupPlacement: "bottom",
2481
+ shouldReturnFocusToEditor: true
2482
+ });
2483
+ popup = rte.createComponent(Popover);
2484
+ popup.anchorId = "current-link";
2485
+ const content = createDiv(ctx, {
2486
+ className: "link-popover",
2487
+ children: [createDiv(ctx, {
2488
+ className: "link-popover-header",
2489
+ children: [createDiv(ctx, {
2490
+ className: "link-popover-label",
2491
+ children: [createText(ctx, { text: () => this.getCurrentLink(ctx.view.state)?.text || "" })]
2492
+ }), createButton(ctx, {
2493
+ icon: "close-line",
2494
+ label: () => ctx.rte.getLocale().richTextEditor.close,
2495
+ noTooltip: true,
2496
+ onClick: () => {
2497
+ popup.dismiss();
2498
+ }
2499
+ })]
2500
+ }), createDiv(ctx, {
2501
+ className: "link-popover-content",
2502
+ children: [createAnchor(ctx, {
2503
+ className: "link",
2504
+ href: () => this.getCurrentLink(ctx.view.state)?.href || "",
2505
+ target: "_blank",
2506
+ rel: "noopener",
2507
+ children: [createText(ctx, { text: () => this.getCurrentLink(ctx.view.state)?.href || "" })]
2508
+ }), createDiv(ctx, {
2509
+ className: "link-action-bar",
2510
+ children: [createButton(ctx, {
2511
+ icon: "delete-line",
2512
+ label: () => ctx.rte.getLocale().richTextEditor.delete,
2513
+ connotation: "alert",
2514
+ variant: "popover",
2515
+ noTooltip: true,
2516
+ onClick: () => {
2517
+ const { state, dispatch } = ctx.view;
2518
+ this.removeLink(state, dispatch);
2519
+ }
2520
+ }), createButton(ctx, {
2521
+ icon: "edit-line",
2522
+ label: () => ctx.rte.getLocale().richTextEditor.edit,
2523
+ variant: "popover",
2524
+ noTooltip: true,
2525
+ onClick: () => {
2526
+ this.toolbarMenu.open = true;
2527
+ popup.requestOpenState(false);
2528
+ return true;
2529
+ }
2530
+ })]
2531
+ })]
2532
+ })]
2533
+ });
2534
+ popup.appendChild(content);
2535
+ view.dom.getRootNode().querySelector(".popovers").appendChild(popup);
2536
+ return {
2537
+ update: (view) => {
2538
+ const state = view.state;
2539
+ ctx.updateBindings();
2540
+ const link = this.getCurrentLink(state);
2541
+ popup.requestOpenState(Boolean(link));
2542
+ },
2543
+ destroy: () => {
2544
+ popup.remove();
2545
+ }
2546
+ };
2547
+ }
2548
+ })), this.contribution(keymap({
2549
+ Escape: (state) => {
2550
+ if (this.getCurrentLink(state)) {
2551
+ popup?.dismiss();
2552
+ return true;
2553
+ }
2554
+ return false;
2555
+ },
2556
+ "Mod-k": insertLinkCommand
2557
+ }))];
2558
+ }
2559
+ getToolbarItems(rte) {
2560
+ const getSelectionText = (state) => {
2561
+ const { from, to } = state.selection;
2562
+ if (from === to) return "";
2563
+ return state.doc.textBetween(from, to, " ");
2564
+ };
2565
+ const isValidUrl = (url) => {
2566
+ try {
2567
+ new URL(url);
2568
+ return true;
2569
+ } catch {
2570
+ return false;
2571
+ }
2572
+ };
2573
+ return [this.contribution({
2574
+ section: "insert",
2575
+ render: (ctx) => {
2576
+ const textField = createTextField(ctx, {
2577
+ label: () => ctx.rte.getLocale().richTextEditor.linkText,
2578
+ placeholder: () => ctx.rte.getLocale().richTextEditor.linkTextPlaceholder,
2579
+ slot: "header",
2580
+ autofocus: true,
2581
+ value: () => this.getCurrentLink(ctx.view.state)?.text || getSelectionText(ctx.view.state) || "",
2582
+ onInput: () => {
2583
+ updateValidation();
2584
+ }
2585
+ });
2586
+ const urlField = createTextField(ctx, {
2587
+ label: () => ctx.rte.getLocale().richTextEditor.linkUrl,
2588
+ type: "url",
2589
+ placeholder: () => ctx.rte.getLocale().richTextEditor.linkUrlPlaceholder,
2590
+ helperText: () => ctx.rte.getLocale().richTextEditor.linkUrlHelperText,
2591
+ slot: "header",
2592
+ value: () => this.getCurrentLink(ctx.view.state)?.href || "",
2593
+ onInput: () => {
2594
+ updateValidation();
2595
+ }
2596
+ });
2597
+ const applyButton = createButton(ctx, {
2598
+ label: () => ctx.rte.getLocale().richTextEditor.apply,
2599
+ variant: "popover-primary",
2600
+ disabled: () => {
2601
+ const link = this.getCurrentLink(ctx.view.state);
2602
+ return !(link && link.text.length && isValidUrl(link.href));
2603
+ },
2604
+ onClick: () => {
2605
+ const { state, dispatch } = ctx.view;
2606
+ this.insertLink(rte, urlField.value, textField.value)(state, dispatch);
2607
+ this.toolbarMenu.open = false;
2608
+ }
2609
+ });
2610
+ const updateValidation = () => {
2611
+ applyButton.querySelector("[data-vvd-component=\"button\"]").disabled = !(textField.value.length && isValidUrl(urlField.value));
2612
+ };
2613
+ const menu = createMenu(ctx, {
2614
+ label: () => ctx.rte.getLocale().richTextEditor.hyperlink,
2615
+ trigger: createButton(ctx, {
2616
+ label: () => ctx.rte.getLocale().richTextEditor.hyperlink,
2617
+ icon: "link-line"
2618
+ }),
2619
+ children: [createDiv(ctx, {
2620
+ className: "link-toolbar-menu",
2621
+ slot: "header",
2622
+ children: [
2623
+ textField,
2624
+ urlField,
2625
+ createDiv(ctx, {
2626
+ className: "link-action-bar",
2627
+ slot: "header",
2628
+ children: [createButton(ctx, {
2629
+ label: () => ctx.rte.getLocale().richTextEditor.cancel,
2630
+ variant: "popover",
2631
+ onClick: () => {
2632
+ this.toolbarMenu.open = false;
2633
+ }
2634
+ }), applyButton]
2635
+ })
2636
+ ]
2637
+ })]
2638
+ });
2639
+ this.toolbarMenu = menu.lastElementChild;
2640
+ return menu;
2641
+ }
2642
+ }, 1)];
2643
+ }
2644
+ getCurrentLink(state) {
2645
+ const selection = state.selection;
2646
+ if (!(selection instanceof TextSelection)) return null;
2647
+ const linkMark = state.schema.marks.link;
2648
+ const { $from, $to } = selection;
2649
+ const selectionStartMarks = state.selection.empty ? $from.marks() : $from.nodeAfter?.marks ?? [];
2650
+ const targetHref = linkMark.isInSet(selectionStartMarks)?.attrs.href;
2651
+ if (!targetHref) return null;
2652
+ const isTargetLink = (node) => linkMark.isInSet(node.marks)?.attrs.href === targetHref;
2653
+ let currentRun = null;
2654
+ const runs = [];
2655
+ state.doc.nodesBetween($from.start(), $to.end(), (node, pos) => {
2656
+ if (!node.isText) return true;
2657
+ const nodeEnd = pos + node.nodeSize;
2658
+ if (isTargetLink(node)) if (!currentRun) {
2659
+ currentRun = {
2660
+ start: pos,
2661
+ end: nodeEnd
2662
+ };
2663
+ runs.push(currentRun);
2664
+ } else currentRun.end = nodeEnd;
2665
+ else currentRun = null;
2666
+ return false;
2667
+ });
2668
+ const selectionRun = runs.find((run) => run.start <= selection.from && run.end >= selection.to);
2669
+ if (!selectionRun) return null;
2670
+ return {
2671
+ text: state.doc.textBetween(selectionRun.start, selectionRun.end, " "),
2672
+ href: targetHref,
2673
+ start: selectionRun.start,
2674
+ end: selectionRun.end
2675
+ };
2676
+ }
2677
+ insertLink(rte, href, text) {
2678
+ return (state, dispatch) => {
2679
+ let { from, to } = state.selection;
2680
+ const tr = state.tr;
2681
+ const existingLink = this.getCurrentLink(state);
2682
+ if (existingLink) {
2683
+ from = existingLink.start;
2684
+ to = existingLink.end;
2685
+ }
2686
+ tr.insertText(text, from, to);
2687
+ tr.addMark(from, from + text.length, rte.schema.marks.link.create({ href }));
2688
+ dispatch?.(tr.scrollIntoView());
2689
+ return true;
2690
+ };
2691
+ }
2692
+ };
2693
+ var RteLinkFeature = featureFacade(RteLinkFeatureImpl);
2694
+ //#endregion
2695
+ //#region src/lib/rich-text-editor/rte/features/inline-image.style.scss?inline
2696
+ var inline_image_style_default = ".inline-image-wrapper{vertical-align:text-bottom;display:inline-block}.inline-image{block-size:auto;display:block}.inline-image-popover{align-items:center;gap:4px;padding:8px;display:flex}.inline-image-placeholder{color:var(--vvd-color-canvas-text);font:var(--vvd-typography-base);font-feature-settings:normal;font-variant-ligatures:normal;overflow-wrap:normal;pointer-events:none;white-space:normal}";
2697
+ //#endregion
2698
+ //#region src/lib/rich-text-editor/rte/features/inline-image.ts
2699
+ var isGenerator$1 = (value) => value !== null && Boolean(value["next"]);
2700
+ var uniqueId = 1;
2701
+ var generateUniqueId = () => uniqueId++;
2702
+ var InlineImageView = class {
2703
+ constructor(node, view, getPos, config) {
2704
+ this.view = view;
2705
+ this.getPos = getPos;
2706
+ this.config = config;
2707
+ this.content = null;
2708
+ this.dom = document.createElement("div");
2709
+ this.dom.className = "inline-image-wrapper";
2710
+ this.imageUrl = node.attrs.imageUrl;
2711
+ this.img = document.createElement("img");
2712
+ this.initializeImg(node);
2713
+ const resolveResult = this.config.resolveUrl ? this.config.resolveUrl(this.imageUrl) : this.imageUrl;
2714
+ const initialResolvedUrl = isGenerator$1(resolveResult) ? null : resolveResult;
2715
+ this.handleResolvedUrl(initialResolvedUrl);
2716
+ if (isGenerator$1(resolveResult)) this.handleResolvedUrlGenerator(resolveResult);
2717
+ }
2718
+ setContent(content, { onDestroy, allowPopover } = {}) {
2719
+ this.content?.remove();
2720
+ this.onContentDestroy?.();
2721
+ this.content = content;
2722
+ if (content) {
2723
+ this.onContentDestroy = onDestroy;
2724
+ this.dom.appendChild(content);
2725
+ }
2726
+ Popover.setBlockPopover(this.dom, !allowPopover);
2727
+ }
2728
+ async handleResolvedUrlGenerator(generator) {
2729
+ const iterator = generator[Symbol.asyncIterator]();
2730
+ let result;
2731
+ do {
2732
+ result = await iterator.next();
2733
+ this.handleResolvedUrl(result.value);
2734
+ } while (!result.done);
2735
+ }
2736
+ handleResolvedUrl(result) {
2737
+ if (typeof result === "string") this.renderImg(result);
2738
+ else if (result?.type === "placeholder") {
2739
+ const slotName = `inline-image-placeholder-${generateUniqueId()}`;
2740
+ const slot = document.createElement("slot");
2741
+ slot.className = "inline-image-placeholder";
2742
+ slot.name = slotName;
2743
+ const onDestroy = result.create?.(slotName);
2744
+ const host = this.view.dom.getRootNode().host;
2745
+ dispatchSlottableRequest(host, "inline-image-placeholder", slotName, { url: this.imageUrl });
2746
+ this.setContent(slot, { onDestroy: () => {
2747
+ dispatchSlottableRequest(host, "inline-image-placeholder", slotName, removeSymbol);
2748
+ onDestroy?.();
2749
+ } });
2750
+ } else this.setContent(null);
2751
+ }
2752
+ initializeImg(node) {
2753
+ this.img.className = "inline-image";
2754
+ this.update(node);
2755
+ this.img.addEventListener("load", () => {
2756
+ const pos = this.getPos();
2757
+ if (pos) {
2758
+ const { state, dispatch } = this.view;
2759
+ const currentNode = state.doc.nodeAt(pos);
2760
+ if (!currentNode || currentNode.attrs.naturalWidth === this.img.naturalWidth && currentNode.attrs.naturalHeight === this.img.naturalHeight) return;
2761
+ const tr = state.tr;
2762
+ tr.setNodeAttribute(pos, "naturalWidth", this.img.naturalWidth);
2763
+ tr.setNodeAttribute(pos, "naturalHeight", this.img.naturalHeight);
2764
+ tr.setMeta("addToHistory", false);
2765
+ dispatch(tr);
2766
+ }
2767
+ });
2768
+ }
2769
+ renderImg(src) {
2770
+ this.img.src = sanitizeImageSrc(src);
2771
+ this.setContent(this.img, { allowPopover: true });
2772
+ }
2773
+ update(node) {
2774
+ this.img.alt = node.attrs.alt;
2775
+ this.img.width = node.attrs.naturalWidth;
2776
+ this.img.height = node.attrs.naturalHeight;
2777
+ this.img.style.maxWidth = node.attrs.size;
2778
+ return true;
2779
+ }
2780
+ destroy() {
2781
+ this.setContent(null);
2782
+ }
2783
+ };
2784
+ var RteInlineImageFeatureImpl = class extends RteFeatureImpl {
2785
+ constructor(config = {}) {
2786
+ super();
2787
+ this.config = config;
2788
+ this.name = "RteInlineImageFeature";
2789
+ }
2790
+ getStyles() {
2791
+ return [this.contribution(inline_image_style_default)];
2792
+ }
2793
+ getSchema() {
2794
+ return [this.contribution({ nodes: { inlineImage: {
2795
+ inline: true,
2796
+ group: "inline",
2797
+ selectable: true,
2798
+ atom: true,
2799
+ attrs: {
2800
+ imageUrl: { validate: "string" },
2801
+ alt: {
2802
+ validate: "string",
2803
+ default: ""
2804
+ },
2805
+ size: {
2806
+ validate: "string|null",
2807
+ default: null
2808
+ },
2809
+ naturalWidth: {
2810
+ validate: "number|null",
2811
+ default: null
2812
+ },
2813
+ naturalHeight: {
2814
+ validate: "number|null",
2815
+ default: null
2816
+ }
2817
+ },
2818
+ parseDOM: [{
2819
+ tag: "img[src],img[data-src]",
2820
+ getAttrs: (dom) => {
2821
+ const parseDimension = (dim) => {
2822
+ const value = parseInt(dim ?? "", 10);
2823
+ return isNaN(value) ? null : value;
2824
+ };
2825
+ const srcAttr = dom.getAttribute("data-src") ?? dom.getAttribute("src");
2826
+ const imageUrl = this.config.parseUrlFromHtml ? this.config.parseUrlFromHtml(srcAttr) : srcAttr;
2827
+ if (imageUrl === null) return false;
2828
+ return {
2829
+ imageUrl,
2830
+ alt: dom.getAttribute("alt") || "",
2831
+ size: dom.style.maxWidth || null,
2832
+ naturalWidth: parseDimension(dom.getAttribute("width")),
2833
+ naturalHeight: parseDimension(dom.getAttribute("height"))
2834
+ };
2835
+ }
2836
+ }],
2837
+ /** Since we use a NodeView, this is only used for HTML serialization */
2838
+ toDOM: (node) => {
2839
+ const { imageUrl, alt, size, naturalWidth, naturalHeight } = node.attrs;
2840
+ const resolvedUrl = this.config.serializeUrlToHtml ? this.config.serializeUrlToHtml(imageUrl) : imageUrl;
2841
+ if (resolvedUrl === null) return document.createTextNode("");
2842
+ const attrs = {
2843
+ src: sanitizeImageSrc(resolvedUrl),
2844
+ "data-src": resolvedUrl,
2845
+ alt
2846
+ };
2847
+ if (size) attrs.style = `max-width: ${escapeCssProperty(size)}; height: auto;`;
2848
+ if (naturalWidth) attrs.width = naturalWidth;
2849
+ if (naturalHeight) attrs.height = naturalHeight;
2850
+ return ["img", attrs];
2851
+ }
2852
+ } } })];
2853
+ }
2854
+ getPlugins(rte) {
2855
+ let popover;
2856
+ return [this.contribution(new Plugin({
2857
+ props: { nodeViews: { inlineImage: (node, view, getPos) => new InlineImageView(node, view, getPos, this.config) } },
2858
+ view: (view) => {
2859
+ const ctx = new UiCtx(view, rte, {
2860
+ popupPlacement: "bottom",
2861
+ shouldReturnFocusToEditor: true
2862
+ });
2863
+ popover = rte.createComponent(Popover);
2864
+ popover.kind = "imageOptions";
2865
+ popover.offset = 4;
2866
+ const content = createDiv(ctx, {
2867
+ className: "inline-image-popover",
2868
+ children: [
2869
+ createButton(ctx, {
2870
+ label: () => ctx.rte.getLocale().richTextEditor.imageSizes.small,
2871
+ variant: "popover",
2872
+ active: () => this.getSelectedImageSize(ctx.view.state) === "small",
2873
+ onClick: () => {
2874
+ this.setSelectedImageSize("small")(ctx.view.state, ctx.view.dispatch);
2875
+ }
2876
+ }),
2877
+ createDivider(ctx),
2878
+ createButton(ctx, {
2879
+ label: () => ctx.rte.getLocale().richTextEditor.imageSizes.fit,
2880
+ variant: "popover",
2881
+ active: () => this.getSelectedImageSize(ctx.view.state) === "fit",
2882
+ onClick: () => {
2883
+ this.setSelectedImageSize("fit")(ctx.view.state, ctx.view.dispatch);
2884
+ }
2885
+ }),
2886
+ createDivider(ctx),
2887
+ createButton(ctx, {
2888
+ label: () => ctx.rte.getLocale().richTextEditor.imageSizes.original,
2889
+ variant: "popover",
2890
+ active: () => this.getSelectedImageSize(ctx.view.state) === "original",
2891
+ onClick: () => {
2892
+ this.setSelectedImageSize("original")(ctx.view.state, ctx.view.dispatch);
2893
+ }
2894
+ })
2895
+ ]
2896
+ });
2897
+ popover.appendChild(content);
2898
+ view.dom.getRootNode().querySelector(".popovers").appendChild(popover);
2899
+ return {
2900
+ update: (view) => {
2901
+ ctx.updateBindings();
2902
+ const selectedImage = this.getSelectedInlineImage(view.state);
2903
+ if (selectedImage) {
2904
+ popover.anchorEl = view.nodeDOM(selectedImage.pos);
2905
+ popover.requestOpenState(true);
2906
+ } else {
2907
+ popover.anchorEl = void 0;
2908
+ popover.requestOpenState(false);
2909
+ }
2910
+ },
2911
+ destroy: () => {
2912
+ popover.remove();
2913
+ }
2914
+ };
2915
+ }
2916
+ })), this.contribution(keymap({ Escape: (state) => {
2917
+ if (this.getSelectedInlineImage(state)) {
2918
+ popover?.dismiss();
2919
+ return true;
2920
+ }
2921
+ return false;
2922
+ } }))];
2923
+ }
2924
+ calculateSmallWidth(naturalWidth) {
2925
+ return `${Math.min(300, naturalWidth / 2)}px`;
2926
+ }
2927
+ getSelectedInlineImage(state) {
2928
+ const sel = state.selection;
2929
+ if (sel instanceof NodeSelection && sel.node.type === state.schema.nodes.inlineImage) return {
2930
+ pos: sel.from,
2931
+ node: sel.node
2932
+ };
2933
+ return null;
2934
+ }
2935
+ setSelectedImageSize(size) {
2936
+ return (state, dispatch) => {
2937
+ const selectedImage = this.getSelectedInlineImage(state);
2938
+ if (!selectedImage) return false;
2939
+ const { naturalWidth } = selectedImage.node.attrs;
2940
+ if (size === "small" && naturalWidth === null) return false;
2941
+ const tr = state.tr;
2942
+ tr.setNodeAttribute(selectedImage.pos, "size", size === "small" ? this.calculateSmallWidth(naturalWidth) : size === "fit" ? "100%" : null);
2943
+ dispatch?.(tr.scrollIntoView());
2944
+ return true;
2945
+ };
2946
+ }
2947
+ getSelectedImageSize(state) {
2948
+ const selectedImage = this.getSelectedInlineImage(state);
2949
+ if (!selectedImage) return null;
2950
+ const { size, naturalWidth } = selectedImage.node.attrs;
2951
+ if (naturalWidth !== null && size === this.calculateSmallWidth(naturalWidth)) return "small";
2952
+ if (size === "100%") return "fit";
2953
+ if (size === null) return "original";
2954
+ return null;
2955
+ }
2956
+ };
2957
+ var RteInlineImageFeature = featureFacade(RteInlineImageFeatureImpl);
2958
+ //#endregion
2959
+ //#region src/shared/utils/promise.ts
2960
+ var resolvePromise = async (promise) => {
2961
+ try {
2962
+ return {
2963
+ type: "ok",
2964
+ result: await promise
2965
+ };
2966
+ } catch (e) {
2967
+ return {
2968
+ type: "error",
2969
+ error: e
2970
+ };
2971
+ }
2972
+ };
2973
+ //#endregion
2974
+ //#region src/lib/rich-text-editor/rte/features/file-handler.ts
2975
+ var RteFileHandlerFeatureImpl = class extends RteFeatureImpl {
2976
+ constructor(config) {
2977
+ super();
2978
+ this.config = config;
2979
+ this.name = "RteFileHandlerFeature";
2980
+ }
2981
+ getPlugins(rte) {
2982
+ const insertPointPlaceholderPlugin = new Plugin({
2983
+ state: {
2984
+ init() {
2985
+ return DecorationSet.empty;
2986
+ },
2987
+ apply(tr, set) {
2988
+ set = set.map(tr.mapping, tr.doc);
2989
+ const action = tr.getMeta(insertPointPlaceholderPlugin);
2990
+ if (action && action.add) {
2991
+ const placeholder = document.createElement("placeholder");
2992
+ const deco = Decoration.widget(action.add.pos, placeholder, {
2993
+ id: action.add.id,
2994
+ relaxedSide: true
2995
+ });
2996
+ set = set.add(tr.doc, [deco]);
2997
+ } else if (action && action.remove) set = set.remove(set.find(void 0, void 0, (spec) => spec.id == action.remove.id));
2998
+ return set;
2999
+ }
3000
+ },
3001
+ props: { decorations(state) {
3002
+ return this.getState(state);
3003
+ } }
3004
+ });
3005
+ const createInsertPointPlaceholder = (tr, pos) => {
3006
+ const id = generateRandomId();
3007
+ tr.setMeta(insertPointPlaceholderPlugin, { add: {
3008
+ id,
3009
+ pos
3010
+ } });
3011
+ return {
3012
+ getPos: (state) => {
3013
+ const found = insertPointPlaceholderPlugin.getState(state).find(void 0, void 0, (spec) => spec.id == id);
3014
+ return found.length ? found[0].from : null;
3015
+ },
3016
+ remove: (tr) => {
3017
+ tr.setMeta(insertPointPlaceholderPlugin, { remove: { id } });
3018
+ }
3019
+ };
3020
+ };
3021
+ const insertFragment = (tr, fragment, insertPoint) => {
3022
+ if (insertPoint.type === "selection") {
3023
+ const parsed = Slice.fromJSON(rte.schema, { content: fragment });
3024
+ tr.replaceSelection(parsed);
3025
+ } else {
3026
+ const parsed = Fragment.fromJSON(rte.schema, fragment);
3027
+ tr.insert(insertPoint.pos, parsed);
3028
+ }
3029
+ };
3030
+ const handleFiles = (files, insertPoint) => {
3031
+ const result = this.config.handleFiles(files);
3032
+ if (result === null) return;
3033
+ else if (result instanceof Promise) handleAsyncResult(result, insertPoint);
3034
+ else handleSyncResult(result, insertPoint);
3035
+ };
3036
+ const handleSyncResult = (result, insertPoint) => {
3037
+ const tr = rte.state.tr;
3038
+ insertFragment(tr, result, insertPoint);
3039
+ rte.dispatchTransaction(tr);
3040
+ };
3041
+ const handleAsyncResult = async (promise, insertPoint) => {
3042
+ const tr = rte.state.tr;
3043
+ if (insertPoint.type === "selection" && !tr.selection.empty) tr.deleteSelection();
3044
+ const placeholder = createInsertPointPlaceholder(tr, insertPoint.type === "selection" ? tr.selection.from : insertPoint.pos);
3045
+ rte.dispatchTransaction(tr);
3046
+ const resolved = await resolvePromise(promise);
3047
+ const updatedPos = placeholder.getPos(rte.state);
3048
+ const insertTr = rte.state.tr;
3049
+ placeholder.remove(insertTr);
3050
+ if (updatedPos !== null && resolved.type === "ok") insertFragment(insertTr, resolved.result, {
3051
+ type: "pos",
3052
+ pos: updatedPos
3053
+ });
3054
+ rte.dispatchTransaction(insertTr);
3055
+ if (resolved.type === "error") console.error("Error in handleFiles handler:", resolved.error);
3056
+ };
3057
+ return [this.contribution(insertPointPlaceholderPlugin), this.contribution(new Plugin({ props: {
3058
+ handlePaste: (_view, event) => {
3059
+ const files = Array.from(event.clipboardData.files);
3060
+ if (!files.length) return false;
3061
+ handleFiles(files, { type: "selection" });
3062
+ return true;
3063
+ },
3064
+ handleDrop: (view, event) => {
3065
+ const files = Array.from(event.dataTransfer.files);
3066
+ if (!files.length) return false;
3067
+ let target = view.posAtCoords({
3068
+ left: event.clientX,
3069
+ top: event.clientY
3070
+ }).pos;
3071
+ if (view.dragging && view.dragging.slice) {
3072
+ const point = dropPoint(view.state.doc, target, view.dragging.slice);
3073
+ if (point != null) target = point;
3074
+ }
3075
+ handleFiles(files, {
3076
+ type: "pos",
3077
+ pos: target
3078
+ });
3079
+ return true;
3080
+ }
3081
+ } }))];
3082
+ }
3083
+ };
3084
+ var RteFileHandlerFeature = featureFacade(RteFileHandlerFeatureImpl);
3085
+ //#endregion
3086
+ //#region src/lib/rich-text-editor/rte/features/drop-handler.ts
3087
+ var RteDropHandlerFeatureImpl = class extends RteFeatureImpl {
3088
+ constructor(config) {
3089
+ super();
3090
+ this.config = config;
3091
+ this.name = "RteDebugFeature";
3092
+ }
3093
+ getPlugins() {
3094
+ const dragOverResults = /* @__PURE__ */ new WeakMap();
3095
+ let lastResult = false;
3096
+ const onDragOver = (event) => {
3097
+ if (dragOverResults.get(event) !== void 0) return;
3098
+ lastResult = this.config.onViewportDragOver?.(event) ?? false;
3099
+ };
3100
+ const onDrop = (event) => {
3101
+ this.config.onViewportDrop?.(event);
3102
+ this.config.onViewportDragFinish?.();
3103
+ };
3104
+ const onDragEnd = () => {
3105
+ this.config.onViewportDragFinish?.();
3106
+ };
3107
+ let isEntering = false;
3108
+ const onDragEnter = () => {
3109
+ isEntering = true;
3110
+ window.setTimeout(() => isEntering = false, 0);
3111
+ };
3112
+ const onDragLeave = () => {
3113
+ if (isEntering) return;
3114
+ this.config.onViewportDragFinish?.();
3115
+ };
3116
+ return [this.contribution(new Plugin({ view: (view) => {
3117
+ const viewport = view.root.host.editorViewportElement;
3118
+ viewport.addEventListener("dragover", onDragOver);
3119
+ viewport.addEventListener("drop", onDrop);
3120
+ viewport.addEventListener("dragend", onDragEnd);
3121
+ viewport.addEventListener("dragenter", onDragEnter);
3122
+ viewport.addEventListener("dragleave", onDragLeave);
3123
+ return { destroy() {
3124
+ viewport.removeEventListener("dragover", onDragOver);
3125
+ viewport.removeEventListener("drop", onDrop);
3126
+ viewport.removeEventListener("dragend", onDragEnd);
3127
+ viewport.removeEventListener("dragenter", onDragEnter);
3128
+ viewport.removeEventListener("dragleave", onDragLeave);
3129
+ } };
3130
+ } })), this.contribution(new Plugin({ props: { handleDOMEvents: {
3131
+ dragover: (_view, event) => {
3132
+ const result = this.config.onViewportDragOver?.(event) ?? false;
3133
+ dragOverResults.set(event, result);
3134
+ lastResult = result;
3135
+ if (result) {
3136
+ event.stopImmediatePropagation();
3137
+ event.preventDefault();
3138
+ return true;
3139
+ }
3140
+ return false;
3141
+ },
3142
+ drop: () => {
3143
+ return lastResult;
3144
+ }
3145
+ } } }), contributionPriority.high)];
3146
+ }
3147
+ };
3148
+ var RteDropHandlerFeature = featureFacade(RteDropHandlerFeatureImpl);
3149
+ //#endregion
3150
+ //#region src/lib/rich-text-editor/rte/features/toolbar-button.ts
3151
+ var RteToolbarButtonFeatureImpl = class extends RteFeatureImpl {
3152
+ constructor(featureId, options) {
3153
+ super();
3154
+ this.featureId = featureId;
3155
+ this.options = options;
3156
+ this.name = `RteToolbarButtonFeature[${featureId}]`;
3157
+ }
3158
+ getToolbarItems() {
3159
+ return [this.contribution({
3160
+ section: "insert",
3161
+ render: (ctx) => createButton(ctx, {
3162
+ label: this.options.label,
3163
+ icon: this.options.icon,
3164
+ onClick: () => {
3165
+ this.executeAction(ctx);
3166
+ }
3167
+ })
3168
+ }, 2 + (this.options.order ?? 0) / Number.MAX_SAFE_INTEGER)];
3169
+ }
3170
+ executeAction(ctx) {
3171
+ const { action } = this.options;
3172
+ switch (action.type) {
3173
+ case "insert-text": {
3174
+ const { state, dispatch } = ctx.view;
3175
+ const { from, to } = state.selection;
3176
+ dispatch(state.tr.insertText(action.text, from, to));
3177
+ break;
3178
+ }
3179
+ }
3180
+ }
3181
+ };
3182
+ var RteToolbarButtonFeature = featureFacade(RteToolbarButtonFeatureImpl);
3183
+ //#endregion
3184
+ //#region src/lib/rich-text-editor/rte/features/atom.ts
3185
+ var isGenerator = (value) => value !== null && typeof value === "object" && "next" in value;
3186
+ var AtomView = class {
3187
+ constructor(node, config, atomName) {
3188
+ this.dom = document.createElement("span");
3189
+ this.dom.className = "atom-wrapper";
3190
+ this.dom.setAttribute("part", `node--${atomName}`);
3191
+ const result = config.resolveValue ? config.resolveValue(node.attrs.value) : node.attrs.value;
3192
+ if (isGenerator(result)) {
3193
+ this.dom.textContent = "";
3194
+ this.handleResolvedGenerator(result);
3195
+ } else this.dom.textContent = result ?? "";
3196
+ }
3197
+ async handleResolvedGenerator(generator) {
3198
+ const iterator = generator[Symbol.asyncIterator]();
3199
+ let result;
3200
+ do {
3201
+ result = await iterator.next();
3202
+ this.dom.textContent = result.value ?? "";
3203
+ } while (!result.done);
3204
+ }
3205
+ };
3206
+ var RteAtomFeatureImpl = class extends RteFeatureImpl {
3207
+ constructor(atomName, config = {}) {
3208
+ super();
3209
+ this.atomName = atomName;
3210
+ this.config = config;
3211
+ this.name = `RteAtomFeature[${atomName}]`;
3212
+ }
3213
+ getSchema() {
3214
+ const atomSpec = {
3215
+ inline: true,
3216
+ group: "inline",
3217
+ selectable: true,
3218
+ atom: true,
3219
+ attrs: { value: { validate: "string" } },
3220
+ parseDOM: [{
3221
+ tag: `span[data-atom-type="${this.atomName}"][data-value]`,
3222
+ getAttrs: (dom) => ({ value: dom.getAttribute("data-value") })
3223
+ }],
3224
+ /** Since we use a NodeView, toDOM is only used for Rich Text View */
3225
+ toDOM: (node) => {
3226
+ const serializedValue = this.config.serializeValueToHtml ? this.config.serializeValueToHtml(node.attrs.value) : node.attrs.value;
3227
+ if (serializedValue === null) return document.createDocumentFragment();
3228
+ return [
3229
+ "span",
3230
+ { part: `node--${this.atomName}` },
3231
+ serializedValue
3232
+ ];
3233
+ },
3234
+ serializeToDOM: (node) => {
3235
+ const serializedValue = this.config.serializeValueToHtml ? this.config.serializeValueToHtml(node.attrs.value) : node.attrs.value;
3236
+ if (serializedValue === null) return document.createTextNode("");
3237
+ return [
3238
+ "span",
3239
+ {
3240
+ "data-atom-type": this.atomName,
3241
+ "data-value": node.attrs.value
3242
+ },
3243
+ serializedValue
3244
+ ];
3245
+ }
3246
+ };
3247
+ return [this.contribution({ nodes: { [this.atomName]: atomSpec } })];
3248
+ }
3249
+ getPlugins(_rte) {
3250
+ return [this.contribution(new Plugin({ props: { nodeViews: { [this.atomName]: (node) => new AtomView(node, this.config, this.atomName) } } }))];
3251
+ }
3252
+ };
3253
+ var RteAtomFeature = featureFacade(RteAtomFeatureImpl);
3254
+ //#endregion
3255
+ //#region src/lib/rich-text-editor/rte/features/input-rule.ts
3256
+ var RteInputRuleFeatureImpl = class extends RteFeatureImpl {
3257
+ constructor(featureId, options) {
3258
+ super();
3259
+ this.featureId = featureId;
3260
+ this.options = options;
3261
+ this.name = `RteInputRuleFeature[${featureId}]`;
3262
+ }
3263
+ getInputRules(rte) {
3264
+ const basePattern = `(?:${this.options.pattern.source})`;
3265
+ const handler = (state, match, start, end) => {
3266
+ const fragment = this.options.handler(match);
3267
+ if (!fragment) return null;
3268
+ return state.tr.replaceWith(start, end, Fragment.fromJSON(rte.schema, fragment));
3269
+ };
3270
+ const spec = { rule: new InputRule(this.options.matchAfterWhitespace ? new RegExp(`${basePattern} $`) : new RegExp(`${basePattern}$`), handler) };
3271
+ if (this.options.matchAfterWhitespace) spec.enterHandler = {
3272
+ regex: new RegExp(`${basePattern}$`),
3273
+ handler
3274
+ };
3275
+ return [this.contribution(spec)];
3276
+ }
3277
+ };
3278
+ var RteInputRuleFeature = featureFacade(RteInputRuleFeatureImpl);
3279
+ //#endregion
3280
+ //#region src/lib/rich-text-editor/rte/features/keyboard-shortcuts.ts
3281
+ function toCommand(handler, rteInstance) {
3282
+ return (_state, _dispatch) => handler(rteInstance);
3283
+ }
3284
+ var RteKeyboardShortcutsFeatureImpl = class extends RteFeatureImpl {
3285
+ constructor(featureId, options) {
3286
+ super();
3287
+ this.featureId = featureId;
3288
+ this.options = options;
3289
+ this.name = `RteKeyboardShortcutsFeature[${featureId}]`;
3290
+ }
3291
+ getPlugins(rte) {
3292
+ const bindings = {};
3293
+ for (const [key, handler] of Object.entries(this.options.shortcuts)) bindings[key] = toCommand(handler, rte.facade);
3294
+ return [this.contribution(keymap(bindings), contributionPriority.high)];
3295
+ }
3296
+ };
3297
+ var RteKeyboardShortcutsFeature = featureFacade(RteKeyboardShortcutsFeatureImpl);
3298
+ //#endregion
3299
+ //#region src/lib/rich-text-editor/rte/features/suggest.style.scss?inline
3300
+ var suggest_style_default = ".suggest-popover{flex-direction:column;gap:2px;max-block-size:408px;min-inline-size:128px;max-inline-size:248px;padding:4px;display:flex}.suggest-loading-widget{vertical-align:middle;white-space:normal;align-items:center;margin-inline-start:2px;display:inline-flex}.suggest-empty-message{color:var(--vvd-color-neutral-300);font:var(--vvd-typography-base);text-align:center;justify-content:center;align-items:center;min-block-size:40px;display:flex}.suggest-item--visible-focus{box-shadow:0 0 0 4px color-mix(in sRGB, var(--focus-stroke-color,var(--vvd-color-cta-500)), transparent 85%), inset 0 0 0 3px var(--focus-stroke-gap-color,currentColor);outline:1px solid var(--focus-stroke-color,var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset,0px));--focus-stroke-gap-color:transparent}";
3301
+ //#endregion
3302
+ //#region src/lib/rich-text-editor/rte/features/suggest.ts
3303
+ var isPopoverOpen = (state) => Boolean(state?.suggestions && !state.dismissed);
3304
+ var popoverShowsResults = (state) => isPopoverOpen(state) && state.suggestions.items.length > 0;
3305
+ function findMatch(state, regex) {
3306
+ const { $cursor } = state.selection;
3307
+ if (!$cursor) return null;
3308
+ const textBefore = textBeforeCursor($cursor);
3309
+ const match = regex.exec(textBefore);
3310
+ if (!match) return null;
3311
+ const blockStart = $cursor.pos - $cursor.parentOffset;
3312
+ return {
3313
+ text: match[0],
3314
+ groups: [...match],
3315
+ start: blockStart + match.index,
3316
+ end: blockStart + match.index + match[0].length
3317
+ };
3318
+ }
3319
+ var replaceMatch = (view, match, fragment) => {
3320
+ const { state } = view;
3321
+ view.dispatch(closeHistory(state.tr));
3322
+ const tr = view.state.tr;
3323
+ tr.replaceWith(match.start, match.end, Fragment.fromJSON(view.state.schema, fragment));
3324
+ const newPos = tr.mapping.map(match.end);
3325
+ tr.setSelection(TextSelection.create(tr.doc, newPos));
3326
+ view.dispatch(tr.scrollIntoView());
3327
+ };
3328
+ var RteSuggestFeatureImpl = class extends RteFeatureImpl {
3329
+ selectSuggestion(view, suggestState, suggestion) {
3330
+ const fragment = this.options.select(suggestion);
3331
+ replaceMatch(view, suggestState.match, fragment);
3332
+ view.focus();
3333
+ }
3334
+ async startLoadingSuggestions(match, dispatch) {
3335
+ const gen = ++this.loadGeneration;
3336
+ const suggestions = await this.options.load(match);
3337
+ if (gen !== this.loadGeneration) return;
3338
+ dispatch({
3339
+ type: "load",
3340
+ generation: gen,
3341
+ suggestions
3342
+ });
3343
+ }
3344
+ constructor(featureId, options) {
3345
+ super();
3346
+ this.featureId = featureId;
3347
+ this.options = options;
3348
+ this.pluginKey = new PluginKey("suggest");
3349
+ this.loadGeneration = 0;
3350
+ this.name = `RteSuggestFeature[${featureId}]`;
3351
+ }
3352
+ getStyles() {
3353
+ return [this.contribution(suggest_style_default)];
3354
+ }
3355
+ getPlugins(rte) {
3356
+ const createSuggestActionTr = (action) => rte.state.tr.setMeta(this.pluginKey, action);
3357
+ const dispatchSuggestAction = (action) => rte.dispatchTransaction(createSuggestActionTr(action));
3358
+ const suggestPlugin = new Plugin({
3359
+ key: this.pluginKey,
3360
+ state: {
3361
+ init: () => null,
3362
+ apply: (tr, prevState, _prevEditor, newEditor) => {
3363
+ const match = findMatch(newEditor, this.options.pattern);
3364
+ if (!match) return null;
3365
+ if (!prevState && !tr.docChanged) return null;
3366
+ if (prevState?.dismissed) return prevState;
3367
+ const loadingDecoration = (isLoading) => {
3368
+ if (!isLoading) return DecorationSet.empty;
3369
+ return Boolean(prevState?.loadingDecoration.find().length ?? 0) ? prevState.loadingDecoration.map(tr.mapping, tr.doc) : DecorationSet.create(tr.doc, [Decoration.widget(match.end, () => {
3370
+ const wrapper = document.createElement("span");
3371
+ wrapper.className = "suggest-loading-widget";
3372
+ const spinner = rte.createComponent(ProgressRing);
3373
+ spinner.size = -6;
3374
+ wrapper.appendChild(spinner);
3375
+ return wrapper;
3376
+ }, {
3377
+ ignoreSelection: true,
3378
+ side: 1
3379
+ })]);
3380
+ };
3381
+ const action = tr.getMeta(this.pluginKey);
3382
+ if (prevState && action) switch (action.type) {
3383
+ case "load": return {
3384
+ ...prevState,
3385
+ suggestions: {
3386
+ generation: action.generation,
3387
+ items: action.suggestions,
3388
+ selectedIndex: 0,
3389
+ visibleFocus: false
3390
+ },
3391
+ loadingDecoration: loadingDecoration(false)
3392
+ };
3393
+ case "navigate": {
3394
+ /* v8 ignore next 3 -- defensive: navigate is only dispatched after results are loaded @preserve */
3395
+ if (!prevState.suggestions?.items.length) return prevState;
3396
+ if (!prevState.suggestions.visibleFocus) return {
3397
+ ...prevState,
3398
+ suggestions: {
3399
+ ...prevState.suggestions,
3400
+ visibleFocus: true
3401
+ }
3402
+ };
3403
+ const newIndex = Math.max(0, Math.min(prevState.suggestions.items.length - 1, prevState.suggestions.selectedIndex + (action.action === "up" ? -1 : 1)));
3404
+ return {
3405
+ ...prevState,
3406
+ suggestions: {
3407
+ ...prevState.suggestions,
3408
+ selectedIndex: newIndex
3409
+ }
3410
+ };
3411
+ }
3412
+ case "dismiss": return {
3413
+ ...prevState,
3414
+ dismissed: true,
3415
+ loadingDecoration: DecorationSet.empty
3416
+ };
3417
+ }
3418
+ if (!prevState) {
3419
+ this.startLoadingSuggestions(match.groups, dispatchSuggestAction);
3420
+ return {
3421
+ match,
3422
+ loadingDecoration: loadingDecoration(true)
3423
+ };
3424
+ }
3425
+ const matchChanged = match.groups[0] !== prevState.match.groups[0];
3426
+ if (matchChanged) this.startLoadingSuggestions(match.groups, dispatchSuggestAction);
3427
+ return {
3428
+ ...prevState,
3429
+ match,
3430
+ suggestions: prevState.suggestions ? {
3431
+ ...prevState.suggestions,
3432
+ visibleFocus: false
3433
+ } : void 0,
3434
+ loadingDecoration: loadingDecoration(matchChanged)
3435
+ };
3436
+ }
3437
+ },
3438
+ props: { decorations: (state) => {
3439
+ const suggestState = this.pluginKey.getState(state);
3440
+ if (!suggestState) return null;
3441
+ return suggestState.loadingDecoration.add(state.doc, [Decoration.inline(suggestState.match.start, suggestState.match.end, { id: `suggest-anchor-${this.featureId}` })]);
3442
+ } },
3443
+ view: (view) => {
3444
+ const ctx = new UiCtx(view, rte, {
3445
+ popupPlacement: "bottom",
3446
+ shouldReturnFocusToEditor: true
3447
+ });
3448
+ const popover = rte.createComponent(Popover);
3449
+ popover.anchorId = `suggest-anchor-${this.featureId}`;
3450
+ popover.kind = "autocomplete";
3451
+ popover.offset = 4;
3452
+ const content = createDiv(ctx, {
3453
+ className: "suggest-popover",
3454
+ children: []
3455
+ });
3456
+ popover.appendChild(content);
3457
+ view.dom.getRootNode().querySelector(".popovers").appendChild(popover);
3458
+ const emptySlotName = `${this.featureId}-suggestions-empty`;
3459
+ const host = view.dom.getRootNode().host;
3460
+ let emptySlotShowing = false;
3461
+ const updateEmptySlotShowing = (showing) => {
3462
+ if (!emptySlotShowing && showing) dispatchSlottableRequest(host, "suggestions-empty-state", emptySlotName, { id: this.featureId });
3463
+ if (emptySlotShowing && !showing) dispatchSlottableRequest(host, "suggestions-empty-state", emptySlotName, removeSymbol);
3464
+ emptySlotShowing = showing;
3465
+ };
3466
+ const updatePopoverContent = (suggestState) => {
3467
+ content.innerHTML = "";
3468
+ const suggestions = suggestState.suggestions;
3469
+ const showEmptyState = suggestions.items.length === 0;
3470
+ updateEmptySlotShowing(showEmptyState);
3471
+ if (showEmptyState) {
3472
+ const emptySlot = document.createElement("slot");
3473
+ emptySlot.name = emptySlotName;
3474
+ emptySlot.textContent = rte.getLocale().richTextEditor.suggestNoResults;
3475
+ content.appendChild(createDiv(ctx, {
3476
+ className: "suggest-empty-message",
3477
+ children: [emptySlot]
3478
+ }));
3479
+ return;
3480
+ }
3481
+ for (const [index, suggestion] of suggestions.items.entries()) {
3482
+ const item = rte.createComponent(ListboxOption);
3483
+ item.text = suggestion.text;
3484
+ item.textSecondary = suggestion.textSecondary;
3485
+ if (index === suggestions.selectedIndex) {
3486
+ item._highlighted = true;
3487
+ item.dataset.highlighted = "true";
3488
+ if (suggestions.visibleFocus) item.classList.add("suggest-item--visible-focus");
3489
+ queueMicrotask(() => {
3490
+ item.scrollIntoView({ block: "nearest" });
3491
+ });
3492
+ }
3493
+ item.addEventListener("click", (e) => {
3494
+ e.preventDefault();
3495
+ e.stopPropagation();
3496
+ this.selectSuggestion(view, suggestState, suggestion);
3497
+ });
3498
+ content.appendChild(item);
3499
+ }
3500
+ };
3501
+ return {
3502
+ update: (view) => {
3503
+ ctx.updateBindings();
3504
+ const suggestState = this.pluginKey.getState(view.state);
3505
+ const showPopover = isPopoverOpen(suggestState);
3506
+ popover.requestOpenState(showPopover);
3507
+ if (showPopover) updatePopoverContent(suggestState);
3508
+ else updateEmptySlotShowing(false);
3509
+ },
3510
+ destroy: () => {
3511
+ updateEmptySlotShowing(false);
3512
+ popover.remove();
3513
+ }
3514
+ };
3515
+ }
3516
+ });
3517
+ return [this.contribution(suggestPlugin), this.contribution(keymap({
3518
+ ArrowUp: (state, dispatch) => {
3519
+ if (!popoverShowsResults(this.pluginKey.getState(state))) return false;
3520
+ dispatch?.(createSuggestActionTr({
3521
+ type: "navigate",
3522
+ action: "up"
3523
+ }));
3524
+ return true;
3525
+ },
3526
+ ArrowDown: (state, dispatch) => {
3527
+ if (!popoverShowsResults(this.pluginKey.getState(state))) return false;
3528
+ dispatch?.(createSuggestActionTr({
3529
+ type: "navigate",
3530
+ action: "down"
3531
+ }));
3532
+ return true;
3533
+ },
3534
+ Enter: (state, _dispatch, view) => {
3535
+ const suggestState = this.pluginKey.getState(state);
3536
+ if (!popoverShowsResults(suggestState)) return false;
3537
+ const suggestion = suggestState.suggestions.items[suggestState.suggestions.selectedIndex];
3538
+ /* v8 ignore next 3 -- defensive: view is always passed by keymap @preserve */
3539
+ if (view) this.selectSuggestion(view, suggestState, suggestion);
3540
+ return true;
3541
+ },
3542
+ Escape: (state, dispatch) => {
3543
+ if (!isPopoverOpen(this.pluginKey.getState(state))) return false;
3544
+ dispatch?.(createSuggestActionTr({ type: "dismiss" }));
3545
+ return true;
3546
+ }
3547
+ }), contributionPriority.high)];
3548
+ }
3549
+ };
3550
+ var RteSuggestFeature = featureFacade(RteSuggestFeatureImpl);
3551
+ //#endregion
3552
+ //#region src/lib/rich-text-editor/rte/features/character-count.ts
3553
+ var countCharacters = (doc) => doc.textBetween(0, doc.content.size, void 0, " ").length;
3554
+ var RteCharacterCountFeatureImpl = class extends RteFeatureImpl {
3555
+ constructor(config) {
3556
+ super();
3557
+ this.config = config;
3558
+ this.name = "RteCharacterCountFeature";
3559
+ }
3560
+ getPlugins() {
3561
+ const limit = this.config?.limit;
3562
+ if (limit === void 0) return [];
3563
+ return [this.contribution(new Plugin({ filterTransaction: (transaction, state) => {
3564
+ if (!transaction.docChanged) return true;
3565
+ const oldSize = countCharacters(state.doc);
3566
+ const newSize = countCharacters(transaction.doc);
3567
+ if (newSize <= limit) return true;
3568
+ if (oldSize > limit) return newSize <= oldSize;
3569
+ if (!transaction.getMeta("paste")) return false;
3570
+ const pos = transaction.selection.$head.pos;
3571
+ const from = pos - (newSize - limit);
3572
+ const to = pos;
3573
+ transaction.deleteRange(from, to);
3574
+ return countCharacters(transaction.doc) <= limit;
3575
+ } }))];
3576
+ }
3577
+ getPublicInterface(rte) {
3578
+ const limit = this.config?.limit;
3579
+ return {
3580
+ get characters() {
3581
+ return countCharacters(rte.state.doc);
3582
+ },
3583
+ get limit() {
3584
+ return limit;
3585
+ }
3586
+ };
3587
+ }
3588
+ };
3589
+ var RteCharacterCountFeature = featureFacade(RteCharacterCountFeatureImpl);
3590
+ //#endregion
3591
+ //#region src/lib/rich-text-editor/definition.ts
3592
+ var richTextEditorDefinition = defineVividComponent("rich-text-editor", RichTextEditor, RichTextEditorTemplate, [
3593
+ dividerDefinition,
3594
+ selectDefinition,
814
3595
  listboxOptionDefinition,
815
3596
  buttonDefinition,
816
- feedbackMessageDefinition
817
- ], { styles: select_default });
3597
+ tooltipDefinition,
3598
+ menuDefinition,
3599
+ menuItemDefinition,
3600
+ textFieldDefinition,
3601
+ popoverDefinition,
3602
+ progressRingDefinition
3603
+ ], {
3604
+ styles: rich_text_editor_default,
3605
+ shadowOptions: { delegatesFocus: true }
3606
+ });
818
3607
  /**
819
- * Registers the select elements with the design system.
3608
+ * Registers the rich-text-editor element with the design system.
820
3609
  *
821
3610
  * @param prefix - the prefix to use for the component name
822
3611
  */
823
- var registerSelect = createRegisterFunction(selectDefinition);
3612
+ var registerRichTextEditor = createRegisterFunction(richTextEditorDefinition);
824
3613
  //#endregion
825
- export { selectDefinition as n, Select as r, registerSelect as t };
3614
+ export { RichTextEditor as A, RtePlaceholderFeature as C, RteConfig as D, RteBase as E, RteHtmlSerializer as O, RteHardBreakFeature as S, RteTextBlockPickerFeature as T, RteStrikethroughFeature as _, RteKeyboardShortcutsFeature as a, RteBoldFeature as b, RteToolbarButtonFeature as c, RteInlineImageFeature as d, RteLinkFeature as f, RteMonospaceFeature as g, RteTextColorPickerFeature as h, RteSuggestFeature as i, RteHtmlParser as k, RteDropHandlerFeature as l, RteListFeature as m, richTextEditorDefinition as n, RteInputRuleFeature as o, RteAlignmentFeature as p, RteCharacterCountFeature as r, RteAtomFeature as s, registerRichTextEditor as t, RteFileHandlerFeature as u, RteUnderlineFeature as v, RteToolbarFeature as w, RteFontSizePickerFeature as x, RteItalicFeature as y };