@seekalfred/primitives 0.5.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (446) hide show
  1. package/README.md +682 -19
  2. package/dist/accordion/accordion.js +10 -4
  3. package/dist/accordion/accordion.js.map +1 -1
  4. package/dist/action-button/action-button.d.ts +50 -0
  5. package/dist/action-button/action-button.js +159 -0
  6. package/dist/action-button/action-button.js.map +1 -0
  7. package/dist/action-button/index.d.ts +2 -0
  8. package/dist/action-button/index.js +2 -0
  9. package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
  10. package/dist/activity-heatmap/activity-heatmap.js +699 -0
  11. package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
  12. package/dist/activity-heatmap/index.d.ts +2 -0
  13. package/dist/activity-heatmap/index.js +2 -0
  14. package/dist/alert/alert.d.ts +19 -1
  15. package/dist/alert/alert.js +180 -23
  16. package/dist/alert/alert.js.map +1 -1
  17. package/dist/alert-dialog/alert-dialog.d.ts +45 -18
  18. package/dist/alert-dialog/alert-dialog.js +128 -9
  19. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  20. package/dist/alert-dialog/index.d.ts +2 -2
  21. package/dist/alert-dialog/index.js +2 -2
  22. package/dist/animated-counter/animated-counter.d.ts +38 -0
  23. package/dist/animated-counter/animated-counter.js +230 -0
  24. package/dist/animated-counter/animated-counter.js.map +1 -0
  25. package/dist/animated-counter/index.d.ts +2 -0
  26. package/dist/animated-counter/index.js +2 -0
  27. package/dist/announcement-bar/announcement-bar.d.ts +67 -0
  28. package/dist/announcement-bar/announcement-bar.js +364 -0
  29. package/dist/announcement-bar/announcement-bar.js.map +1 -0
  30. package/dist/announcement-bar/index.d.ts +2 -0
  31. package/dist/announcement-bar/index.js +2 -0
  32. package/dist/avatar/avatar.d.ts +6 -0
  33. package/dist/avatar/avatar.js +47 -16
  34. package/dist/avatar/avatar.js.map +1 -1
  35. package/dist/badge/badge.d.ts +10 -3
  36. package/dist/badge/badge.js +35 -5
  37. package/dist/badge/badge.js.map +1 -1
  38. package/dist/bar-chart/bar-chart.d.ts +51 -0
  39. package/dist/bar-chart/bar-chart.js +565 -0
  40. package/dist/bar-chart/bar-chart.js.map +1 -0
  41. package/dist/bar-chart/index.d.ts +2 -0
  42. package/dist/bar-chart/index.js +2 -0
  43. package/dist/breadcrumb/breadcrumb.d.ts +2 -29
  44. package/dist/breadcrumb/breadcrumb.js +32 -9
  45. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  46. package/dist/brush-chart/brush-chart.d.ts +64 -0
  47. package/dist/brush-chart/brush-chart.js +1056 -0
  48. package/dist/brush-chart/brush-chart.js.map +1 -0
  49. package/dist/brush-chart/index.d.ts +2 -0
  50. package/dist/brush-chart/index.js +2 -0
  51. package/dist/button/button.d.ts +36 -23
  52. package/dist/button/button.js +198 -45
  53. package/dist/button/button.js.map +1 -1
  54. package/dist/button-group/button-group.d.ts +76 -0
  55. package/dist/button-group/button-group.js +402 -0
  56. package/dist/button-group/button-group.js.map +1 -0
  57. package/dist/button-group/index.d.ts +2 -0
  58. package/dist/button-group/index.js +2 -0
  59. package/dist/calendar/calendar.d.ts +1 -1
  60. package/dist/calendar/calendar.js +257 -30
  61. package/dist/calendar/calendar.js.map +1 -1
  62. package/dist/card/card.d.ts +9 -2
  63. package/dist/card/card.js +16 -5
  64. package/dist/card/card.js.map +1 -1
  65. package/dist/card-stack/card-stack.d.ts +54 -0
  66. package/dist/card-stack/card-stack.js +492 -0
  67. package/dist/card-stack/card-stack.js.map +1 -0
  68. package/dist/card-stack/index.d.ts +2 -0
  69. package/dist/card-stack/index.js +2 -0
  70. package/dist/carousel/carousel.d.ts +56 -0
  71. package/dist/carousel/carousel.js +389 -0
  72. package/dist/carousel/carousel.js.map +1 -0
  73. package/dist/carousel/index.d.ts +2 -0
  74. package/dist/carousel/index.js +2 -0
  75. package/dist/checkbox/checkbox.d.ts +0 -7
  76. package/dist/checkbox/checkbox.js +26 -29
  77. package/dist/checkbox/checkbox.js.map +1 -1
  78. package/dist/chip-group/chip-group.d.ts +37 -0
  79. package/dist/chip-group/chip-group.js +148 -0
  80. package/dist/chip-group/chip-group.js.map +1 -0
  81. package/dist/chip-group/index.d.ts +2 -0
  82. package/dist/chip-group/index.js +2 -0
  83. package/dist/confirm-morph/confirm-morph.d.ts +85 -0
  84. package/dist/confirm-morph/confirm-morph.js +652 -0
  85. package/dist/confirm-morph/confirm-morph.js.map +1 -0
  86. package/dist/confirm-morph/index.d.ts +2 -0
  87. package/dist/confirm-morph/index.js +2 -0
  88. package/dist/copy-button/copy-button.d.ts +32 -0
  89. package/dist/copy-button/copy-button.js +134 -0
  90. package/dist/copy-button/copy-button.js.map +1 -0
  91. package/dist/copy-button/index.d.ts +2 -0
  92. package/dist/copy-button/index.js +2 -0
  93. package/dist/countdown/countdown.d.ts +45 -0
  94. package/dist/countdown/countdown.js +298 -0
  95. package/dist/countdown/countdown.js.map +1 -0
  96. package/dist/countdown/index.d.ts +2 -0
  97. package/dist/countdown/index.js +2 -0
  98. package/dist/date-picker/date-picker.d.ts +51 -0
  99. package/dist/date-picker/date-picker.js +241 -0
  100. package/dist/date-picker/date-picker.js.map +1 -0
  101. package/dist/date-picker/date-range-picker.d.ts +78 -0
  102. package/dist/date-picker/date-range-picker.js +1015 -0
  103. package/dist/date-picker/date-range-picker.js.map +1 -0
  104. package/dist/date-picker/index.d.ts +4 -0
  105. package/dist/date-picker/index.js +4 -0
  106. package/dist/date-picker/picker-parts.d.ts +46 -0
  107. package/dist/date-picker/picker-parts.js +135 -0
  108. package/dist/date-picker/picker-parts.js.map +1 -0
  109. package/dist/dialog/dialog.d.ts +10 -14
  110. package/dist/dialog/dialog.js +40 -12
  111. package/dist/dialog/dialog.js.map +1 -1
  112. package/dist/donut-chart/donut-chart.d.ts +64 -0
  113. package/dist/donut-chart/donut-chart.js +576 -0
  114. package/dist/donut-chart/donut-chart.js.map +1 -0
  115. package/dist/donut-chart/index.d.ts +2 -0
  116. package/dist/donut-chart/index.js +2 -0
  117. package/dist/empty-state/empty-state.d.ts +55 -0
  118. package/dist/empty-state/empty-state.js +89 -0
  119. package/dist/empty-state/empty-state.js.map +1 -0
  120. package/dist/empty-state/index.d.ts +2 -0
  121. package/dist/empty-state/index.js +2 -0
  122. package/dist/expanding-button-group/expanding-button-group.d.ts +54 -0
  123. package/dist/expanding-button-group/expanding-button-group.js +350 -0
  124. package/dist/expanding-button-group/expanding-button-group.js.map +1 -0
  125. package/dist/expanding-button-group/index.d.ts +2 -0
  126. package/dist/expanding-button-group/index.js +2 -0
  127. package/dist/file-drop-zone/file-drop-zone.d.ts +71 -0
  128. package/dist/file-drop-zone/file-drop-zone.js +116 -0
  129. package/dist/file-drop-zone/file-drop-zone.js.map +1 -0
  130. package/dist/file-drop-zone/index.d.ts +2 -0
  131. package/dist/file-drop-zone/index.js +2 -0
  132. package/dist/filter-bar/filter-bar.d.ts +142 -0
  133. package/dist/filter-bar/filter-bar.js +416 -0
  134. package/dist/filter-bar/filter-bar.js.map +1 -0
  135. package/dist/filter-bar/index.d.ts +2 -0
  136. package/dist/filter-bar/index.js +2 -0
  137. package/dist/floating-button-group/floating-button-group.d.ts +61 -0
  138. package/dist/floating-button-group/floating-button-group.js +340 -0
  139. package/dist/floating-button-group/floating-button-group.js.map +1 -0
  140. package/dist/floating-button-group/index.d.ts +2 -0
  141. package/dist/floating-button-group/index.js +2 -0
  142. package/dist/gauge/gauge.d.ts +45 -0
  143. package/dist/gauge/gauge.js +219 -0
  144. package/dist/gauge/gauge.js.map +1 -0
  145. package/dist/gauge/index.d.ts +2 -0
  146. package/dist/gauge/index.js +2 -0
  147. package/dist/icon-morph/icon-morph.d.ts +55 -0
  148. package/dist/icon-morph/icon-morph.js +331 -0
  149. package/dist/icon-morph/icon-morph.js.map +1 -0
  150. package/dist/icon-morph/index.d.ts +2 -0
  151. package/dist/icon-morph/index.js +2 -0
  152. package/dist/in-view-title/in-view-title.d.ts +33 -0
  153. package/dist/in-view-title/in-view-title.js +119 -0
  154. package/dist/in-view-title/in-view-title.js.map +1 -0
  155. package/dist/in-view-title/index.d.ts +2 -0
  156. package/dist/in-view-title/index.js +2 -0
  157. package/dist/index.d.ts +71 -6
  158. package/dist/index.js +73 -11
  159. package/dist/input/input.d.ts +22 -0
  160. package/dist/input/input.js +36 -12
  161. package/dist/input/input.js.map +1 -1
  162. package/dist/lib/cn.js +11 -1
  163. package/dist/lib/cn.js.map +1 -1
  164. package/dist/lib/count-to.js +113 -0
  165. package/dist/lib/count-to.js.map +1 -0
  166. package/dist/lib/eye-morph.js +62 -0
  167. package/dist/lib/eye-morph.js.map +1 -0
  168. package/dist/lib/field-message.js +354 -0
  169. package/dist/lib/field-message.js.map +1 -0
  170. package/dist/lib/field-shell.js +81 -0
  171. package/dist/lib/field-shell.js.map +1 -0
  172. package/dist/lib/field-surface.js +11 -8
  173. package/dist/lib/field-surface.js.map +1 -1
  174. package/dist/lib/flag-emoji.js +50 -0
  175. package/dist/lib/flag-emoji.js.map +1 -0
  176. package/dist/lib/flip.js +88 -0
  177. package/dist/lib/flip.js.map +1 -0
  178. package/dist/lib/height-follow.js +59 -0
  179. package/dist/lib/height-follow.js.map +1 -0
  180. package/dist/lib/icon-swap.js +47 -0
  181. package/dist/lib/icon-swap.js.map +1 -0
  182. package/dist/lib/leaving-list.js +57 -0
  183. package/dist/lib/leaving-list.js.map +1 -0
  184. package/dist/lib/menu-highlight.js +64 -0
  185. package/dist/lib/menu-highlight.js.map +1 -0
  186. package/dist/lib/merge-refs.js +3 -3
  187. package/dist/lib/merge-refs.js.map +1 -1
  188. package/dist/lib/morph-text.js +128 -0
  189. package/dist/lib/morph-text.js.map +1 -0
  190. package/dist/lib/motion.js +169 -0
  191. package/dist/lib/motion.js.map +1 -0
  192. package/dist/lib/pausable-timeout.js +67 -0
  193. package/dist/lib/pausable-timeout.js.map +1 -0
  194. package/dist/lib/rolling-value.js +31 -0
  195. package/dist/lib/rolling-value.js.map +1 -0
  196. package/dist/lib/spring-progress.js +114 -0
  197. package/dist/lib/spring-progress.js.map +1 -0
  198. package/dist/lib/spring-tween.js +500 -0
  199. package/dist/lib/spring-tween.js.map +1 -0
  200. package/dist/lib/svg-id.js +10 -0
  201. package/dist/lib/svg-id.js.map +1 -0
  202. package/dist/lib/swap-text.js +79 -0
  203. package/dist/lib/swap-text.js.map +1 -0
  204. package/dist/lib/use-copy-feedback.js +36 -0
  205. package/dist/lib/use-copy-feedback.js.map +1 -0
  206. package/dist/line-chart/index.d.ts +2 -0
  207. package/dist/line-chart/index.js +2 -0
  208. package/dist/line-chart/line-chart.d.ts +76 -0
  209. package/dist/line-chart/line-chart.js +611 -0
  210. package/dist/line-chart/line-chart.js.map +1 -0
  211. package/dist/mention-input/index.d.ts +2 -0
  212. package/dist/mention-input/index.js +2 -0
  213. package/dist/mention-input/mention-input.d.ts +98 -0
  214. package/dist/mention-input/mention-input.js +576 -0
  215. package/dist/mention-input/mention-input.js.map +1 -0
  216. package/dist/menu/menu.d.ts +2 -0
  217. package/dist/menu/menu.js +23 -12
  218. package/dist/menu/menu.js.map +1 -1
  219. package/dist/money-input/index.d.ts +2 -0
  220. package/dist/money-input/index.js +2 -0
  221. package/dist/money-input/money-input.d.ts +65 -0
  222. package/dist/money-input/money-input.js +607 -0
  223. package/dist/money-input/money-input.js.map +1 -0
  224. package/dist/morph-select/index.d.ts +2 -0
  225. package/dist/morph-select/index.js +2 -0
  226. package/dist/morph-select/morph-select.d.ts +71 -0
  227. package/dist/morph-select/morph-select.js +693 -0
  228. package/dist/morph-select/morph-select.js.map +1 -0
  229. package/dist/multi-select/index.d.ts +2 -0
  230. package/dist/multi-select/index.js +2 -0
  231. package/dist/multi-select/multi-select.d.ts +36 -0
  232. package/dist/multi-select/multi-select.js +152 -0
  233. package/dist/multi-select/multi-select.js.map +1 -0
  234. package/dist/number-field/index.d.ts +2 -0
  235. package/dist/number-field/index.js +2 -0
  236. package/dist/number-field/number-field.d.ts +42 -0
  237. package/dist/number-field/number-field.js +199 -0
  238. package/dist/number-field/number-field.js.map +1 -0
  239. package/dist/onboarding-checklist/index.d.ts +2 -0
  240. package/dist/onboarding-checklist/index.js +2 -0
  241. package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
  242. package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
  243. package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
  244. package/dist/page-header/index.d.ts +2 -0
  245. package/dist/page-header/index.js +2 -0
  246. package/dist/page-header/page-header.d.ts +75 -0
  247. package/dist/page-header/page-header.js +83 -0
  248. package/dist/page-header/page-header.js.map +1 -0
  249. package/dist/password-field/index.d.ts +2 -0
  250. package/dist/password-field/index.js +2 -0
  251. package/dist/password-field/password-field.d.ts +37 -0
  252. package/dist/password-field/password-field.js +101 -0
  253. package/dist/password-field/password-field.js.map +1 -0
  254. package/dist/password-strength/index.d.ts +2 -0
  255. package/dist/password-strength/index.js +2 -0
  256. package/dist/password-strength/password-strength.d.ts +127 -0
  257. package/dist/password-strength/password-strength.js +455 -0
  258. package/dist/password-strength/password-strength.js.map +1 -0
  259. package/dist/phone-input/index.d.ts +3 -0
  260. package/dist/phone-input/index.js +3 -0
  261. package/dist/phone-input/phone-countries.d.ts +29 -0
  262. package/dist/phone-input/phone-countries.js +170 -0
  263. package/dist/phone-input/phone-countries.js.map +1 -0
  264. package/dist/phone-input/phone-input.d.ts +66 -0
  265. package/dist/phone-input/phone-input.js +440 -0
  266. package/dist/phone-input/phone-input.js.map +1 -0
  267. package/dist/popover/popover.d.ts +20 -0
  268. package/dist/popover/popover.js +33 -9
  269. package/dist/popover/popover.js.map +1 -1
  270. package/dist/progress/progress.js +46 -5
  271. package/dist/progress/progress.js.map +1 -1
  272. package/dist/radio-group/radio-group.js +8 -7
  273. package/dist/radio-group/radio-group.js.map +1 -1
  274. package/dist/reactions/index.d.ts +2 -0
  275. package/dist/reactions/index.js +2 -0
  276. package/dist/reactions/reactions.d.ts +50 -0
  277. package/dist/reactions/reactions.js +315 -0
  278. package/dist/reactions/reactions.js.map +1 -0
  279. package/dist/rich-text-editor/index.d.ts +3 -0
  280. package/dist/rich-text-editor/index.js +2 -0
  281. package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
  282. package/dist/rich-text-editor/rich-text-editor.js +909 -0
  283. package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
  284. package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
  285. package/dist/rich-text-editor/rich-text-engine.js +366 -0
  286. package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
  287. package/dist/rich-text-editor/rich-text-html.js +174 -0
  288. package/dist/rich-text-editor/rich-text-html.js.map +1 -0
  289. package/dist/rich-text-editor/rich-text-icons.js +43 -0
  290. package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
  291. package/dist/ridgeline/index.d.ts +2 -0
  292. package/dist/ridgeline/index.js +2 -0
  293. package/dist/ridgeline/ridgeline.d.ts +55 -0
  294. package/dist/ridgeline/ridgeline.js +701 -0
  295. package/dist/ridgeline/ridgeline.js.map +1 -0
  296. package/dist/scroll-area/index.d.ts +2 -2
  297. package/dist/scroll-area/index.js +2 -2
  298. package/dist/scroll-area/scroll-area.d.ts +75 -28
  299. package/dist/scroll-area/scroll-area.js +212 -41
  300. package/dist/scroll-area/scroll-area.js.map +1 -1
  301. package/dist/scrub-input/evaluate.d.ts +14 -0
  302. package/dist/scrub-input/evaluate.js +72 -0
  303. package/dist/scrub-input/evaluate.js.map +1 -0
  304. package/dist/scrub-input/index.d.ts +3 -0
  305. package/dist/scrub-input/index.js +3 -0
  306. package/dist/scrub-input/scrub-input.d.ts +74 -0
  307. package/dist/scrub-input/scrub-input.js +486 -0
  308. package/dist/scrub-input/scrub-input.js.map +1 -0
  309. package/dist/search-field/index.d.ts +2 -0
  310. package/dist/search-field/index.js +2 -0
  311. package/dist/search-field/search-field.d.ts +27 -0
  312. package/dist/search-field/search-field.js +155 -0
  313. package/dist/search-field/search-field.js.map +1 -0
  314. package/dist/select/select.d.ts +3 -1
  315. package/dist/select/select.js +95 -25
  316. package/dist/select/select.js.map +1 -1
  317. package/dist/separator/separator.d.ts +1 -1
  318. package/dist/sheet/sheet.js +4 -2
  319. package/dist/sheet/sheet.js.map +1 -1
  320. package/dist/shortcut-recorder/index.d.ts +3 -0
  321. package/dist/shortcut-recorder/index.js +3 -0
  322. package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
  323. package/dist/shortcut-recorder/shortcut-model.js +206 -0
  324. package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
  325. package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
  326. package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
  327. package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
  328. package/dist/side-nav/index.d.ts +2 -0
  329. package/dist/side-nav/index.js +2 -0
  330. package/dist/side-nav/side-nav.d.ts +72 -0
  331. package/dist/side-nav/side-nav.js +142 -0
  332. package/dist/side-nav/side-nav.js.map +1 -0
  333. package/dist/skeleton/skeleton.d.ts +8 -2
  334. package/dist/skeleton/skeleton.js +6 -2
  335. package/dist/skeleton/skeleton.js.map +1 -1
  336. package/dist/slider/index.d.ts +2 -2
  337. package/dist/slider/slider.d.ts +46 -14
  338. package/dist/slider/slider.js +188 -50
  339. package/dist/slider/slider.js.map +1 -1
  340. package/dist/slope-chart/index.d.ts +2 -0
  341. package/dist/slope-chart/index.js +2 -0
  342. package/dist/slope-chart/slope-chart.d.ts +54 -0
  343. package/dist/slope-chart/slope-chart.js +568 -0
  344. package/dist/slope-chart/slope-chart.js.map +1 -0
  345. package/dist/sparkline/index.d.ts +2 -0
  346. package/dist/sparkline/index.js +2 -0
  347. package/dist/sparkline/sparkline.d.ts +46 -0
  348. package/dist/sparkline/sparkline.js +390 -0
  349. package/dist/sparkline/sparkline.js.map +1 -0
  350. package/dist/split-bar/index.d.ts +2 -0
  351. package/dist/split-bar/index.js +2 -0
  352. package/dist/split-bar/split-bar.d.ts +62 -0
  353. package/dist/split-bar/split-bar.js +513 -0
  354. package/dist/split-bar/split-bar.js.map +1 -0
  355. package/dist/split-button/index.d.ts +2 -0
  356. package/dist/split-button/index.js +2 -0
  357. package/dist/split-button/split-button.d.ts +46 -0
  358. package/dist/split-button/split-button.js +123 -0
  359. package/dist/split-button/split-button.js.map +1 -0
  360. package/dist/stat-card/index.d.ts +2 -0
  361. package/dist/stat-card/index.js +2 -0
  362. package/dist/stat-card/stat-card.d.ts +101 -0
  363. package/dist/stat-card/stat-card.js +249 -0
  364. package/dist/stat-card/stat-card.js.map +1 -0
  365. package/dist/stepper/index.d.ts +2 -0
  366. package/dist/stepper/index.js +2 -0
  367. package/dist/stepper/stepper.d.ts +51 -0
  368. package/dist/stepper/stepper.js +215 -0
  369. package/dist/stepper/stepper.js.map +1 -0
  370. package/dist/streamgraph/index.d.ts +2 -0
  371. package/dist/streamgraph/index.js +2 -0
  372. package/dist/streamgraph/streamgraph.d.ts +70 -0
  373. package/dist/streamgraph/streamgraph.js +613 -0
  374. package/dist/streamgraph/streamgraph.js.map +1 -0
  375. package/dist/styles.css +1 -1
  376. package/dist/swipe-actions/index.d.ts +2 -0
  377. package/dist/swipe-actions/index.js +2 -0
  378. package/dist/swipe-actions/swipe-actions.d.ts +67 -0
  379. package/dist/swipe-actions/swipe-actions.js +552 -0
  380. package/dist/swipe-actions/swipe-actions.js.map +1 -0
  381. package/dist/switch/switch.js +10 -9
  382. package/dist/switch/switch.js.map +1 -1
  383. package/dist/table/index.d.ts +2 -2
  384. package/dist/table/index.js +2 -2
  385. package/dist/table/table.d.ts +87 -4
  386. package/dist/table/table.js +441 -165
  387. package/dist/table/table.js.map +1 -1
  388. package/dist/tabs/tabs.js +143 -7
  389. package/dist/tabs/tabs.js.map +1 -1
  390. package/dist/tag-input/index.d.ts +2 -0
  391. package/dist/tag-input/index.js +2 -0
  392. package/dist/tag-input/tag-input.d.ts +40 -0
  393. package/dist/tag-input/tag-input.js +269 -0
  394. package/dist/tag-input/tag-input.js.map +1 -0
  395. package/dist/text-morph/index.d.ts +2 -0
  396. package/dist/text-morph/index.js +2 -0
  397. package/dist/text-morph/text-morph.d.ts +23 -0
  398. package/dist/text-morph/text-morph.js +21 -0
  399. package/dist/text-morph/text-morph.js.map +1 -0
  400. package/dist/text-reveal/index.d.ts +2 -0
  401. package/dist/text-reveal/index.js +2 -0
  402. package/dist/text-reveal/text-reveal.d.ts +27 -0
  403. package/dist/text-reveal/text-reveal.js +51 -0
  404. package/dist/text-reveal/text-reveal.js.map +1 -0
  405. package/dist/text-shimmer/index.d.ts +2 -0
  406. package/dist/text-shimmer/index.js +2 -0
  407. package/dist/text-shimmer/text-shimmer.d.ts +29 -0
  408. package/dist/text-shimmer/text-shimmer.js +29 -0
  409. package/dist/text-shimmer/text-shimmer.js.map +1 -0
  410. package/dist/textarea/textarea.d.ts +23 -0
  411. package/dist/textarea/textarea.js +24 -2
  412. package/dist/textarea/textarea.js.map +1 -1
  413. package/dist/theme-switch/index.d.ts +2 -0
  414. package/dist/theme-switch/index.js +2 -0
  415. package/dist/theme-switch/theme-switch.d.ts +37 -0
  416. package/dist/theme-switch/theme-switch.js +123 -0
  417. package/dist/theme-switch/theme-switch.js.map +1 -0
  418. package/dist/time-picker/index.d.ts +2 -0
  419. package/dist/time-picker/index.js +2 -0
  420. package/dist/time-picker/time-picker.d.ts +54 -0
  421. package/dist/time-picker/time-picker.js +201 -0
  422. package/dist/time-picker/time-picker.js.map +1 -0
  423. package/dist/toast/index.d.ts +2 -2
  424. package/dist/toast/index.js +2 -2
  425. package/dist/toast/toast.d.ts +6 -0
  426. package/dist/toast/toast.js +98 -36
  427. package/dist/toast/toast.js.map +1 -1
  428. package/dist/tooltip/tooltip.d.ts +10 -3
  429. package/dist/tooltip/tooltip.js +67 -18
  430. package/dist/tooltip/tooltip.js.map +1 -1
  431. package/dist/treemap/index.d.ts +2 -0
  432. package/dist/treemap/index.js +2 -0
  433. package/dist/treemap/treemap.d.ts +53 -0
  434. package/dist/treemap/treemap.js +699 -0
  435. package/dist/treemap/treemap.js.map +1 -0
  436. package/dist/usage-meter/index.d.ts +2 -0
  437. package/dist/usage-meter/index.js +2 -0
  438. package/dist/usage-meter/usage-meter.d.ts +50 -0
  439. package/dist/usage-meter/usage-meter.js +440 -0
  440. package/dist/usage-meter/usage-meter.js.map +1 -0
  441. package/dist/waffle-chart/index.d.ts +2 -0
  442. package/dist/waffle-chart/index.js +2 -0
  443. package/dist/waffle-chart/waffle-chart.d.ts +57 -0
  444. package/dist/waffle-chart/waffle-chart.js +426 -0
  445. package/dist/waffle-chart/waffle-chart.js.map +1 -0
  446. package/package.json +245 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../src/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n CAN_REDO_COMMAND,\n CAN_UNDO_COMMAND,\n COMMAND_PRIORITY_HIGH,\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_DOWN_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND,\n KEY_TAB_COMMAND,\n REDO_COMMAND,\n UNDO_COMMAND,\n type LexicalEditor,\n} from \"lexical\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\n\nimport { Button } from \"../button/button.js\";\nimport { Label } from \"../label/label.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { FieldShell, useFieldWiring } from \"../lib/field-shell.js\";\nimport { useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { Tooltip, TooltipTrigger } from \"../tooltip/tooltip.js\";\nimport {\n $isDocumentEmpty,\n $readFormats,\n LOAD_TAG,\n NO_FORMATS,\n applyLink,\n beginLink,\n createRichTextEditor,\n loadHtml,\n loadMarkdown,\n readValue,\n setBlock,\n syncDividers,\n toggleMark,\n type BlockType,\n type Formats,\n type RichTextValue,\n} from \"./rich-text-engine.js\";\nimport { isSafeUrl, normalizeUrl } from \"./rich-text-html.js\";\nimport {\n BackIcon,\n BoldIcon,\n CheckIcon,\n CodeBlockIcon,\n CodeIcon,\n DividerIcon,\n Heading1Icon,\n Heading2Icon,\n Heading3Icon,\n ItalicIcon,\n LinkIcon,\n ListIcon,\n ListOrderedIcon,\n ParagraphIcon,\n QuoteIcon,\n StrikeIcon,\n UnderlineIcon,\n UnlinkIcon,\n} from \"./rich-text-icons.js\";\n\nexport type { BlockType, RichTextValue };\n\n/** What the editor can be told to do from outside. */\nexport interface RichTextEditorHandle {\n focus: () => void;\n getHTML: () => string;\n getMarkdown: () => string;\n getText: () => string;\n /** Replaces the document. Reports a change, like an edit. */\n setHTML: (html: string) => void;\n /** Replaces the document with Markdown. Reports a change, like an edit. */\n setMarkdown: (markdown: string) => void;\n /** Empties the document. Reports a change, like an edit. */\n clear: () => void;\n undo: () => void;\n redo: () => void;\n /** The editable element. Null before mount. */\n element: HTMLDivElement | null;\n}\n\n/**\n * A rich text field: headings, lists, quotes, code, dividers, links and marks, with a floating\n * selection toolbar, a slash menu for blocks and Markdown shortcuts as you type.\n *\n * The value is canonical HTML in a fixed vocabulary (p, h1-h3, ul, ol, li, blockquote, pre, hr,\n * strong, em, u, s, code, a[href], br), cleaned on the way in and on the way out. It is not the\n * engine's own format, so a stored value does not depend on the engine.\n *\n * @example\n * <RichTextEditor label=\"Notes\" value={html} onChange={(v) => setHtml(v.html)} />\n */\nexport interface RichTextEditorProps {\n /** Controlled HTML. The editor rewrites its content only when this differs from what it last reported, so typing never fights the caret. */\n value?: string;\n /** Initial HTML for an uncontrolled editor. */\n defaultValue?: string;\n /** Initial content as Markdown, used when no HTML is given. */\n defaultMarkdown?: string;\n /** Called with the document in every format after each edit (not after a controlled `value` arrives). */\n onChange?: (value: RichTextValue) => void;\n /** Reports whether undo and redo are available, for your own buttons. */\n onHistoryChange?: (state: { canUndo: boolean; canRedo: boolean }) => void;\n /** Shown while the document is empty. @default \"Start writing\" */\n placeholder?: string;\n /** The hint on an empty line while typing. @default \"Type / for blocks\" */\n blockHint?: string;\n /** Not focusable and not editable, muted. */\n isDisabled?: boolean;\n /** Focusable and selectable, but not editable. The toolbar and slash menu do not open. */\n isReadOnly?: boolean;\n autoFocus?: boolean;\n /** A visible label above the field, which names it. */\n label?: ReactNode;\n /** Helper text under the field, named by `aria-describedby`. */\n description?: string;\n /** Error text under the field. Sets `aria-invalid` and is announced when it appears. */\n error?: string;\n /** The accessible name when there is no `label`. @default \"Editor\" */\n \"aria-label\"?: string;\n id?: string;\n /** Extra classes on the outer element. */\n className?: string;\n}\n\n/* ------------------------------------------------------------------------------------------------\n * The toolbar's and the slash menu's items.\n * ---------------------------------------------------------------------------------------------- */\n\ntype Mark = \"bold\" | \"italic\" | \"underline\" | \"strikethrough\" | \"code\";\n\ninterface ToolItem {\n id: string;\n label: string;\n shortcut?: string;\n icon: ReactNode;\n pressed: (formats: Formats) => boolean;\n run: (editor: LexicalEditor, openLink: () => void) => void;\n}\n\nconst markTool = (\n mark: Mark,\n id: string,\n label: string,\n shortcut: string,\n icon: ReactNode,\n key: keyof Formats,\n): ToolItem => ({\n id,\n label,\n shortcut,\n icon,\n pressed: (formats) => !!formats[key],\n run: (editor) => toggleMark(editor, mark),\n});\nconst blockTool = (type: BlockType, label: string, icon: ReactNode): ToolItem => ({\n id: type,\n label,\n icon,\n pressed: (formats) => formats.block === type,\n run: (editor) => setBlock(editor, type),\n});\n\nconst FORMAT_TOOLS: ToolItem[] = [\n markTool(\"bold\", \"bold\", \"Bold\", \"B\", <BoldIcon />, \"bold\"),\n markTool(\"italic\", \"italic\", \"Italic\", \"I\", <ItalicIcon />, \"italic\"),\n markTool(\"underline\", \"underline\", \"Underline\", \"U\", <UnderlineIcon />, \"underline\"),\n markTool(\"strikethrough\", \"strike\", \"Strikethrough\", \"⇧X\", <StrikeIcon />, \"strike\"),\n markTool(\"code\", \"code\", \"Inline code\", \"E\", <CodeIcon />, \"code\"),\n {\n id: \"link\",\n label: \"Link\",\n shortcut: \"K\",\n icon: <LinkIcon />,\n pressed: (formats) => formats.link !== null,\n run: (_editor, openLink) => openLink(),\n },\n];\nconst BLOCK_TOOLS: ToolItem[] = [\n blockTool(\"h1\", \"Heading 1\", <Heading1Icon />),\n blockTool(\"h2\", \"Heading 2\", <Heading2Icon />),\n blockTool(\"blockquote\", \"Quote\", <QuoteIcon />),\n];\n\ninterface SlashItem {\n type: BlockType;\n label: string;\n hint: string;\n keywords: string;\n icon: ReactNode;\n}\nconst SLASH_ITEMS: SlashItem[] = [\n { type: \"p\", label: \"Text\", hint: \"\", keywords: \"paragraph plain body\", icon: <ParagraphIcon /> },\n { type: \"h1\", label: \"Heading 1\", hint: \"#\", keywords: \"title h1 large\", icon: <Heading1Icon /> },\n {\n type: \"h2\",\n label: \"Heading 2\",\n hint: \"##\",\n keywords: \"subtitle h2 section\",\n icon: <Heading2Icon />,\n },\n { type: \"h3\", label: \"Heading 3\", hint: \"###\", keywords: \"h3 small\", icon: <Heading3Icon /> },\n {\n type: \"ul\",\n label: \"Bulleted list\",\n hint: \"-\",\n keywords: \"bullet unordered ul points\",\n icon: <ListIcon />,\n },\n {\n type: \"ol\",\n label: \"Numbered list\",\n hint: \"1.\",\n keywords: \"ordered ol steps numbers\",\n icon: <ListOrderedIcon />,\n },\n {\n type: \"blockquote\",\n label: \"Quote\",\n hint: \">\",\n keywords: \"blockquote citation callout\",\n icon: <QuoteIcon />,\n },\n {\n type: \"pre\",\n label: \"Code block\",\n hint: \"```\",\n keywords: \"pre snippet monospace\",\n icon: <CodeBlockIcon />,\n },\n {\n type: \"hr\",\n label: \"Divider\",\n hint: \"---\",\n keywords: \"rule hr line separator\",\n icon: <DividerIcon />,\n },\n];\n\n/** ⌘ on Apple platforms, Ctrl elsewhere. Read when a tooltip opens, never during the first render. */\nfunction Hint({ label, shortcut }: { label: string; shortcut?: string }) {\n const apple = typeof navigator !== \"undefined\" && /Mac|iPhone|iPad/.test(navigator.userAgent);\n return (\n <>\n {label}\n {shortcut ? (\n <kbd className=\"ms-2 font-sans opacity-80\">{`${apple ? \"⌘\" : \"Ctrl+\"}${shortcut}`}</kbd>\n ) : null}\n </>\n );\n}\n\nconst toolButton =\n \"size-8 rounded-md p-0 aria-pressed:bg-primary-subtle aria-pressed:text-primary-strong data-[hovered]:aria-pressed:bg-primary-subtle\";\n\n/* ------------------------------------------------------------------------------------------------\n * Geometry.\n * ---------------------------------------------------------------------------------------------- */\n\n/** The visible band of the nearest scrolling or clipping ancestor, so floating layers flip before they get cut off. */\nfunction clipBand(element: HTMLElement) {\n let top = 0;\n let bottom = window.innerHeight;\n for (let node = element.parentElement; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (style.overflowY !== \"visible\" || style.overflowX !== \"visible\") {\n const rect = node.getBoundingClientRect();\n top = Math.max(top, rect.top);\n bottom = Math.min(bottom, rect.bottom);\n }\n }\n return { top, bottom };\n}\n\ninterface Bar {\n x: number;\n y: number;\n below: boolean;\n}\ninterface Slash {\n key: string;\n offset: number;\n query: string;\n x: number;\n y: number;\n above: boolean;\n max: number;\n}\n\nconst BLOCK_SELECTOR = \"p, h1, h2, h3, li, blockquote\";\n\nexport const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(\n function RichTextEditor(\n {\n value,\n defaultValue,\n defaultMarkdown,\n onChange,\n onHistoryChange,\n placeholder = \"Start writing\",\n blockHint = \"Type / for blocks\",\n isDisabled = false,\n isReadOnly = false,\n autoFocus = false,\n label,\n description,\n error,\n \"aria-label\": ariaLabel = \"Editor\",\n id,\n className,\n },\n ref,\n ) {\n const uid = useId();\n const labelId = `${uid}-label`;\n const field = useFieldWiring({\n enabled: true,\n id,\n describedBy: undefined,\n invalid: undefined,\n description,\n error,\n });\n const editable = !isDisabled && !isReadOnly;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const surfaceRef = useRef<HTMLDivElement>(null);\n const editorRef = useRef<LexicalEditor | null>(null);\n const lastEmitted = useRef<string | null>(null);\n const dragging = useRef(false);\n const typedSlash = useRef(false);\n const hinted = useRef<Element | null>(null);\n const callbacks = useRef({ onChange, onHistoryChange });\n const initial = useRef({ value, defaultValue, defaultMarkdown, autoFocus, editable });\n useIsomorphicLayoutEffect(() => {\n callbacks.current = { onChange, onHistoryChange };\n });\n\n const [empty, setEmpty] = useState(true);\n const [formats, setFormats] = useState<Formats>(NO_FORMATS);\n const [bar, setBar] = useState<Bar | null>(null);\n const [placed, setPlaced] = useState(false);\n const [face, setFace] = useState<\"format\" | \"link\">(\"format\");\n const [size, setSize] = useState({ width: 0, height: 0 });\n const [linkDraft, setLinkDraft] = useState(\"\");\n const [stop, setStop] = useState(0);\n const [slash, setSlash] = useState<Slash | null>(null);\n const [slashActive, setSlashActive] = useState(0);\n const [panel, setPanel] = useState<{ height: number; sized: boolean }>({\n height: 0,\n sized: false,\n });\n const [highlight, setHighlight] = useState<{ y: number; h: number; placed: boolean }>({\n y: 0,\n h: 0,\n placed: false,\n });\n const [announce, setAnnounce] = useState(\"\");\n const faceRef = useRef(face);\n const slashRef = useRef(slash);\n const sizeRef = useRef(size);\n const savedLink = useRef<ReturnType<typeof beginLink>>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n const formatFaceRef = useRef<HTMLDivElement>(null);\n const linkFaceRef = useRef<HTMLFormElement>(null);\n const linkInputRef = useRef<HTMLInputElement>(null);\n const slashPanelRef = useRef<HTMLDivElement>(null);\n const slashBodyRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n useIsomorphicLayoutEffect(() => {\n faceRef.current = face;\n slashRef.current = slash;\n sizeRef.current = size;\n });\n\n const slashResults = useMemo(() => {\n const query = slash?.query.trim().toLowerCase() ?? \"\";\n if (!query) return SLASH_ITEMS;\n return SLASH_ITEMS.filter(\n (item) =>\n `${item.label} ${item.keywords}`\n .toLowerCase()\n .split(/\\s+/)\n .some((word) => word.startsWith(query)) || item.label.toLowerCase().includes(query),\n );\n }, [slash?.query]);\n const slashIndex = Math.min(slashActive, Math.max(0, slashResults.length - 1));\n const slashOpen = !!slash && editable && slashResults.length > 0;\n const slashLive = useRef({ open: slashOpen, results: slashResults, index: slashIndex });\n useIsomorphicLayoutEffect(() => {\n slashLive.current = { open: slashOpen, results: slashResults, index: slashIndex };\n });\n // The panel stays in the document once opened, holding what it last showed, so it can leave on a transition.\n const [shownSlash, setShownSlash] = useState<Slash | null>(null);\n if (slash && slash !== shownSlash && slashOpen) setShownSlash(slash);\n const panelSlash = slash ?? shownSlash;\n const open = !!bar && editable;\n\n /* Everything the selection decides: the marks and block it is in, the empty-line hint, the slash query, the toolbar. */\n const sync = () => {\n const editor = editorRef.current;\n const surface = surfaceRef.current;\n const root = rootRef.current;\n if (!editor || !surface || !root) return;\n const selection = window.getSelection();\n const inside = !!selection?.rangeCount && surface.contains(selection.anchorNode);\n const range = inside ? selection.getRangeAt(0) : null;\n\n const next = editor.getEditorState().read($readFormats);\n setFormats((current) =>\n (Object.keys(next) as (keyof Formats)[]).every((key) => current[key] === next[key])\n ? current\n : next,\n );\n syncDividers(editor);\n\n // The hint sits on the empty line holding the caret.\n const anchorElement = range\n ? range.startContainer instanceof Element\n ? range.startContainer\n : range.startContainer.parentElement\n : null;\n const block = anchorElement?.closest(BLOCK_SELECTOR);\n const blockInEditor = block && surface.contains(block) ? block : null;\n const hint =\n range?.collapsed &&\n blockInEditor &&\n !blockInEditor.textContent &&\n !blockInEditor.querySelector(\"li, hr\")\n ? blockInEditor\n : null;\n if (hinted.current !== hint) {\n hinted.current?.removeAttribute(\"data-hint\");\n hint?.setAttribute(\"data-hint\", \"\");\n hinted.current = hint;\n }\n\n if (!range) {\n if (faceRef.current !== \"link\") setBar(null);\n setSlash(null);\n return;\n }\n\n const open = slashRef.current;\n if (open) {\n const text = editor.getEditorState().read(() => {\n const sel = $getSelection();\n const node = $getNodeByKey(open.key);\n if (\n !$isRangeSelection(sel) ||\n !$isTextNode(node) ||\n !sel.isCollapsed() ||\n sel.anchor.key !== open.key\n )\n return null;\n const caret = sel.anchor.offset;\n const content = node.getTextContent();\n return caret > open.offset && content[open.offset] === \"/\"\n ? content.slice(open.offset + 1, caret)\n : null;\n });\n if (text === null || text.length > 24 || /^\\s/.test(text) || /\\s\\s/.test(text))\n setSlash(null);\n else if (text !== open.query) setSlash({ ...open, query: text });\n }\n\n const inCode = next.block === \"pre\";\n if (range.collapsed || dragging.current || inCode || slashRef.current || !editable) {\n if (faceRef.current !== \"link\") setBar(null);\n return;\n }\n const rects = range.getClientRects();\n const rect = rects.length ? rects[0]! : range.getBoundingClientRect();\n const whole = range.getBoundingClientRect();\n const box = root.getBoundingClientRect();\n const below = rect.top - clipBand(root).top < 60;\n const half = (sizeRef.current.width || 280) / 2;\n const x = Math.max(\n half + 4,\n Math.min(whole.left + whole.width / 2 - box.left, box.width - half - 4),\n );\n const y = below ? whole.bottom - box.top + 8 : rect.top - box.top - 8;\n setBar((current) =>\n current && current.x === x && current.y === y && current.below === below\n ? current\n : { x, y, below },\n );\n };\n const syncRef = useRef(sync);\n useIsomorphicLayoutEffect(() => {\n syncRef.current = sync;\n });\n\n /* Puts focus back in the text. The surface is focused directly, so the selection the toolbar was acting on survives. */\n const focusSurface = () => surfaceRef.current?.focus({ preventScroll: true });\n const focusEditor = () => {\n editorRef.current?.focus();\n focusSurface();\n };\n\n /* Links. */\n const closeLink = (refocus = true) => {\n const editor = editorRef.current;\n const saved = savedLink.current;\n savedLink.current = null;\n faceRef.current = \"format\";\n setFace(\"format\");\n if (refocus && editor) {\n if (saved) editor.update(() => $setSelection(saved.selection.clone()));\n focusSurface();\n }\n };\n const openLink = () => {\n const editor = editorRef.current;\n if (!editor || !editable) return;\n const link = beginLink(editor);\n if (!link) return;\n savedLink.current = link;\n faceRef.current = \"link\";\n setLinkDraft(link.url ?? \"\");\n setFace(\"link\");\n syncRef.current();\n };\n const openLinkRef = useRef(openLink);\n useIsomorphicLayoutEffect(() => {\n openLinkRef.current = openLink;\n });\n const submitLink = (remove = false) => {\n const editor = editorRef.current;\n const saved = savedLink.current;\n if (!editor || !saved) return closeLink();\n const url = remove ? \"\" : normalizeUrl(linkDraft);\n if (url && !isSafeUrl(url)) {\n setAnnounce(\"That address cannot be linked\");\n return;\n }\n savedLink.current = null;\n faceRef.current = \"format\";\n setFace(\"format\");\n setBar(null);\n focusSurface();\n applyLink(editor, saved.selection, url || null);\n setAnnounce(url ? \"Link added\" : \"Link removed\");\n };\n\n /* Choosing from the slash menu: the typed \"/query\" goes, and the line turns into the block. */\n const chooseSlash = (item: SlashItem | undefined) => {\n const editor = editorRef.current;\n const open = slashRef.current;\n if (!editor || !open || !item) return;\n setSlash(null);\n editor.update(\n () => {\n const node = $getNodeByKey(open.key);\n if (!$isTextNode(node)) return;\n const selection = $getSelection();\n const caret =\n $isRangeSelection(selection) && selection.anchor.key === open.key\n ? selection.anchor.offset\n : open.offset + 1 + open.query.length;\n node.spliceText(open.offset, Math.max(1, caret - open.offset), \"\", true);\n },\n { discrete: true },\n );\n setBlock(editor, item.type);\n setAnnounce(`${item.label} added`);\n };\n const chooseRef = useRef(chooseSlash);\n useIsomorphicLayoutEffect(() => {\n chooseRef.current = chooseSlash;\n });\n\n /* The editor: created once, and torn down with the element. */\n useIsomorphicLayoutEffect(() => {\n const surface = surfaceRef.current;\n if (!surface) return;\n const { editor, destroy } = createRichTextEditor(surface);\n editorRef.current = editor;\n const start = initial.current;\n editor.setEditable(start.editable);\n const html = start.value ?? start.defaultValue;\n if (html !== undefined) loadHtml(editor, html, true, true);\n else if (start.defaultMarkdown !== undefined)\n loadMarkdown(editor, start.defaultMarkdown, true, true);\n else loadHtml(editor, \"\", true, true);\n lastEmitted.current = start.value ?? null;\n setEmpty(editor.getEditorState().read($isDocumentEmpty));\n\n let canUndo = false;\n let canRedo = false;\n const reportHistory = () => callbacks.current.onHistoryChange?.({ canUndo, canRedo });\n reportHistory();\n\n const onBeforeInput = (event: InputEvent) => {\n typedSlash.current = event.inputType === \"insertText\" && event.data === \"/\";\n };\n surface.addEventListener(\"beforeinput\", onBeforeInput);\n\n const openSlash = () => {\n const root = rootRef.current;\n const selection = window.getSelection();\n const dom = selection?.anchorNode;\n if (\n !root ||\n !selection ||\n !dom ||\n dom.nodeType !== Node.TEXT_NODE ||\n !selection.isCollapsed\n )\n return;\n const caret = selection.anchorOffset;\n const data = (dom as Text).data;\n if (data[caret - 1] !== \"/\" || (caret > 1 && !/\\s/.test(data[caret - 2]!))) return;\n const target = editor.getEditorState().read(() => {\n const sel = $getSelection();\n if (!$isRangeSelection(sel) || !sel.isCollapsed() || !$isTextNode(sel.anchor.getNode()))\n return null;\n return $readFormats().block === \"pre\"\n ? null\n : { key: sel.anchor.key, offset: sel.anchor.offset - 1 };\n });\n if (!target) return;\n const mark = document.createRange();\n mark.setStart(dom, caret - 1);\n mark.setEnd(dom, caret);\n const rect = mark.getBoundingClientRect();\n const box = root.getBoundingClientRect();\n const band = clipBand(root);\n const above =\n band.bottom - rect.bottom < 330 && rect.top - band.top > band.bottom - rect.bottom;\n const room = above ? rect.top - band.top - 12 : band.bottom - rect.bottom - 12;\n setSlash({\n ...target,\n query: \"\",\n x: Math.max(0, Math.min(rect.left - box.left - 8, box.width - 244)),\n y: above ? rect.top - box.top - 6 : rect.bottom - box.top + 6,\n above,\n max: Math.max(150, room),\n });\n setSlashActive(0);\n setBar(null);\n };\n\n function moveSlash(event: KeyboardEvent | null, step: number) {\n const live = slashLive.current;\n if (!live.open || !event) return false;\n event.preventDefault();\n setSlashActive((live.index + step + live.results.length) % live.results.length);\n return true;\n }\n function pickSlash(event: KeyboardEvent | null) {\n const live = slashLive.current;\n if (!live.open || !event) return false;\n event.preventDefault();\n const item = live.results[live.index];\n queueMicrotask(() => chooseRef.current(item));\n return true;\n }\n\n const off = [\n editor.registerUpdateListener(({ editorState, dirtyElements, dirtyLeaves, tags }) => {\n if (dirtyElements.size > 0 || dirtyLeaves.size > 0) {\n setEmpty(editorState.read($isDocumentEmpty));\n if (!tags.has(LOAD_TAG)) {\n const next = readValue(editor);\n lastEmitted.current = next.html;\n callbacks.current.onChange?.(next);\n }\n }\n if (typedSlash.current) {\n typedSlash.current = false;\n openSlash();\n }\n syncRef.current();\n }),\n editor.registerCommand(\n CAN_UNDO_COMMAND,\n (payload) => {\n canUndo = payload;\n reportHistory();\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n editor.registerCommand(\n CAN_REDO_COMMAND,\n (payload) => {\n canRedo = payload;\n reportHistory();\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n // The slash menu takes the arrows, Enter, Tab and Escape while it is open.\n editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n (event) => moveSlash(event, 1),\n COMMAND_PRIORITY_HIGH,\n ),\n editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n (event) => moveSlash(event, -1),\n COMMAND_PRIORITY_HIGH,\n ),\n editor.registerCommand(\n KEY_ENTER_COMMAND,\n (event) => pickSlash(event),\n COMMAND_PRIORITY_HIGH,\n ),\n editor.registerCommand(KEY_TAB_COMMAND, (event) => pickSlash(event), COMMAND_PRIORITY_HIGH),\n editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n (event) => {\n if (!slashLive.current.open) return false;\n event.preventDefault();\n event.stopPropagation();\n setSlash(null);\n return true;\n },\n COMMAND_PRIORITY_HIGH,\n ),\n editor.registerCommand(\n KEY_DOWN_COMMAND,\n (event) => {\n if (\n !(event.metaKey || event.ctrlKey) ||\n event.altKey ||\n event.shiftKey ||\n event.key.toLowerCase() !== \"k\"\n )\n return false;\n event.preventDefault();\n // A command runs inside an engine update; opening the link starts updates of its own, so it waits for this one.\n queueMicrotask(() => openLinkRef.current());\n return true;\n },\n COMMAND_PRIORITY_LOW,\n ),\n ];\n\n if (start.autoFocus && start.editable) {\n editor.focus();\n surface.focus({ preventScroll: true });\n }\n\n return () => {\n off.forEach((unregister) => unregister());\n surface.removeEventListener(\"beforeinput\", onBeforeInput);\n destroy();\n editorRef.current = null;\n };\n }, []);\n\n useEffect(() => {\n editorRef.current?.setEditable(editable);\n }, [editable]);\n\n /* A controlled value that differs from what the editor last reported replaces the document. */\n useEffect(() => {\n const editor = editorRef.current;\n if (!editor || value === undefined || value === lastEmitted.current) return;\n lastEmitted.current = value;\n loadHtml(editor, value, true);\n }, [value]);\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => {\n editorRef.current?.focus();\n surfaceRef.current?.focus({ preventScroll: true });\n },\n getHTML: () => (editorRef.current ? readValue(editorRef.current).html : \"\"),\n getMarkdown: () => (editorRef.current ? readValue(editorRef.current).markdown : \"\"),\n getText: () => (editorRef.current ? readValue(editorRef.current).text : \"\"),\n setHTML: (html) => editorRef.current && loadHtml(editorRef.current, html, false),\n setMarkdown: (markdown) =>\n editorRef.current && loadMarkdown(editorRef.current, markdown, false),\n clear: () => editorRef.current && loadHtml(editorRef.current, \"\", false),\n undo: () => {\n editorRef.current?.dispatchCommand(UNDO_COMMAND, undefined);\n setAnnounce(\"Undone\");\n },\n redo: () => {\n editorRef.current?.dispatchCommand(REDO_COMMAND, undefined);\n setAnnounce(\"Redone\");\n },\n get element() {\n return surfaceRef.current;\n },\n }),\n [],\n );\n\n /* A drag that selects text shows the toolbar when it ends, and a click away closes the link face. */\n useEffect(() => {\n const up = () => {\n if (!dragging.current) return;\n dragging.current = false;\n syncRef.current();\n };\n const down = (event: PointerEvent) => {\n if (faceRef.current !== \"link\" || toolbarRef.current?.contains(event.target as Node))\n return;\n savedLink.current = null;\n faceRef.current = \"format\";\n setFace(\"format\");\n setBar(null);\n };\n // The engine reports selection changes it makes itself; a selection moved by the browser or by a drag is read here.\n let frame = 0;\n const changed = () => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => syncRef.current());\n };\n document.addEventListener(\"pointerup\", up);\n document.addEventListener(\"pointerdown\", down);\n document.addEventListener(\"selectionchange\", changed);\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener(\"pointerup\", up);\n document.removeEventListener(\"pointerdown\", down);\n document.removeEventListener(\"selectionchange\", changed);\n };\n }, []);\n\n /* The link field takes focus once its face is showing (until then it is inert). */\n useEffect(() => {\n if (face !== \"link\") return;\n const frame = requestAnimationFrame(() =>\n linkInputRef.current?.focus({ preventScroll: true }),\n );\n return () => cancelAnimationFrame(frame);\n }, [face]);\n\n /* The toolbar is placed, not glided, the first time it opens: the glide exists only once it has painted. */\n useEffect(() => {\n if (!open) return;\n let second = 0;\n const first = requestAnimationFrame(() => {\n second = requestAnimationFrame(() => setPlaced(true));\n });\n return () => {\n cancelAnimationFrame(first);\n cancelAnimationFrame(second);\n setPlaced(false);\n };\n }, [open]);\n\n /* The surface springs to the size of the face showing. Both faces stay mounted; the other one is inert. */\n useIsomorphicLayoutEffect(() => {\n const active = face === \"format\" ? formatFaceRef.current : linkFaceRef.current;\n if (toolbarRef.current) toolbarRef.current.inert = !open;\n if (formatFaceRef.current) formatFaceRef.current.inert = face !== \"format\";\n if (linkFaceRef.current) linkFaceRef.current.inert = face !== \"link\";\n if (!active) return;\n const report = () =>\n setSize((current) =>\n current.width === active.offsetWidth && current.height === active.offsetHeight\n ? current\n : { width: active.offsetWidth, height: active.offsetHeight },\n );\n report();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(report);\n observer.observe(active);\n return () => observer.disconnect();\n }, [face, open]);\n\n /* Slash menu geometry: the highlight glides to the active row and the panel's height follows its rows. */\n useIsomorphicLayoutEffect(() => {\n if (!slashOpen) {\n setHighlight((current) => (current.placed ? { ...current, placed: false } : current));\n setPanel((current) => (current.sized ? { ...current, sized: false } : current));\n return;\n }\n const row = listRef.current?.querySelector<HTMLElement>(`[data-index=\"${slashIndex}\"]`);\n if (row) {\n setHighlight((current) => ({\n y: row.offsetTop,\n h: row.offsetHeight,\n placed: current.placed || current.h > 0,\n }));\n const panelEl = slashPanelRef.current;\n if (panelEl) {\n const top = row.offsetTop + 6;\n const bottom = top + row.offsetHeight;\n if (top - 6 < panelEl.scrollTop) panelEl.scrollTop = top - 6;\n else if (bottom + 6 > panelEl.scrollTop + panelEl.clientHeight)\n panelEl.scrollTop = bottom + 6 - panelEl.clientHeight;\n }\n }\n const body = slashBodyRef.current;\n if (!body) return;\n const max = panelSlash?.max ?? 320;\n const fit = () =>\n setPanel((current) => {\n const height = Math.min(body.offsetHeight, max);\n return current.height === height\n ? { ...current, sized: true }\n : { height, sized: current.height > 0 };\n });\n fit();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(fit);\n observer.observe(body);\n return () => observer.disconnect();\n }, [slashOpen, slashIndex, slashResults, panelSlash?.max]);\n\n /* Keyboard. */\n const focusToolbar = () =>\n formatFaceRef.current?.querySelectorAll<HTMLElement>(\"button\")[stop]?.focus();\n const onSurfaceKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n if (event.altKey && event.key === \"F10\" && open) {\n event.preventDefault();\n focusToolbar();\n }\n };\n const onToolbarKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n if (face === \"link\") return;\n const buttons = Array.from(\n formatFaceRef.current?.querySelectorAll<HTMLButtonElement>(\"button:not([disabled])\") ?? [],\n );\n const at = buttons.indexOf(document.activeElement as HTMLButtonElement);\n if (\n at >= 0 &&\n (event.key === \"ArrowRight\" ||\n event.key === \"ArrowLeft\" ||\n event.key === \"Home\" ||\n event.key === \"End\")\n ) {\n event.preventDefault();\n const next =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? buttons.length - 1\n : (at + (event.key === \"ArrowRight\" ? 1 : -1) + buttons.length) % buttons.length;\n buttons[next]?.focus();\n } else if (event.key === \"Escape\") {\n // The first Escape closes the focused button's tooltip, if one is showing; the next arrives here.\n event.preventDefault();\n event.stopPropagation();\n focusSurface();\n }\n };\n\n const tools = [...FORMAT_TOOLS, ...BLOCK_TOOLS];\n const renderTool = (tool: ToolItem) => {\n const index = tools.indexOf(tool);\n return (\n <TooltipTrigger key={tool.id}>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={toolButton}\n aria-label={tool.label === \"Link\" && formats.link ? \"Edit link\" : tool.label}\n aria-pressed={tool.pressed(formats)}\n excludeFromTabOrder={stop !== index}\n preventFocusOnPress\n onFocus={() => setStop(index)}\n onPress={() => {\n const editor = editorRef.current;\n if (editor) tool.run(editor, openLink);\n }}\n >\n {tool.icon}\n </Button>\n <Tooltip placement=\"top\">\n <Hint label={tool.label} shortcut={tool.shortcut} />\n </Tooltip>\n </TooltipTrigger>\n );\n };\n\n const optionId = (index: number) => `${uid}-slash-${index}`;\n const cssVars = {\n \"--rich-text-placeholder\": JSON.stringify(placeholder),\n \"--rich-text-hint\": JSON.stringify(blockHint),\n } as CSSProperties;\n const toolbarStyle = {\n left: bar?.x ?? 0,\n top: bar?.y ?? 0,\n width: size.width,\n height: size.height,\n } as CSSProperties;\n\n const surface = (\n <div ref={rootRef} data-slot=\"rich-text-editor-root\" className=\"rich-text\">\n <div\n ref={surfaceRef}\n {...field.controlProps}\n data-slot=\"rich-text-editor\"\n data-empty={empty || undefined}\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label={label == null ? ariaLabel : undefined}\n aria-labelledby={label == null ? undefined : labelId}\n aria-placeholder={placeholder}\n aria-readonly={isReadOnly || undefined}\n aria-disabled={isDisabled || undefined}\n aria-controls={slashOpen ? `${uid}-slash` : undefined}\n aria-activedescendant={slashOpen ? optionId(slashIndex) : undefined}\n contentEditable={editable}\n suppressContentEditableWarning\n tabIndex={isReadOnly && !isDisabled ? 0 : undefined}\n spellCheck\n className=\"rich-text-surface\"\n style={cssVars}\n onKeyDown={onSurfaceKeyDown}\n onPointerDown={() => {\n dragging.current = true;\n }}\n />\n <span\n role=\"status\"\n aria-live=\"polite\"\n data-slot=\"rich-text-editor-status\"\n className=\"sr-only\"\n >\n {announce}\n </span>\n\n <div\n ref={toolbarRef}\n data-slot=\"rich-text-editor-toolbar\"\n role=\"toolbar\"\n aria-label=\"Formatting\"\n aria-keyshortcuts=\"Alt+F10\"\n data-open={open || undefined}\n data-below={bar?.below || undefined}\n data-placed={(open && placed) || undefined}\n className=\"rich-text-toolbar\"\n style={toolbarStyle}\n onKeyDown={onToolbarKeyDown}\n >\n <div\n ref={formatFaceRef}\n data-face=\"format\"\n data-active={face === \"format\" || undefined}\n className=\"rich-text-face\"\n >\n <div className=\"rich-text-row\">\n {FORMAT_TOOLS.map(renderTool)}\n <span className=\"rich-text-block-tools\">\n <span aria-hidden=\"true\" className=\"rich-text-divider\" />\n {BLOCK_TOOLS.map(renderTool)}\n </span>\n </div>\n </div>\n <form\n ref={linkFaceRef}\n data-face=\"link\"\n data-active={face === \"link\" || undefined}\n className=\"rich-text-face\"\n onSubmit={(event) => {\n event.preventDefault();\n submitLink();\n }}\n >\n <div className=\"rich-text-row\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={toolButton}\n type=\"button\"\n aria-label=\"Back to formatting\"\n preventFocusOnPress\n onPress={() => closeLink()}\n >\n <BackIcon />\n </Button>\n <input\n ref={linkInputRef}\n className=\"rich-text-link-input\"\n value={linkDraft}\n onChange={(event) => setLinkDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n event.stopPropagation();\n closeLink();\n }}\n placeholder=\"Paste or type a link\"\n aria-label=\"Link address\"\n inputMode=\"url\"\n autoComplete=\"off\"\n spellCheck={false}\n />\n {formats.link ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={toolButton}\n type=\"button\"\n aria-label=\"Remove link\"\n preventFocusOnPress\n onPress={() => submitLink(true)}\n >\n <UnlinkIcon />\n </Button>\n ) : null}\n <Button\n variant={linkDraft.trim() ? \"primary\" : \"secondary\"}\n size=\"icon\"\n className=\"size-8 rounded-md p-0\"\n type=\"submit\"\n aria-label=\"Apply link\"\n >\n <CheckIcon />\n </Button>\n </div>\n </form>\n </div>\n\n {panelSlash ? (\n <div\n ref={slashPanelRef}\n data-slot=\"rich-text-editor-slash\"\n data-open={slashOpen || undefined}\n data-above={panelSlash.above || undefined}\n data-sized={panel.sized || undefined}\n className=\"rich-text-slash\"\n style={{\n left: panelSlash.x,\n top: panelSlash.y,\n height: panel.height || undefined,\n maxHeight: panelSlash.max,\n }}\n onMouseDown={(event) => event.preventDefault()}\n >\n <div ref={slashBodyRef} className=\"rich-text-slash-body\">\n <ul\n ref={listRef}\n id={`${uid}-slash`}\n role=\"listbox\"\n aria-label=\"Blocks\"\n className=\"rich-text-slash-list\"\n >\n <li\n aria-hidden=\"true\"\n data-placed={highlight.placed || undefined}\n className=\"rich-text-slash-highlight\"\n style={\n {\n \"--rich-text-y\": `${highlight.y}px`,\n \"--rich-text-h\": `${highlight.h}px`,\n } as CSSProperties\n }\n />\n {slashResults.map((item, index) => (\n <li\n key={item.type}\n id={optionId(index)}\n role=\"option\"\n aria-selected={index === slashIndex}\n data-index={index}\n className=\"rich-text-slash-option\"\n onPointerMove={() => {\n if (index !== slashIndex) setSlashActive(index);\n }}\n onClick={() => chooseSlash(item)}\n >\n <span className=\"grid w-5 flex-none place-items-center\">{item.icon}</span>\n <span className=\"min-w-0 flex-1 truncate font-medium\">{item.label}</span>\n {item.hint ? (\n <kbd className=\"flex-none font-mono text-xs text-muted-foreground\">\n {item.hint}\n </kbd>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n </div>\n ) : null}\n </div>\n );\n\n return (\n <div data-slot=\"rich-text-editor-field\" className={cn(\"w-full min-w-0 font-sans\", className)}>\n <FieldShell\n label={null}\n controlId={field.controlId}\n description={description}\n hintId={field.hintId}\n error={error}\n errorId={field.errorId}\n wordExit=\"quick\"\n >\n {label == null ? null : (\n <Label id={labelId} className=\"mb-1.5\" onClick={focusEditor}>\n {label}\n </Label>\n )}\n {surface}\n </FieldShell>\n </div>\n );\n },\n);\n\nRichTextEditor.displayName = \"RichTextEditor\";\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { DecoratorNode } from "lexical";
2
+ import "@lexical/markdown";
3
+ //#region src/rich-text-editor/rich-text-engine.d.ts
4
+ export type BlockType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "blockquote" | "pre" | "hr";
5
+ export interface RichTextValue {
6
+ /** Canonical HTML: p, h1-h3, ul, ol, li, blockquote, pre, hr, strong, em, u, s, code, a[href], br. An empty document is "". */
7
+ html: string;
8
+ /** The same content as Markdown. Underline has no Markdown form and is dropped. */
9
+ markdown: string;
10
+ /** Plain text, one line per block. */
11
+ text: string;
12
+ /** True when there is no text and no divider. */
13
+ empty: boolean;
14
+ }
15
+ //#endregion
16
+ //# sourceMappingURL=rich-text-engine.d.ts.map
@@ -0,0 +1,366 @@
1
+ import { canonicalDom, plainText, sanitizeToDom } from "./rich-text-html.js";
2
+ import { $create, $createParagraphNode, $getRoot, $getSelection, $isDecoratorNode, $isElementNode, $isLineBreakNode, $isRangeSelection, $isTextNode, $setSelection, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, DROP_COMMAND, DecoratorNode, FORMAT_TEXT_COMMAND, INDENT_CONTENT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND, createEditor } from "lexical";
3
+ import { $createCodeNode, $isCodeNode, CodeNode } from "@lexical/code";
4
+ import { createEmptyHistoryState, registerHistory } from "@lexical/history";
5
+ import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html";
6
+ import { $isLinkNode, $toggleLink, LinkNode } from "@lexical/link";
7
+ import { $isListItemNode, $isListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListItemNode, ListNode, REMOVE_LIST_COMMAND, registerList } from "@lexical/list";
8
+ import { $convertFromMarkdownString, $convertToMarkdownString, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, CODE, HEADING, INLINE_CODE, ITALIC_STAR, ITALIC_UNDERSCORE, LINK, ORDERED_LIST, QUOTE, STRIKETHROUGH, UNORDERED_LIST, registerMarkdownShortcuts } from "@lexical/markdown";
9
+ import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode, HeadingNode, QuoteNode, registerRichText } from "@lexical/rich-text";
10
+ import { $setBlocksType } from "@lexical/selection";
11
+ import { $findMatchingParent, $getNearestNodeOfType, $insertNodeToNearestRoot, mergeRegister } from "@lexical/utils";
12
+ //#region src/rich-text-editor/rich-text-engine.ts
13
+ const NO_FORMATS = {
14
+ bold: false,
15
+ italic: false,
16
+ underline: false,
17
+ strike: false,
18
+ code: false,
19
+ link: null,
20
+ block: "p"
21
+ };
22
+ var DividerNode = class extends DecoratorNode {
23
+ $config() {
24
+ return this.config("divider", {
25
+ extends: DecoratorNode,
26
+ importDOM: { hr: () => ({
27
+ conversion: () => ({ node: $createDivider() }),
28
+ priority: 0
29
+ }) }
30
+ });
31
+ }
32
+ exportDOM() {
33
+ return { element: document.createElement("hr") };
34
+ }
35
+ createDOM() {
36
+ return document.createElement("hr");
37
+ }
38
+ updateDOM() {
39
+ return false;
40
+ }
41
+ getTextContent() {
42
+ return "\n";
43
+ }
44
+ isInline() {
45
+ return false;
46
+ }
47
+ };
48
+ const $isDivider = (node) => node instanceof DividerNode;
49
+ const $createDivider = () => $create(DividerNode);
50
+ const TRANSFORMERS = [
51
+ HEADING,
52
+ QUOTE,
53
+ CODE,
54
+ UNORDERED_LIST,
55
+ ORDERED_LIST,
56
+ {
57
+ dependencies: [DividerNode],
58
+ export: (node) => $isDivider(node) ? "---" : null,
59
+ regExp: /^(?:---|\*\*\*|___)\s?$/,
60
+ replace: (parent, _children, _match, isImport) => {
61
+ const line = $createDivider();
62
+ if (isImport || parent.getNextSibling() !== null) parent.replace(line);
63
+ else parent.insertBefore(line);
64
+ line.selectNext();
65
+ },
66
+ triggerOnEnter: true,
67
+ type: "element"
68
+ },
69
+ INLINE_CODE,
70
+ BOLD_ITALIC_STAR,
71
+ BOLD_ITALIC_UNDERSCORE,
72
+ BOLD_STAR,
73
+ BOLD_UNDERSCORE,
74
+ STRIKETHROUGH,
75
+ ITALIC_STAR,
76
+ ITALIC_UNDERSCORE,
77
+ LINK
78
+ ];
79
+ /** Static class strings, so Tailwind sees them. The look of blocks and links lives in the rich-text-content utility. */
80
+ const theme = {
81
+ text: {
82
+ bold: "font-semibold",
83
+ italic: "italic",
84
+ underline: "underline",
85
+ strikethrough: "line-through",
86
+ underlineStrikethrough: "underline line-through"
87
+ },
88
+ list: { nested: { listitem: "list-none" } },
89
+ code: "rich-text-code-block"
90
+ };
91
+ /** Creates the editor and registers everything it does. Returns it with one call that undoes all of it. */
92
+ function createRichTextEditor(root) {
93
+ const editor = createEditor({
94
+ namespace: "alfred-rich-text",
95
+ nodes: [
96
+ HeadingNode,
97
+ QuoteNode,
98
+ ListNode,
99
+ ListItemNode,
100
+ LinkNode,
101
+ CodeNode,
102
+ DividerNode
103
+ ],
104
+ theme,
105
+ editable: false,
106
+ onError: (error) => {
107
+ throw error;
108
+ }
109
+ });
110
+ editor.setRootElement(root);
111
+ const unregister = mergeRegister(registerRichText(editor), registerHistory(editor, createEmptyHistoryState(), 600), registerList(editor), registerMarkdownShortcuts(editor, TRANSFORMERS), editor.registerNodeTransform(HeadingNode, (node) => {
112
+ if (node.getTag() > "h3") node.setTag("h3");
113
+ }), editor.registerCommand(DROP_COMMAND, (event) => {
114
+ event.preventDefault();
115
+ return true;
116
+ }, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_TAB_COMMAND, (event) => {
117
+ const selection = $getSelection();
118
+ if (!$isRangeSelection(selection)) return false;
119
+ const block = $blockType(selection);
120
+ if (block === "ul" || block === "ol") {
121
+ event.preventDefault();
122
+ editor.dispatchCommand(event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND, void 0);
123
+ return true;
124
+ }
125
+ if (block === "pre" && !event.shiftKey) {
126
+ event.preventDefault();
127
+ selection.insertText(" ");
128
+ return true;
129
+ }
130
+ return false;
131
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, (event) => {
132
+ const selection = $getSelection();
133
+ if (!$isRangeSelection(selection) || !selection.isCollapsed() || selection.anchor.offset !== 0) return false;
134
+ const node = selection.anchor.getNode();
135
+ const top = node.getTopLevelElement();
136
+ if (!top || !($isHeadingNode(top) || $isQuoteNode(top) || $isCodeNode(top))) return false;
137
+ if (!node.is(top) && !node.is(top.getFirstDescendant())) return false;
138
+ event.preventDefault();
139
+ $setBlocksType(selection, $createParagraphNode);
140
+ return true;
141
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
142
+ const selection = $getSelection();
143
+ if (!$isRangeSelection(selection) || !selection.isCollapsed() || event?.shiftKey) return false;
144
+ const code = selection.anchor.getNode().getTopLevelElement();
145
+ if (!$isCodeNode(code)) return false;
146
+ const last = code.getLastChild();
147
+ const atEnd = selection.anchor.key === code.getKey() ? selection.anchor.offset === code.getChildrenSize() : last !== null && selection.anchor.getNode().is(last) && selection.anchor.offset === last.getTextContentSize();
148
+ if (!$isLineBreakNode(last) || !atEnd) return false;
149
+ event?.preventDefault();
150
+ last.remove();
151
+ const paragraph = $createParagraphNode();
152
+ code.insertAfter(paragraph);
153
+ paragraph.select();
154
+ return true;
155
+ }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DOWN_COMMAND, (event) => {
156
+ if (!(event.metaKey || event.ctrlKey) || event.altKey) return false;
157
+ const key = event.key.toLowerCase();
158
+ if (key === "x" && event.shiftKey) {
159
+ event.preventDefault();
160
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "strikethrough");
161
+ return true;
162
+ }
163
+ if (key === "e" && !event.shiftKey) {
164
+ event.preventDefault();
165
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "code");
166
+ return true;
167
+ }
168
+ return false;
169
+ }, COMMAND_PRIORITY_LOW));
170
+ return {
171
+ editor,
172
+ destroy: () => {
173
+ unregister();
174
+ editor.setRootElement(null);
175
+ }
176
+ };
177
+ }
178
+ /** An update tag for programmatic loads, which must not report as an edit. */
179
+ const LOAD_TAG = "rich-text-load";
180
+ function $fill(nodes) {
181
+ const root = $getRoot();
182
+ root.clear();
183
+ for (const node of nodes) if ($isElementNode(node) || $isDecoratorNode(node)) root.append(node);
184
+ else root.append($createParagraphNode().append(node));
185
+ if (!root.getChildrenSize()) root.append($createParagraphNode());
186
+ }
187
+ /**
188
+ * How a load is tagged. `silent` loads are not edits: no change is reported. `first` is the
189
+ * initial content, which becomes the history's starting point rather than a step to undo.
190
+ */
191
+ const loadTags = (silent, first) => [...silent ? [LOAD_TAG] : [], ...first ? ["history-merge"] : []];
192
+ /** Replaces the document with HTML (cleaned first). */
193
+ function loadHtml(editor, html, silent, first = false) {
194
+ editor.update(() => {
195
+ const dom = sanitizeToDom(html);
196
+ $fill($generateNodesFromDOM(editor, dom));
197
+ }, {
198
+ tag: loadTags(silent, first),
199
+ discrete: true
200
+ });
201
+ }
202
+ function loadMarkdown(editor, markdown, silent, first = false) {
203
+ editor.update(() => {
204
+ $convertFromMarkdownString(markdown, TRANSFORMERS);
205
+ if (!$getRoot().getChildrenSize()) $getRoot().append($createParagraphNode());
206
+ }, {
207
+ tag: loadTags(silent, first),
208
+ discrete: true
209
+ });
210
+ }
211
+ /** True when no block holds text and there is no divider. Call inside a read or update. */
212
+ function $isDocumentEmpty() {
213
+ return $getRoot().getChildren().every((block) => !$isDivider(block) && block.getTextContent().trim() === "");
214
+ }
215
+ /** Markdown with empty blocks left out: one blank line between blocks, none at the ends, code blocks untouched. */
216
+ function tidyMarkdown(markdown) {
217
+ let fenced = false;
218
+ let blank = false;
219
+ const out = [];
220
+ for (const line of markdown.split("\n")) {
221
+ if (/^\s*`{3,}/.test(line)) fenced = !fenced;
222
+ if (!fenced && !line.trim()) {
223
+ blank = out.length > 0;
224
+ continue;
225
+ }
226
+ if (blank) out.push("");
227
+ blank = false;
228
+ out.push(line);
229
+ }
230
+ return out.join("\n");
231
+ }
232
+ /** The whole document, in every format. */
233
+ function readValue(editor) {
234
+ return editor.getEditorState().read(() => {
235
+ const empty = $isDocumentEmpty();
236
+ const dom = canonicalDom($generateHtmlFromNodes(editor));
237
+ return {
238
+ html: empty ? "" : dom.innerHTML,
239
+ markdown: empty ? "" : tidyMarkdown($convertToMarkdownString(TRANSFORMERS)),
240
+ text: plainText(dom),
241
+ empty
242
+ };
243
+ });
244
+ }
245
+ /** The block type at the selection's anchor. Call inside a read or update. */
246
+ function $blockType(selection) {
247
+ if (!$isRangeSelection(selection)) return "p";
248
+ const anchor = selection.anchor.getNode();
249
+ const top = anchor.getKey() === "root" ? anchor : anchor.getTopLevelElementOrThrow();
250
+ if ($isListNode(top) || $isListItemNode(top)) return $getNearestNodeOfType(anchor, ListNode)?.getListType() === "number" ? "ol" : "ul";
251
+ if ($isHeadingNode(top)) return top.getTag();
252
+ if ($isQuoteNode(top)) return "blockquote";
253
+ if ($isCodeNode(top)) return "pre";
254
+ return "p";
255
+ }
256
+ const linkAt = (node) => $findMatchingParent(node, $isLinkNode);
257
+ /** The marks, link and block at the selection. Call inside a read. */
258
+ function $readFormats() {
259
+ const selection = $getSelection();
260
+ if (!$isRangeSelection(selection)) return NO_FORMATS;
261
+ const link = linkAt(selection.anchor.getNode());
262
+ return {
263
+ bold: selection.hasFormat("bold"),
264
+ italic: selection.hasFormat("italic"),
265
+ underline: selection.hasFormat("underline"),
266
+ strike: selection.hasFormat("strikethrough"),
267
+ code: selection.hasFormat("code"),
268
+ link: link ? link.getURL() : null,
269
+ block: $blockType(selection)
270
+ };
271
+ }
272
+ const toggleMark = (editor, mark) => editor.dispatchCommand(FORMAT_TEXT_COMMAND, mark);
273
+ /**
274
+ * Turns the block at the selection into another type. Choosing the type a block already has turns it
275
+ * back into a paragraph. A divider is added after the block, or in place of an empty one.
276
+ */
277
+ function setBlock(editor, type) {
278
+ const current = editor.getEditorState().read(() => $blockType($getSelection()));
279
+ if (type === "hr") {
280
+ editor.update(() => {
281
+ const selection = $getSelection();
282
+ if (!$isRangeSelection(selection)) return;
283
+ const block = selection.anchor.getNode().getTopLevelElement();
284
+ const divider = $createDivider();
285
+ if (block && !$isListNode(block) && !block.getTextContent() && block.getType() === "paragraph") block.replace(divider);
286
+ else $insertNodeToNearestRoot(divider);
287
+ const after = divider.getNextSibling();
288
+ if (after) after.selectStart();
289
+ else {
290
+ const paragraph = $createParagraphNode();
291
+ divider.insertAfter(paragraph);
292
+ paragraph.select();
293
+ }
294
+ });
295
+ return;
296
+ }
297
+ const target = current === type ? "p" : type;
298
+ if (target === "ul" || target === "ol") {
299
+ editor.dispatchCommand(target === "ul" ? INSERT_UNORDERED_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND, void 0);
300
+ return;
301
+ }
302
+ if (current === "ul" || current === "ol") editor.dispatchCommand(REMOVE_LIST_COMMAND, void 0);
303
+ if (target === "p" && (current === "ul" || current === "ol")) return;
304
+ editor.update(() => {
305
+ const selection = $getSelection();
306
+ if (!$isRangeSelection(selection)) return;
307
+ $setBlocksType(selection, () => {
308
+ switch (target) {
309
+ case "h1":
310
+ case "h2":
311
+ case "h3": return $createHeadingNode(target);
312
+ case "blockquote": return $createQuoteNode();
313
+ case "pre": return $createCodeNode();
314
+ default: return $createParagraphNode();
315
+ }
316
+ });
317
+ });
318
+ }
319
+ /**
320
+ * Starts a link edit: selects the whole of a link the caret is in, and remembers the selection so the
321
+ * address field (which takes focus) can apply it later. Null when there is nothing to link: a caret
322
+ * outside any link.
323
+ */
324
+ function beginLink(editor) {
325
+ let result = null;
326
+ editor.update(() => {
327
+ const selection = $getSelection();
328
+ if (!$isRangeSelection(selection)) return;
329
+ const link = linkAt(selection.anchor.getNode());
330
+ if (link) {
331
+ const first = link.getFirstDescendant();
332
+ const last = link.getLastDescendant();
333
+ if ($isTextNode(first) && $isTextNode(last)) {
334
+ selection.anchor.set(first.getKey(), 0, "text");
335
+ selection.focus.set(last.getKey(), last.getTextContentSize(), "text");
336
+ }
337
+ } else if (selection.isCollapsed()) return;
338
+ result = {
339
+ url: link ? link.getURL() : null,
340
+ selection: selection.clone()
341
+ };
342
+ }, { discrete: true });
343
+ return result;
344
+ }
345
+ /** Applies the address to the remembered selection; null removes the link. */
346
+ function applyLink(editor, selection, url) {
347
+ editor.update(() => {
348
+ $setSelection(selection.clone());
349
+ $toggleLink(url);
350
+ const next = $getSelection();
351
+ if ($isRangeSelection(next)) next.anchor.set(next.focus.key, next.focus.offset, next.focus.type);
352
+ });
353
+ }
354
+ /** Marks the divider that is the current selection, for its focus ring. */
355
+ function syncDividers(editor) {
356
+ editor.getEditorState().read(() => {
357
+ $getRoot().getChildren().forEach((block) => {
358
+ if (!$isDivider(block)) return;
359
+ editor.getElementByKey(block.getKey())?.toggleAttribute("data-selected", block.isSelected());
360
+ });
361
+ });
362
+ }
363
+ //#endregion
364
+ export { $blockType, $isDocumentEmpty, $readFormats, DividerNode, LOAD_TAG, NO_FORMATS, TRANSFORMERS, applyLink, beginLink, createRichTextEditor, loadHtml, loadMarkdown, readValue, setBlock, syncDividers, toggleMark };
365
+
366
+ //# sourceMappingURL=rich-text-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-text-engine.js","names":[],"sources":["../../src/rich-text-editor/rich-text-engine.ts"],"sourcesContent":["import { $createCodeNode, $isCodeNode, CodeNode } from \"@lexical/code\";\nimport { createEmptyHistoryState, registerHistory } from \"@lexical/history\";\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from \"@lexical/html\";\nimport { $isLinkNode, $toggleLink, LinkNode } from \"@lexical/link\";\nimport {\n $isListItemNode,\n $isListNode,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND,\n ListItemNode,\n ListNode,\n REMOVE_LIST_COMMAND,\n registerList,\n} from \"@lexical/list\";\nimport {\n $convertFromMarkdownString,\n $convertToMarkdownString,\n BOLD_ITALIC_STAR,\n BOLD_ITALIC_UNDERSCORE,\n BOLD_STAR,\n BOLD_UNDERSCORE,\n CODE,\n HEADING,\n INLINE_CODE,\n ITALIC_STAR,\n ITALIC_UNDERSCORE,\n LINK,\n ORDERED_LIST,\n QUOTE,\n STRIKETHROUGH,\n UNORDERED_LIST,\n registerMarkdownShortcuts,\n type ElementTransformer,\n type Transformer,\n} from \"@lexical/markdown\";\nimport {\n $createHeadingNode,\n $createQuoteNode,\n $isHeadingNode,\n $isQuoteNode,\n HeadingNode,\n QuoteNode,\n registerRichText,\n} from \"@lexical/rich-text\";\nimport { $setBlocksType } from \"@lexical/selection\";\nimport {\n $findMatchingParent,\n $getNearestNodeOfType,\n $insertNodeToNearestRoot,\n mergeRegister,\n} from \"@lexical/utils\";\nimport {\n $create,\n $createParagraphNode,\n $getRoot,\n $getSelection,\n $isDecoratorNode,\n $isElementNode,\n $isLineBreakNode,\n $isRangeSelection,\n $isTextNode,\n $setSelection,\n COMMAND_PRIORITY_HIGH,\n COMMAND_PRIORITY_LOW,\n DROP_COMMAND,\n FORMAT_TEXT_COMMAND,\n INDENT_CONTENT_COMMAND,\n KEY_BACKSPACE_COMMAND,\n KEY_DOWN_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_TAB_COMMAND,\n OUTDENT_CONTENT_COMMAND,\n DecoratorNode,\n createEditor,\n type BaseSelection,\n type LexicalEditor,\n type LexicalNode,\n type TextFormatType,\n} from \"lexical\";\n\nimport { canonicalDom, plainText, sanitizeToDom } from \"./rich-text-html.js\";\n\n/*\n * The editing engine: Lexical, configured for the editor's fixed vocabulary of blocks and marks.\n * Everything here is plain functions on a LexicalEditor, so the React component stays about\n * layout, the toolbar and the slash menu.\n */\n\nexport type BlockType = \"p\" | \"h1\" | \"h2\" | \"h3\" | \"ul\" | \"ol\" | \"blockquote\" | \"pre\" | \"hr\";\n\nexport interface RichTextValue {\n /** Canonical HTML: p, h1-h3, ul, ol, li, blockquote, pre, hr, strong, em, u, s, code, a[href], br. An empty document is \"\". */\n html: string;\n /** The same content as Markdown. Underline has no Markdown form and is dropped. */\n markdown: string;\n /** Plain text, one line per block. */\n text: string;\n /** True when there is no text and no divider. */\n empty: boolean;\n}\n\nexport interface Formats {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strike: boolean;\n code: boolean;\n /** The address of the link at the caret, or null. */\n link: string | null;\n block: BlockType;\n}\n\nexport const NO_FORMATS: Formats = {\n bold: false,\n italic: false,\n underline: false,\n strike: false,\n code: false,\n link: null,\n block: \"p\",\n};\n\n/*\n * The divider. A block with no text that the caret skips over as one unit; it renders a plain <hr>.\n * Kept here, not taken from a Lexical package, because the packaged one needs the extension runtime.\n */\nexport class DividerNode extends DecoratorNode<null> {\n $config() {\n return this.config(\"divider\", {\n extends: DecoratorNode,\n importDOM: {\n hr: () => ({ conversion: () => ({ node: $createDivider() }), priority: 0 as const }),\n },\n });\n }\n exportDOM() {\n return { element: document.createElement(\"hr\") };\n }\n createDOM() {\n return document.createElement(\"hr\");\n }\n updateDOM() {\n return false;\n }\n getTextContent() {\n return \"\\n\";\n }\n isInline(): false {\n return false;\n }\n}\nconst $isDivider = (node: LexicalNode | null | undefined): node is DividerNode =>\n node instanceof DividerNode;\nconst $createDivider = () => $create(DividerNode);\n\nconst DIVIDER: ElementTransformer = {\n dependencies: [DividerNode],\n export: (node) => ($isDivider(node) ? \"---\" : null),\n regExp: /^(?:---|\\*\\*\\*|___)\\s?$/,\n replace: (parent, _children, _match, isImport) => {\n const line = $createDivider();\n if (isImport || parent.getNextSibling() !== null) parent.replace(line);\n else parent.insertBefore(line);\n line.selectNext();\n },\n triggerOnEnter: true,\n type: \"element\",\n};\n\nexport const TRANSFORMERS: Transformer[] = [\n HEADING,\n QUOTE,\n CODE,\n UNORDERED_LIST,\n ORDERED_LIST,\n DIVIDER,\n INLINE_CODE,\n BOLD_ITALIC_STAR,\n BOLD_ITALIC_UNDERSCORE,\n BOLD_STAR,\n BOLD_UNDERSCORE,\n STRIKETHROUGH,\n ITALIC_STAR,\n ITALIC_UNDERSCORE,\n LINK,\n];\n\n/** Static class strings, so Tailwind sees them. The look of blocks and links lives in the rich-text-content utility. */\nconst theme = {\n text: {\n bold: \"font-semibold\",\n italic: \"italic\",\n underline: \"underline\",\n strikethrough: \"line-through\",\n underlineStrikethrough: \"underline line-through\",\n },\n list: { nested: { listitem: \"list-none\" } },\n // A marker the content styles key on: the block's <code> and an inline <code> are the same element.\n code: \"rich-text-code-block\",\n};\n\n/** Creates the editor and registers everything it does. Returns it with one call that undoes all of it. */\nexport function createRichTextEditor(root: HTMLElement) {\n const editor = createEditor({\n namespace: \"alfred-rich-text\",\n nodes: [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode, CodeNode, DividerNode],\n theme,\n editable: false,\n onError: (error) => {\n throw error;\n },\n });\n editor.setRootElement(root);\n const unregister = mergeRegister(\n registerRichText(editor),\n registerHistory(editor, createEmptyHistoryState(), 600),\n registerList(editor),\n registerMarkdownShortcuts(editor, TRANSFORMERS),\n // Heading levels stop at three; a four or five from a paste or Markdown becomes the third.\n editor.registerNodeTransform(HeadingNode, (node) => {\n if (node.getTag() > \"h3\") node.setTag(\"h3\");\n }),\n // Dropped content is never inserted: text moves by cut and paste.\n editor.registerCommand(\n DROP_COMMAND,\n (event) => {\n event.preventDefault();\n return true;\n },\n COMMAND_PRIORITY_HIGH,\n ),\n editor.registerCommand(\n KEY_TAB_COMMAND,\n (event) => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n const block = $blockType(selection);\n if (block === \"ul\" || block === \"ol\") {\n event.preventDefault();\n editor.dispatchCommand(\n event.shiftKey ? OUTDENT_CONTENT_COMMAND : INDENT_CONTENT_COMMAND,\n undefined,\n );\n return true;\n }\n if (block === \"pre\" && !event.shiftKey) {\n event.preventDefault();\n selection.insertText(\" \");\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n // Backspace at the very start of a heading, quote or code block turns it back into a paragraph (the engine does that only for an empty one).\n editor.registerCommand(\n KEY_BACKSPACE_COMMAND,\n (event) => {\n const selection = $getSelection();\n if (\n !$isRangeSelection(selection) ||\n !selection.isCollapsed() ||\n selection.anchor.offset !== 0\n )\n return false;\n const node = selection.anchor.getNode();\n const top = node.getTopLevelElement();\n if (!top || !($isHeadingNode(top) || $isQuoteNode(top) || $isCodeNode(top))) return false;\n if (!node.is(top) && !node.is(top.getFirstDescendant())) return false;\n event.preventDefault();\n $setBlocksType(selection, $createParagraphNode);\n return true;\n },\n COMMAND_PRIORITY_LOW,\n ),\n // A second Enter at the end of a code block leaves it, into a paragraph (the first one adds a line).\n editor.registerCommand(\n KEY_ENTER_COMMAND,\n (event) => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection) || !selection.isCollapsed() || event?.shiftKey)\n return false;\n const code = selection.anchor.getNode().getTopLevelElement();\n if (!$isCodeNode(code)) return false;\n const last = code.getLastChild();\n const atEnd =\n selection.anchor.key === code.getKey()\n ? selection.anchor.offset === code.getChildrenSize()\n : last !== null &&\n selection.anchor.getNode().is(last) &&\n selection.anchor.offset === last.getTextContentSize();\n if (!$isLineBreakNode(last) || !atEnd) return false;\n event?.preventDefault();\n last.remove();\n const paragraph = $createParagraphNode();\n code.insertAfter(paragraph);\n paragraph.select();\n return true;\n },\n COMMAND_PRIORITY_LOW,\n ),\n // Strikethrough, inline code and link, beside the bold, italic, underline and history keys the engine already binds.\n editor.registerCommand(\n KEY_DOWN_COMMAND,\n (event) => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey) return false;\n const key = event.key.toLowerCase();\n if (key === \"x\" && event.shiftKey) {\n event.preventDefault();\n editor.dispatchCommand(FORMAT_TEXT_COMMAND, \"strikethrough\");\n return true;\n }\n if (key === \"e\" && !event.shiftKey) {\n event.preventDefault();\n editor.dispatchCommand(FORMAT_TEXT_COMMAND, \"code\");\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_LOW,\n ),\n );\n return {\n editor,\n destroy: () => {\n unregister();\n editor.setRootElement(null);\n },\n };\n}\n\n/* ------------------------------------------------------------------------------------------------\n * Content in and out.\n * ---------------------------------------------------------------------------------------------- */\n\n/** An update tag for programmatic loads, which must not report as an edit. */\nexport const LOAD_TAG = \"rich-text-load\";\n\nfunction $fill(nodes: LexicalNode[]) {\n const root = $getRoot();\n root.clear();\n for (const node of nodes) {\n // Every child of the root is a block; the cleaned input has no stray inline nodes, but a guard costs one line.\n if ($isElementNode(node) || $isDecoratorNode(node)) root.append(node);\n else root.append($createParagraphNode().append(node));\n }\n if (!root.getChildrenSize()) root.append($createParagraphNode());\n}\n\n/**\n * How a load is tagged. `silent` loads are not edits: no change is reported. `first` is the\n * initial content, which becomes the history's starting point rather than a step to undo.\n */\nconst loadTags = (silent: boolean, first: boolean) => [\n ...(silent ? [LOAD_TAG] : []),\n ...(first ? [\"history-merge\"] : []),\n];\n\n/** Replaces the document with HTML (cleaned first). */\nexport function loadHtml(editor: LexicalEditor, html: string, silent: boolean, first = false) {\n editor.update(\n () => {\n const dom = sanitizeToDom(html);\n $fill($generateNodesFromDOM(editor, dom));\n },\n { tag: loadTags(silent, first), discrete: true },\n );\n}\n\nexport function loadMarkdown(\n editor: LexicalEditor,\n markdown: string,\n silent: boolean,\n first = false,\n) {\n editor.update(\n () => {\n $convertFromMarkdownString(markdown, TRANSFORMERS);\n if (!$getRoot().getChildrenSize()) $getRoot().append($createParagraphNode());\n },\n { tag: loadTags(silent, first), discrete: true },\n );\n}\n\n/** True when no block holds text and there is no divider. Call inside a read or update. */\nexport function $isDocumentEmpty() {\n return $getRoot()\n .getChildren()\n .every((block) => !$isDivider(block) && block.getTextContent().trim() === \"\");\n}\n\n/** Markdown with empty blocks left out: one blank line between blocks, none at the ends, code blocks untouched. */\nfunction tidyMarkdown(markdown: string) {\n let fenced = false;\n let blank = false;\n const out: string[] = [];\n for (const line of markdown.split(\"\\n\")) {\n if (/^\\s*`{3,}/.test(line)) fenced = !fenced;\n if (!fenced && !line.trim()) {\n blank = out.length > 0;\n continue;\n }\n if (blank) out.push(\"\");\n blank = false;\n out.push(line);\n }\n return out.join(\"\\n\");\n}\n\n/** The whole document, in every format. */\nexport function readValue(editor: LexicalEditor): RichTextValue {\n return editor.getEditorState().read(() => {\n const empty = $isDocumentEmpty();\n const dom = canonicalDom($generateHtmlFromNodes(editor));\n return {\n html: empty ? \"\" : dom.innerHTML,\n markdown: empty ? \"\" : tidyMarkdown($convertToMarkdownString(TRANSFORMERS)),\n text: plainText(dom),\n empty,\n };\n });\n}\n\n/* ------------------------------------------------------------------------------------------------\n * What the selection is in, and what to do to it.\n * ---------------------------------------------------------------------------------------------- */\n\n/** The block type at the selection's anchor. Call inside a read or update. */\nexport function $blockType(selection: BaseSelection | null): BlockType {\n if (!$isRangeSelection(selection)) return \"p\";\n const anchor = selection.anchor.getNode();\n const top = anchor.getKey() === \"root\" ? anchor : anchor.getTopLevelElementOrThrow();\n if ($isListNode(top) || $isListItemNode(top)) {\n return $getNearestNodeOfType(anchor, ListNode)?.getListType() === \"number\" ? \"ol\" : \"ul\";\n }\n if ($isHeadingNode(top)) return top.getTag() as BlockType;\n if ($isQuoteNode(top)) return \"blockquote\";\n if ($isCodeNode(top)) return \"pre\";\n return \"p\";\n}\n\nconst linkAt = (node: LexicalNode) => $findMatchingParent(node, $isLinkNode);\n\n/** The marks, link and block at the selection. Call inside a read. */\nexport function $readFormats(): Formats {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return NO_FORMATS;\n const link = linkAt(selection.anchor.getNode());\n return {\n bold: selection.hasFormat(\"bold\"),\n italic: selection.hasFormat(\"italic\"),\n underline: selection.hasFormat(\"underline\"),\n strike: selection.hasFormat(\"strikethrough\"),\n code: selection.hasFormat(\"code\"),\n link: link ? link.getURL() : null,\n block: $blockType(selection),\n };\n}\n\nexport const toggleMark = (editor: LexicalEditor, mark: TextFormatType) =>\n editor.dispatchCommand(FORMAT_TEXT_COMMAND, mark);\n\n/**\n * Turns the block at the selection into another type. Choosing the type a block already has turns it\n * back into a paragraph. A divider is added after the block, or in place of an empty one.\n */\nexport function setBlock(editor: LexicalEditor, type: BlockType) {\n const current = editor.getEditorState().read(() => $blockType($getSelection()));\n if (type === \"hr\") {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const block = selection.anchor.getNode().getTopLevelElement();\n const divider = $createDivider();\n if (\n block &&\n !$isListNode(block) &&\n !block.getTextContent() &&\n block.getType() === \"paragraph\"\n ) {\n block.replace(divider);\n } else {\n $insertNodeToNearestRoot(divider);\n }\n const after = divider.getNextSibling();\n if (after) after.selectStart();\n else {\n const paragraph = $createParagraphNode();\n divider.insertAfter(paragraph);\n paragraph.select();\n }\n });\n return;\n }\n const target = current === type ? \"p\" : type;\n if (target === \"ul\" || target === \"ol\") {\n editor.dispatchCommand(\n target === \"ul\" ? INSERT_UNORDERED_LIST_COMMAND : INSERT_ORDERED_LIST_COMMAND,\n undefined,\n );\n return;\n }\n if (current === \"ul\" || current === \"ol\") editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);\n if (target === \"p\" && (current === \"ul\" || current === \"ol\")) return;\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n $setBlocksType(selection, () => {\n switch (target) {\n case \"h1\":\n case \"h2\":\n case \"h3\":\n return $createHeadingNode(target);\n case \"blockquote\":\n return $createQuoteNode();\n case \"pre\":\n return $createCodeNode();\n default:\n return $createParagraphNode();\n }\n });\n });\n}\n\n/* ------------------------------------------------------------------------------------------------\n * Links.\n * ---------------------------------------------------------------------------------------------- */\n\n/**\n * Starts a link edit: selects the whole of a link the caret is in, and remembers the selection so the\n * address field (which takes focus) can apply it later. Null when there is nothing to link: a caret\n * outside any link.\n */\nexport function beginLink(\n editor: LexicalEditor,\n): { url: string | null; selection: BaseSelection } | null {\n let result: { url: string | null; selection: BaseSelection } | null = null;\n editor.update(\n () => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const link = linkAt(selection.anchor.getNode());\n if (link) {\n const first = link.getFirstDescendant();\n const last = link.getLastDescendant();\n if ($isTextNode(first) && $isTextNode(last)) {\n selection.anchor.set(first.getKey(), 0, \"text\");\n selection.focus.set(last.getKey(), last.getTextContentSize(), \"text\");\n }\n } else if (selection.isCollapsed()) return;\n result = { url: link ? link.getURL() : null, selection: selection.clone() };\n },\n { discrete: true },\n );\n return result;\n}\n\n/** Applies the address to the remembered selection; null removes the link. */\nexport function applyLink(editor: LexicalEditor, selection: BaseSelection, url: string | null) {\n editor.update(() => {\n $setSelection(selection.clone());\n $toggleLink(url);\n // The caret lands after the linked text, as it does in any editor, so the selection toolbar closes.\n const next = $getSelection();\n if ($isRangeSelection(next))\n next.anchor.set(next.focus.key, next.focus.offset, next.focus.type);\n });\n}\n\n/** Marks the divider that is the current selection, for its focus ring. */\nexport function syncDividers(editor: LexicalEditor) {\n editor.getEditorState().read(() => {\n $getRoot()\n .getChildren()\n .forEach((block) => {\n if (!$isDivider(block)) return;\n editor\n .getElementByKey(block.getKey())\n ?.toggleAttribute(\"data-selected\", block.isSelected());\n });\n });\n}\n"],"mappings":"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"}