@lukso/web-components 1.154.0 → 1.155.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 (335) hide show
  1. package/README.md +12 -0
  2. package/dist/attach-square-BDYuLWN1.js +3 -0
  3. package/dist/attach-square-BEkoBfpV.js +3 -0
  4. package/dist/attach-square-BF4bK2lN.cjs +7 -0
  5. package/dist/attach-square-B_oIBENK.js +3 -0
  6. package/dist/attach-square-CMjY_cQG.cjs +7 -0
  7. package/dist/attach-square-CPsLNqIT.cjs +7 -0
  8. package/dist/attach-square-Ch9_iq5a.js +3 -0
  9. package/dist/attach-square-D0YgLg2d.cjs +7 -0
  10. package/dist/attach-square-DGJ30O7H.js +3 -0
  11. package/dist/attach-square-DHjVapDw.cjs +7 -0
  12. package/dist/attach-square-Dtfj1Edy.js +3 -0
  13. package/dist/attach-square-nLmVYCe2.cjs +7 -0
  14. package/dist/components/index.cjs +14 -4
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/index.d.ts.map +1 -1
  17. package/dist/components/index.js +6 -4
  18. package/dist/components/lukso-button/index.cjs +3 -3
  19. package/dist/components/lukso-button/index.js +3 -3
  20. package/dist/components/lukso-card/index.cjs +7 -7
  21. package/dist/components/lukso-card/index.js +7 -7
  22. package/dist/components/lukso-checkbox/index.cjs +3 -3
  23. package/dist/components/lukso-checkbox/index.js +3 -3
  24. package/dist/components/lukso-collapse/index.cjs +5 -11
  25. package/dist/components/lukso-collapse/index.js +4 -10
  26. package/dist/components/lukso-color-picker/index.cjs +4 -4
  27. package/dist/components/lukso-color-picker/index.js +4 -4
  28. package/dist/components/lukso-dropdown/index.cjs +11 -7
  29. package/dist/components/lukso-dropdown/index.d.ts +1 -0
  30. package/dist/components/lukso-dropdown/index.d.ts.map +1 -1
  31. package/dist/components/lukso-dropdown/index.js +11 -7
  32. package/dist/components/lukso-dropdown-option/index.cjs +2 -2
  33. package/dist/components/lukso-dropdown-option/index.js +2 -2
  34. package/dist/components/lukso-footer/index.cjs +2 -2
  35. package/dist/components/lukso-footer/index.js +2 -2
  36. package/dist/components/lukso-icon/index.cjs +136 -18
  37. package/dist/components/lukso-icon/index.d.ts +24 -0
  38. package/dist/components/lukso-icon/index.d.ts.map +1 -1
  39. package/dist/components/lukso-icon/index.js +136 -18
  40. package/dist/components/lukso-icon/lukso-icon.stories.d.ts +5 -0
  41. package/dist/components/lukso-icon/lukso-icon.stories.d.ts.map +1 -1
  42. package/dist/components/lukso-icon/vuesax/bold/attach-square.svg +3 -0
  43. package/dist/components/lukso-icon/vuesax/bold/eye-slash.svg +7 -0
  44. package/dist/components/lukso-icon/vuesax/bold/eye.svg +4 -0
  45. package/dist/components/lukso-icon/vuesax/bold/link.svg +5 -0
  46. package/dist/components/lukso-icon/vuesax/bold/smallcaps.svg +3 -0
  47. package/dist/components/lukso-icon/vuesax/bold/task.svg +8 -0
  48. package/dist/components/lukso-icon/vuesax/bold/text-bold.svg +5 -0
  49. package/dist/components/lukso-icon/vuesax/bold/text-italic.svg +3 -0
  50. package/dist/components/lukso-icon/vuesax/bold/textalign-center.svg +6 -0
  51. package/dist/components/lukso-icon/vuesax/bold/textalign-justifycenter.svg +6 -0
  52. package/dist/components/lukso-icon/vuesax/bold/textalign-left.svg +6 -0
  53. package/dist/components/lukso-icon/vuesax/bold/textalign-right.svg +6 -0
  54. package/dist/components/lukso-icon/vuesax/broken/attach-square.svg +4 -0
  55. package/dist/components/lukso-icon/vuesax/broken/eye-slash.svg +9 -0
  56. package/dist/components/lukso-icon/vuesax/broken/eye.svg +4 -0
  57. package/dist/components/lukso-icon/vuesax/broken/link.svg +6 -0
  58. package/dist/components/lukso-icon/vuesax/broken/smallcaps.svg +9 -0
  59. package/dist/components/lukso-icon/vuesax/broken/task.svg +9 -0
  60. package/dist/components/lukso-icon/vuesax/broken/text-bold.svg +4 -0
  61. package/dist/components/lukso-icon/vuesax/broken/text-italic.svg +6 -0
  62. package/dist/components/lukso-icon/vuesax/broken/textalign-center.svg +7 -0
  63. package/dist/components/lukso-icon/vuesax/broken/textalign-justifycenter.svg +7 -0
  64. package/dist/components/lukso-icon/vuesax/broken/textalign-left.svg +7 -0
  65. package/dist/components/lukso-icon/vuesax/broken/textalign-right.svg +7 -0
  66. package/dist/components/lukso-icon/vuesax/bulk/attach-square.svg +4 -0
  67. package/dist/components/lukso-icon/vuesax/bulk/eye-slash.svg +7 -0
  68. package/dist/components/lukso-icon/vuesax/bulk/frame.svg +4 -0
  69. package/dist/components/lukso-icon/vuesax/bulk/link.svg +5 -0
  70. package/dist/components/lukso-icon/vuesax/bulk/smallcaps.svg +5 -0
  71. package/dist/components/lukso-icon/vuesax/bulk/task.svg +8 -0
  72. package/dist/components/lukso-icon/vuesax/bulk/text-bold.svg +4 -0
  73. package/dist/components/lukso-icon/vuesax/bulk/text-italic.svg +4 -0
  74. package/dist/components/lukso-icon/vuesax/bulk/textalign-center.svg +6 -0
  75. package/dist/components/lukso-icon/vuesax/bulk/textalign-justifycenter.svg +6 -0
  76. package/dist/components/lukso-icon/vuesax/bulk/textalign-left.svg +6 -0
  77. package/dist/components/lukso-icon/vuesax/bulk/textalign-right.svg +6 -0
  78. package/dist/components/lukso-icon/vuesax/linear/attach-square.svg +4 -0
  79. package/dist/components/lukso-icon/vuesax/linear/eye-slash.svg +8 -0
  80. package/dist/components/lukso-icon/vuesax/linear/eye.svg +4 -0
  81. package/dist/components/lukso-icon/vuesax/linear/link.svg +5 -0
  82. package/dist/components/lukso-icon/vuesax/linear/smallcaps.svg +8 -0
  83. package/dist/components/lukso-icon/vuesax/linear/task.svg +8 -0
  84. package/dist/components/lukso-icon/vuesax/linear/text-bold.svg +4 -0
  85. package/dist/components/lukso-icon/vuesax/linear/text-italic.svg +5 -0
  86. package/dist/components/lukso-icon/vuesax/linear/textalign-center.svg +6 -0
  87. package/dist/components/lukso-icon/vuesax/linear/textalign-justifycenter.svg +6 -0
  88. package/dist/components/lukso-icon/vuesax/linear/textalign-left.svg +6 -0
  89. package/dist/components/lukso-icon/vuesax/linear/textalign-right.svg +6 -0
  90. package/dist/components/lukso-icon/vuesax/outline/attach-square.svg +4 -0
  91. package/dist/components/lukso-icon/vuesax/outline/eye-slash.svg +8 -0
  92. package/dist/components/lukso-icon/vuesax/outline/eye.svg +4 -0
  93. package/dist/components/lukso-icon/vuesax/outline/link.svg +5 -0
  94. package/dist/components/lukso-icon/vuesax/outline/smallcaps.svg +8 -0
  95. package/dist/components/lukso-icon/vuesax/outline/task.svg +8 -0
  96. package/dist/components/lukso-icon/vuesax/outline/text-bold.svg +4 -0
  97. package/dist/components/lukso-icon/vuesax/outline/text-italic.svg +5 -0
  98. package/dist/components/lukso-icon/vuesax/outline/textalign-center.svg +6 -0
  99. package/dist/components/lukso-icon/vuesax/outline/textalign-justifycenter.svg +6 -0
  100. package/dist/components/lukso-icon/vuesax/outline/textalign-left.svg +6 -0
  101. package/dist/components/lukso-icon/vuesax/outline/textalign-right.svg +6 -0
  102. package/dist/components/lukso-icon/vuesax/twotone/attach-square.svg +4 -0
  103. package/dist/components/lukso-icon/vuesax/twotone/eye-slash.svg +8 -0
  104. package/dist/components/lukso-icon/vuesax/twotone/eye.svg +4 -0
  105. package/dist/components/lukso-icon/vuesax/twotone/link.svg +5 -0
  106. package/dist/components/lukso-icon/vuesax/twotone/smallcaps.svg +10 -0
  107. package/dist/components/lukso-icon/vuesax/twotone/task.svg +8 -0
  108. package/dist/components/lukso-icon/vuesax/twotone/text-bold.svg +4 -0
  109. package/dist/components/lukso-icon/vuesax/twotone/text-italic.svg +5 -0
  110. package/dist/components/lukso-icon/vuesax/twotone/textalign-center.svg +6 -0
  111. package/dist/components/lukso-icon/vuesax/twotone/textalign-justifycenter.svg +6 -0
  112. package/dist/components/lukso-icon/vuesax/twotone/textalign-left.svg +6 -0
  113. package/dist/components/lukso-icon/vuesax/twotone/textalign-right.svg +6 -0
  114. package/dist/components/lukso-image/index.cjs +4 -4
  115. package/dist/components/lukso-image/index.js +4 -4
  116. package/dist/components/lukso-input/index.cjs +3 -3
  117. package/dist/components/lukso-input/index.js +3 -3
  118. package/dist/components/lukso-markdown/index.cjs +168 -0
  119. package/dist/components/lukso-markdown/index.d.ts +22 -0
  120. package/dist/components/lukso-markdown/index.d.ts.map +1 -0
  121. package/dist/components/lukso-markdown/index.js +166 -0
  122. package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts +13 -0
  123. package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts.map +1 -0
  124. package/dist/components/lukso-markdown-editor/index.cjs +2008 -0
  125. package/dist/components/lukso-markdown-editor/index.d.ts +255 -0
  126. package/dist/components/lukso-markdown-editor/index.d.ts.map +1 -0
  127. package/dist/components/lukso-markdown-editor/index.js +2006 -0
  128. package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts +27 -0
  129. package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts.map +1 -0
  130. package/dist/components/lukso-modal/index.cjs +2 -2
  131. package/dist/components/lukso-modal/index.js +2 -2
  132. package/dist/components/lukso-navbar/index.cjs +3 -3
  133. package/dist/components/lukso-navbar/index.js +3 -3
  134. package/dist/components/lukso-pagination/index.cjs +3 -3
  135. package/dist/components/lukso-pagination/index.js +3 -3
  136. package/dist/components/lukso-profile/index.cjs +3 -3
  137. package/dist/components/lukso-profile/index.js +3 -3
  138. package/dist/components/lukso-progress/index.cjs +3 -3
  139. package/dist/components/lukso-progress/index.js +3 -3
  140. package/dist/components/lukso-radio/index.cjs +3 -3
  141. package/dist/components/lukso-radio/index.js +3 -3
  142. package/dist/components/lukso-radio-group/index.cjs +3 -3
  143. package/dist/components/lukso-radio-group/index.js +3 -3
  144. package/dist/components/lukso-sanitize/index.cjs +4 -10
  145. package/dist/components/lukso-sanitize/index.js +4 -10
  146. package/dist/components/lukso-search/index.cjs +6 -6
  147. package/dist/components/lukso-search/index.d.ts.map +1 -1
  148. package/dist/components/lukso-search/index.js +6 -6
  149. package/dist/components/lukso-select/index.cjs +5 -5
  150. package/dist/components/lukso-select/index.js +5 -5
  151. package/dist/components/lukso-share/index.cjs +2 -2
  152. package/dist/components/lukso-share/index.js +2 -2
  153. package/dist/components/lukso-switch/index.cjs +3 -3
  154. package/dist/components/lukso-switch/index.js +3 -3
  155. package/dist/components/lukso-tag/index.cjs +3 -3
  156. package/dist/components/lukso-tag/index.js +3 -3
  157. package/dist/components/lukso-terms/index.cjs +3 -3
  158. package/dist/components/lukso-terms/index.js +3 -3
  159. package/dist/components/lukso-textarea/index.cjs +3 -3
  160. package/dist/components/lukso-textarea/index.js +3 -3
  161. package/dist/components/lukso-tooltip/index.cjs +4 -4
  162. package/dist/components/lukso-tooltip/index.js +4 -4
  163. package/dist/components/lukso-username/index.cjs +5 -5
  164. package/dist/components/lukso-username/index.js +5 -5
  165. package/dist/components/lukso-wizard/index.cjs +2 -2
  166. package/dist/components/lukso-wizard/index.js +2 -2
  167. package/dist/docs/VuesaxPack.stories.d.ts +6 -0
  168. package/dist/docs/VuesaxPack.stories.d.ts.map +1 -0
  169. package/dist/eye-BGOT4dkg.cjs +7 -0
  170. package/dist/eye-BJFvKUDu.cjs +7 -0
  171. package/dist/eye-BRB1atdh.js +3 -0
  172. package/dist/eye-Bf4VFl7a.js +3 -0
  173. package/dist/eye-CC9LXMQ1.js +3 -0
  174. package/dist/eye-CK1M03ez.cjs +7 -0
  175. package/dist/eye-CXBFLyYh.cjs +7 -0
  176. package/dist/eye-CcM-Nmq0.js +3 -0
  177. package/dist/eye-DP4zhXsm.cjs +7 -0
  178. package/dist/eye-DaGlp3S9.js +3 -0
  179. package/dist/eye-slash-4QawqpXV.js +3 -0
  180. package/dist/eye-slash-5K5tDUZr.cjs +7 -0
  181. package/dist/eye-slash-BnjvF1ME.cjs +7 -0
  182. package/dist/eye-slash-BxKMkFDP.js +3 -0
  183. package/dist/eye-slash-CZVpq_gN.cjs +7 -0
  184. package/dist/eye-slash-Chha_f6F.js +3 -0
  185. package/dist/eye-slash-CzBrFoLA.js +3 -0
  186. package/dist/eye-slash-DD4uAbjM.cjs +7 -0
  187. package/dist/eye-slash-DGM6ST4a.js +3 -0
  188. package/dist/eye-slash-DaVNSGPe.cjs +7 -0
  189. package/dist/eye-slash-iagfBjcI.cjs +7 -0
  190. package/dist/eye-slash-j5X2mtyc.js +3 -0
  191. package/dist/frame-BcRKV975.js +3 -0
  192. package/dist/frame-CHLzNIw4.cjs +7 -0
  193. package/dist/{index-6Bz9XVC3.js → index-1cnTXnRX.js} +4 -4
  194. package/dist/{index-DUwutUFV.js → index-B5_11hN3.js} +5 -5
  195. package/dist/index-BWp0TAbf.js +41 -0
  196. package/dist/{index-Dg9hcDqR.cjs → index-CO57mpzm.cjs} +5 -5
  197. package/dist/{index-gJTlTDGh.js → index-CsepkLbs.js} +1 -1
  198. package/dist/{index-m3XGqZFz.cjs → index-D-a6OWyj.cjs} +1 -1
  199. package/dist/{index-U4Y7KwZv.cjs → index-D4HqZcbk.cjs} +2 -2
  200. package/dist/{index-fSZGRljb.cjs → index-D9mdD_OM.cjs} +4 -4
  201. package/dist/{index-CvWyP3CS.js → index-DFculCCQ.js} +2 -2
  202. package/dist/index-KrWvJ44l.cjs +50 -0
  203. package/dist/index.cjs +14 -4
  204. package/dist/index.js +6 -4
  205. package/dist/{isAddress-B3b91Jxf.cjs → isAddress-7c5mkwjj.cjs} +1 -1
  206. package/dist/{isAddress-Dq9UN07g.js → isAddress-DyEmEF7O.js} +1 -1
  207. package/dist/link-BWjOQDxe.js +3 -0
  208. package/dist/link-C248CAet.cjs +7 -0
  209. package/dist/link-CaiWNqlz.cjs +7 -0
  210. package/dist/link-Ccxf5n-l.cjs +7 -0
  211. package/dist/link-CrnK4TCj.js +3 -0
  212. package/dist/link-CtsNQupk.cjs +7 -0
  213. package/dist/link-CxQZZHzv.js +3 -0
  214. package/dist/link-DCLn1IDs.cjs +7 -0
  215. package/dist/link-DUkoe5Km.js +3 -0
  216. package/dist/link-DkkL7LfC.js +3 -0
  217. package/dist/link-YlDhxD95.js +3 -0
  218. package/dist/link-ck4nib4k.cjs +7 -0
  219. package/dist/{property-BXmHod5d.cjs → property-CLMAG2Rj.cjs} +1 -1
  220. package/dist/{property-B4XYi6Sk.js → property-DkFGx5Fg.js} +1 -1
  221. package/dist/query-CHb9Ft_d.js +9 -0
  222. package/dist/query-EFiHeHdi.cjs +11 -0
  223. package/dist/shared/tailwind-element/index.cjs +1 -1
  224. package/dist/shared/tailwind-element/index.js +1 -1
  225. package/dist/smallcaps-4db6OP5z.cjs +7 -0
  226. package/dist/smallcaps-BRGmz5X1.js +3 -0
  227. package/dist/smallcaps-C3aFFEMg.cjs +7 -0
  228. package/dist/smallcaps-CQH0e-Qr.js +3 -0
  229. package/dist/smallcaps-CrTAH_fl.cjs +7 -0
  230. package/dist/smallcaps-Csx5r5fL.js +3 -0
  231. package/dist/smallcaps-D57em6lZ.js +3 -0
  232. package/dist/smallcaps-DMxoMhLq.cjs +7 -0
  233. package/dist/smallcaps-DTc90-wB.js +3 -0
  234. package/dist/smallcaps-DvQw3mgt.cjs +7 -0
  235. package/dist/smallcaps-EMohyYps.js +3 -0
  236. package/dist/smallcaps-tS0-FTm4.cjs +7 -0
  237. package/dist/{state-CkvZ4IP8.js → state-DPXXwNMf.js} +1 -1
  238. package/dist/{state-CW2YmM3f.cjs → state-DXBdLH-W.cjs} +1 -1
  239. package/dist/{style-map-c2S85yDu.cjs → style-map-BFG88xg5.cjs} +1 -1
  240. package/dist/{style-map-D1R4wi4h.js → style-map-CXXmrGLe.js} +1 -1
  241. package/dist/task-5wAtmLia.cjs +7 -0
  242. package/dist/task-BFFgtsR7.cjs +7 -0
  243. package/dist/task-CPHbx6Xp.js +3 -0
  244. package/dist/task-CPK0Xitw.js +3 -0
  245. package/dist/task-CWMoBPrR.js +3 -0
  246. package/dist/task-CZeuxLHS.cjs +7 -0
  247. package/dist/task-CpUWZ14w.cjs +7 -0
  248. package/dist/task-D2dHPypM.js +3 -0
  249. package/dist/task-DHjlHB5u.js +3 -0
  250. package/dist/task-INl8gJof.cjs +7 -0
  251. package/dist/task-YBjBROjF.cjs +7 -0
  252. package/dist/task-rAZ4_dJi.js +3 -0
  253. package/dist/text-bold-B9Uuus_K.js +3 -0
  254. package/dist/text-bold-Bpds56iN.cjs +7 -0
  255. package/dist/text-bold-BwjfWLnV.js +3 -0
  256. package/dist/text-bold-CGib54xr.js +3 -0
  257. package/dist/text-bold-D9E9gOwG.js +3 -0
  258. package/dist/text-bold-D9y0G3W6.cjs +7 -0
  259. package/dist/text-bold-DA18Cobf.cjs +7 -0
  260. package/dist/text-bold-FVlP-onb.js +3 -0
  261. package/dist/text-bold-dNsqnxrJ.cjs +7 -0
  262. package/dist/text-bold-hD59fjBM.cjs +7 -0
  263. package/dist/text-bold-q4PQl2lp.cjs +7 -0
  264. package/dist/text-bold-yLyZsv3k.js +3 -0
  265. package/dist/text-italic-BAQsDLCD.cjs +7 -0
  266. package/dist/text-italic-BBbdgOV8.js +3 -0
  267. package/dist/text-italic-BLRmyoa_.cjs +7 -0
  268. package/dist/text-italic-BRpMpFEP.cjs +7 -0
  269. package/dist/text-italic-BbSEOHaR.js +3 -0
  270. package/dist/text-italic-BbY_nLh3.cjs +7 -0
  271. package/dist/text-italic-BqvfDpZ_.js +3 -0
  272. package/dist/text-italic-COwZp8nN.js +3 -0
  273. package/dist/text-italic-D-86ejcb.js +3 -0
  274. package/dist/text-italic-D5L8cO7S.cjs +7 -0
  275. package/dist/text-italic-Dqj-AGrY.cjs +7 -0
  276. package/dist/text-italic-JVNLjL6A.js +3 -0
  277. package/dist/textalign-center-BNXKb7o1.js +3 -0
  278. package/dist/textalign-center-BgDrvLgu.js +3 -0
  279. package/dist/textalign-center-BiW7-UK8.cjs +7 -0
  280. package/dist/textalign-center-BjXTeLZ9.js +3 -0
  281. package/dist/textalign-center-CMfGM3nt.cjs +7 -0
  282. package/dist/textalign-center-CZUB_mi5.cjs +7 -0
  283. package/dist/textalign-center-DV1ZVVJ9.js +3 -0
  284. package/dist/textalign-center-DhIAARrX.cjs +7 -0
  285. package/dist/textalign-center-DssUllZx.cjs +7 -0
  286. package/dist/textalign-center-DuFr4Z0N.js +3 -0
  287. package/dist/textalign-center-TtJrRcy1.cjs +7 -0
  288. package/dist/textalign-center-XZiUcsoS.js +3 -0
  289. package/dist/textalign-justifycenter-1H0ry4i1.cjs +7 -0
  290. package/dist/textalign-justifycenter-B4Okp5WQ.js +3 -0
  291. package/dist/textalign-justifycenter-BanoqoY2.cjs +7 -0
  292. package/dist/textalign-justifycenter-BrM7y8Q-.cjs +7 -0
  293. package/dist/textalign-justifycenter-BvuL2Tc9.js +3 -0
  294. package/dist/textalign-justifycenter-ByaUTZOq.cjs +7 -0
  295. package/dist/textalign-justifycenter-C7GGAIEd.cjs +7 -0
  296. package/dist/textalign-justifycenter-C_15oG-O.js +3 -0
  297. package/dist/textalign-justifycenter-Cd3T_URi.js +3 -0
  298. package/dist/textalign-justifycenter-Cuq0nA7n.js +3 -0
  299. package/dist/textalign-justifycenter-DTB7BpEM.cjs +7 -0
  300. package/dist/textalign-justifycenter-GJYh78KA.js +3 -0
  301. package/dist/textalign-left-BBkJw9sM.js +3 -0
  302. package/dist/textalign-left-CQFeWNky.cjs +7 -0
  303. package/dist/textalign-left-CVLtezzT.cjs +7 -0
  304. package/dist/textalign-left-CrkiT20G.js +3 -0
  305. package/dist/textalign-left-Czv9gCWL.js +3 -0
  306. package/dist/textalign-left-DDV2YTsX.js +3 -0
  307. package/dist/textalign-left-DbbIELEG.js +3 -0
  308. package/dist/textalign-left-DmbcMnUt.cjs +7 -0
  309. package/dist/textalign-left-DwMDZkz6.cjs +7 -0
  310. package/dist/textalign-left-FcEEgVUa.js +3 -0
  311. package/dist/textalign-left-HOX6BrC8.cjs +7 -0
  312. package/dist/textalign-left-Tim7PD2T.cjs +7 -0
  313. package/dist/textalign-right-AzUv7Wy_.cjs +7 -0
  314. package/dist/textalign-right-B4RMoyPu.js +3 -0
  315. package/dist/textalign-right-Bh1GtPWc.cjs +7 -0
  316. package/dist/textalign-right-BwpxVvNc.js +3 -0
  317. package/dist/textalign-right-CKoFhqEE.js +3 -0
  318. package/dist/textalign-right-CQKHpAQn.cjs +7 -0
  319. package/dist/textalign-right-CSi5EldQ.js +3 -0
  320. package/dist/textalign-right-CaDWcT07.cjs +7 -0
  321. package/dist/textalign-right-CoIc3IEi.js +3 -0
  322. package/dist/textalign-right-D-peBkxs.cjs +7 -0
  323. package/dist/textalign-right-DxQZxeBV.cjs +7 -0
  324. package/dist/textalign-right-LtrQalb-.js +3 -0
  325. package/dist/unsafe-html-C4RqiLkE.js +10 -0
  326. package/dist/unsafe-html-CxwvRvgp.cjs +12 -0
  327. package/dist/vite.full.config.d.ts.map +1 -1
  328. package/package.json +11 -1
  329. package/tailwind.config.cjs +1 -0
  330. package/tools/copy-assets.cjs +16 -16
  331. package/tools/copy-assets.js +2 -2
  332. package/tools/index.cjs +1 -1
  333. package/tools/index.js +1 -1
  334. package/dist/index-C9vH8YlV.js +0 -41
  335. package/dist/index-DkfODalz.cjs +0 -50
@@ -0,0 +1,2008 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const shared_tailwindElement_index = require('../../index-KrWvJ44l.cjs');
6
+ const property = require('../../property-CLMAG2Rj.cjs');
7
+ const state = require('../../state-DXBdLH-W.cjs');
8
+ const query = require('../../query-EFiHeHdi.cjs');
9
+ const index = require('../../index-CaJky2qL.cjs');
10
+ require('../../tailwind-config.cjs');
11
+ const cn = require('../../cn-CNdKneQ1.cjs');
12
+ require('../lukso-textarea/index.cjs');
13
+ require('../lukso-markdown/index.cjs');
14
+ require('../lukso-switch/index.cjs');
15
+ require('../lukso-button/index.cjs');
16
+ require('../lukso-icon/index.cjs');
17
+ require('../lukso-sanitize/index.cjs');
18
+ require('../lukso-dropdown/index.cjs');
19
+ require('../lukso-dropdown-option/index.cjs');
20
+ require('../lukso-tooltip/index.cjs');
21
+
22
+ const style = ":host {\n display: flex\n}";
23
+
24
+ var __defProp = Object.defineProperty;
25
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
26
+ var __decorateClass = (decorators, target, key, kind) => {
27
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
28
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
29
+ if (decorator = decorators[i])
30
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31
+ if (kind && result) __defProp(target, key, result);
32
+ return result;
33
+ };
34
+ exports.LuksoMarkdownEditor = class LuksoMarkdownEditor extends shared_tailwindElement_index.TailwindStyledElement(style) {
35
+ constructor() {
36
+ super(...arguments);
37
+ this.value = "";
38
+ this.name = "";
39
+ this.label = "";
40
+ this.description = "";
41
+ this.error = "";
42
+ this.isFullWidth = false;
43
+ this.isReadonly = false;
44
+ this.isDisabled = false;
45
+ this.isNonResizable = false;
46
+ this.autofocus = false;
47
+ this.size = "large";
48
+ this.isPreview = false;
49
+ this.rows = 6;
50
+ this.placeholder = "";
51
+ this.savedSelectionForPreview = null;
52
+ this.isHeadingDropdownOpen = false;
53
+ this.isColorDropdownOpen = false;
54
+ this.isListDropdownOpen = false;
55
+ this.headingTriggerId = "heading-dropdown-trigger";
56
+ this.colorTriggerId = "color-dropdown-trigger";
57
+ this.listTriggerId = "list-dropdown-trigger";
58
+ this.currentSelection = { start: 0, end: 0 };
59
+ this.savedSelection = null;
60
+ this.defaultColor = "#374151";
61
+ this.activeFormats = {
62
+ bold: false,
63
+ italic: false,
64
+ link: false,
65
+ h1: false,
66
+ h2: false,
67
+ h3: false,
68
+ color: false,
69
+ activeColor: this.defaultColor,
70
+ unorderedList: false,
71
+ orderedList: false
72
+ };
73
+ // Undo/Redo state
74
+ this.undoStack = [];
75
+ this.redoStack = [];
76
+ this.isUndoRedoAction = false;
77
+ this.lastSavedValue = "";
78
+ this.undoTimeout = null;
79
+ this.MAX_UNDO_STACK_SIZE = 100;
80
+ this.UNDO_SAVE_DELAY = 500;
81
+ this.handleOutsideClick = (event) => {
82
+ const target = event.target;
83
+ const isInsideThisComponent = this.contains(target) || this.shadowRoot?.contains(target);
84
+ if (!isInsideThisComponent) {
85
+ if (this.isHeadingDropdownOpen) {
86
+ this.isHeadingDropdownOpen = false;
87
+ }
88
+ if (this.isColorDropdownOpen) {
89
+ this.isColorDropdownOpen = false;
90
+ }
91
+ if (this.isListDropdownOpen) {
92
+ this.isListDropdownOpen = false;
93
+ }
94
+ return;
95
+ }
96
+ const isInsideHeadingDropdown = this.shadowRoot?.getElementById("headingDropdown")?.contains(target);
97
+ const isInsideColorDropdown = this.shadowRoot?.getElementById("colorDropdown")?.contains(target);
98
+ const isInsideListDropdown = this.shadowRoot?.getElementById("listDropdown")?.contains(target);
99
+ const isHeadingTrigger = this.shadowRoot?.getElementById(this.headingTriggerId)?.contains(target);
100
+ const isColorTrigger = this.shadowRoot?.getElementById(this.colorTriggerId)?.contains(target);
101
+ const isListTrigger = this.shadowRoot?.getElementById(this.listTriggerId)?.contains(target);
102
+ if (!isInsideHeadingDropdown && !isHeadingTrigger && this.isHeadingDropdownOpen) {
103
+ this.isHeadingDropdownOpen = false;
104
+ }
105
+ if (!isInsideColorDropdown && !isColorTrigger && this.isColorDropdownOpen) {
106
+ this.isColorDropdownOpen = false;
107
+ }
108
+ if (!isInsideListDropdown && !isListTrigger && this.isListDropdownOpen) {
109
+ this.isListDropdownOpen = false;
110
+ }
111
+ };
112
+ this.styles = index.ce({
113
+ slots: {
114
+ wrapper: "w-[inherit] grid gap-3",
115
+ header: "flex items-center justify-between gap-2 border border-neutral-90 rounded-12 px-3 py-2 bg-neutral-100",
116
+ toolbar: "flex flex-wrap items-center gap-1",
117
+ area: "",
118
+ editor: "",
119
+ preview: "p-3",
120
+ colorMenu: "relative",
121
+ headingMenu: "relative",
122
+ listMenu: "relative",
123
+ label: "heading-inter-14-bold text-neutral-20",
124
+ description: "paragraph-inter-12-regular text-neutral-20",
125
+ divider: "w-[1px] h-4 bg-neutral-90"
126
+ },
127
+ variants: {
128
+ isFullWidth: {
129
+ true: { wrapper: "w-full" },
130
+ false: { wrapper: "w-[350px]" }
131
+ }
132
+ },
133
+ compoundVariants: [{ isFullWidth: false, class: { wrapper: "w-[500px]" } }]
134
+ });
135
+ this.toolbarButton = index.ce({
136
+ base: "hover:bg-neutral-95 transition border-0 !shadow-none",
137
+ variants: {
138
+ active: { true: "bg-neutral-95" },
139
+ disabled: { true: "opacity-50 cursor-not-allowed" }
140
+ }
141
+ });
142
+ /**
143
+ * Hex color palette for the color picker.
144
+ * A curated collection of colors organized by hue families,
145
+ * ranging from light pastels to bold colors.
146
+ */
147
+ this.colorSamples = [
148
+ "#FFE5E5",
149
+ // very light red
150
+ "#FFB3B3",
151
+ "#FF8080",
152
+ "#FF6666",
153
+ "#FF4D4D",
154
+ "#E63946",
155
+ // strong pastel red
156
+ "#FFEBD5",
157
+ // very light orange
158
+ "#FFD1A3",
159
+ "#FFB870",
160
+ "#FFA54D",
161
+ "#FF944D",
162
+ "#FF7F11",
163
+ // bold pastel orange
164
+ "#FFFBD5",
165
+ // very light yellow
166
+ "#FFF3A3",
167
+ "#FFE870",
168
+ "#FFDD4D",
169
+ "#FFD633",
170
+ "#F4C430",
171
+ // deep pastel yellow
172
+ "#E6F9EC",
173
+ // very light green
174
+ "#B3E6C1",
175
+ "#80D499",
176
+ "#66CC80",
177
+ "#4DB870",
178
+ "#2D9C5B",
179
+ // bold pastel green
180
+ "#E6F3FF",
181
+ // very light blue
182
+ "#B3DAFF",
183
+ "#80C2FF",
184
+ "#66B2FF",
185
+ "#4DA6FF",
186
+ "#3A86FF",
187
+ // bold pastel blue
188
+ "#F3E6FF",
189
+ // very light purple
190
+ "#D9B3FF",
191
+ "#BF80FF",
192
+ "#A64DFF",
193
+ "#9333FF",
194
+ "#7B2CBF",
195
+ // bold pastel purple
196
+ "#FFE6F3",
197
+ // very light pink
198
+ "#FFB3D9",
199
+ "#FF80BF",
200
+ "#FF66B2",
201
+ "#FF4DA6",
202
+ "#E75480",
203
+ // bold pastel pink
204
+ "#F5E6DA",
205
+ // very light brown
206
+ "#E6CBB3",
207
+ "#D9B38C",
208
+ "#CC9966",
209
+ "#B3773A",
210
+ "#8B5E3C",
211
+ // bold pastel brown
212
+ "#FFFFFF",
213
+ // white
214
+ "#F5F5F5",
215
+ // very light gray
216
+ "#E0E0E0",
217
+ // light gray
218
+ "#BDBDBD",
219
+ // medium gray
220
+ "#757575",
221
+ // dark gray
222
+ "#000000",
223
+ // black
224
+ this.defaultColor
225
+ ];
226
+ /**
227
+ * Handle input event from the internal textarea component.
228
+ * @param event
229
+ */
230
+ this.handleTextareaInput = (event) => {
231
+ const newValue = event.detail?.value || "";
232
+ if (!this.isUndoRedoAction) {
233
+ this.scheduleUndoStateSave();
234
+ }
235
+ this.value = newValue;
236
+ this.updateActiveFormats();
237
+ };
238
+ /**
239
+ * Textarea keyup handler.
240
+ * Update active formats when user navigates with keyboard.
241
+ */
242
+ this.handleTextareaKeyUp = () => {
243
+ requestAnimationFrame(() => this.updateActiveFormats());
244
+ };
245
+ /**
246
+ * Textarea click handler.
247
+ * Update active formats when user clicks to move cursor.
248
+ */
249
+ this.handleTextareaClick = () => {
250
+ requestAnimationFrame(() => this.updateActiveFormats());
251
+ };
252
+ /**
253
+ * Handle keydown events for undo/redo shortcuts and list continuation.
254
+ */
255
+ this.handleKeyDown = (event) => {
256
+ const isUndo = (event.metaKey || event.ctrlKey) && event.key === "z" && !event.shiftKey;
257
+ const isRedo = (event.metaKey || event.ctrlKey) && (event.key === "y" || event.key === "z" && event.shiftKey);
258
+ if (isUndo) {
259
+ event.preventDefault();
260
+ this.undo();
261
+ } else if (isRedo) {
262
+ event.preventDefault();
263
+ this.redo();
264
+ } else if (event.key === "Enter" && !event.metaKey && !event.ctrlKey && !event.shiftKey) {
265
+ if (this.handleListContinuation()) {
266
+ event.preventDefault();
267
+ }
268
+ } else if (event.key === "Backspace" && !event.metaKey && !event.ctrlKey && !event.shiftKey) {
269
+ if (this.handleListBackspace()) {
270
+ event.preventDefault();
271
+ }
272
+ } else if (event.key === "Tab" && !event.metaKey && !event.ctrlKey) {
273
+ if (event.shiftKey) {
274
+ if (this.handleListOutdent()) {
275
+ event.preventDefault();
276
+ }
277
+ } else {
278
+ if (this.handleListIndent()) {
279
+ event.preventDefault();
280
+ }
281
+ }
282
+ }
283
+ };
284
+ }
285
+ dispatchChange(event) {
286
+ this.updateComplete.then(() => {
287
+ const changeEvent = new CustomEvent("on-change", {
288
+ detail: { value: this.value, event },
289
+ bubbles: false,
290
+ composed: true
291
+ });
292
+ this.dispatchEvent(changeEvent);
293
+ });
294
+ }
295
+ /**
296
+ * Utility to perform an operation with the current textarea selection.
297
+ *
298
+ * @param callback -
299
+ */
300
+ withSelection(callback) {
301
+ const textarea = this.textareaEl?.shadowRoot?.querySelector(
302
+ "textarea"
303
+ );
304
+ if (!textarea) return;
305
+ const start = textarea.selectionStart ?? 0;
306
+ const end = textarea.selectionEnd ?? 0;
307
+ const value = this.value;
308
+ callback(textarea, start, end, value);
309
+ textarea.focus();
310
+ }
311
+ /**
312
+ * Expand empty selection to current word boundaries
313
+ *
314
+ * @param start - selection start
315
+ * @param end - selection end
316
+ * @param value - full textarea value
317
+ */
318
+ expandSelectionToWord(start, end, value) {
319
+ if (start !== end) return { start, end };
320
+ const charBefore = start > 0 ? value[start - 1] : "";
321
+ const charAfter = start < value.length ? value[start] : "";
322
+ if (charBefore === "(" && charAfter === ")" || charBefore === "[" && charAfter === "]") {
323
+ return { start, end };
324
+ }
325
+ let _start = start;
326
+ let _end = end;
327
+ const isWord = (ch) => /[\p{L}\p{N}_-]/u.test(ch);
328
+ while (_start > 0 && isWord(value[_start - 1])) _start--;
329
+ while (_end < value.length && isWord(value[_end])) _end++;
330
+ return { start: _start, end: _end };
331
+ }
332
+ /**
333
+ * Apply or toggle heading formatting for the current line(s).
334
+ *
335
+ * @param level - 0 to remove heading, 1-3 for heading levels
336
+ */
337
+ applyHeading(level) {
338
+ if (this.isReadonly || this.isDisabled) return;
339
+ this.saveUndoStateBeforeChange();
340
+ const desiredPrefix = level > 0 ? `${"#".repeat(level)} ` : "";
341
+ this.withSelection((textarea, start, end, value) => {
342
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
343
+ let lineEnd = value.indexOf("\n", end);
344
+ if (lineEnd === -1) lineEnd = value.length;
345
+ const before = value.slice(0, lineStart);
346
+ const selected = value.slice(lineStart, lineEnd);
347
+ const after = value.slice(lineEnd);
348
+ const lines = selected.split("\n");
349
+ const headingRegex = /^(#{1,6})\s+/;
350
+ const allAlreadyLevel = lines.every((l) => l.startsWith(desiredPrefix));
351
+ let transformed;
352
+ if (level === 0) {
353
+ transformed = lines.map((l) => l.replace(headingRegex, "")).join("\n");
354
+ } else {
355
+ transformed = lines.map((l) => {
356
+ const withoutAny = l.replace(headingRegex, "");
357
+ if (allAlreadyLevel) {
358
+ return withoutAny;
359
+ }
360
+ return desiredPrefix + withoutAny;
361
+ }).join("\n");
362
+ }
363
+ this.value = before + transformed + after;
364
+ textarea.value = before + transformed + after;
365
+ let cursorPosition = before.length;
366
+ if (level > 0 && !allAlreadyLevel) {
367
+ const firstLine = lines[0] || "";
368
+ const contentAfterHeading = firstLine.replace(headingRegex, "");
369
+ if (contentAfterHeading.trim()) {
370
+ const firstLineEnd = transformed.indexOf("\n");
371
+ cursorPosition = before.length + (firstLineEnd === -1 ? transformed.length : firstLineEnd);
372
+ } else {
373
+ cursorPosition = before.length + desiredPrefix.length;
374
+ }
375
+ } else if (level === 0 || allAlreadyLevel) {
376
+ const firstLineEnd = transformed.indexOf("\n");
377
+ cursorPosition = before.length + (firstLineEnd === -1 ? transformed.length : firstLineEnd);
378
+ }
379
+ requestAnimationFrame(() => {
380
+ textarea.setSelectionRange(cursorPosition, cursorPosition);
381
+ this.updateActiveFormats();
382
+ });
383
+ this.dispatchChange();
384
+ });
385
+ }
386
+ /**
387
+ * Apply or toggle list formatting for the current line(s).
388
+ *
389
+ * @param listType - 'none' to remove list, 'unordered' for bullet list, 'ordered' for numbered list
390
+ */
391
+ applyList(listType) {
392
+ if (this.isReadonly || this.isDisabled) return;
393
+ this.saveUndoStateBeforeChange();
394
+ this.withSelection((textarea, start, end, value) => {
395
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
396
+ let lineEnd = value.indexOf("\n", end);
397
+ if (lineEnd === -1) lineEnd = value.length;
398
+ const before = value.slice(0, lineStart);
399
+ const selected = value.slice(lineStart, lineEnd);
400
+ const after = value.slice(lineEnd);
401
+ const lines = selected.split("\n");
402
+ const unorderedRegex = /^(\s*)[-*+]\s+/;
403
+ const orderedRegex = /^(\s*)\d+\.\s+/;
404
+ let transformed;
405
+ if (listType === "none") {
406
+ transformed = lines.map((l) => {
407
+ if (unorderedRegex.test(l)) {
408
+ return l.replace(unorderedRegex, "$1");
409
+ }
410
+ if (orderedRegex.test(l)) {
411
+ return l.replace(orderedRegex, "$1");
412
+ }
413
+ return l;
414
+ }).join("\n");
415
+ } else if (listType === "unordered") {
416
+ const allAlreadyUnordered = lines.every(
417
+ (l) => l.trim() === "" || unorderedRegex.test(l)
418
+ );
419
+ if (allAlreadyUnordered && lines.some((l) => unorderedRegex.test(l))) {
420
+ transformed = lines.map((l) => {
421
+ if (unorderedRegex.test(l)) {
422
+ return l.replace(unorderedRegex, "$1");
423
+ }
424
+ return l;
425
+ }).join("\n");
426
+ } else {
427
+ transformed = lines.map((l) => {
428
+ if (l.trim() === "") return l;
429
+ let cleaned = l;
430
+ if (unorderedRegex.test(l)) {
431
+ cleaned = l.replace(unorderedRegex, "$1");
432
+ } else if (orderedRegex.test(l)) {
433
+ cleaned = l.replace(orderedRegex, "$1");
434
+ }
435
+ const indentMatch = cleaned.match(/^(\s*)/);
436
+ const indent = indentMatch ? indentMatch[1] : "";
437
+ const content = cleaned.replace(/^\s*/, "");
438
+ return `${indent}- ${content}`;
439
+ }).join("\n");
440
+ }
441
+ } else if (listType === "ordered") {
442
+ const allAlreadyOrdered = lines.every(
443
+ (l) => l.trim() === "" || orderedRegex.test(l)
444
+ );
445
+ if (allAlreadyOrdered && lines.some((l) => orderedRegex.test(l))) {
446
+ transformed = lines.map((l) => {
447
+ if (orderedRegex.test(l)) {
448
+ return l.replace(orderedRegex, "$1");
449
+ }
450
+ return l;
451
+ }).join("\n");
452
+ } else {
453
+ let counter = 1;
454
+ const beforeLines = before.split("\n");
455
+ for (let i = beforeLines.length - 1; i >= 0; i--) {
456
+ const line = beforeLines[i];
457
+ const orderedMatch = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
458
+ if (orderedMatch) {
459
+ counter = parseInt(orderedMatch[2], 10) + 1;
460
+ break;
461
+ } else if (line.trim() !== "" && !line.match(/^\s*[-*+]\s+/)) {
462
+ break;
463
+ }
464
+ }
465
+ transformed = lines.map((l) => {
466
+ if (l.trim() === "") return l;
467
+ let cleaned = l;
468
+ if (unorderedRegex.test(l)) {
469
+ cleaned = l.replace(unorderedRegex, "$1");
470
+ } else if (orderedRegex.test(l)) {
471
+ cleaned = l.replace(orderedRegex, "$1");
472
+ }
473
+ const indentMatch = cleaned.match(/^(\s*)/);
474
+ const indent = indentMatch ? indentMatch[1] : "";
475
+ const content = cleaned.replace(/^\s*/, "");
476
+ return `${indent}${counter++}. ${content}`;
477
+ }).join("\n");
478
+ }
479
+ }
480
+ let finalValue = before + transformed + after;
481
+ if (listType === "ordered") {
482
+ const allAlreadyOrdered = lines.every(
483
+ (l) => l.trim() === "" || orderedRegex.test(l)
484
+ );
485
+ if (!allAlreadyOrdered || !lines.some((l) => orderedRegex.test(l))) {
486
+ const transformedLines = transformed.split("\n");
487
+ const lastTransformedLine = transformedLines[transformedLines.length - 1];
488
+ const indentMatch = lastTransformedLine.match(/^(\s*)/);
489
+ const indent = indentMatch ? indentMatch[1] : "";
490
+ const endPosition = before.length + transformed.length;
491
+ finalValue = this.renumberOrderedListItems(
492
+ finalValue,
493
+ endPosition,
494
+ indent
495
+ );
496
+ }
497
+ }
498
+ if (listType === "none") {
499
+ const removedOrderedItems = lines.some((l) => orderedRegex.test(l));
500
+ if (removedOrderedItems) {
501
+ finalValue = this.renumberSubsequentOrderedLists(
502
+ finalValue,
503
+ before.length + transformed.length
504
+ );
505
+ }
506
+ }
507
+ this.value = finalValue;
508
+ textarea.value = finalValue;
509
+ const firstLineEnd = transformed.indexOf("\n");
510
+ const cursorPosition = before.length + (firstLineEnd === -1 ? transformed.length : firstLineEnd);
511
+ requestAnimationFrame(() => {
512
+ textarea.setSelectionRange(cursorPosition, cursorPosition);
513
+ this.updateActiveFormats();
514
+ });
515
+ this.dispatchChange();
516
+ });
517
+ }
518
+ /**
519
+ * Get the current active list type based on activeFormats.
520
+ */
521
+ getActiveListType() {
522
+ if (this.activeFormats.unorderedList) return "unordered";
523
+ if (this.activeFormats.orderedList) return "ordered";
524
+ return "none";
525
+ }
526
+ /**
527
+ * Toggle inline formatting by wrapping/unwrapping selection or current word.
528
+ *
529
+ * @param wrapper - the markdown wrapper to toggle, e.g. '**' for bold, '*' for italic
530
+ */
531
+ toggleWrap(wrapper) {
532
+ if (this.isReadonly || this.isDisabled) return;
533
+ this.saveUndoStateBeforeChange();
534
+ this.withSelection((textarea, start, end, value) => {
535
+ if (this.isSelectionInLinkUrl(start, end, value)) {
536
+ return;
537
+ }
538
+ const { start: s, end: e } = this.expandSelectionToWord(start, end, value);
539
+ let before = value.slice(0, s);
540
+ let selected = value.slice(s, e);
541
+ let after = value.slice(e);
542
+ const hasOuterWrap = before.endsWith(wrapper) && after.startsWith(wrapper);
543
+ if (hasOuterWrap) {
544
+ before = before.slice(0, before.length - wrapper.length);
545
+ after = after.slice(wrapper.length);
546
+ this.value = before + selected + after;
547
+ textarea.value = before + selected + after;
548
+ const selStart2 = before.length;
549
+ const selEnd2 = selStart2 + selected.length;
550
+ requestAnimationFrame(() => {
551
+ textarea.setSelectionRange(selStart2, selEnd2);
552
+ this.updateActiveFormats();
553
+ });
554
+ this.dispatchChange();
555
+ return;
556
+ }
557
+ const innerWrapped = selected.startsWith(wrapper) && selected.endsWith(wrapper);
558
+ if (innerWrapped) {
559
+ selected = selected.slice(
560
+ wrapper.length,
561
+ selected.length - wrapper.length
562
+ );
563
+ this.value = before + selected + after;
564
+ textarea.value = before + selected + after;
565
+ const selStart2 = before.length;
566
+ const selEnd2 = selStart2 + selected.length;
567
+ requestAnimationFrame(() => {
568
+ textarea.setSelectionRange(selStart2, selEnd2);
569
+ this.updateActiveFormats();
570
+ });
571
+ this.dispatchChange();
572
+ return;
573
+ }
574
+ const wrapped = `${wrapper}${selected || ""}${wrapper}`;
575
+ this.value = before + wrapped + after;
576
+ textarea.value = before + wrapped + after;
577
+ const selStart = before.length + wrapper.length;
578
+ const selEnd = selStart + (selected ? selected.length : 0);
579
+ requestAnimationFrame(() => {
580
+ textarea.setSelectionRange(selStart, selEnd);
581
+ this.updateActiveFormats();
582
+ });
583
+ this.dispatchChange();
584
+ });
585
+ }
586
+ /**
587
+ * Toggle preview mode on or off.
588
+ */
589
+ togglePreview() {
590
+ if (this.isPreview) {
591
+ this.exitPreview();
592
+ } else {
593
+ this.enterPreview();
594
+ }
595
+ this.isPreview = !this.isPreview;
596
+ }
597
+ /**
598
+ * Enter preview mode - save current state and remove keyboard listeners from textarea
599
+ */
600
+ enterPreview() {
601
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
602
+ if (textarea) {
603
+ this.savedSelectionForPreview = {
604
+ start: textarea.selectionStart ?? 0,
605
+ end: textarea.selectionEnd ?? 0
606
+ };
607
+ this.removeKeyboardListeners();
608
+ }
609
+ }
610
+ /**
611
+ * Exit preview mode - restore state and reattach keyboard listeners
612
+ */
613
+ exitPreview() {
614
+ requestAnimationFrame(() => {
615
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
616
+ if (textarea && this.savedSelectionForPreview) {
617
+ textarea.focus();
618
+ textarea.setSelectionRange(
619
+ this.savedSelectionForPreview.start,
620
+ this.savedSelectionForPreview.end
621
+ );
622
+ this.currentSelection = this.savedSelectionForPreview;
623
+ this.savedSelectionForPreview = null;
624
+ this.updateActiveFormats();
625
+ }
626
+ this.addKeyboardListeners();
627
+ });
628
+ }
629
+ /**
630
+ * Insert or edit a markdown link [text](url).
631
+ */
632
+ insertLink() {
633
+ if (this.isReadonly || this.isDisabled) return;
634
+ this.saveUndoStateBeforeChange();
635
+ const placeholderText = "link text";
636
+ const placeholderUrl = "";
637
+ this.withSelection((textarea, start, end, value) => {
638
+ if (this.isSelectionInLinkUrl(start, end, value) || this.isSelectionInLinkText(start, end, value)) {
639
+ const leftBracket2 = value.lastIndexOf("[", start);
640
+ const rightParen2 = value.indexOf(")", Math.max(start, end));
641
+ const rightBracket2 = value.indexOf("]", leftBracket2);
642
+ const openParen2 = value.indexOf("(", rightBracket2);
643
+ if (leftBracket2 !== -1 && rightBracket2 !== -1 && openParen2 !== -1 && rightParen2 !== -1) {
644
+ const candidate = value.slice(leftBracket2, rightParen2 + 1);
645
+ const linkRegex2 = /^\[([^\]]+)\]\(([^)]*)\)$/;
646
+ const match = candidate.match(linkRegex2);
647
+ if (match) {
648
+ const textOnly = match[1];
649
+ this.value = value.slice(0, leftBracket2) + textOnly + value.slice(rightParen2 + 1);
650
+ textarea.value = value.slice(0, leftBracket2) + textOnly + value.slice(rightParen2 + 1);
651
+ const newCursor = leftBracket2 + textOnly.length;
652
+ requestAnimationFrame(() => {
653
+ textarea.setSelectionRange(newCursor, newCursor);
654
+ this.updateActiveFormats();
655
+ });
656
+ this.dispatchChange();
657
+ return;
658
+ }
659
+ }
660
+ return;
661
+ }
662
+ const { start: s, end: e } = this.expandSelectionToWord(start, end, value);
663
+ const before = value.slice(0, s);
664
+ const selected = value.slice(s, e);
665
+ const after = value.slice(e);
666
+ const linkRegex = /^\[([^\]]+)\]\(([^)]+)\)$/;
667
+ if (linkRegex.test(selected)) {
668
+ const match = selected.match(linkRegex);
669
+ const textOnly = match?.[1] ?? selected;
670
+ this.value = before + textOnly + after;
671
+ textarea.value = before + textOnly + after;
672
+ const newStart = before.length;
673
+ const newEnd = newStart + textOnly.length;
674
+ requestAnimationFrame(() => {
675
+ textarea.setSelectionRange(newStart, newEnd);
676
+ this.updateActiveFormats();
677
+ });
678
+ this.dispatchChange();
679
+ return;
680
+ }
681
+ const leftBracket = value.lastIndexOf("[", s);
682
+ const rightParen = value.indexOf(")", e);
683
+ const rightBracket = value.indexOf("]", e);
684
+ const openParen = value.indexOf("(", e);
685
+ if (leftBracket !== -1 && rightBracket !== -1 && openParen !== -1 && rightParen !== -1 && leftBracket < rightBracket && rightBracket < openParen && openParen < rightParen) {
686
+ const candidate = value.slice(leftBracket, rightParen + 1);
687
+ if (linkRegex.test(candidate)) {
688
+ const match = candidate.match(linkRegex);
689
+ const textOnly = match?.[1] ?? candidate;
690
+ this.value = value.slice(0, leftBracket) + textOnly + value.slice(rightParen + 1);
691
+ textarea.value = value.slice(0, leftBracket) + textOnly + value.slice(rightParen + 1);
692
+ const newCursor = leftBracket + textOnly.length;
693
+ requestAnimationFrame(() => {
694
+ textarea.setSelectionRange(newCursor, newCursor);
695
+ this.updateActiveFormats();
696
+ });
697
+ this.dispatchChange();
698
+ return;
699
+ }
700
+ }
701
+ const text = selected || placeholderText;
702
+ const md = `[${text}](${placeholderUrl})`;
703
+ this.value = before + md + after;
704
+ textarea.value = before + md + after;
705
+ const cursorPosition = before.length + 1 + text.length + 2;
706
+ requestAnimationFrame(() => {
707
+ textarea.focus();
708
+ textarea.setSelectionRange(cursorPosition, cursorPosition);
709
+ this.updateActiveFormats();
710
+ });
711
+ this.dispatchChange();
712
+ });
713
+ }
714
+ /**
715
+ * Update active formatting states based on current selection or cursor position.
716
+ */
717
+ updateActiveFormats() {
718
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
719
+ if (!textarea || !this.value) return;
720
+ const start = textarea.selectionStart ?? 0;
721
+ const end = textarea.selectionEnd ?? 0;
722
+ this.currentSelection = { start, end };
723
+ const { start: s, end: e } = this.expandSelectionToWord(
724
+ start,
725
+ end,
726
+ this.value
727
+ );
728
+ const selectedText = this.value.slice(s, e);
729
+ const beforeSelection = this.value.slice(0, s);
730
+ const afterSelection = this.value.slice(e);
731
+ const hasBoldWrap = beforeSelection.endsWith("**") && afterSelection.startsWith("**") || selectedText.startsWith("**") && selectedText.endsWith("**");
732
+ const hasItalicWrap = beforeSelection.endsWith("*") && afterSelection.startsWith("*") && !beforeSelection.endsWith("**") || selectedText.startsWith("*") && selectedText.endsWith("*") && !selectedText.startsWith("**");
733
+ const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/;
734
+ const hasLink = linkRegex.test(selectedText) || this.isWithinLink(start, this.value);
735
+ const lineStart = this.value.lastIndexOf("\n", start - 1) + 1;
736
+ const lineEnd = this.value.indexOf("\n", start);
737
+ const currentLine = this.value.slice(
738
+ lineStart,
739
+ lineEnd === -1 ? this.value.length : lineEnd
740
+ );
741
+ const headingMatch = currentLine.match(/^(#{1,6})\s/);
742
+ const headingLevel = headingMatch ? headingMatch[1].length : 0;
743
+ const unorderedListMatch = currentLine.match(/^\s*[-*+]\s/);
744
+ const orderedListMatch = currentLine.match(/^\s*\d+\.\s/);
745
+ const hasUnorderedList = !!unorderedListMatch;
746
+ const hasOrderedList = !!orderedListMatch;
747
+ const colorRegex = /<span style="color: ([^"]+)">/;
748
+ const hasColorWrap = !!(beforeSelection.match(colorRegex) && afterSelection.includes("</span>") || selectedText.match(/^<span style="color: ([^"]+)">(.*)<\/span>$/s));
749
+ let activeColor = this.defaultColor;
750
+ if (hasColorWrap) {
751
+ const beforeColorMatch = beforeSelection.match(
752
+ /<span style="color: ([^"]+)">([^<]*)$/
753
+ );
754
+ const selectedColorMatch = selectedText.match(
755
+ /^<span style="color: ([^"]+)">/
756
+ );
757
+ activeColor = beforeColorMatch?.[1] || selectedColorMatch?.[1] || "";
758
+ }
759
+ this.activeFormats = {
760
+ bold: hasBoldWrap,
761
+ italic: hasItalicWrap,
762
+ link: hasLink,
763
+ h1: headingLevel === 1,
764
+ h2: headingLevel === 2,
765
+ h3: headingLevel === 3,
766
+ color: hasColorWrap,
767
+ activeColor,
768
+ unorderedList: hasUnorderedList,
769
+ orderedList: hasOrderedList
770
+ };
771
+ }
772
+ /**
773
+ * Check if a given position is within a markdown link [text](url).
774
+ * @param position - cursor position
775
+ * @param value - full textarea value
776
+ */
777
+ isWithinLink(position, value) {
778
+ const leftBracket = value.lastIndexOf("[", position);
779
+ const rightParen = value.indexOf(")", position);
780
+ if (leftBracket === -1 || rightParen === -1) return false;
781
+ const candidate = value.slice(leftBracket, rightParen + 1);
782
+ return /^\[([^\]]+)\]\(([^)]+)\)$/.test(candidate);
783
+ }
784
+ /**
785
+ * Check if selection is within the text part [] of a markdown link
786
+ * @param start - selection start position
787
+ * @param end - selection end position
788
+ * @param value - full textarea value
789
+ */
790
+ isSelectionInLinkText(start, end, value) {
791
+ const leftBracket = value.lastIndexOf("[", start);
792
+ const rightParen = value.indexOf(")", Math.max(start, end));
793
+ if (leftBracket === -1 || rightParen === -1) return false;
794
+ const rightBracket = value.indexOf("]", leftBracket);
795
+ const openParen = value.indexOf("(", rightBracket);
796
+ if (rightBracket === -1 || openParen === -1) return false;
797
+ if (!(leftBracket < rightBracket && rightBracket < openParen && openParen < rightParen))
798
+ return false;
799
+ const candidate = value.slice(leftBracket, rightParen + 1);
800
+ if (!/^\[([^\]]+)\]\(([^)]*)\)$/.test(candidate)) return false;
801
+ return start >= leftBracket + 1 && end <= rightBracket;
802
+ }
803
+ /**
804
+ * Check if selection is within the URL part () of a markdown link
805
+ * @param start - selection start position
806
+ * @param end - selection end position
807
+ * @param value - full textarea value
808
+ */
809
+ isSelectionInLinkUrl(start, end, value) {
810
+ const leftBracket = value.lastIndexOf("[", start);
811
+ const rightParen = value.indexOf(")", Math.max(start, end));
812
+ if (leftBracket === -1 || rightParen === -1) return false;
813
+ const rightBracket = value.indexOf("]", leftBracket);
814
+ const openParen = value.indexOf("(", rightBracket);
815
+ if (rightBracket === -1 || openParen === -1) return false;
816
+ if (!(leftBracket < rightBracket && rightBracket < openParen && openParen < rightParen))
817
+ return false;
818
+ const candidate = value.slice(leftBracket, rightParen + 1);
819
+ if (!/^\[([^\]]+)\]\(([^)]*)\)$/.test(candidate)) return false;
820
+ return start >= openParen + 1 && end <= rightParen;
821
+ }
822
+ /**
823
+ * Add keyboard event listeners to the textarea for undo/redo functionality.
824
+ */
825
+ addKeyboardListeners() {
826
+ const tryAddListener = (attempts = 0) => {
827
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
828
+ if (textarea) {
829
+ textarea.removeEventListener("keydown", this.handleKeyDown);
830
+ textarea.addEventListener("keydown", this.handleKeyDown);
831
+ } else if (attempts < 15) {
832
+ requestAnimationFrame(() => tryAddListener(attempts + 1));
833
+ }
834
+ };
835
+ tryAddListener();
836
+ }
837
+ /**
838
+ * Remove keyboard event listeners from the textarea to prevent memory leaks.
839
+ */
840
+ removeKeyboardListeners() {
841
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
842
+ if (textarea) {
843
+ textarea.removeEventListener("keydown", this.handleKeyDown);
844
+ }
845
+ }
846
+ /**
847
+ * Toggle color formatting by wrapping/unwrapping selection or current word.
848
+ *
849
+ * @param color - the hex color code to apply, e.g. '#FF0000' for red
850
+ */
851
+ toggleColorWrap(color) {
852
+ if (this.isReadonly || this.isDisabled) return;
853
+ this.saveUndoStateBeforeChange();
854
+ this.withSelection((textarea, start, end, value) => {
855
+ if (this.isSelectionInLinkUrl(start, end, value)) {
856
+ return;
857
+ }
858
+ const { start: s, end: e } = this.expandSelectionToWord(start, end, value);
859
+ let before = value.slice(0, s);
860
+ let selected = value.slice(s, e);
861
+ let after = value.slice(e);
862
+ const colorTagClose = "</span>";
863
+ const anyColorSpanRegex = /<span style="color: ([^"]+)">$/;
864
+ const beforeColorMatch = before.match(anyColorSpanRegex);
865
+ const hasOuterWrap = beforeColorMatch && after.startsWith(colorTagClose);
866
+ if (hasOuterWrap) {
867
+ const existingColor = beforeColorMatch[1];
868
+ let selStart2;
869
+ let selEnd2;
870
+ if (existingColor === color) {
871
+ before = before.slice(0, before.length - beforeColorMatch[0].length);
872
+ after = after.slice(colorTagClose.length);
873
+ this.value = before + selected + after;
874
+ textarea.value = before + selected + after;
875
+ selStart2 = before.length;
876
+ selEnd2 = selStart2 + selected.length;
877
+ } else {
878
+ const newColorTagOpen2 = `<span style="color: ${color}">`;
879
+ before = before.slice(0, before.length - beforeColorMatch[0].length) + newColorTagOpen2;
880
+ this.value = before + selected + after;
881
+ textarea.value = before + selected + after;
882
+ selStart2 = before.length;
883
+ selEnd2 = selStart2 + selected.length;
884
+ }
885
+ requestAnimationFrame(() => {
886
+ textarea.setSelectionRange(selStart2, selEnd2);
887
+ this.updateActiveFormats();
888
+ });
889
+ this.dispatchChange();
890
+ return;
891
+ }
892
+ const colorRegex = /^<span style="color: ([^"]+)">(.*)<\/span>$/s;
893
+ const innerMatch = selected.match(colorRegex);
894
+ if (innerMatch) {
895
+ const existingColor = innerMatch[1];
896
+ const innerText = innerMatch[2];
897
+ if (existingColor === color) {
898
+ selected = innerText;
899
+ } else {
900
+ selected = `<span style="color: ${color}">${innerText}</span>`;
901
+ }
902
+ this.value = before + selected + after;
903
+ textarea.value = before + selected + after;
904
+ const selStart2 = before.length;
905
+ const selEnd2 = selStart2 + (existingColor === color ? innerText.length : innerText.length);
906
+ requestAnimationFrame(() => {
907
+ textarea.setSelectionRange(selStart2, selEnd2);
908
+ this.updateActiveFormats();
909
+ });
910
+ this.dispatchChange();
911
+ return;
912
+ }
913
+ const newColorTagOpen = `<span style="color: ${color}">`;
914
+ const wrapped = `${newColorTagOpen}${selected || ""}${colorTagClose}`;
915
+ this.value = before + wrapped + after;
916
+ textarea.value = before + wrapped + after;
917
+ const selStart = before.length + newColorTagOpen.length;
918
+ const selEnd = selStart + (selected ? selected.length : 4);
919
+ requestAnimationFrame(() => {
920
+ textarea.setSelectionRange(selStart, selEnd);
921
+ this.updateActiveFormats();
922
+ });
923
+ this.dispatchChange();
924
+ });
925
+ }
926
+ /**
927
+ * Handle color selection from the dropdown.
928
+ *
929
+ * @param color - the selected hex color code
930
+ */
931
+ selectColor(color) {
932
+ if (this.savedSelection) {
933
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
934
+ if (textarea) {
935
+ textarea.focus();
936
+ textarea.setSelectionRange(
937
+ this.savedSelection.start,
938
+ this.savedSelection.end
939
+ );
940
+ this.currentSelection = this.savedSelection;
941
+ this.savedSelection = null;
942
+ this.toggleColorWrap(color);
943
+ }
944
+ } else {
945
+ this.toggleColorWrap(color);
946
+ }
947
+ }
948
+ /**
949
+ * Clear color formatting from the current selection or word.
950
+ */
951
+ clearColor() {
952
+ if (this.isReadonly || this.isDisabled) return;
953
+ this.saveUndoStateBeforeChange();
954
+ if (this.savedSelection) {
955
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
956
+ if (textarea) {
957
+ textarea.focus();
958
+ textarea.setSelectionRange(
959
+ this.savedSelection.start,
960
+ this.savedSelection.end
961
+ );
962
+ this.currentSelection = this.savedSelection;
963
+ this.savedSelection = null;
964
+ }
965
+ }
966
+ this.withSelection((textarea, start, end, value) => {
967
+ if (this.isSelectionInLinkUrl(start, end, value)) {
968
+ return;
969
+ }
970
+ const { start: s, end: e } = this.expandSelectionToWord(start, end, value);
971
+ const before = value.slice(0, s);
972
+ let selected = value.slice(s, e);
973
+ const after = value.slice(e);
974
+ const colorRegex = /<span style="color: ([^"]+)">(.*?)<\/span>/gs;
975
+ selected = selected.replace(colorRegex, "$2");
976
+ const fullColorRegex = /<span style="color: ([^"]+)">(.*?)<\/span>/g;
977
+ let match;
978
+ let foundMatch = false;
979
+ const searchText = value.slice(
980
+ Math.max(0, s - 100),
981
+ Math.min(value.length, e + 100)
982
+ );
983
+ const searchOffset = Math.max(0, s - 100);
984
+ match = fullColorRegex.exec(searchText);
985
+ while (match !== null) {
986
+ const matchStart = searchOffset + match.index;
987
+ const matchEnd = searchOffset + match.index + match[0].length;
988
+ const spanOpenTag = `<span style="color: ${match[1]}">`;
989
+ const contentStart = searchOffset + match.index + spanOpenTag.length;
990
+ const contentEnd = matchEnd - 7;
991
+ if (contentStart <= s && e <= contentEnd) {
992
+ const beforeContent = value.slice(contentStart, s);
993
+ const afterContent = value.slice(e, contentEnd);
994
+ const newContent = beforeContent + selected + afterContent;
995
+ this.value = value.slice(0, matchStart) + newContent + value.slice(matchEnd);
996
+ textarea.value = value.slice(0, matchStart) + newContent + value.slice(matchEnd);
997
+ const selStart = matchStart + beforeContent.length;
998
+ const selEnd = selStart + selected.length;
999
+ requestAnimationFrame(() => {
1000
+ textarea.setSelectionRange(selStart, selEnd);
1001
+ this.updateActiveFormats();
1002
+ });
1003
+ this.dispatchChange();
1004
+ foundMatch = true;
1005
+ break;
1006
+ }
1007
+ match = fullColorRegex.exec(searchText);
1008
+ }
1009
+ if (!foundMatch) {
1010
+ this.value = before + selected + after;
1011
+ textarea.value = before + selected + after;
1012
+ const selStart = before.length;
1013
+ const selEnd = selStart + selected.length;
1014
+ requestAnimationFrame(() => {
1015
+ textarea.setSelectionRange(selStart, selEnd);
1016
+ this.updateActiveFormats();
1017
+ });
1018
+ this.dispatchChange();
1019
+ }
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Determine the current active heading level (1-3) based on activeFormats.
1024
+ */
1025
+ getActiveHeadingLevel() {
1026
+ if (this.activeFormats.h1) return 1;
1027
+ if (this.activeFormats.h2) return 2;
1028
+ if (this.activeFormats.h3) return 3;
1029
+ return 0;
1030
+ }
1031
+ /**
1032
+ * Save the initial state to the undo stack.
1033
+ */
1034
+ saveInitialUndoState() {
1035
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
1036
+ const initialSelection = textarea ? { start: textarea.selectionStart ?? 0, end: textarea.selectionEnd ?? 0 } : { start: 0, end: 0 };
1037
+ this.undoStack = [{ value: this.value, selection: initialSelection }];
1038
+ this.redoStack = [];
1039
+ this.lastSavedValue = this.value;
1040
+ }
1041
+ /**
1042
+ * Save the current state to the undo stack before making a change.
1043
+ *
1044
+ */
1045
+ saveUndoStateBeforeChange() {
1046
+ if (this.isUndoRedoAction) return;
1047
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
1048
+ const selection = textarea ? { start: textarea.selectionStart ?? 0, end: textarea.selectionEnd ?? 0 } : { start: 0, end: 0 };
1049
+ this.undoStack.push({
1050
+ value: this.value,
1051
+ selection
1052
+ });
1053
+ if (this.undoStack.length > this.MAX_UNDO_STACK_SIZE) {
1054
+ this.undoStack.shift();
1055
+ }
1056
+ this.redoStack = [];
1057
+ }
1058
+ /**
1059
+ * Save the current state to the undo stack if the value has changed.
1060
+ */
1061
+ saveUndoState() {
1062
+ if (this.isUndoRedoAction) return;
1063
+ if (this.value !== this.lastSavedValue) {
1064
+ this.undoStack.push({
1065
+ value: this.lastSavedValue,
1066
+ selection: this.currentSelection
1067
+ });
1068
+ if (this.undoStack.length > this.MAX_UNDO_STACK_SIZE) {
1069
+ this.undoStack.shift();
1070
+ }
1071
+ this.redoStack = [];
1072
+ this.lastSavedValue = this.value;
1073
+ }
1074
+ }
1075
+ /**
1076
+ * Schedule an undo state save after a short delay.
1077
+ */
1078
+ scheduleUndoStateSave() {
1079
+ if (this.undoTimeout) {
1080
+ clearTimeout(this.undoTimeout);
1081
+ }
1082
+ this.undoTimeout = window.setTimeout(() => {
1083
+ this.saveUndoState();
1084
+ this.undoTimeout = null;
1085
+ }, this.UNDO_SAVE_DELAY);
1086
+ }
1087
+ /**
1088
+ * Handle list continuation when Enter is pressed within a list item.
1089
+ * Works against the textarea value/selection.
1090
+ * Returns true if handled.
1091
+ */
1092
+ handleListContinuation() {
1093
+ const textarea = this.textareaEl?.shadowRoot?.querySelector(
1094
+ "textarea"
1095
+ );
1096
+ if (!textarea) return false;
1097
+ const start = textarea.selectionStart ?? 0;
1098
+ const end = textarea.selectionEnd ?? 0;
1099
+ if (start !== end) return false;
1100
+ const value = this.value;
1101
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
1102
+ let lineEnd = value.indexOf("\n", start);
1103
+ if (lineEnd === -1) lineEnd = value.length;
1104
+ const currentLine = value.slice(lineStart, lineEnd);
1105
+ const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s*(.*)$/);
1106
+ const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s*(.*)$/);
1107
+ if (!unorderedMatch && !orderedMatch) {
1108
+ return false;
1109
+ }
1110
+ this.saveUndoStateBeforeChange();
1111
+ if (unorderedMatch) {
1112
+ const indent = unorderedMatch[1] ?? "";
1113
+ const marker = unorderedMatch[2] ?? "-";
1114
+ const content = unorderedMatch[3] ?? "";
1115
+ if (content.trim() === "") {
1116
+ const before2 = value.slice(0, lineStart);
1117
+ const after2 = value.slice(lineEnd);
1118
+ const newValue2 = before2 + (lineEnd === value.length ? "" : "") + after2;
1119
+ this.value = newValue2;
1120
+ textarea.value = newValue2;
1121
+ const newCursor2 = before2.length;
1122
+ requestAnimationFrame(() => {
1123
+ textarea.setSelectionRange(newCursor2, newCursor2);
1124
+ this.updateActiveFormats();
1125
+ });
1126
+ this.dispatchChange();
1127
+ return true;
1128
+ }
1129
+ const before = value.slice(0, start);
1130
+ const after = value.slice(start);
1131
+ const prefix = `
1132
+ ${indent}${marker} `;
1133
+ const newValue = before + prefix + after;
1134
+ this.value = newValue;
1135
+ textarea.value = newValue;
1136
+ const newCursor = start + prefix.length;
1137
+ requestAnimationFrame(() => {
1138
+ textarea.setSelectionRange(newCursor, newCursor);
1139
+ this.updateActiveFormats();
1140
+ });
1141
+ this.dispatchChange();
1142
+ return true;
1143
+ }
1144
+ if (orderedMatch) {
1145
+ const indent = orderedMatch[1] ?? "";
1146
+ const numberStr = orderedMatch[2] ?? "1";
1147
+ const content = orderedMatch[3] ?? "";
1148
+ if (content.trim() === "") {
1149
+ const before2 = value.slice(0, lineStart);
1150
+ const after2 = value.slice(lineEnd);
1151
+ const newValue2 = before2 + (lineEnd === value.length ? "" : "") + after2;
1152
+ this.value = newValue2;
1153
+ textarea.value = newValue2;
1154
+ const newCursor2 = before2.length;
1155
+ requestAnimationFrame(() => {
1156
+ textarea.setSelectionRange(newCursor2, newCursor2);
1157
+ this.updateActiveFormats();
1158
+ });
1159
+ this.dispatchChange();
1160
+ return true;
1161
+ }
1162
+ let nextNumber = parseInt(numberStr, 10) + 1;
1163
+ const beforeText = value.slice(0, lineStart);
1164
+ const beforeLines = beforeText.split("\n");
1165
+ let lastNumberAtThisLevel = 0;
1166
+ for (let i = beforeLines.length - 1; i >= 0; i--) {
1167
+ const line = beforeLines[i];
1168
+ const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
1169
+ if (match && match[1] === indent) {
1170
+ lastNumberAtThisLevel = parseInt(match[2], 10);
1171
+ break;
1172
+ } else if (line.trim() !== "" && !line.match(/^\s*[-*+]\s+/) && !match) {
1173
+ break;
1174
+ }
1175
+ }
1176
+ if (lastNumberAtThisLevel > 0) {
1177
+ nextNumber = lastNumberAtThisLevel + 1;
1178
+ }
1179
+ const before = value.slice(0, start);
1180
+ const after = value.slice(start);
1181
+ const prefix = `
1182
+ ${indent}${nextNumber}. `;
1183
+ const newValue = before + prefix + after;
1184
+ const renumberedValue = this.renumberOrderedListItems(
1185
+ newValue,
1186
+ start + prefix.length,
1187
+ indent
1188
+ );
1189
+ this.value = renumberedValue;
1190
+ textarea.value = renumberedValue;
1191
+ const newCursor = start + prefix.length;
1192
+ requestAnimationFrame(() => {
1193
+ textarea.setSelectionRange(newCursor, newCursor);
1194
+ this.updateActiveFormats();
1195
+ });
1196
+ this.dispatchChange();
1197
+ return true;
1198
+ }
1199
+ return false;
1200
+ }
1201
+ /**
1202
+ * Handle Tab key to indent a list item (increase nesting level).
1203
+ * Returns true if handled.
1204
+ */
1205
+ handleListIndent() {
1206
+ const textarea = this.textareaEl?.shadowRoot?.querySelector(
1207
+ "textarea"
1208
+ );
1209
+ if (!textarea) return false;
1210
+ const start = textarea.selectionStart ?? 0;
1211
+ const end = textarea.selectionEnd ?? 0;
1212
+ if (start !== end) return false;
1213
+ const value = this.value;
1214
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
1215
+ let lineEnd = value.indexOf("\n", start);
1216
+ if (lineEnd === -1) lineEnd = value.length;
1217
+ const currentLine = value.slice(lineStart, lineEnd);
1218
+ const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s*(.*)$/);
1219
+ const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s*(.*)$/);
1220
+ if (!unorderedMatch && !orderedMatch) {
1221
+ return false;
1222
+ }
1223
+ this.saveUndoStateBeforeChange();
1224
+ const before = value.slice(0, lineStart);
1225
+ const after = value.slice(lineEnd);
1226
+ const indent = " ";
1227
+ let newLine;
1228
+ let newCursorOffset = 0;
1229
+ if (unorderedMatch) {
1230
+ const currentIndent = unorderedMatch[1] ?? "";
1231
+ const marker = unorderedMatch[2] ?? "-";
1232
+ const content = unorderedMatch[3] ?? "";
1233
+ newLine = `${currentIndent}${indent}${marker} ${content}`;
1234
+ newCursorOffset = indent.length;
1235
+ } else if (orderedMatch) {
1236
+ const currentIndent = orderedMatch[1] ?? "";
1237
+ const content = orderedMatch[3] ?? "";
1238
+ newLine = `${currentIndent}${indent}1. ${content}`;
1239
+ newCursorOffset = indent.length;
1240
+ } else {
1241
+ return false;
1242
+ }
1243
+ const newValue = before + newLine + after;
1244
+ this.value = newValue;
1245
+ textarea.value = newValue;
1246
+ const cursorInLine = start - lineStart;
1247
+ const newCursor = lineStart + cursorInLine + newCursorOffset;
1248
+ requestAnimationFrame(() => {
1249
+ textarea.setSelectionRange(newCursor, newCursor);
1250
+ this.updateActiveFormats();
1251
+ });
1252
+ this.dispatchChange();
1253
+ return true;
1254
+ }
1255
+ /**
1256
+ * Handle Shift+Tab key to outdent a list item (decrease nesting level).
1257
+ * Returns true if handled.
1258
+ */
1259
+ handleListOutdent() {
1260
+ const textarea = this.textareaEl?.shadowRoot?.querySelector(
1261
+ "textarea"
1262
+ );
1263
+ if (!textarea) return false;
1264
+ const start = textarea.selectionStart ?? 0;
1265
+ const end = textarea.selectionEnd ?? 0;
1266
+ if (start !== end) return false;
1267
+ const value = this.value;
1268
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
1269
+ let lineEnd = value.indexOf("\n", start);
1270
+ if (lineEnd === -1) lineEnd = value.length;
1271
+ const currentLine = value.slice(lineStart, lineEnd);
1272
+ const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s*(.*)$/);
1273
+ const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s*(.*)$/);
1274
+ if (!unorderedMatch && !orderedMatch) {
1275
+ return false;
1276
+ }
1277
+ const currentIndent = (unorderedMatch || orderedMatch)?.[1] ?? "";
1278
+ if (currentIndent.length < 4) {
1279
+ return false;
1280
+ }
1281
+ this.saveUndoStateBeforeChange();
1282
+ const before = value.slice(0, lineStart);
1283
+ const after = value.slice(lineEnd);
1284
+ const outdent = " ";
1285
+ let newLine;
1286
+ let newCursorOffset = 0;
1287
+ if (unorderedMatch) {
1288
+ const marker = unorderedMatch[2] ?? "-";
1289
+ const content = unorderedMatch[3] ?? "";
1290
+ const newIndent = currentIndent.slice(outdent.length);
1291
+ newLine = `${newIndent}${marker} ${content}`;
1292
+ newCursorOffset = -outdent.length;
1293
+ } else if (orderedMatch) {
1294
+ const content = orderedMatch[3] ?? "";
1295
+ const newIndent = currentIndent.slice(outdent.length);
1296
+ let newNumber = 1;
1297
+ const beforeLines = before.split("\n");
1298
+ for (let i = beforeLines.length - 1; i >= 0; i--) {
1299
+ const line = beforeLines[i];
1300
+ const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
1301
+ if (match && match[1] === newIndent) {
1302
+ newNumber = parseInt(match[2], 10) + 1;
1303
+ break;
1304
+ } else if (line.trim() !== "" && !line.match(/^\s*[-*+]\s+/) && !match) {
1305
+ break;
1306
+ }
1307
+ }
1308
+ newLine = `${newIndent}${newNumber}. ${content}`;
1309
+ newCursorOffset = -outdent.length;
1310
+ } else {
1311
+ return false;
1312
+ }
1313
+ let newValue = before + newLine + after;
1314
+ if (orderedMatch) {
1315
+ const newIndent = currentIndent.slice(outdent.length);
1316
+ newValue = this.renumberOrderedListItems(
1317
+ newValue,
1318
+ lineStart + newLine.length,
1319
+ newIndent
1320
+ );
1321
+ }
1322
+ this.value = newValue;
1323
+ textarea.value = newValue;
1324
+ const cursorInLine = start - lineStart;
1325
+ const newCursor = Math.max(
1326
+ lineStart,
1327
+ lineStart + cursorInLine + newCursorOffset
1328
+ );
1329
+ requestAnimationFrame(() => {
1330
+ textarea.setSelectionRange(newCursor, newCursor);
1331
+ this.updateActiveFormats();
1332
+ });
1333
+ this.dispatchChange();
1334
+ return true;
1335
+ }
1336
+ /**
1337
+ * Renumber ordered list items that come after the given position with the same indentation level.
1338
+ *
1339
+ * @param value - The text content to process
1340
+ * @param fromPosition - Start looking for list items from this position
1341
+ * @param targetIndent - Only renumber items with this exact indentation
1342
+ * @returns The text with renumbered list items
1343
+ */
1344
+ renumberOrderedListItems(value, fromPosition, targetIndent) {
1345
+ const lines = value.split("\n");
1346
+ const fromLineIndex = Math.max(
1347
+ 0,
1348
+ value.slice(0, fromPosition).split("\n").length - 1
1349
+ );
1350
+ let nextExpectedNumber = 1;
1351
+ const currentLine = lines[fromLineIndex];
1352
+ const currentMatch = currentLine?.match(/^(\s*)(\d+)\.\s*(.*)$/);
1353
+ if (currentMatch && currentMatch[1] === targetIndent) {
1354
+ nextExpectedNumber = parseInt(currentMatch[2], 10) + 1;
1355
+ } else {
1356
+ for (let i = fromLineIndex - 1; i >= 0; i--) {
1357
+ const line = lines[i];
1358
+ const orderedMatch = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
1359
+ if (orderedMatch && orderedMatch[1] === targetIndent) {
1360
+ nextExpectedNumber = parseInt(orderedMatch[2], 10) + 1;
1361
+ break;
1362
+ }
1363
+ }
1364
+ }
1365
+ let currentNumber = nextExpectedNumber;
1366
+ const orderedRegex = /^(\s*)(\d+)\.\s*(.*)$/;
1367
+ for (let i = fromLineIndex + 1; i < lines.length; i++) {
1368
+ const line = lines[i];
1369
+ const orderedMatch = line.match(orderedRegex);
1370
+ if (orderedMatch && orderedMatch[1] === targetIndent) {
1371
+ const indent = orderedMatch[1];
1372
+ const content = orderedMatch[3];
1373
+ lines[i] = `${indent}${currentNumber}. ${content}`;
1374
+ currentNumber++;
1375
+ } else if (orderedMatch && orderedMatch[1].length < targetIndent.length) {
1376
+ break;
1377
+ } else if (line.trim() !== "" && !orderedMatch && !line.match(/^\s*[-*+]\s+/)) {
1378
+ if (targetIndent === "") {
1379
+ break;
1380
+ }
1381
+ }
1382
+ }
1383
+ return lines.join("\n");
1384
+ }
1385
+ /**
1386
+ * Renumber any ordered lists that come after the given position, starting each new sequence from 1.
1387
+ * This is used when removing list formatting breaks the continuity of a list.
1388
+ *
1389
+ * @param value - The text content to process
1390
+ * @param fromPosition - Start looking for list items from this position
1391
+ * @returns The text with renumbered list sequences
1392
+ */
1393
+ renumberSubsequentOrderedLists(value, fromPosition) {
1394
+ const lines = value.split("\n");
1395
+ const fromLineIndex = Math.max(
1396
+ 0,
1397
+ value.slice(0, fromPosition).split("\n").length - 1
1398
+ );
1399
+ const orderedRegex = /^(\s*)(\d+)\.\s*(.*)$/;
1400
+ let currentSequenceNumber = 1;
1401
+ let inSequence = false;
1402
+ let currentIndent = "";
1403
+ for (let i = fromLineIndex + 1; i < lines.length; i++) {
1404
+ const line = lines[i];
1405
+ const orderedMatch = line.match(orderedRegex);
1406
+ if (orderedMatch) {
1407
+ const indent = orderedMatch[1];
1408
+ const content = orderedMatch[3];
1409
+ if (!inSequence || indent !== currentIndent) {
1410
+ currentSequenceNumber = 1;
1411
+ inSequence = true;
1412
+ currentIndent = indent;
1413
+ }
1414
+ lines[i] = `${indent}${currentSequenceNumber}. ${content}`;
1415
+ currentSequenceNumber++;
1416
+ } else if (line.trim() !== "" && !line.match(/^\s*[-*+]\s+/)) {
1417
+ inSequence = false;
1418
+ }
1419
+ }
1420
+ return lines.join("\n");
1421
+ }
1422
+ /**
1423
+ * Handle backspace to remove empty list items.
1424
+ * Returns true if handled.
1425
+ */
1426
+ handleListBackspace() {
1427
+ const textarea = this.textareaEl?.shadowRoot?.querySelector(
1428
+ "textarea"
1429
+ );
1430
+ if (!textarea) return false;
1431
+ const start = textarea.selectionStart ?? 0;
1432
+ const end = textarea.selectionEnd ?? 0;
1433
+ if (start !== end) return false;
1434
+ const value = this.value;
1435
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
1436
+ let lineEnd = value.indexOf("\n", start);
1437
+ if (lineEnd === -1) lineEnd = value.length;
1438
+ const currentLine = value.slice(lineStart, lineEnd);
1439
+ const cursorPositionInLine = start - lineStart;
1440
+ const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s*(.*)$/);
1441
+ const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s*(.*)$/);
1442
+ if (!unorderedMatch && !orderedMatch) {
1443
+ return false;
1444
+ }
1445
+ let markerEndPosition = 0;
1446
+ let hasContent = false;
1447
+ if (unorderedMatch) {
1448
+ const indent = unorderedMatch[1] ?? "";
1449
+ const marker = unorderedMatch[2] ?? "-";
1450
+ const content = unorderedMatch[3] ?? "";
1451
+ markerEndPosition = indent.length + marker.length + 1;
1452
+ hasContent = content.trim().length > 0;
1453
+ } else if (orderedMatch) {
1454
+ const indent = orderedMatch[1] ?? "";
1455
+ const numberStr = orderedMatch[2] ?? "1";
1456
+ const content = orderedMatch[3] ?? "";
1457
+ markerEndPosition = indent.length + numberStr.length + 2;
1458
+ hasContent = content.trim().length > 0;
1459
+ }
1460
+ if (cursorPositionInLine === markerEndPosition && !hasContent) {
1461
+ this.saveUndoStateBeforeChange();
1462
+ const before = value.slice(0, lineStart);
1463
+ const after = value.slice(
1464
+ lineEnd === value.length ? lineEnd : lineEnd + 1
1465
+ );
1466
+ let newValue = before + after;
1467
+ if (orderedMatch) {
1468
+ const indent = orderedMatch[1] ?? "";
1469
+ newValue = this.renumberOrderedListItems(
1470
+ newValue,
1471
+ before.length,
1472
+ indent
1473
+ );
1474
+ }
1475
+ this.value = newValue;
1476
+ textarea.value = newValue;
1477
+ let newCursor = before.length;
1478
+ if (before.endsWith("\n") && before.length > 1) {
1479
+ newCursor = before.length - 1;
1480
+ }
1481
+ requestAnimationFrame(() => {
1482
+ textarea.setSelectionRange(newCursor, newCursor);
1483
+ this.updateActiveFormats();
1484
+ });
1485
+ this.dispatchChange();
1486
+ return true;
1487
+ }
1488
+ return false;
1489
+ }
1490
+ /**
1491
+ /**
1492
+ * Perform an undo operation, reverting to the previous state.
1493
+ */
1494
+ undo() {
1495
+ if (this.isReadonly || this.isDisabled || this.undoStack.length <= 1) {
1496
+ return;
1497
+ }
1498
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
1499
+ const currentSelection = textarea ? { start: textarea.selectionStart ?? 0, end: textarea.selectionEnd ?? 0 } : { start: 0, end: 0 };
1500
+ this.redoStack.push({ value: this.value, selection: currentSelection });
1501
+ const previousState = this.undoStack.pop();
1502
+ if (!previousState) {
1503
+ return;
1504
+ }
1505
+ this.isUndoRedoAction = true;
1506
+ this.value = previousState.value;
1507
+ this.lastSavedValue = previousState.value;
1508
+ if (textarea) {
1509
+ textarea.value = previousState.value;
1510
+ }
1511
+ requestAnimationFrame(() => {
1512
+ if (textarea) {
1513
+ textarea.setSelectionRange(
1514
+ previousState.selection.start,
1515
+ previousState.selection.end
1516
+ );
1517
+ }
1518
+ this.updateActiveFormats();
1519
+ this.isUndoRedoAction = false;
1520
+ });
1521
+ this.dispatchChange();
1522
+ }
1523
+ /**
1524
+ * Perform a redo operation, reapplying a previously undone state.
1525
+ */
1526
+ redo() {
1527
+ if (this.isReadonly || this.isDisabled || this.redoStack.length === 0) {
1528
+ return;
1529
+ }
1530
+ const textarea = this.textareaEl?.shadowRoot?.querySelector("textarea");
1531
+ const currentSelection = textarea ? { start: textarea.selectionStart ?? 0, end: textarea.selectionEnd ?? 0 } : { start: 0, end: 0 };
1532
+ this.undoStack.push({ value: this.value, selection: currentSelection });
1533
+ const nextState = this.redoStack.pop();
1534
+ if (!nextState) {
1535
+ return;
1536
+ }
1537
+ this.isUndoRedoAction = true;
1538
+ this.value = nextState.value;
1539
+ this.lastSavedValue = nextState.value;
1540
+ if (textarea) {
1541
+ textarea.value = nextState.value;
1542
+ }
1543
+ requestAnimationFrame(() => {
1544
+ if (textarea) {
1545
+ textarea.setSelectionRange(
1546
+ nextState.selection.start,
1547
+ nextState.selection.end
1548
+ );
1549
+ }
1550
+ this.updateActiveFormats();
1551
+ this.isUndoRedoAction = false;
1552
+ });
1553
+ this.dispatchChange();
1554
+ }
1555
+ connectedCallback() {
1556
+ super.connectedCallback();
1557
+ document.addEventListener("click", this.handleOutsideClick);
1558
+ }
1559
+ firstUpdated(changedProperties) {
1560
+ super.firstUpdated(changedProperties);
1561
+ requestAnimationFrame(() => {
1562
+ this.saveInitialUndoState();
1563
+ this.updateActiveFormats();
1564
+ this.addKeyboardListeners();
1565
+ });
1566
+ }
1567
+ disconnectedCallback() {
1568
+ super.disconnectedCallback();
1569
+ document.removeEventListener("click", this.handleOutsideClick);
1570
+ if (this.undoTimeout) {
1571
+ clearTimeout(this.undoTimeout);
1572
+ }
1573
+ this.removeKeyboardListeners();
1574
+ this.savedSelectionForPreview = null;
1575
+ }
1576
+ labelTemplate() {
1577
+ return this.label ? shared_tailwindElement_index.x`<label class="heading-inter-14-bold text-neutral-20 block"
1578
+ >${this.label}</label
1579
+ >` : shared_tailwindElement_index.E;
1580
+ }
1581
+ descriptionTemplate() {
1582
+ return this.description ? shared_tailwindElement_index.x`<div class="paragraph-inter-12-regular text-neutral-20">
1583
+ <lukso-sanitize html-content=${this.description}></lukso-sanitize>
1584
+ </div>` : shared_tailwindElement_index.E;
1585
+ }
1586
+ /**
1587
+ * Restore focus and selection to the textarea after toolbar interactions.
1588
+ */
1589
+ restoreFocusAndSelection() {
1590
+ const ta = this.textareaEl?.shadowRoot?.querySelector(
1591
+ "textarea"
1592
+ );
1593
+ if (ta) {
1594
+ ta.focus();
1595
+ const sel = this.currentSelection;
1596
+ const start = typeof sel.start === "number" ? sel.start : ta.selectionStart ?? 0;
1597
+ const end = typeof sel.end === "number" ? sel.end : ta.selectionEnd ?? 0;
1598
+ ta.setSelectionRange(start, end);
1599
+ }
1600
+ }
1601
+ buttonTemplate(icon, handler, name, isActive = false) {
1602
+ return shared_tailwindElement_index.x`
1603
+ <lukso-tooltip text=${name} placement="top">
1604
+ <lukso-button
1605
+ @click=${() => {
1606
+ this.restoreFocusAndSelection();
1607
+ handler();
1608
+ }}
1609
+ aria-label=${name}
1610
+ aria-pressed=${isActive ? "true" : "false"}
1611
+ type="button"
1612
+ variant="secondary"
1613
+ size="small"
1614
+ custom-class=${this.toolbarButton({ active: isActive })}
1615
+ is-icon
1616
+ >
1617
+ <lukso-icon
1618
+ name=${icon}
1619
+ size="small"
1620
+ pack="vuesax"
1621
+ variant="linear"
1622
+ ></lukso-icon></lukso-button
1623
+ ></lukso-tooltip>
1624
+ `;
1625
+ }
1626
+ toolbarTemplate() {
1627
+ return shared_tailwindElement_index.x`
1628
+ <div class="flex items-center gap-2">
1629
+ <div class=${cn.cn(this.styles().headingMenu())}>
1630
+ <!-- Heading -->
1631
+ <lukso-tooltip text="Heading options" placement="top">
1632
+ <lukso-button
1633
+ id=${this.headingTriggerId}
1634
+ @click=${(e) => {
1635
+ e.stopPropagation();
1636
+ this.isColorDropdownOpen = false;
1637
+ this.isListDropdownOpen = false;
1638
+ this.isHeadingDropdownOpen = !this.isHeadingDropdownOpen;
1639
+ }}
1640
+ aria-expanded=${this.isHeadingDropdownOpen ? "true" : "false"}
1641
+ aria-label="Heading options"
1642
+ variant="secondary"
1643
+ size="small"
1644
+ custom-class=${this.toolbarButton({
1645
+ active: this.getActiveHeadingLevel() > 0
1646
+ })}
1647
+ is-icon
1648
+ >
1649
+ <lukso-icon
1650
+ name="smallcaps"
1651
+ size="small"
1652
+ pack="vuesax"
1653
+ variant="linear"
1654
+ ></lukso-icon>
1655
+ </lukso-button>
1656
+ </lukso-tooltip>
1657
+ <lukso-dropdown
1658
+ id="headingDropdown"
1659
+ trigger-id=""
1660
+ size="medium"
1661
+ ?is-open=${this.isHeadingDropdownOpen}
1662
+ >
1663
+ <lukso-dropdown-option
1664
+ ?is-selected=${this.getActiveHeadingLevel() === 0}
1665
+ @click=${(e) => {
1666
+ e.stopPropagation();
1667
+ this.restoreFocusAndSelection();
1668
+ this.applyHeading(0);
1669
+ this.isHeadingDropdownOpen = false;
1670
+ }}
1671
+ size="medium"
1672
+ >
1673
+ Normal text
1674
+ </lukso-dropdown-option>
1675
+ <lukso-dropdown-option
1676
+ ?is-selected=${this.getActiveHeadingLevel() === 1}
1677
+ @click=${(e) => {
1678
+ e.stopPropagation();
1679
+ this.restoreFocusAndSelection();
1680
+ this.applyHeading(1);
1681
+ this.isHeadingDropdownOpen = false;
1682
+ }}
1683
+ size="medium"
1684
+ >
1685
+ Heading 1
1686
+ </lukso-dropdown-option>
1687
+ <lukso-dropdown-option
1688
+ ?is-selected=${this.getActiveHeadingLevel() === 2}
1689
+ @click=${(e) => {
1690
+ e.stopPropagation();
1691
+ this.restoreFocusAndSelection();
1692
+ this.applyHeading(2);
1693
+ this.isHeadingDropdownOpen = false;
1694
+ }}
1695
+ size="medium"
1696
+ >
1697
+ Heading 2
1698
+ </lukso-dropdown-option>
1699
+ <lukso-dropdown-option
1700
+ ?is-selected=${this.getActiveHeadingLevel() === 3}
1701
+ @click=${(e) => {
1702
+ e.stopPropagation();
1703
+ this.restoreFocusAndSelection();
1704
+ this.applyHeading(3);
1705
+ this.isHeadingDropdownOpen = false;
1706
+ }}
1707
+ size="medium"
1708
+ >
1709
+ Heading 3
1710
+ </lukso-dropdown-option>
1711
+ </lukso-dropdown>
1712
+ </div>
1713
+
1714
+ <!-- Bold -->
1715
+ ${this.buttonTemplate(
1716
+ "text-bold",
1717
+ () => this.toggleWrap("**"),
1718
+ "Bold",
1719
+ this.activeFormats.bold
1720
+ )}
1721
+
1722
+ <!-- Italic -->
1723
+ ${this.buttonTemplate(
1724
+ "text-italic",
1725
+ () => this.toggleWrap("*"),
1726
+ "Italic",
1727
+ this.activeFormats.italic
1728
+ )}
1729
+
1730
+ <!-- List -->
1731
+ <div class=${this.styles().listMenu()}>
1732
+ <lukso-tooltip text="List options" placement="top">
1733
+ <lukso-button
1734
+ id=${this.listTriggerId}
1735
+ @click=${(e) => {
1736
+ e.stopPropagation();
1737
+ this.restoreFocusAndSelection();
1738
+ this.isHeadingDropdownOpen = false;
1739
+ this.isColorDropdownOpen = false;
1740
+ this.isListDropdownOpen = !this.isListDropdownOpen;
1741
+ }}
1742
+ aria-expanded=${this.isListDropdownOpen ? "true" : "false"}
1743
+ aria-label="List options"
1744
+ variant="secondary"
1745
+ size="small"
1746
+ custom-class=${this.toolbarButton({
1747
+ active: this.activeFormats.unorderedList || this.activeFormats.orderedList
1748
+ })}
1749
+ is-icon
1750
+ >
1751
+ <lukso-icon
1752
+ name="task"
1753
+ size="small"
1754
+ pack="vuesax"
1755
+ variant="linear"
1756
+ ></lukso-icon>
1757
+ </lukso-button>
1758
+ </lukso-tooltip>
1759
+ <lukso-dropdown
1760
+ id="listDropdown"
1761
+ trigger-id=""
1762
+ size="medium"
1763
+ ?is-open=${this.isListDropdownOpen}
1764
+ >
1765
+ <lukso-dropdown-option
1766
+ ?is-selected=${this.getActiveListType() === "none"}
1767
+ @click=${(e) => {
1768
+ e.stopPropagation();
1769
+ this.restoreFocusAndSelection();
1770
+ this.applyList("none");
1771
+ this.isListDropdownOpen = false;
1772
+ }}
1773
+ size="medium"
1774
+ >
1775
+ No list
1776
+ </lukso-dropdown-option>
1777
+ <lukso-dropdown-option
1778
+ ?is-selected=${this.getActiveListType() === "unordered"}
1779
+ @click=${(e) => {
1780
+ e.stopPropagation();
1781
+ this.restoreFocusAndSelection();
1782
+ this.applyList("unordered");
1783
+ this.isListDropdownOpen = false;
1784
+ }}
1785
+ size="medium"
1786
+ >
1787
+ Unordered
1788
+ </lukso-dropdown-option>
1789
+ <lukso-dropdown-option
1790
+ ?is-selected=${this.getActiveListType() === "ordered"}
1791
+ @click=${(e) => {
1792
+ e.stopPropagation();
1793
+ this.restoreFocusAndSelection();
1794
+ this.applyList("ordered");
1795
+ this.isListDropdownOpen = false;
1796
+ }}
1797
+ size="medium"
1798
+ >
1799
+ Ordered
1800
+ </lukso-dropdown-option>
1801
+ </lukso-dropdown>
1802
+ </div>
1803
+
1804
+ <!-- Link -->
1805
+ ${this.buttonTemplate(
1806
+ "link",
1807
+ () => this.insertLink(),
1808
+ "Link",
1809
+ this.activeFormats.link
1810
+ )}
1811
+
1812
+ <!-- Color -->
1813
+ <div class=${this.styles().colorMenu()}>
1814
+ <lukso-tooltip text="Text color" placement="top">
1815
+ <lukso-button
1816
+ id=${this.colorTriggerId}
1817
+ @click=${(e) => {
1818
+ e.stopPropagation();
1819
+ this.restoreFocusAndSelection();
1820
+ this.isHeadingDropdownOpen = false;
1821
+ this.isListDropdownOpen = false;
1822
+ if (!this.isColorDropdownOpen) {
1823
+ const ta = this.textareaEl?.shadowRoot?.querySelector("textarea");
1824
+ if (ta) {
1825
+ this.savedSelection = {
1826
+ start: ta.selectionStart ?? 0,
1827
+ end: ta.selectionEnd ?? 0
1828
+ };
1829
+ }
1830
+ }
1831
+ this.isColorDropdownOpen = !this.isColorDropdownOpen;
1832
+ }}
1833
+ aria-expanded=${this.isColorDropdownOpen ? "true" : "false"}
1834
+ aria-pressed=${this.activeFormats.color ? "true" : "false"}
1835
+ aria-label="Text color"
1836
+ variant="secondary"
1837
+ size="small"
1838
+ custom-class=${this.toolbarButton({
1839
+ active: this.activeFormats.color
1840
+ })}
1841
+ is-icon
1842
+ >
1843
+ <div
1844
+ class="size-4 rounded-full"
1845
+ style="background-color: ${this.activeFormats.activeColor};"
1846
+ ></div>
1847
+ </lukso-button>
1848
+ </lukso-tooltip>
1849
+ <lukso-dropdown
1850
+ id="colorDropdown"
1851
+ trigger-id=""
1852
+ size="medium"
1853
+ max-height="300"
1854
+ ?is-open=${this.isColorDropdownOpen}
1855
+ >
1856
+ <div class="grid grid-cols-8 gap-2 p-2 w-[260px]">
1857
+ <div class="col-span-8 mb-2 flex items-center justify-between">
1858
+ <span class="text-xs text-neutral-60">Text Color</span>
1859
+ ${this.activeFormats.color ? shared_tailwindElement_index.x`<button
1860
+ class="text-xs text-neutral-60 hover:text-neutral-20 underline"
1861
+ @click=${(e) => {
1862
+ e.stopPropagation();
1863
+ this.clearColor();
1864
+ this.isColorDropdownOpen = false;
1865
+ }}
1866
+ type="button"
1867
+ >
1868
+ Clear
1869
+ </button>` : shared_tailwindElement_index.E}
1870
+ </div>
1871
+ ${this.colorSamples.map(
1872
+ (color) => shared_tailwindElement_index.x`
1873
+ <button
1874
+ class="w-6 h-6 rounded-4 border transition-all ${this.activeFormats.activeColor === color ? "border-neutral-20 ring-2 ring-purple-51" : "border-neutral-90 hover:border-neutral-60"}"
1875
+ style="background-color: ${color}"
1876
+ title=${color}
1877
+ aria-pressed=${this.activeFormats.activeColor === color ? "true" : "false"}
1878
+ @click=${(e) => {
1879
+ e.stopPropagation();
1880
+ this.selectColor(color);
1881
+ this.isColorDropdownOpen = false;
1882
+ }}
1883
+ ></button>
1884
+ `
1885
+ )}
1886
+ </div>
1887
+ </lukso-dropdown>
1888
+ </div>
1889
+
1890
+ <div class=${this.styles().divider()}></div>
1891
+ </div>
1892
+ `;
1893
+ }
1894
+ render() {
1895
+ const { wrapper, header, toolbar, area, editor, preview } = this.styles({
1896
+ isFullWidth: this.isFullWidth
1897
+ });
1898
+ return shared_tailwindElement_index.x`
1899
+ <div class=${wrapper()}>
1900
+ ${this.labelTemplate()} ${this.descriptionTemplate()}
1901
+
1902
+ <div class=${header()}>
1903
+ <div class=${toolbar()}>${this.toolbarTemplate()}</div>
1904
+ ${this.buttonTemplate(
1905
+ "eye",
1906
+ () => this.togglePreview(),
1907
+ "Toggle preview",
1908
+ this.isPreview
1909
+ )}
1910
+ </div>
1911
+
1912
+ <div class=${area()}>
1913
+ ${!this.isPreview ? shared_tailwindElement_index.x`<div class=${editor()}>
1914
+ <lukso-textarea
1915
+ .value=${this.value}
1916
+ name=${this.name ? this.name : shared_tailwindElement_index.E}
1917
+ size=${this.size ? this.size : shared_tailwindElement_index.E}
1918
+ rows=${this.rows ? this.rows : shared_tailwindElement_index.E}
1919
+ placeholder=${this.placeholder ? this.placeholder : shared_tailwindElement_index.E}
1920
+ error=${this.error ? this.error : shared_tailwindElement_index.E}
1921
+ ?is-full-width=${true}
1922
+ ?is-disabled=${this.isDisabled}
1923
+ ?is-readonly=${this.isReadonly}
1924
+ ?is-non-resizable=${this.isNonResizable}
1925
+ @on-input=${this.handleTextareaInput}
1926
+ @on-key-up=${this.handleTextareaKeyUp}
1927
+ @on-input-click=${this.handleTextareaClick}
1928
+ ></lukso-textarea>
1929
+ </div>` : shared_tailwindElement_index.x`<div class=${preview()}>
1930
+ <lukso-markdown
1931
+ value=${this.value}
1932
+ prose-classes="prose prose-base prose-gray"
1933
+ ></lukso-markdown>
1934
+ </div>`}
1935
+ </div>
1936
+ </div>
1937
+ `;
1938
+ }
1939
+ };
1940
+ __decorateClass([
1941
+ property.n({ type: String })
1942
+ ], exports.LuksoMarkdownEditor.prototype, "value", 2);
1943
+ __decorateClass([
1944
+ property.n({ type: String })
1945
+ ], exports.LuksoMarkdownEditor.prototype, "name", 2);
1946
+ __decorateClass([
1947
+ property.n({ type: String })
1948
+ ], exports.LuksoMarkdownEditor.prototype, "label", 2);
1949
+ __decorateClass([
1950
+ property.n({ type: String })
1951
+ ], exports.LuksoMarkdownEditor.prototype, "description", 2);
1952
+ __decorateClass([
1953
+ property.n({ type: String })
1954
+ ], exports.LuksoMarkdownEditor.prototype, "error", 2);
1955
+ __decorateClass([
1956
+ property.n({ type: Boolean, attribute: "is-full-width" })
1957
+ ], exports.LuksoMarkdownEditor.prototype, "isFullWidth", 2);
1958
+ __decorateClass([
1959
+ property.n({ type: Boolean, attribute: "is-readonly" })
1960
+ ], exports.LuksoMarkdownEditor.prototype, "isReadonly", 2);
1961
+ __decorateClass([
1962
+ property.n({ type: Boolean, attribute: "is-disabled" })
1963
+ ], exports.LuksoMarkdownEditor.prototype, "isDisabled", 2);
1964
+ __decorateClass([
1965
+ property.n({ type: Boolean, attribute: "is-non-resizable" })
1966
+ ], exports.LuksoMarkdownEditor.prototype, "isNonResizable", 2);
1967
+ __decorateClass([
1968
+ property.n({ type: Boolean })
1969
+ ], exports.LuksoMarkdownEditor.prototype, "autofocus", 2);
1970
+ __decorateClass([
1971
+ property.n({ type: String, reflect: true })
1972
+ ], exports.LuksoMarkdownEditor.prototype, "size", 2);
1973
+ __decorateClass([
1974
+ property.n({ type: Boolean, attribute: "is-preview", reflect: true })
1975
+ ], exports.LuksoMarkdownEditor.prototype, "isPreview", 2);
1976
+ __decorateClass([
1977
+ property.n({ type: Number })
1978
+ ], exports.LuksoMarkdownEditor.prototype, "rows", 2);
1979
+ __decorateClass([
1980
+ property.n({ type: String })
1981
+ ], exports.LuksoMarkdownEditor.prototype, "placeholder", 2);
1982
+ __decorateClass([
1983
+ state.r()
1984
+ ], exports.LuksoMarkdownEditor.prototype, "savedSelectionForPreview", 2);
1985
+ __decorateClass([
1986
+ state.r()
1987
+ ], exports.LuksoMarkdownEditor.prototype, "isHeadingDropdownOpen", 2);
1988
+ __decorateClass([
1989
+ state.r()
1990
+ ], exports.LuksoMarkdownEditor.prototype, "isColorDropdownOpen", 2);
1991
+ __decorateClass([
1992
+ state.r()
1993
+ ], exports.LuksoMarkdownEditor.prototype, "isListDropdownOpen", 2);
1994
+ __decorateClass([
1995
+ state.r()
1996
+ ], exports.LuksoMarkdownEditor.prototype, "currentSelection", 2);
1997
+ __decorateClass([
1998
+ state.r()
1999
+ ], exports.LuksoMarkdownEditor.prototype, "savedSelection", 2);
2000
+ __decorateClass([
2001
+ state.r()
2002
+ ], exports.LuksoMarkdownEditor.prototype, "activeFormats", 2);
2003
+ __decorateClass([
2004
+ query.e("lukso-textarea")
2005
+ ], exports.LuksoMarkdownEditor.prototype, "textareaEl", 2);
2006
+ exports.LuksoMarkdownEditor = __decorateClass([
2007
+ property.t("lukso-markdown-editor")
2008
+ ], exports.LuksoMarkdownEditor);