@threadlabs/looma 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/chunk-G53JEAQK.js +94 -0
  4. package/dist/chunk-OF57X5AR.js +10 -0
  5. package/dist/chunk-UL7UIUJZ.js +20 -0
  6. package/dist/chunk-YK4MTZGJ.js +1580 -0
  7. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  8. package/dist/cjs/events-TcQIzpNv.js +19 -0
  9. package/dist/cjs/id-CYbKpaYr.js +9 -0
  10. package/dist/cjs/index-D07f6BOw.js +1569 -0
  11. package/dist/cjs/index.cjs.js +2 -0
  12. package/dist/cjs/loader.cjs.js +13 -0
  13. package/dist/cjs/looma.cjs.js +25 -0
  14. package/dist/cjs/manager-BOpVXb92.js +93 -0
  15. package/dist/cjs/ui-avatar-group.cjs.entry.js +51 -0
  16. package/dist/cjs/ui-avatar.cjs.entry.js +50 -0
  17. package/dist/cjs/ui-badge.cjs.entry.js +19 -0
  18. package/dist/cjs/ui-button.cjs.entry.js +62 -0
  19. package/dist/cjs/ui-checkbox.cjs.entry.js +91 -0
  20. package/dist/cjs/ui-context-menu.cjs.entry.js +201 -0
  21. package/dist/cjs/ui-dialog.cjs.entry.js +93 -0
  22. package/dist/cjs/ui-disclosure.cjs.entry.js +109 -0
  23. package/dist/cjs/ui-floating-action-button.cjs.entry.js +20 -0
  24. package/dist/cjs/ui-form-field.cjs.entry.js +59 -0
  25. package/dist/cjs/ui-icon-button.cjs.entry.js +21 -0
  26. package/dist/cjs/ui-input.cjs.entry.js +101 -0
  27. package/dist/cjs/ui-menu-item.cjs.entry.js +19 -0
  28. package/dist/cjs/ui-menu.cjs.entry.js +96 -0
  29. package/dist/cjs/ui-popover.cjs.entry.js +92 -0
  30. package/dist/cjs/ui-radio-group.cjs.entry.js +134 -0
  31. package/dist/cjs/ui-radio.cjs.entry.js +85 -0
  32. package/dist/cjs/ui-search-result-row.cjs.entry.js +47 -0
  33. package/dist/cjs/ui-search-shell.cjs.entry.js +39 -0
  34. package/dist/cjs/ui-select.cjs.entry.js +100 -0
  35. package/dist/cjs/ui-switch.cjs.entry.js +65 -0
  36. package/dist/cjs/ui-tabs.cjs.entry.js +117 -0
  37. package/dist/cjs/ui-textarea.cjs.entry.js +106 -0
  38. package/dist/cjs/ui-toast-region.cjs.entry.js +67 -0
  39. package/dist/cjs/ui-tooltip.cjs.entry.js +133 -0
  40. package/dist/cjs/ui-top-bar.cjs.entry.js +43 -0
  41. package/dist/collection/collection-manifest.json +38 -0
  42. package/dist/collection/components/ui-avatar/ui-avatar.css +35 -0
  43. package/dist/collection/components/ui-avatar/ui-avatar.js +130 -0
  44. package/dist/collection/components/ui-avatar-group/ui-avatar-group.css +32 -0
  45. package/dist/collection/components/ui-avatar-group/ui-avatar-group.js +103 -0
  46. package/dist/collection/components/ui-badge/ui-badge.css +74 -0
  47. package/dist/collection/components/ui-badge/ui-badge.js +62 -0
  48. package/dist/collection/components/ui-button/ui-button.css +101 -0
  49. package/dist/collection/components/ui-button/ui-button.js +127 -0
  50. package/dist/collection/components/ui-checkbox/ui-checkbox.css +24 -0
  51. package/dist/collection/components/ui-checkbox/ui-checkbox.js +223 -0
  52. package/dist/collection/components/ui-context-menu/ui-context-menu.css +17 -0
  53. package/dist/collection/components/ui-context-menu/ui-context-menu.js +272 -0
  54. package/dist/collection/components/ui-dialog/ui-dialog.css +65 -0
  55. package/dist/collection/components/ui-dialog/ui-dialog.js +185 -0
  56. package/dist/collection/components/ui-disclosure/ui-disclosure.css +7 -0
  57. package/dist/collection/components/ui-disclosure/ui-disclosure.js +182 -0
  58. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.css +70 -0
  59. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.js +85 -0
  60. package/dist/collection/components/ui-form-field/ui-form-field.css +21 -0
  61. package/dist/collection/components/ui-form-field/ui-form-field.js +125 -0
  62. package/dist/collection/components/ui-icon-button/ui-icon-button.css +92 -0
  63. package/dist/collection/components/ui-icon-button/ui-icon-button.js +106 -0
  64. package/dist/collection/components/ui-input/ui-input.css +46 -0
  65. package/dist/collection/components/ui-input/ui-input.js +213 -0
  66. package/dist/collection/components/ui-menu/ui-menu.css +37 -0
  67. package/dist/collection/components/ui-menu/ui-menu.js +149 -0
  68. package/dist/collection/components/ui-menu-item/ui-menu-item.css +26 -0
  69. package/dist/collection/components/ui-menu-item/ui-menu-item.js +64 -0
  70. package/dist/collection/components/ui-popover/ui-popover.css +8 -0
  71. package/dist/collection/components/ui-popover/ui-popover.js +144 -0
  72. package/dist/collection/components/ui-radio/ui-radio.css +22 -0
  73. package/dist/collection/components/ui-radio/ui-radio.js +213 -0
  74. package/dist/collection/components/ui-radio-group/ui-radio-group.css +10 -0
  75. package/dist/collection/components/ui-radio-group/ui-radio-group.js +247 -0
  76. package/dist/collection/components/ui-search-result-row/ui-search-result-row.css +80 -0
  77. package/dist/collection/components/ui-search-result-row/ui-search-result-row.js +100 -0
  78. package/dist/collection/components/ui-search-shell/ui-search-shell.css +61 -0
  79. package/dist/collection/components/ui-search-shell/ui-search-shell.js +46 -0
  80. package/dist/collection/components/ui-select/ui-select.css +62 -0
  81. package/dist/collection/components/ui-select/ui-select.js +212 -0
  82. package/dist/collection/components/ui-switch/ui-switch.css +63 -0
  83. package/dist/collection/components/ui-switch/ui-switch.js +177 -0
  84. package/dist/collection/components/ui-tabs/ui-tabs.css +65 -0
  85. package/dist/collection/components/ui-tabs/ui-tabs.js +190 -0
  86. package/dist/collection/components/ui-textarea/ui-textarea.css +48 -0
  87. package/dist/collection/components/ui-textarea/ui-textarea.js +238 -0
  88. package/dist/collection/components/ui-toast-region/ui-toast-region.css +52 -0
  89. package/dist/collection/components/ui-toast-region/ui-toast-region.js +100 -0
  90. package/dist/collection/components/ui-tooltip/ui-tooltip.css +14 -0
  91. package/dist/collection/components/ui-tooltip/ui-tooltip.js +205 -0
  92. package/dist/collection/components/ui-top-bar/ui-top-bar.css +43 -0
  93. package/dist/collection/components/ui-top-bar/ui-top-bar.js +52 -0
  94. package/dist/collection/overlay/manager.js +90 -0
  95. package/dist/collection/utils/events.js +13 -0
  96. package/dist/collection/utils/id.js +5 -0
  97. package/dist/collection/utils/initials.js +11 -0
  98. package/dist/components/index.d.ts +88 -0
  99. package/dist/components/index.js +1 -0
  100. package/dist/components/p-CIA4RyEp.js +1 -0
  101. package/dist/components/p-CR7f2MQC.js +1 -0
  102. package/dist/components/p-JwSoedEO.js +1 -0
  103. package/dist/components/p-WvL4iAhX.js +1 -0
  104. package/dist/components/p-hgBUJRDa.js +1 -0
  105. package/dist/components/ui-avatar-group.d.ts +11 -0
  106. package/dist/components/ui-avatar-group.js +1 -0
  107. package/dist/components/ui-avatar.d.ts +11 -0
  108. package/dist/components/ui-avatar.js +1 -0
  109. package/dist/components/ui-badge.d.ts +11 -0
  110. package/dist/components/ui-badge.js +1 -0
  111. package/dist/components/ui-button.d.ts +11 -0
  112. package/dist/components/ui-button.js +1 -0
  113. package/dist/components/ui-checkbox.d.ts +11 -0
  114. package/dist/components/ui-checkbox.js +1 -0
  115. package/dist/components/ui-context-menu.d.ts +11 -0
  116. package/dist/components/ui-context-menu.js +1 -0
  117. package/dist/components/ui-dialog.d.ts +11 -0
  118. package/dist/components/ui-dialog.js +1 -0
  119. package/dist/components/ui-disclosure.d.ts +11 -0
  120. package/dist/components/ui-disclosure.js +1 -0
  121. package/dist/components/ui-floating-action-button.d.ts +11 -0
  122. package/dist/components/ui-floating-action-button.js +1 -0
  123. package/dist/components/ui-form-field.d.ts +11 -0
  124. package/dist/components/ui-form-field.js +1 -0
  125. package/dist/components/ui-icon-button.d.ts +11 -0
  126. package/dist/components/ui-icon-button.js +1 -0
  127. package/dist/components/ui-input.d.ts +11 -0
  128. package/dist/components/ui-input.js +1 -0
  129. package/dist/components/ui-menu-item.d.ts +11 -0
  130. package/dist/components/ui-menu-item.js +1 -0
  131. package/dist/components/ui-menu.d.ts +11 -0
  132. package/dist/components/ui-menu.js +1 -0
  133. package/dist/components/ui-popover.d.ts +11 -0
  134. package/dist/components/ui-popover.js +1 -0
  135. package/dist/components/ui-radio-group.d.ts +11 -0
  136. package/dist/components/ui-radio-group.js +1 -0
  137. package/dist/components/ui-radio.d.ts +11 -0
  138. package/dist/components/ui-radio.js +1 -0
  139. package/dist/components/ui-search-result-row.d.ts +11 -0
  140. package/dist/components/ui-search-result-row.js +1 -0
  141. package/dist/components/ui-search-shell.d.ts +11 -0
  142. package/dist/components/ui-search-shell.js +1 -0
  143. package/dist/components/ui-select.d.ts +11 -0
  144. package/dist/components/ui-select.js +1 -0
  145. package/dist/components/ui-switch.d.ts +11 -0
  146. package/dist/components/ui-switch.js +1 -0
  147. package/dist/components/ui-tabs.d.ts +11 -0
  148. package/dist/components/ui-tabs.js +1 -0
  149. package/dist/components/ui-textarea.d.ts +11 -0
  150. package/dist/components/ui-textarea.js +1 -0
  151. package/dist/components/ui-toast-region.d.ts +11 -0
  152. package/dist/components/ui-toast-region.js +1 -0
  153. package/dist/components/ui-tooltip.d.ts +11 -0
  154. package/dist/components/ui-tooltip.js +1 -0
  155. package/dist/components/ui-top-bar.d.ts +11 -0
  156. package/dist/components/ui-top-bar.js +1 -0
  157. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  158. package/dist/esm/events-JwSoedEO.js +15 -0
  159. package/dist/esm/id-hgBUJRDa.js +7 -0
  160. package/dist/esm/index-CEeiinfk.js +1561 -0
  161. package/dist/esm/index.js +1 -0
  162. package/dist/esm/loader.js +11 -0
  163. package/dist/esm/looma.js +21 -0
  164. package/dist/esm/manager-CR7f2MQC.js +89 -0
  165. package/dist/esm/ui-avatar-group.entry.js +49 -0
  166. package/dist/esm/ui-avatar.entry.js +48 -0
  167. package/dist/esm/ui-badge.entry.js +17 -0
  168. package/dist/esm/ui-button.entry.js +60 -0
  169. package/dist/esm/ui-checkbox.entry.js +89 -0
  170. package/dist/esm/ui-context-menu.entry.js +199 -0
  171. package/dist/esm/ui-dialog.entry.js +91 -0
  172. package/dist/esm/ui-disclosure.entry.js +107 -0
  173. package/dist/esm/ui-floating-action-button.entry.js +18 -0
  174. package/dist/esm/ui-form-field.entry.js +57 -0
  175. package/dist/esm/ui-icon-button.entry.js +19 -0
  176. package/dist/esm/ui-input.entry.js +99 -0
  177. package/dist/esm/ui-menu-item.entry.js +17 -0
  178. package/dist/esm/ui-menu.entry.js +94 -0
  179. package/dist/esm/ui-popover.entry.js +90 -0
  180. package/dist/esm/ui-radio-group.entry.js +132 -0
  181. package/dist/esm/ui-radio.entry.js +83 -0
  182. package/dist/esm/ui-search-result-row.entry.js +45 -0
  183. package/dist/esm/ui-search-shell.entry.js +37 -0
  184. package/dist/esm/ui-select.entry.js +98 -0
  185. package/dist/esm/ui-switch.entry.js +63 -0
  186. package/dist/esm/ui-tabs.entry.js +115 -0
  187. package/dist/esm/ui-textarea.entry.js +104 -0
  188. package/dist/esm/ui-toast-region.entry.js +65 -0
  189. package/dist/esm/ui-tooltip.entry.js +131 -0
  190. package/dist/esm/ui-top-bar.entry.js +41 -0
  191. package/dist/index.cjs +4062 -0
  192. package/dist/index.cjs.js +1 -0
  193. package/dist/index.d.cts +16 -0
  194. package/dist/index.d.ts +16 -0
  195. package/dist/index.js +129 -0
  196. package/dist/looma/index.esm.js +0 -0
  197. package/dist/looma/looma.esm.js +1 -0
  198. package/dist/looma/p-03f0594b.entry.js +1 -0
  199. package/dist/looma/p-15e619fd.entry.js +1 -0
  200. package/dist/looma/p-201243dc.entry.js +1 -0
  201. package/dist/looma/p-24d7aa5b.entry.js +1 -0
  202. package/dist/looma/p-341ba64a.entry.js +1 -0
  203. package/dist/looma/p-41d62a83.entry.js +1 -0
  204. package/dist/looma/p-4742e6b4.entry.js +1 -0
  205. package/dist/looma/p-4c54d489.entry.js +1 -0
  206. package/dist/looma/p-52c537fa.entry.js +1 -0
  207. package/dist/looma/p-5a645647.entry.js +1 -0
  208. package/dist/looma/p-610b2eca.entry.js +1 -0
  209. package/dist/looma/p-649dad92.entry.js +1 -0
  210. package/dist/looma/p-66a203a1.entry.js +1 -0
  211. package/dist/looma/p-754cfff3.entry.js +1 -0
  212. package/dist/looma/p-93ce1c62.entry.js +1 -0
  213. package/dist/looma/p-955fb814.entry.js +1 -0
  214. package/dist/looma/p-96de71ad.entry.js +1 -0
  215. package/dist/looma/p-CEeiinfk.js +2 -0
  216. package/dist/looma/p-CR7f2MQC.js +1 -0
  217. package/dist/looma/p-DQuL1Twl.js +1 -0
  218. package/dist/looma/p-JwSoedEO.js +1 -0
  219. package/dist/looma/p-ab4151d5.entry.js +1 -0
  220. package/dist/looma/p-c14233bc.entry.js +1 -0
  221. package/dist/looma/p-dc857ed4.entry.js +1 -0
  222. package/dist/looma/p-dfcb2cca.entry.js +1 -0
  223. package/dist/looma/p-dff144bd.entry.js +1 -0
  224. package/dist/looma/p-ebb74106.entry.js +1 -0
  225. package/dist/looma/p-ecb5739b.entry.js +1 -0
  226. package/dist/looma/p-ee31c7b4.entry.js +1 -0
  227. package/dist/looma/p-fa4659c4.entry.js +1 -0
  228. package/dist/looma/p-hgBUJRDa.js +1 -0
  229. package/dist/types/components/ui-avatar/ui-avatar.d.ts +11 -0
  230. package/dist/types/components/ui-avatar-group/ui-avatar-group.d.ts +12 -0
  231. package/dist/types/components/ui-badge/ui-badge.d.ts +5 -0
  232. package/dist/types/components/ui-button/ui-button.d.ts +13 -0
  233. package/dist/types/components/ui-checkbox/ui-checkbox.d.ts +19 -0
  234. package/dist/types/components/ui-context-menu/ui-context-menu.d.ts +37 -0
  235. package/dist/types/components/ui-dialog/ui-dialog.d.ts +19 -0
  236. package/dist/types/components/ui-disclosure/ui-disclosure.d.ts +20 -0
  237. package/dist/types/components/ui-floating-action-button/ui-floating-action-button.d.ts +6 -0
  238. package/dist/types/components/ui-form-field/ui-form-field.d.ts +10 -0
  239. package/dist/types/components/ui-icon-button/ui-icon-button.d.ts +7 -0
  240. package/dist/types/components/ui-input/ui-input.d.ts +19 -0
  241. package/dist/types/components/ui-menu/ui-menu.d.ts +14 -0
  242. package/dist/types/components/ui-menu-item/ui-menu-item.d.ts +5 -0
  243. package/dist/types/components/ui-popover/ui-popover.d.ts +16 -0
  244. package/dist/types/components/ui-radio/ui-radio.d.ts +17 -0
  245. package/dist/types/components/ui-radio-group/ui-radio-group.d.ts +21 -0
  246. package/dist/types/components/ui-search-result-row/ui-search-result-row.d.ts +15 -0
  247. package/dist/types/components/ui-search-shell/ui-search-shell.d.ts +9 -0
  248. package/dist/types/components/ui-select/ui-select.d.ts +19 -0
  249. package/dist/types/components/ui-switch/ui-switch.d.ts +15 -0
  250. package/dist/types/components/ui-tabs/ui-tabs.d.ts +17 -0
  251. package/dist/types/components/ui-textarea/ui-textarea.d.ts +20 -0
  252. package/dist/types/components/ui-toast-region/ui-toast-region.d.ts +12 -0
  253. package/dist/types/components/ui-tooltip/ui-tooltip.d.ts +24 -0
  254. package/dist/types/components/ui-top-bar/ui-top-bar.d.ts +12 -0
  255. package/dist/types/components.d.ts +1148 -0
  256. package/dist/types/overlay/manager.d.ts +14 -0
  257. package/dist/types/stencil-public-runtime.d.ts +1860 -0
  258. package/dist/types/utils/events.d.ts +4 -0
  259. package/dist/types/utils/id.d.ts +1 -0
  260. package/dist/types/utils/initials.d.ts +1 -0
  261. package/dist/ui-avatar-group.entry-BZGXBOSE.js +59 -0
  262. package/dist/ui-avatar.entry-S2O2W5SA.js +51 -0
  263. package/dist/ui-badge.entry-CVJDISCR.js +22 -0
  264. package/dist/ui-button.entry-LNJBEJFE.js +72 -0
  265. package/dist/ui-checkbox.entry-5RA2CB43.js +102 -0
  266. package/dist/ui-context-menu.entry-UUOCT75F.js +211 -0
  267. package/dist/ui-dialog.entry-OEPJTEES.js +106 -0
  268. package/dist/ui-disclosure.entry-LRRISGUD.js +120 -0
  269. package/dist/ui-floating-action-button.entry-7TSAZRXP.js +23 -0
  270. package/dist/ui-form-field.entry-73YOVICF.js +67 -0
  271. package/dist/ui-icon-button.entry-MNXGPG36.js +24 -0
  272. package/dist/ui-input.entry-UWRVAOSW.js +112 -0
  273. package/dist/ui-menu-item.entry-5AOJO5MP.js +22 -0
  274. package/dist/ui-menu.entry-YDS6UMB5.js +98 -0
  275. package/dist/ui-popover.entry-PGWDCQIX.js +104 -0
  276. package/dist/ui-radio-group.entry-RHP5GNWU.js +142 -0
  277. package/dist/ui-radio.entry-5WRWPSTK.js +96 -0
  278. package/dist/ui-search-result-row.entry-IKJB2SJJ.js +50 -0
  279. package/dist/ui-search-shell.entry-ZIWF4ZHH.js +41 -0
  280. package/dist/ui-select.entry-N5TIKHR7.js +111 -0
  281. package/dist/ui-switch.entry-WUSZTXIR.js +75 -0
  282. package/dist/ui-tabs.entry-UFAVAQIF.js +124 -0
  283. package/dist/ui-textarea.entry-BYT47RAQ.js +117 -0
  284. package/dist/ui-toast-region.entry-6UYR3ZU2.js +78 -0
  285. package/dist/ui-tooltip.entry-YS7UX4FS.js +145 -0
  286. package/dist/ui-top-bar.entry-V27H6NFO.js +49 -0
  287. package/editor/chunk-JKRA4D4W.js +435 -0
  288. package/editor/chunk-NOOV344H.js +783 -0
  289. package/editor/extensions/index.d.ts +78 -0
  290. package/editor/extensions/index.js +28 -0
  291. package/editor/index.d.ts +7 -0
  292. package/editor/index.js +29 -0
  293. package/editor/table-overlay-DTr3KC9e.d.ts +12 -0
  294. package/editor/ui.d.ts +48 -0
  295. package/editor/ui.js +1 -0
  296. package/editor.css +662 -0
  297. package/layout/index.cjs +207 -0
  298. package/layout/index.css +166 -0
  299. package/layout/index.d.cts +3 -0
  300. package/layout/index.d.ts +3 -0
  301. package/layout/index.js +182 -0
  302. package/layout.css +124 -0
  303. package/loader/cdn.js +1 -0
  304. package/loader/index.cjs.js +1 -0
  305. package/loader/index.d.ts +24 -0
  306. package/loader/index.es2017.js +1 -0
  307. package/loader/index.js +2 -0
  308. package/package.json +244 -0
  309. package/styles.css +899 -0
  310. package/theme-dark.css +59 -0
  311. package/theme-high-contrast.css +21 -0
  312. package/theme-light.css +30 -0
  313. package/tokens.css +148 -0
  314. package/vue/chunk-J4UBEIIL.js +83 -0
  315. package/vue/editor/index.d.ts +89 -0
  316. package/vue/editor/index.js +125 -0
  317. package/vue/index.d.ts +167 -0
  318. package/vue/index.js +113 -0
@@ -0,0 +1,783 @@
1
+ // src/table-context-menu.ts
2
+ var TAG = "ui-editor-table-context-menu";
3
+ function dispatchTableAction(element, action) {
4
+ element.dispatchEvent(
5
+ new CustomEvent("looma-editor-table-action", {
6
+ detail: { action },
7
+ bubbles: true,
8
+ composed: true
9
+ })
10
+ );
11
+ }
12
+ if (typeof HTMLElement !== "undefined") {
13
+ class UIEditorTableContextMenuElement extends HTMLElement {
14
+ static get observedAttributes() {
15
+ return [
16
+ "open",
17
+ "cell-background",
18
+ "can-add-row-before",
19
+ "can-add-row-after",
20
+ "can-add-column-before",
21
+ "can-add-column-after",
22
+ "can-delete-row",
23
+ "can-delete-column",
24
+ "can-delete-table",
25
+ "can-merge-cells",
26
+ "can-split-cell"
27
+ ];
28
+ }
29
+ getBoolAttr(name) {
30
+ return this.hasAttribute(name) && this.getAttribute(name) !== "false";
31
+ }
32
+ connectedCallback() {
33
+ this.render();
34
+ this.addEventListener("click", this.onClick);
35
+ }
36
+ disconnectedCallback() {
37
+ this.removeEventListener("click", this.onClick);
38
+ }
39
+ attributeChangedCallback() {
40
+ this.render();
41
+ }
42
+ onClick(e) {
43
+ const target = e.target;
44
+ const trigger = target?.closest("[data-action]");
45
+ const action = trigger?.getAttribute("data-action");
46
+ if (action) {
47
+ dispatchTableAction(this, action);
48
+ }
49
+ }
50
+ render() {
51
+ const open = this.getBoolAttr("open");
52
+ this.hidden = !open;
53
+ if (!open) return;
54
+ const currentBackground = this.getAttribute("cell-background");
55
+ const backgroundActions = [
56
+ { action: "background-none", label: "Default", value: null, swatch: null },
57
+ { action: "background-gray", label: "Gray", value: "#f3f4f6", swatch: "#f3f4f6" },
58
+ { action: "background-yellow", label: "Yellow", value: "#fef3c7", swatch: "#fef3c7" },
59
+ { action: "background-blue", label: "Blue", value: "#dbeafe", swatch: "#dbeafe" },
60
+ { action: "background-green", label: "Green", value: "#dcfce7", swatch: "#dcfce7" },
61
+ { action: "background-red", label: "Red", value: "#fee2e2", swatch: "#fee2e2" }
62
+ ];
63
+ const sections = [
64
+ {
65
+ heading: "Cell background",
66
+ backgrounds: backgroundActions
67
+ },
68
+ {
69
+ heading: "Structure",
70
+ actions: [
71
+ { action: "add-row-before", label: "Add row above", can: "can-add-row-before" },
72
+ { action: "add-row-after", label: "Add row below", can: "can-add-row-after" },
73
+ { action: "add-column-before", label: "Add column left", can: "can-add-column-before" },
74
+ { action: "add-column-after", label: "Add column right", can: "can-add-column-after" }
75
+ ]
76
+ },
77
+ {
78
+ heading: "Cells",
79
+ actions: [
80
+ { action: "merge-cells", label: "Merge cells", can: "can-merge-cells" },
81
+ { action: "split-cell", label: "Split cell", can: "can-split-cell" }
82
+ ]
83
+ },
84
+ {
85
+ heading: "Table",
86
+ actions: [
87
+ { action: "delete-row", label: "Delete row", can: "can-delete-row", tone: "danger" },
88
+ { action: "delete-column", label: "Delete column", can: "can-delete-column", tone: "danger" },
89
+ { action: "delete-table", label: "Delete table", can: "can-delete-table", tone: "danger" }
90
+ ]
91
+ }
92
+ ];
93
+ const availableSections = sections.map((section) => {
94
+ if ("backgrounds" in section) {
95
+ return section;
96
+ }
97
+ return {
98
+ ...section,
99
+ actions: section.actions.filter((action) => this.getBoolAttr(action.can))
100
+ };
101
+ }).filter((section) => "backgrounds" in section ? section.backgrounds.length > 0 : section.actions.length > 0);
102
+ let html = '<div class="ui-editor-table-context-menu" role="menu">';
103
+ availableSections.forEach((section, sectionIndex) => {
104
+ if (sectionIndex > 0) {
105
+ html += '<div class="ui-editor-table-context-menu__sep"></div>';
106
+ }
107
+ html += '<div class="ui-editor-table-context-menu__section" role="none">';
108
+ html += `<div class="ui-editor-table-context-menu__heading" role="presentation">${section.heading}</div>`;
109
+ if ("backgrounds" in section) {
110
+ html += '<div class="ui-editor-table-context-menu__swatches" role="group" aria-label="Cell background">';
111
+ section.backgrounds.forEach((background) => {
112
+ const isSelected = (background.value ?? "") === (currentBackground ?? "");
113
+ html += `<button type="button" class="ui-editor-table-context-menu__swatch-button" role="menuitemradio" aria-checked="${isSelected ? "true" : "false"}" data-action="${background.action}"${isSelected ? ' data-selected="true"' : ""}><span class="ui-editor-table-context-menu__swatch${background.swatch ? "" : " ui-editor-table-context-menu__swatch--default"}"${background.swatch ? ` style="--ui-editor-table-context-swatch:${background.swatch}"` : ""}></span><span class="ui-editor-table-context-menu__swatch-label">${background.label}</span></button>`;
114
+ });
115
+ html += "</div>";
116
+ } else {
117
+ section.actions.forEach((action) => {
118
+ const tone = "tone" in action ? action.tone : void 0;
119
+ html += `<button type="button" role="menuitem" data-action="${action.action}"${tone ? ` data-tone="${tone}"` : ""}>${action.label}</button>`;
120
+ });
121
+ }
122
+ html += "</div>";
123
+ });
124
+ html += "</div>";
125
+ this.innerHTML = html;
126
+ }
127
+ }
128
+ if (typeof window !== "undefined" && !customElements.get(TAG)) {
129
+ customElements.define(TAG, UIEditorTableContextMenuElement);
130
+ }
131
+ }
132
+
133
+ // src/table-toolbar.ts
134
+ var TAG2 = "ui-editor-table-toolbar";
135
+ function dispatchTableAction2(element, action) {
136
+ element.dispatchEvent(
137
+ new CustomEvent("looma-editor-table-action", {
138
+ detail: { action },
139
+ bubbles: true,
140
+ composed: true
141
+ })
142
+ );
143
+ }
144
+ if (typeof HTMLElement !== "undefined") {
145
+ class UIEditorTableToolbarElement extends HTMLElement {
146
+ #overflowOpen = false;
147
+ static get observedAttributes() {
148
+ return [
149
+ "open",
150
+ "cell-alignment",
151
+ "can-add-row-after",
152
+ "can-add-column-after",
153
+ "can-add-row-before",
154
+ "can-add-column-before",
155
+ "can-delete-row",
156
+ "can-delete-column",
157
+ "can-delete-table",
158
+ "can-merge-cells",
159
+ "can-split-cell"
160
+ ];
161
+ }
162
+ getBoolAttr(name) {
163
+ return this.hasAttribute(name) && this.getAttribute(name) !== "false";
164
+ }
165
+ getAlignmentAttr() {
166
+ const value = this.getAttribute("cell-alignment");
167
+ if (value === "center") {
168
+ return "align-center";
169
+ }
170
+ if (value === "right") {
171
+ return "align-right";
172
+ }
173
+ return "align-left";
174
+ }
175
+ connectedCallback() {
176
+ this.render();
177
+ this.addEventListener("click", this.onClick);
178
+ document.addEventListener("pointerdown", this.onDocumentPointerDown, true);
179
+ }
180
+ disconnectedCallback() {
181
+ this.removeEventListener("click", this.onClick);
182
+ document.removeEventListener("pointerdown", this.onDocumentPointerDown, true);
183
+ }
184
+ attributeChangedCallback() {
185
+ this.render();
186
+ }
187
+ onClick = (event) => {
188
+ const target = event.target.closest("[data-action]");
189
+ if (!target) {
190
+ return;
191
+ }
192
+ if (target.dataset.action === "toggle-overflow") {
193
+ this.#overflowOpen = !this.#overflowOpen;
194
+ this.render();
195
+ return;
196
+ }
197
+ const action = target.dataset.action;
198
+ if (!action) {
199
+ return;
200
+ }
201
+ this.#overflowOpen = false;
202
+ this.render();
203
+ dispatchTableAction2(this, action);
204
+ };
205
+ onDocumentPointerDown = (event) => {
206
+ if (!this.#overflowOpen) {
207
+ return;
208
+ }
209
+ const path = typeof event.composedPath === "function" ? event.composedPath() : [];
210
+ if (path.includes(this)) {
211
+ return;
212
+ }
213
+ if (event.target instanceof Node && this.contains(event.target)) {
214
+ return;
215
+ }
216
+ this.#overflowOpen = false;
217
+ this.render();
218
+ };
219
+ render() {
220
+ const open = this.getBoolAttr("open");
221
+ this.hidden = !open;
222
+ if (!open) {
223
+ this.#overflowOpen = false;
224
+ return;
225
+ }
226
+ const activeAlignment = this.getAlignmentAttr();
227
+ const alignmentActions = [
228
+ { action: "align-left", label: "Left" },
229
+ { action: "align-center", label: "Center" },
230
+ { action: "align-right", label: "Right" }
231
+ ];
232
+ const structuralActions = [
233
+ { action: "add-row-after", label: "Add row", can: "can-add-row-after" },
234
+ { action: "add-column-after", label: "Add column", can: "can-add-column-after" }
235
+ ].filter((action) => this.getBoolAttr(action.can));
236
+ const overflowSections = [
237
+ {
238
+ heading: "Structure",
239
+ actions: [
240
+ { action: "add-row-before", label: "Add row above", can: "can-add-row-before" },
241
+ { action: "add-column-before", label: "Add column left", can: "can-add-column-before" }
242
+ ]
243
+ },
244
+ {
245
+ heading: "Table",
246
+ actions: [
247
+ { action: "delete-row", label: "Delete row", can: "can-delete-row", tone: "danger" },
248
+ { action: "delete-column", label: "Delete column", can: "can-delete-column", tone: "danger" },
249
+ { action: "delete-table", label: "Delete table", can: "can-delete-table", tone: "danger" }
250
+ ]
251
+ }
252
+ ];
253
+ const availableOverflowSections = overflowSections.map((section) => ({
254
+ ...section,
255
+ actions: section.actions.filter((action) => this.getBoolAttr(action.can))
256
+ })).filter((section) => section.actions.length > 0);
257
+ this.innerHTML = [
258
+ '<div class="ui-editor-table-toolbar" role="toolbar" aria-label="Table actions">',
259
+ '<div class="ui-editor-table-toolbar__group" role="group" aria-label="Cell alignment">',
260
+ alignmentActions.map(
261
+ (action) => `<button type="button" data-action="${action.action}" aria-pressed="${action.action === activeAlignment ? "true" : "false"}" data-active="${action.action === activeAlignment ? "true" : "false"}">${action.label}</button>`
262
+ ).join(""),
263
+ "</div>",
264
+ structuralActions.length > 0 ? '<div class="ui-editor-table-toolbar__sep" aria-hidden="true"></div>' : "",
265
+ structuralActions.length > 0 ? '<div class="ui-editor-table-toolbar__group" role="group" aria-label="Table structure">' : "",
266
+ structuralActions.map(
267
+ (action) => `<button type="button" data-action="${action.action}">${action.label}</button>`
268
+ ).join(""),
269
+ structuralActions.length > 0 ? "</div>" : "",
270
+ availableOverflowSections.length > 0 ? '<div class="ui-editor-table-toolbar__sep" aria-hidden="true"></div>' : "",
271
+ availableOverflowSections.length > 0 ? '<div class="ui-editor-table-toolbar__overflow">' : "",
272
+ availableOverflowSections.length > 0 ? `<button type="button" class="ui-editor-table-toolbar__more" data-action="toggle-overflow" aria-haspopup="menu" aria-expanded="${this.#overflowOpen ? "true" : "false"}">Table options</button>` : "",
273
+ availableOverflowSections.length > 0 && this.#overflowOpen ? [
274
+ '<div class="ui-editor-table-toolbar__menu" role="menu" aria-label="More table actions">',
275
+ availableOverflowSections.map(
276
+ (section) => [
277
+ '<div class="ui-editor-table-toolbar__menu-section" role="none">',
278
+ `<div class="ui-editor-table-toolbar__menu-heading" role="presentation">${section.heading}</div>`,
279
+ section.actions.map((action) => {
280
+ const tone = "tone" in action ? action.tone : void 0;
281
+ return `<button type="button" role="menuitem" data-action="${action.action}"${tone ? ` data-tone="${tone}"` : ""}>${action.label}</button>`;
282
+ }).join(""),
283
+ "</div>"
284
+ ].join("")
285
+ ).join(""),
286
+ "</div>"
287
+ ].join("") : "",
288
+ availableOverflowSections.length > 0 ? "</div>" : "",
289
+ "</div>"
290
+ ].join("");
291
+ }
292
+ }
293
+ if (typeof window !== "undefined" && !customElements.get(TAG2)) {
294
+ customElements.define(TAG2, UIEditorTableToolbarElement);
295
+ }
296
+ }
297
+
298
+ // src/insert-table-grid.ts
299
+ var TAG3 = "ui-editor-insert-table-grid";
300
+ var DEFAULT_MAX_ROWS = 8;
301
+ var DEFAULT_MAX_COLS = 8;
302
+ if (typeof HTMLElement !== "undefined") {
303
+ class UIEditorInsertTableGridElement extends HTMLElement {
304
+ static get observedAttributes() {
305
+ return ["open", "max-rows", "max-cols"];
306
+ }
307
+ #maxRows = DEFAULT_MAX_ROWS;
308
+ #maxCols = DEFAULT_MAX_COLS;
309
+ #selectedRows = 3;
310
+ #selectedCols = 3;
311
+ #previewRows = null;
312
+ #previewCols = null;
313
+ #withHeaderRow = true;
314
+ #selectionPinned = false;
315
+ connectedCallback() {
316
+ this.#maxRows = Math.min(10, Math.max(1, parseInt(this.getAttribute("max-rows") ?? String(DEFAULT_MAX_ROWS), 10) || DEFAULT_MAX_ROWS));
317
+ this.#maxCols = Math.min(10, Math.max(1, parseInt(this.getAttribute("max-cols") ?? String(DEFAULT_MAX_COLS), 10) || DEFAULT_MAX_COLS));
318
+ this.render();
319
+ this.addEventListener("click", this.onClick);
320
+ this.addEventListener("mouseover", this.onMouseOver);
321
+ }
322
+ disconnectedCallback() {
323
+ this.removeEventListener("click", this.onClick);
324
+ this.removeEventListener("mouseover", this.onMouseOver);
325
+ }
326
+ attributeChangedCallback(name) {
327
+ if (name === "max-rows") this.#maxRows = Math.min(10, Math.max(1, parseInt(this.getAttribute("max-rows") ?? String(DEFAULT_MAX_ROWS), 10) || DEFAULT_MAX_ROWS));
328
+ if (name === "max-cols") this.#maxCols = Math.min(10, Math.max(1, parseInt(this.getAttribute("max-cols") ?? String(DEFAULT_MAX_COLS), 10) || DEFAULT_MAX_COLS));
329
+ this.render();
330
+ }
331
+ onClick(e) {
332
+ const cell = e.target.closest("[data-row][data-col]");
333
+ if (cell) {
334
+ this.#selectedRows = parseInt(cell.getAttribute("data-row") ?? "1", 10);
335
+ this.#selectedCols = parseInt(cell.getAttribute("data-col") ?? "1", 10);
336
+ this.#previewRows = null;
337
+ this.#previewCols = null;
338
+ this.#selectionPinned = true;
339
+ this.updateSelectionPreview();
340
+ return;
341
+ }
342
+ const target = e.target.closest("[data-insert-table]");
343
+ if (target) {
344
+ const checkbox = this.querySelector('input[type="checkbox"]');
345
+ const withHeaderRow = checkbox?.checked ?? this.#withHeaderRow;
346
+ this.dispatchEvent(
347
+ new CustomEvent("looma-editor-insert-table", {
348
+ detail: { rows: this.#selectedRows, cols: this.#selectedCols, withHeaderRow },
349
+ bubbles: true,
350
+ composed: true
351
+ })
352
+ );
353
+ }
354
+ }
355
+ onMouseOver(e) {
356
+ if (this.#selectionPinned) {
357
+ return;
358
+ }
359
+ const cell = e.target.closest("[data-row][data-col]");
360
+ if (cell) {
361
+ const nextRows = parseInt(cell.getAttribute("data-row") ?? "1", 10);
362
+ const nextCols = parseInt(cell.getAttribute("data-col") ?? "1", 10);
363
+ if (nextRows === this.#previewRows && nextCols === this.#previewCols) {
364
+ return;
365
+ }
366
+ this.#previewRows = nextRows;
367
+ this.#previewCols = nextCols;
368
+ this.updateSelectionPreview();
369
+ }
370
+ }
371
+ updateSelectionPreview() {
372
+ const activeRows = this.#previewRows ?? this.#selectedRows;
373
+ const activeCols = this.#previewCols ?? this.#selectedCols;
374
+ const hint = this.querySelector(".ui-editor-insert-table-grid__hint");
375
+ if (hint) {
376
+ hint.textContent = this.#selectionPinned ? `${this.#selectedRows} \xD7 ${this.#selectedCols} selected` : `${activeRows} \xD7 ${activeCols}`;
377
+ }
378
+ const cells = this.querySelectorAll("[data-row][data-col]");
379
+ for (const cell of cells) {
380
+ const row = parseInt(cell.getAttribute("data-row") ?? "1", 10);
381
+ const col = parseInt(cell.getAttribute("data-col") ?? "1", 10);
382
+ const selected = row <= activeRows && col <= activeCols;
383
+ cell.classList.toggle("ui-editor-insert-table-grid__cell--selected", selected);
384
+ cell.setAttribute("aria-pressed", selected ? "true" : "false");
385
+ }
386
+ }
387
+ render() {
388
+ const open = this.hasAttribute("open") && this.getAttribute("open") !== "false";
389
+ this.hidden = !open;
390
+ if (!open) return;
391
+ let html = '<div class="ui-editor-insert-table-grid">';
392
+ html += `<p class="ui-editor-insert-table-grid__hint">${this.#selectedRows} \xD7 ${this.#selectedCols}</p>`;
393
+ html += '<div class="ui-editor-insert-table-grid__grid" role="group" aria-label="Table dimensions">';
394
+ for (let r = 1; r <= this.#maxRows; r++) {
395
+ for (let c = 1; c <= this.#maxCols; c++) {
396
+ const selected = r <= this.#selectedRows && c <= this.#selectedCols;
397
+ html += `<button type="button" data-row="${r}" data-col="${c}" aria-label="${r} rows by ${c} columns" aria-pressed="${selected ? "true" : "false"}" class="ui-editor-insert-table-grid__cell${selected ? " ui-editor-insert-table-grid__cell--selected" : ""}"></button>`;
398
+ }
399
+ }
400
+ html += "</div>";
401
+ html += '<label class="ui-editor-insert-table-grid__header"><input type="checkbox" checked /> Header row</label>';
402
+ html += '<button type="button" data-insert-table>Insert table</button>';
403
+ html += "</div>";
404
+ this.innerHTML = html;
405
+ const checkbox = this.querySelector('input[type="checkbox"]');
406
+ if (checkbox) {
407
+ checkbox.checked = this.#withHeaderRow;
408
+ checkbox.addEventListener("change", () => {
409
+ this.#withHeaderRow = checkbox.checked;
410
+ });
411
+ }
412
+ this.updateSelectionPreview();
413
+ }
414
+ }
415
+ if (typeof window !== "undefined" && !customElements.get(TAG3)) {
416
+ customElements.define(TAG3, UIEditorInsertTableGridElement);
417
+ }
418
+ }
419
+
420
+ // src/table-overlay.ts
421
+ var TAG4 = "ui-editor-table-overlay";
422
+ var DEFAULT_ROWS = 3;
423
+ var DEFAULT_COLS = 3;
424
+ if (typeof HTMLElement !== "undefined") {
425
+ class UIEditorTableOverlayElement extends HTMLElement {
426
+ static get observedAttributes() {
427
+ return ["open", "rows", "cols"];
428
+ }
429
+ #rows = DEFAULT_ROWS;
430
+ #cols = DEFAULT_COLS;
431
+ #activeControlKey = null;
432
+ connectedCallback() {
433
+ this.#rows = this.#readBoundedNumber("rows", DEFAULT_ROWS);
434
+ this.#cols = this.#readBoundedNumber("cols", DEFAULT_COLS);
435
+ this.render();
436
+ this.addEventListener("click", this.onClick);
437
+ this.addEventListener("pointerover", this.onPointerOver);
438
+ this.addEventListener("pointerout", this.onPointerOut);
439
+ this.addEventListener("focusin", this.onFocusIn);
440
+ this.addEventListener("focusout", this.onFocusOut);
441
+ }
442
+ disconnectedCallback() {
443
+ this.removeEventListener("click", this.onClick);
444
+ this.removeEventListener("pointerover", this.onPointerOver);
445
+ this.removeEventListener("pointerout", this.onPointerOut);
446
+ this.removeEventListener("focusin", this.onFocusIn);
447
+ this.removeEventListener("focusout", this.onFocusOut);
448
+ }
449
+ attributeChangedCallback(name) {
450
+ if (name === "rows") this.#rows = this.#readBoundedNumber("rows", DEFAULT_ROWS);
451
+ if (name === "cols") this.#cols = this.#readBoundedNumber("cols", DEFAULT_COLS);
452
+ this.render();
453
+ }
454
+ #readBoundedNumber(name, fallback) {
455
+ const parsed = parseInt(this.getAttribute(name) ?? String(fallback), 10);
456
+ if (!Number.isFinite(parsed)) {
457
+ return fallback;
458
+ }
459
+ return Math.min(100, Math.max(1, parsed));
460
+ }
461
+ onClick = (event) => {
462
+ const target = event.target.closest("[data-action]");
463
+ if (!target) {
464
+ return;
465
+ }
466
+ const action = target.getAttribute("data-action");
467
+ const boundaryIndex = parseInt(target.getAttribute("data-boundary-index") ?? "-1", 10);
468
+ if (!action || !Number.isFinite(boundaryIndex) || boundaryIndex < 0) {
469
+ return;
470
+ }
471
+ this.dispatchEvent(
472
+ new CustomEvent("looma-editor-table-overlay-action", {
473
+ detail: { action, boundaryIndex },
474
+ bubbles: true,
475
+ composed: true
476
+ })
477
+ );
478
+ };
479
+ onPointerOver = (event) => {
480
+ const control = event.target.closest("[data-control-key]");
481
+ this.#setActiveControl(control?.dataset.controlKey ?? null);
482
+ };
483
+ onPointerOut = (event) => {
484
+ const relatedTarget = event.relatedTarget;
485
+ const nextControl = relatedTarget instanceof Element ? relatedTarget.closest("[data-control-key]") : null;
486
+ this.#setActiveControl(nextControl?.dataset.controlKey ?? null);
487
+ };
488
+ onFocusIn = (event) => {
489
+ const control = event.target.closest("[data-control-key]");
490
+ this.#setActiveControl(control?.dataset.controlKey ?? null);
491
+ };
492
+ onFocusOut = (event) => {
493
+ const relatedTarget = event.relatedTarget;
494
+ const nextControl = relatedTarget instanceof Element ? relatedTarget.closest("[data-control-key]") : null;
495
+ this.#setActiveControl(nextControl?.dataset.controlKey ?? null);
496
+ };
497
+ #setActiveControl(controlKey) {
498
+ if (this.#activeControlKey === controlKey) {
499
+ return;
500
+ }
501
+ this.#activeControlKey = controlKey;
502
+ this.#syncActiveControl();
503
+ }
504
+ #syncActiveControl() {
505
+ const controls = this.querySelectorAll("[data-control-key]");
506
+ controls.forEach((control) => {
507
+ control.dataset.active = this.#activeControlKey && control.dataset.controlKey === this.#activeControlKey ? "true" : "false";
508
+ });
509
+ }
510
+ render() {
511
+ const open = this.hasAttribute("open") && this.getAttribute("open") !== "false";
512
+ this.hidden = !open;
513
+ if (!open) {
514
+ this.#setActiveControl(null);
515
+ return;
516
+ }
517
+ let html = '<div class="ui-editor-table-overlay" aria-label="Table insertion controls">';
518
+ html += `<div class="ui-editor-table-overlay__rows" style="--ui-editor-table-overlay-row-boundaries:${this.#rows + 1};">`;
519
+ for (let i = 0; i <= this.#rows; i++) {
520
+ const action = i === 0 ? "add-row-before" : "add-row-after";
521
+ const controlKey = `row:${i}`;
522
+ html += `<button type="button" class="ui-editor-table-overlay__control ui-editor-table-overlay__control--row" data-action="${action}" data-boundary-index="${i}" data-control-key="${controlKey}" data-active="${this.#activeControlKey === controlKey ? "true" : "false"}" aria-label="Add row"><span class="ui-editor-table-overlay__handle" aria-hidden="true">+</span></button>`;
523
+ }
524
+ html += "</div>";
525
+ html += `<div class="ui-editor-table-overlay__cols" style="--ui-editor-table-overlay-col-boundaries:${this.#cols + 1};">`;
526
+ for (let i = 0; i <= this.#cols; i++) {
527
+ const action = i === 0 ? "add-column-before" : "add-column-after";
528
+ const controlKey = `col:${i}`;
529
+ html += `<button type="button" class="ui-editor-table-overlay__control ui-editor-table-overlay__control--col" data-action="${action}" data-boundary-index="${i}" data-control-key="${controlKey}" data-active="${this.#activeControlKey === controlKey ? "true" : "false"}" aria-label="Add column"><span class="ui-editor-table-overlay__handle" aria-hidden="true">+</span></button>`;
530
+ }
531
+ html += "</div>";
532
+ html += "</div>";
533
+ this.innerHTML = html;
534
+ this.#syncActiveControl();
535
+ }
536
+ }
537
+ if (typeof window !== "undefined" && !customElements.get(TAG4)) {
538
+ customElements.define(TAG4, UIEditorTableOverlayElement);
539
+ }
540
+ }
541
+
542
+ // src/slash-menu.ts
543
+ var TAG5 = "ui-editor-slash-menu";
544
+ var MOBILE_BREAKPOINT = 768;
545
+ var MENU_HEIGHT_ESTIMATE = 320;
546
+ var MENU_WIDTH = 280;
547
+ var OFFSET = 8;
548
+ function finiteCoordinate(value) {
549
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
550
+ }
551
+ function normalizeAnchorRect(value) {
552
+ if (!value || typeof value !== "object") {
553
+ return null;
554
+ }
555
+ const rect = value;
556
+ const x = finiteCoordinate(rect.x);
557
+ const y = finiteCoordinate(rect.y);
558
+ const width = finiteCoordinate(rect.width);
559
+ const height = finiteCoordinate(rect.height);
560
+ const left = finiteCoordinate(rect.left) ?? x;
561
+ const top = finiteCoordinate(rect.top) ?? y;
562
+ const right = finiteCoordinate(rect.right) ?? (left !== null && width !== null ? left + width : null);
563
+ const bottom = finiteCoordinate(rect.bottom) ?? (top !== null && height !== null ? top + height : null);
564
+ if (left === null || top === null || right === null || bottom === null) {
565
+ return null;
566
+ }
567
+ return { left, top, right, bottom };
568
+ }
569
+ function dispatchSlashMenuEvent(element, name, detail) {
570
+ element.dispatchEvent(
571
+ new CustomEvent(name, {
572
+ detail,
573
+ bubbles: true,
574
+ composed: true
575
+ })
576
+ );
577
+ }
578
+ function escapeHtml(value) {
579
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
580
+ }
581
+ if (typeof HTMLElement !== "undefined") {
582
+ class UIEditorSlashMenuElement extends HTMLElement {
583
+ #open = false;
584
+ #query = "";
585
+ #items = [];
586
+ #selectedIndex = 0;
587
+ #anchorRect = null;
588
+ #normalizedAnchorRect = null;
589
+ get open() {
590
+ return this.#open;
591
+ }
592
+ set open(value) {
593
+ this.#open = Boolean(value);
594
+ this.render();
595
+ }
596
+ get query() {
597
+ return this.#query;
598
+ }
599
+ set query(value) {
600
+ this.#query = typeof value === "string" ? value : "";
601
+ this.render();
602
+ }
603
+ get items() {
604
+ return this.#items;
605
+ }
606
+ set items(value) {
607
+ this.#items = Array.isArray(value) ? value : [];
608
+ this.render();
609
+ }
610
+ get selectedIndex() {
611
+ return this.#selectedIndex;
612
+ }
613
+ set selectedIndex(value) {
614
+ this.#selectedIndex = Number.isFinite(value) ? Math.max(0, value) : 0;
615
+ this.render();
616
+ }
617
+ get anchorRect() {
618
+ return this.#anchorRect;
619
+ }
620
+ set anchorRect(value) {
621
+ const normalized = normalizeAnchorRect(value);
622
+ this.#anchorRect = normalized ? value : null;
623
+ this.#normalizedAnchorRect = normalized;
624
+ this.render();
625
+ }
626
+ connectedCallback() {
627
+ this.setAttribute("role", "listbox");
628
+ this.setAttribute("aria-label", "Insert block");
629
+ this.addEventListener("mousedown", this.onMouseDown);
630
+ this.addEventListener("click", this.onClick);
631
+ this.addEventListener("mouseover", this.onMouseOver);
632
+ window.addEventListener("resize", this.onViewportChange);
633
+ window.addEventListener("scroll", this.onViewportChange, true);
634
+ this.render();
635
+ }
636
+ disconnectedCallback() {
637
+ this.removeEventListener("mousedown", this.onMouseDown);
638
+ this.removeEventListener("click", this.onClick);
639
+ this.removeEventListener("mouseover", this.onMouseOver);
640
+ window.removeEventListener("resize", this.onViewportChange);
641
+ window.removeEventListener("scroll", this.onViewportChange, true);
642
+ }
643
+ onMouseDown = (event) => {
644
+ event.preventDefault();
645
+ };
646
+ onClick = (event) => {
647
+ const target = event.target.closest("[data-index]");
648
+ if (!target) {
649
+ return;
650
+ }
651
+ const index = Number.parseInt(target.dataset.index ?? "", 10);
652
+ if (!Number.isFinite(index)) {
653
+ return;
654
+ }
655
+ dispatchSlashMenuEvent(this, "looma-editor-slash-menu-select", {
656
+ index
657
+ });
658
+ };
659
+ onMouseOver = (event) => {
660
+ const target = event.target.closest("[data-index]");
661
+ if (!target) {
662
+ return;
663
+ }
664
+ const index = Number.parseInt(target.dataset.index ?? "", 10);
665
+ if (!Number.isFinite(index) || index === this.#selectedIndex) {
666
+ return;
667
+ }
668
+ this.#selectedIndex = index;
669
+ this.render();
670
+ dispatchSlashMenuEvent(
671
+ this,
672
+ "looma-editor-slash-menu-highlight",
673
+ { index }
674
+ );
675
+ };
676
+ onViewportChange = () => {
677
+ if (this.#open) {
678
+ this.applyHostPosition();
679
+ }
680
+ };
681
+ applyHostPosition() {
682
+ const rect = this.#normalizedAnchorRect;
683
+ if (!rect) {
684
+ this.style.display = "none";
685
+ return;
686
+ }
687
+ const viewportWidth = window.innerWidth;
688
+ const viewportHeight = window.innerHeight;
689
+ this.style.display = "block";
690
+ this.style.position = "fixed";
691
+ this.style.zIndex = "500";
692
+ if (viewportWidth < MOBILE_BREAKPOINT) {
693
+ this.style.left = "0";
694
+ this.style.right = "0";
695
+ this.style.bottom = "0";
696
+ this.style.top = "";
697
+ this.style.width = "100%";
698
+ this.style.maxHeight = "60dvh";
699
+ return;
700
+ }
701
+ let top;
702
+ const spaceBelow = viewportHeight - rect.bottom - OFFSET;
703
+ const spaceAbove = rect.top - OFFSET;
704
+ if (spaceBelow >= MENU_HEIGHT_ESTIMATE || spaceBelow >= spaceAbove) {
705
+ top = rect.bottom + OFFSET;
706
+ } else {
707
+ top = rect.top - OFFSET - MENU_HEIGHT_ESTIMATE;
708
+ }
709
+ let left = rect.left;
710
+ if (left + MENU_WIDTH > viewportWidth - 8) {
711
+ left = viewportWidth - MENU_WIDTH - 8;
712
+ }
713
+ if (left < 8) {
714
+ left = 8;
715
+ }
716
+ this.style.top = `${Math.max(8, top)}px`;
717
+ this.style.left = `${left}px`;
718
+ this.style.right = "";
719
+ this.style.bottom = "";
720
+ this.style.width = `${MENU_WIDTH}px`;
721
+ this.style.maxHeight = "";
722
+ }
723
+ render() {
724
+ const visible = this.#open && this.#items.length > 0 && this.#normalizedAnchorRect;
725
+ this.hidden = !visible;
726
+ if (!visible) {
727
+ return;
728
+ }
729
+ this.applyHostPosition();
730
+ const query = this.#query.trim();
731
+ const items = this.#items.map((item, index) => {
732
+ const activeClass = index === this.#selectedIndex ? " ui-editor-slash-menu__item--active" : "";
733
+ return [
734
+ `<li`,
735
+ ` class="ui-editor-slash-menu__item${activeClass}"`,
736
+ ` role="option"`,
737
+ ` aria-selected="${index === this.#selectedIndex ? "true" : "false"}"`,
738
+ ` data-index="${index}"`,
739
+ `>`,
740
+ `<span class="ui-editor-slash-menu__icon" aria-hidden="true">${escapeHtml(item.icon)}</span>`,
741
+ `<span class="ui-editor-slash-menu__body">`,
742
+ `<span class="ui-editor-slash-menu__title">${escapeHtml(item.title)}</span>`,
743
+ `<span class="ui-editor-slash-menu__description">${escapeHtml(item.description)}</span>`,
744
+ `</span>`,
745
+ `</li>`
746
+ ].join("");
747
+ }).join("");
748
+ this.innerHTML = [
749
+ `<div class="ui-editor-slash-menu">`,
750
+ `<div class="ui-editor-slash-menu__header" aria-hidden="true">`,
751
+ `<span class="ui-editor-slash-menu__header-label">Insert</span>`,
752
+ query ? `<span class="ui-editor-slash-menu__header-query">${escapeHtml(query)}</span>` : "",
753
+ `</div>`,
754
+ `<ul class="ui-editor-slash-menu__list" role="presentation">${items}</ul>`,
755
+ `<div class="ui-editor-slash-menu__footer" aria-hidden="true">`,
756
+ `<kbd>\u2191\u2193</kbd> navigate &nbsp;\xB7&nbsp; <kbd>\u21B5</kbd> insert &nbsp;\xB7&nbsp; <kbd>Esc</kbd> close`,
757
+ `</div>`,
758
+ `</div>`
759
+ ].join("");
760
+ }
761
+ }
762
+ if (typeof window !== "undefined" && !customElements.get(TAG5)) {
763
+ customElements.define(TAG5, UIEditorSlashMenuElement);
764
+ }
765
+ }
766
+
767
+ // src/toolbar.ts
768
+ var TAG6 = "ui-editor-toolbar";
769
+ if (typeof HTMLElement !== "undefined") {
770
+ class UIEditorToolbarElement extends HTMLElement {
771
+ connectedCallback() {
772
+ if (!this.hasAttribute("role")) {
773
+ this.setAttribute("role", "toolbar");
774
+ }
775
+ if (!this.hasAttribute("aria-label")) {
776
+ this.setAttribute("aria-label", "Editor toolbar");
777
+ }
778
+ }
779
+ }
780
+ if (typeof window !== "undefined" && !customElements.get(TAG6)) {
781
+ customElements.define(TAG6, UIEditorToolbarElement);
782
+ }
783
+ }