le-kit 0.1.12 → 0.1.14

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 (313) hide show
  1. package/dist/components/index.d.ts +33 -0
  2. package/dist/components/le-box.d.ts +11 -0
  3. package/dist/components/le-button.d.ts +11 -0
  4. package/dist/components/le-card.d.ts +11 -0
  5. package/dist/components/le-checkbox.d.ts +11 -0
  6. package/dist/components/le-component.d.ts +11 -0
  7. package/dist/components/le-number-input.d.ts +11 -0
  8. package/dist/components/le-popover.d.ts +11 -0
  9. package/dist/components/le-popup.d.ts +11 -0
  10. package/dist/components/le-round-progress.d.ts +11 -0
  11. package/dist/components/le-slot.d.ts +11 -0
  12. package/dist/components/le-stack.d.ts +11 -0
  13. package/dist/components/le-string-input.d.ts +11 -0
  14. package/dist/components/le-text.d.ts +11 -0
  15. package/dist/components/le-turntable.d.ts +11 -0
  16. package/dist/core/cjs/{index-BsRb_UTe.js → index-B0mg71He.js} +6 -6
  17. package/dist/core/cjs/index-B0mg71He.js.map +1 -0
  18. package/dist/core/cjs/index.cjs.js +2 -2
  19. package/dist/core/cjs/le-box.cjs.entry.js +2 -2
  20. package/dist/core/cjs/le-button.cjs.entry.js +2 -2
  21. package/dist/core/cjs/le-card.cjs.entry.js +2 -2
  22. package/dist/core/cjs/le-checkbox.cjs.entry.js +2 -2
  23. package/dist/core/cjs/le-kit.cjs.js +1 -1
  24. package/dist/core/cjs/le-number-input.cjs.entry.js +2 -2
  25. package/dist/core/cjs/le-popover.cjs.entry.js +1 -1
  26. package/dist/core/cjs/le-popup.cjs.entry.js +1 -1
  27. package/dist/core/cjs/le-round-progress.cjs.entry.js +1 -1
  28. package/dist/core/cjs/le-stack.cjs.entry.js +2 -2
  29. package/dist/core/cjs/le-string-input.cjs.entry.js +2 -2
  30. package/dist/core/cjs/le-text.cjs.entry.js +2 -2
  31. package/dist/core/cjs/le-turntable.cjs.entry.js +1 -1
  32. package/dist/core/cjs/loader.cjs.js +1 -1
  33. package/dist/{cjs/utils-DqhadIxH.js → core/cjs/utils-jdqP71LP.js} +3 -3
  34. package/dist/core/cjs/{utils-nsP8_w8_.js.map → utils-jdqP71LP.js.map} +1 -1
  35. package/dist/core/collection/global/app.js +4 -4
  36. package/dist/core/collection/global/app.js.map +1 -1
  37. package/dist/core/components/index.d.ts +33 -0
  38. package/dist/{esm → core/components}/index.js +9 -2
  39. package/dist/core/components/index.js.map +1 -0
  40. package/dist/core/components/le-box.d.ts +11 -0
  41. package/dist/{cjs/le-box.cjs.entry.js → core/components/le-box.js} +87 -14
  42. package/dist/core/components/le-box.js.map +1 -0
  43. package/dist/core/components/le-button.d.ts +11 -0
  44. package/dist/core/components/le-button.js +9 -0
  45. package/dist/core/components/le-button.js.map +1 -0
  46. package/dist/{esm/le-button_6.entry.js → core/components/le-button2.js} +919 -972
  47. package/dist/core/components/le-button2.js.map +1 -0
  48. package/dist/core/components/le-card.d.ts +11 -0
  49. package/dist/core/components/le-card.js +84 -0
  50. package/dist/core/components/le-card.js.map +1 -0
  51. package/dist/core/components/le-checkbox.d.ts +11 -0
  52. package/dist/core/components/le-checkbox.js +9 -0
  53. package/dist/core/components/le-checkbox.js.map +1 -0
  54. package/dist/core/components/le-component.d.ts +11 -0
  55. package/dist/core/components/le-component.js +9 -0
  56. package/dist/core/components/le-component.js.map +1 -0
  57. package/dist/core/components/le-number-input.d.ts +11 -0
  58. package/dist/{cjs/le-number-input.cjs.entry.js → core/components/le-number-input.js} +85 -15
  59. package/dist/core/components/le-number-input.js.map +1 -0
  60. package/dist/core/components/le-popover.d.ts +11 -0
  61. package/dist/core/components/le-popover.js +9 -0
  62. package/dist/core/components/le-popover.js.map +1 -0
  63. package/dist/{collection/components/le-popover/le-popover.js → core/components/le-popover2.js} +49 -360
  64. package/dist/core/components/le-popover2.js.map +1 -0
  65. package/dist/core/components/le-popup.d.ts +11 -0
  66. package/dist/{cjs/le-popup.cjs.entry.js → core/components/le-popup.js} +88 -21
  67. package/dist/core/components/le-popup.js.map +1 -0
  68. package/dist/core/components/le-round-progress.d.ts +11 -0
  69. package/dist/{cjs/le-round-progress.cjs.entry.js → core/components/le-round-progress.js} +43 -14
  70. package/dist/core/components/le-round-progress.js.map +1 -0
  71. package/dist/core/components/le-slot.d.ts +11 -0
  72. package/dist/core/components/le-slot.js +9 -0
  73. package/dist/core/components/le-slot.js.map +1 -0
  74. package/dist/core/components/le-stack.d.ts +11 -0
  75. package/dist/{cjs/le-stack.cjs.entry.js → core/components/le-stack.js} +78 -14
  76. package/dist/core/components/le-stack.js.map +1 -0
  77. package/dist/core/components/le-string-input.d.ts +11 -0
  78. package/dist/core/components/le-string-input.js +9 -0
  79. package/dist/core/components/le-string-input.js.map +1 -0
  80. package/dist/core/components/le-text.d.ts +11 -0
  81. package/dist/{cjs/le-text.cjs.entry.js → core/components/le-text.js} +80 -16
  82. package/dist/core/components/le-text.js.map +1 -0
  83. package/dist/core/components/le-turntable.d.ts +11 -0
  84. package/dist/{cjs/le-turntable.cjs.entry.js → core/components/le-turntable.js} +37 -12
  85. package/dist/core/components/le-turntable.js.map +1 -0
  86. package/dist/core/components/utils.js +310 -0
  87. package/dist/core/components/utils.js.map +1 -0
  88. package/dist/core/esm/{index-CJ-z5Zj1.js → index-SKsXnjWI.js} +6 -6
  89. package/dist/core/{le-kit/p-CJ-z5Zj1.js.map → esm/index-SKsXnjWI.js.map} +1 -1
  90. package/dist/core/esm/index.js +2 -2
  91. package/dist/core/esm/le-box.entry.js +2 -2
  92. package/dist/core/esm/le-button.entry.js +2 -2
  93. package/dist/core/esm/le-card.entry.js +2 -2
  94. package/dist/core/esm/le-checkbox.entry.js +2 -2
  95. package/dist/core/esm/le-kit.js +2 -2
  96. package/dist/core/esm/le-number-input.entry.js +2 -2
  97. package/dist/core/esm/le-popover.entry.js +1 -1
  98. package/dist/core/esm/le-popup.entry.js +1 -1
  99. package/dist/core/esm/le-round-progress.entry.js +1 -1
  100. package/dist/core/esm/le-stack.entry.js +2 -2
  101. package/dist/core/esm/le-string-input.entry.js +2 -2
  102. package/dist/core/esm/le-text.entry.js +2 -2
  103. package/dist/core/esm/le-turntable.entry.js +1 -1
  104. package/dist/core/esm/loader.js +2 -2
  105. package/dist/{esm/utils-Cf7fMI0j.js → core/esm/utils-DZdP1JiG.js} +3 -3
  106. package/dist/core/esm/{utils-Bxmld82M.js.map → utils-DZdP1JiG.js.map} +1 -1
  107. package/dist/core/le-kit/index.esm.js +1 -1
  108. package/dist/core/le-kit/le-kit.esm.js +1 -1
  109. package/dist/core/le-kit/p--VxUdzYV.js +2 -0
  110. package/dist/core/le-kit/{p-Drz36PDp.js.map → p--VxUdzYV.js.map} +1 -1
  111. package/dist/core/le-kit/{p-2ac4789a.entry.js → p-189cb775.entry.js} +2 -2
  112. package/dist/core/le-kit/{p-556086ca.entry.js → p-35c1d413.entry.js} +2 -2
  113. package/dist/core/le-kit/{p-aa6e906f.entry.js → p-4f133e72.entry.js} +2 -2
  114. package/dist/core/le-kit/{p-df552906.entry.js → p-55f70091.entry.js} +2 -2
  115. package/dist/core/le-kit/{p-e0861e82.entry.js → p-5fd7b23a.entry.js} +2 -2
  116. package/dist/core/le-kit/{p-5ef81068.entry.js → p-6e414a5c.entry.js} +2 -2
  117. package/dist/core/le-kit/{p-d75214f9.entry.js → p-7b121ca7.entry.js} +2 -2
  118. package/dist/core/le-kit/{p-45eace7c.entry.js → p-8c81fa95.entry.js} +2 -2
  119. package/dist/core/le-kit/{p-257495cc.entry.js → p-9aa81442.entry.js} +2 -2
  120. package/dist/core/le-kit/p-SKsXnjWI.js +3 -0
  121. package/dist/core/le-kit/p-SKsXnjWI.js.map +1 -0
  122. package/dist/core/le-kit/{p-66d35f48.entry.js → p-a9d05ef6.entry.js} +2 -2
  123. package/dist/core/le-kit/{p-73682c5e.entry.js → p-b2bd2a80.entry.js} +2 -2
  124. package/dist/core/le-kit/{p-0308bd1f.entry.js → p-ccac9611.entry.js} +2 -2
  125. package/dist/core/types/global/app.d.ts +4 -4
  126. package/dist/le-kit/assets/custom-elements.json +1230 -1230
  127. package/dist/le-kit/index-CAY3Hk_i.js +4559 -0
  128. package/dist/le-kit/index-CAY3Hk_i.js.map +1 -0
  129. package/dist/le-kit/index.esm.js +116 -2
  130. package/dist/le-kit/index.esm.js.map +1 -1
  131. package/dist/{esm → le-kit}/le-box.entry.js +3 -3
  132. package/dist/le-kit/le-button.entry.esm.js.map +1 -0
  133. package/dist/le-kit/le-button.entry.js +90 -0
  134. package/dist/{esm → le-kit}/le-card.entry.js +3 -3
  135. package/dist/le-kit/le-checkbox.entry.esm.js.map +1 -0
  136. package/dist/le-kit/le-checkbox.entry.js +59 -0
  137. package/dist/le-kit/le-component.entry.esm.js.map +1 -0
  138. package/dist/{collection/components/le-component/le-component.js → le-kit/le-component.entry.js} +19 -138
  139. package/dist/le-kit/le-kit.css +1010 -1
  140. package/dist/le-kit/le-kit.esm.js +48 -2
  141. package/dist/le-kit/le-kit.esm.js.map +1 -1
  142. package/dist/{esm → le-kit}/le-number-input.entry.js +5 -5
  143. package/dist/le-kit/le-popover.entry.esm.js.map +1 -0
  144. package/dist/le-kit/le-popover.entry.js +346 -0
  145. package/dist/{esm → le-kit}/le-popup.entry.js +6 -6
  146. package/dist/{esm → le-kit}/le-round-progress.entry.js +2 -2
  147. package/dist/le-kit/le-slot.entry.esm.js.map +1 -0
  148. package/dist/{collection/components/le-slot/le-slot.js → le-kit/le-slot.entry.js} +20 -273
  149. package/dist/{esm → le-kit}/le-stack.entry.js +3 -3
  150. package/dist/le-kit/le-string-input.entry.esm.js.map +1 -0
  151. package/dist/le-kit/le-string-input.entry.js +93 -0
  152. package/dist/{esm → le-kit}/le-text.entry.js +3 -3
  153. package/dist/{esm → le-kit}/le-turntable.entry.js +2 -2
  154. package/dist/{core/esm/utils-Bxmld82M.js → le-kit/utils-cwSNy7ZS.js} +3 -3
  155. package/dist/{esm/utils-Cf7fMI0j.js.map → le-kit/utils-cwSNy7ZS.js.map} +1 -1
  156. package/dist/types/global/app.d.ts +4 -4
  157. package/package.json +4 -5
  158. package/readme.md +2 -2
  159. package/custom-elements.json +0 -4305
  160. package/dist/cjs/index-o1DRKw1g.js +0 -1842
  161. package/dist/cjs/index-o1DRKw1g.js.map +0 -1
  162. package/dist/cjs/index.cjs.js +0 -119
  163. package/dist/cjs/index.cjs.js.map +0 -1
  164. package/dist/cjs/le-box.entry.cjs.js.map +0 -1
  165. package/dist/cjs/le-button.le-checkbox.le-component.le-popover.le-slot.le-string-input.entry.cjs.js.map +0 -1
  166. package/dist/cjs/le-button_6.cjs.entry.js +0 -1206
  167. package/dist/cjs/le-card.cjs.entry.js +0 -29
  168. package/dist/cjs/le-card.entry.cjs.js.map +0 -1
  169. package/dist/cjs/le-kit.cjs.js +0 -25
  170. package/dist/cjs/le-kit.cjs.js.map +0 -1
  171. package/dist/cjs/le-number-input.entry.cjs.js.map +0 -1
  172. package/dist/cjs/le-popup.entry.cjs.js.map +0 -1
  173. package/dist/cjs/le-round-progress.entry.cjs.js.map +0 -1
  174. package/dist/cjs/le-stack.entry.cjs.js.map +0 -1
  175. package/dist/cjs/le-text.entry.cjs.js.map +0 -1
  176. package/dist/cjs/le-turntable.entry.cjs.js.map +0 -1
  177. package/dist/cjs/loader.cjs.js +0 -13
  178. package/dist/cjs/loader.cjs.js.map +0 -1
  179. package/dist/cjs/utils-DqhadIxH.js.map +0 -1
  180. package/dist/collection/assets/custom-elements.json +0 -4305
  181. package/dist/collection/collection-manifest.json +0 -26
  182. package/dist/collection/components/le-box/le-box.default.css +0 -37
  183. package/dist/collection/components/le-box/le-box.js +0 -614
  184. package/dist/collection/components/le-box/le-box.js.map +0 -1
  185. package/dist/collection/components/le-button/le-button.default.css +0 -263
  186. package/dist/collection/components/le-button/le-button.js +0 -368
  187. package/dist/collection/components/le-button/le-button.js.map +0 -1
  188. package/dist/collection/components/le-card/le-card.default.css +0 -74
  189. package/dist/collection/components/le-card/le-card.js +0 -102
  190. package/dist/collection/components/le-card/le-card.js.map +0 -1
  191. package/dist/collection/components/le-checkbox/le-checkbox.css +0 -93
  192. package/dist/collection/components/le-checkbox/le-checkbox.js +0 -192
  193. package/dist/collection/components/le-checkbox/le-checkbox.js.map +0 -1
  194. package/dist/collection/components/le-component/le-component.css +0 -189
  195. package/dist/collection/components/le-component/le-component.js.map +0 -1
  196. package/dist/collection/components/le-number-input/le-number-input.css +0 -135
  197. package/dist/collection/components/le-number-input/le-number-input.js +0 -515
  198. package/dist/collection/components/le-number-input/le-number-input.js.map +0 -1
  199. package/dist/collection/components/le-popover/le-popover.css +0 -143
  200. package/dist/collection/components/le-popover/le-popover.js.map +0 -1
  201. package/dist/collection/components/le-popup/le-popup.api.js +0 -101
  202. package/dist/collection/components/le-popup/le-popup.api.js.map +0 -1
  203. package/dist/collection/components/le-popup/le-popup.css +0 -222
  204. package/dist/collection/components/le-popup/le-popup.js +0 -596
  205. package/dist/collection/components/le-popup/le-popup.js.map +0 -1
  206. package/dist/collection/components/le-round-progress/le-round-progress.css +0 -34
  207. package/dist/collection/components/le-round-progress/le-round-progress.js +0 -184
  208. package/dist/collection/components/le-round-progress/le-round-progress.js.map +0 -1
  209. package/dist/collection/components/le-slot/le-slot.default.css +0 -222
  210. package/dist/collection/components/le-slot/le-slot.js.map +0 -1
  211. package/dist/collection/components/le-stack/le-stack.default.css +0 -37
  212. package/dist/collection/components/le-stack/le-stack.js +0 -389
  213. package/dist/collection/components/le-stack/le-stack.js.map +0 -1
  214. package/dist/collection/components/le-string-input/le-string-input.css +0 -83
  215. package/dist/collection/components/le-string-input/le-string-input.js +0 -359
  216. package/dist/collection/components/le-string-input/le-string-input.js.map +0 -1
  217. package/dist/collection/components/le-text/le-text.default.css +0 -169
  218. package/dist/collection/components/le-text/le-text.js +0 -475
  219. package/dist/collection/components/le-text/le-text.js.map +0 -1
  220. package/dist/collection/components/le-turntable/le-turntable.css +0 -10
  221. package/dist/collection/components/le-turntable/le-turntable.js +0 -210
  222. package/dist/collection/components/le-turntable/le-turntable.js.map +0 -1
  223. package/dist/collection/global/app.js +0 -167
  224. package/dist/collection/global/app.js.map +0 -1
  225. package/dist/collection/index.js +0 -15
  226. package/dist/collection/index.js.map +0 -1
  227. package/dist/collection/types/blocks.js +0 -115
  228. package/dist/collection/types/blocks.js.map +0 -1
  229. package/dist/collection/types/options.js +0 -2
  230. package/dist/collection/types/options.js.map +0 -1
  231. package/dist/collection/utils/utils.js +0 -141
  232. package/dist/collection/utils/utils.js.map +0 -1
  233. package/dist/core/cjs/index-BsRb_UTe.js.map +0 -1
  234. package/dist/core/cjs/utils-nsP8_w8_.js +0 -152
  235. package/dist/core/esm/index-CJ-z5Zj1.js.map +0 -1
  236. package/dist/core/le-kit/p-CJ-z5Zj1.js +0 -3
  237. package/dist/core/le-kit/p-Drz36PDp.js +0 -2
  238. package/dist/docs.d.ts +0 -443
  239. package/dist/docs.json +0 -5185
  240. package/dist/esm/index-CwNQ1GTa.js +0 -1824
  241. package/dist/esm/index-CwNQ1GTa.js.map +0 -1
  242. package/dist/esm/index.js.map +0 -1
  243. package/dist/esm/le-box.entry.js.map +0 -1
  244. package/dist/esm/le-button.le-checkbox.le-component.le-popover.le-slot.le-string-input.entry.js.map +0 -1
  245. package/dist/esm/le-card.entry.js.map +0 -1
  246. package/dist/esm/le-kit.js +0 -21
  247. package/dist/esm/le-kit.js.map +0 -1
  248. package/dist/esm/le-number-input.entry.js.map +0 -1
  249. package/dist/esm/le-popup.entry.js.map +0 -1
  250. package/dist/esm/le-round-progress.entry.js.map +0 -1
  251. package/dist/esm/le-stack.entry.js.map +0 -1
  252. package/dist/esm/le-text.entry.js.map +0 -1
  253. package/dist/esm/le-turntable.entry.js.map +0 -1
  254. package/dist/esm/loader.js +0 -11
  255. package/dist/esm/loader.js.map +0 -1
  256. package/dist/index.cjs.js +0 -1
  257. package/dist/index.js +0 -1
  258. package/dist/le-kit/le-button.le-checkbox.le-component.le-popover.le-slot.le-string-input.entry.esm.js.map +0 -1
  259. package/dist/le-kit/p-08dbcc25.entry.js +0 -2
  260. package/dist/le-kit/p-08dbcc25.entry.js.map +0 -1
  261. package/dist/le-kit/p-5dc35729.entry.js +0 -2
  262. package/dist/le-kit/p-5dc35729.entry.js.map +0 -1
  263. package/dist/le-kit/p-64374730.entry.js +0 -2
  264. package/dist/le-kit/p-64374730.entry.js.map +0 -1
  265. package/dist/le-kit/p-79ec6f7c.entry.js +0 -2
  266. package/dist/le-kit/p-79ec6f7c.entry.js.map +0 -1
  267. package/dist/le-kit/p-8daf3c7f.entry.js +0 -2
  268. package/dist/le-kit/p-8daf3c7f.entry.js.map +0 -1
  269. package/dist/le-kit/p-9c69235d.entry.js +0 -2
  270. package/dist/le-kit/p-9c69235d.entry.js.map +0 -1
  271. package/dist/le-kit/p-CwNQ1GTa.js +0 -3
  272. package/dist/le-kit/p-CwNQ1GTa.js.map +0 -1
  273. package/dist/le-kit/p-ad398acd.entry.js +0 -2
  274. package/dist/le-kit/p-ad398acd.entry.js.map +0 -1
  275. package/dist/le-kit/p-b8122ad6.entry.js +0 -2
  276. package/dist/le-kit/p-b8122ad6.entry.js.map +0 -1
  277. package/dist/le-kit/p-f9008505.entry.js +0 -2
  278. package/dist/le-kit/p-f9008505.entry.js.map +0 -1
  279. package/dist/le-kit/p-y3FECAx9.js +0 -2
  280. package/dist/le-kit/p-y3FECAx9.js.map +0 -1
  281. package/dist/themes/base.css +0 -89
  282. package/dist/themes/dark.css +0 -100
  283. package/dist/themes/default.css +0 -108
  284. package/dist/themes/gradient.css +0 -100
  285. package/dist/themes/index.css +0 -413
  286. package/dist/themes/minimal.css +0 -100
  287. package/dist/themes/warm.css +0 -100
  288. /package/dist/{collection → components}/themes/base.css +0 -0
  289. /package/dist/{collection → components}/themes/dark.css +0 -0
  290. /package/dist/{collection → components}/themes/default.css +0 -0
  291. /package/dist/{collection → components}/themes/gradient.css +0 -0
  292. /package/dist/{collection → components}/themes/index.css +0 -0
  293. /package/dist/{collection → components}/themes/minimal.css +0 -0
  294. /package/dist/{collection → components}/themes/warm.css +0 -0
  295. /package/dist/core/le-kit/{p-2ac4789a.entry.js.map → p-189cb775.entry.js.map} +0 -0
  296. /package/dist/core/le-kit/{p-556086ca.entry.js.map → p-35c1d413.entry.js.map} +0 -0
  297. /package/dist/core/le-kit/{p-aa6e906f.entry.js.map → p-4f133e72.entry.js.map} +0 -0
  298. /package/dist/core/le-kit/{p-df552906.entry.js.map → p-55f70091.entry.js.map} +0 -0
  299. /package/dist/core/le-kit/{p-e0861e82.entry.js.map → p-5fd7b23a.entry.js.map} +0 -0
  300. /package/dist/core/le-kit/{p-5ef81068.entry.js.map → p-6e414a5c.entry.js.map} +0 -0
  301. /package/dist/core/le-kit/{p-d75214f9.entry.js.map → p-7b121ca7.entry.js.map} +0 -0
  302. /package/dist/core/le-kit/{p-45eace7c.entry.js.map → p-8c81fa95.entry.js.map} +0 -0
  303. /package/dist/core/le-kit/{p-257495cc.entry.js.map → p-9aa81442.entry.js.map} +0 -0
  304. /package/dist/core/le-kit/{p-66d35f48.entry.js.map → p-a9d05ef6.entry.js.map} +0 -0
  305. /package/dist/core/le-kit/{p-73682c5e.entry.js.map → p-b2bd2a80.entry.js.map} +0 -0
  306. /package/dist/core/le-kit/{p-0308bd1f.entry.js.map → p-ccac9611.entry.js.map} +0 -0
  307. /package/dist/le-kit/{themes → dist/components/themes}/base.css +0 -0
  308. /package/dist/le-kit/{themes → dist/components/themes}/dark.css +0 -0
  309. /package/dist/le-kit/{themes → dist/components/themes}/default.css +0 -0
  310. /package/dist/le-kit/{themes → dist/components/themes}/gradient.css +0 -0
  311. /package/dist/le-kit/{themes → dist/components/themes}/index.css +0 -0
  312. /package/dist/le-kit/{themes → dist/components/themes}/minimal.css +0 -0
  313. /package/dist/le-kit/{themes → dist/components/themes}/warm.css +0 -0
@@ -1,1199 +1,1146 @@
1
- import { r as registerInstance, i as createEvent, j as getElement, k as h, F as Fragment, h as getLeKitConfig, l as getAssetPath, H as Host } from './index-CwNQ1GTa.js';
2
- import { c as classnames, o as observeModeChanges } from './utils-Cf7fMI0j.js';
1
+ import { proxyCustomElement, HTMLElement, createEvent, h, getAssetPath, Host, Fragment } from '@stencil/core/internal/client';
2
+ import { h as classnames, o as observeModeChanges, f as getLeKitConfig } from './utils.js';
3
+ import { d as defineCustomElement$5 } from './le-popover2.js';
3
4
 
4
- const leButtonDefaultCss = ":host{display:inline-block;--le-button-border-radius:var(--le-radius-md);--le-button-padding-x:0.4rem;--le-button-padding-y:0.4rem;--le-button-small-padding:0.25rem;--le-button-font-size:var(--le-font-size-md);--le-button-font-weight:var(--le-font-weight-medium);--le-button-transition:var(--le-transition-fast);--le-button-icon-aspect-ratio:1;--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-bg-system:var(--le-color-black);--_btn-color:var(--le-color-primary-contrast);--_btn-border-color:var(--le-color-primary)}:host([full-width]){display:block;width:100%}.button{display:inline-flex;align-items:center;justify-content:center;gap:var(--le-spacing-3);width:100%;padding:var(--le-button-padding-y) var(--le-button-padding-x);border:1px solid var(--_btn-border-color);border-radius:var(--le-button-border-radius);background:var(--_btn-bg);color:var(--_btn-color);font-family:var(--le-font-family-base);font-size:var(--le-button-font-size);font-weight:var(--le-button-font-weight);line-height:var(--le-line-height-tight);text-decoration:none;cursor:pointer;transition:background-color var(--le-button-transition) var(--le-transition-easing),\n border-color var(--le-button-transition) var(--le-transition-easing),\n box-shadow var(--le-button-transition) var(--le-transition-easing),\n transform var(--le-button-transition) var(--le-transition-easing)}.button:hover:not(:disabled){background:var(--_btn-bg-hover);border-color:var(--_btn-bg-hover)}.button:active:not(:disabled){transform:translateY(1px)}.button:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.button:disabled{opacity:0.5;cursor:not-allowed}:host>le-component.color-primary{--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-color:var(--le-color-primary-contrast);--_btn-border-color:var(--le-color-primary)}:host>le-component.color-secondary{--_btn-bg:var(--le-color-secondary);--_btn-bg-hover:var(--le-color-secondary-dark);--_btn-color:var(--le-color-secondary-contrast);--_btn-border-color:var(--le-color-secondary)}:host>le-component.color-success{--_btn-bg:var(--le-color-success);--_btn-bg-hover:var(--le-color-success-dark);--_btn-color:var(--le-color-success-contrast);--_btn-border-color:var(--le-color-success)}:host>le-component.color-warning{--_btn-bg:var(--le-color-warning);--_btn-bg-hover:var(--le-color-warning-dark);--_btn-color:var(--le-color-warning-contrast);--_btn-border-color:var(--le-color-warning)}:host>le-component.color-danger{--_btn-bg:var(--le-color-danger);--_btn-bg-hover:var(--le-color-danger-dark);--_btn-color:var(--le-color-danger-contrast);--_btn-border-color:var(--le-color-danger)}:host>le-component.color-info{--_btn-bg:var(--le-color-info);--_btn-bg-hover:var(--le-color-info-dark);--_btn-color:var(--le-color-info-contrast);--_btn-border-color:var(--le-color-info)}:host>le-component.variant-solid .button{box-shadow:var(--le-shadow-sm)}:host>le-component.variant-solid .button:hover:not(:disabled){box-shadow:var(--le-shadow-md)}:host>le-component.variant-outlined .button{background:transparent;color:var(--_btn-bg);border-color:var(--_btn-border-color)}:host>le-component.variant-outlined .button:hover:not(:disabled){background:var(--_btn-bg);color:var(--_btn-color)}:host>le-component.variant-clear .button{background:transparent;color:var(--_btn-bg);border-color:transparent}:host>le-component.variant-clear .button:hover:not(:disabled){background:var(--le-color-gray-100);border-color:transparent}:host>le-component.variant-system .button{background:transparent;color:var(--_btn-bg-system);border-color:transparent}:host>le-component.size-small .button{--le-button-padding-x:0.4rem;--le-button-padding-y:0.3rem;--le-button-padding-top:0.35rem;--le-button-font-size:var(--le-button-small-font-size, var(--le-font-size-xs))}:host>le-component.size-large .button{--le-button-padding-x:0.9rem;--le-button-padding-y:0.6rem;--le-button-font-size:var(--le-font-size-xl)}:host>le-component.full-width{display:block;width:100%}:host>le-component.selected .button{box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.2)}:host>le-component.variant-outlined.selected .button,:host>le-component.variant-clear.selected .button{background:var(--_btn-bg);color:var(--_btn-color)}:host>le-component.icon-only .button{padding:0.5rem;padding-bottom:0.6rem;aspect-ratio:var(--le-button-icon-aspect-ratio, 1)}:host>le-component.icon-only.size-small .button{padding:var(--le-button-small-padding, 0.25rem)}:host>le-component.icon-only.size-large .button{padding:0.75rem}:host>le-component.icon-only .content{display:none}.content{display:inline}.content:empty{display:none}.icon-start,.icon-only,.icon-end{display:flex;align-items:center;justify-content:center}.icon-start:empty,.icon-only:empty,.icon-end:empty{display:none}::slotted([slot=\"icon-start\"]),::slotted([slot=\"icon-only\"]),::slotted([slot=\"icon-end\"]){display:flex;align-items:center;justify-content:center;width:1.125em;height:1.125em}";
5
+ const leStringInputCss = ":host{display:block;--le-input-bg:var(--le-color-surface, #ffffff);--le-input-color:var(--le-color-text-primary, #333333);--le-input-border:var(--le-border-width, 2px) solid var(--le-color-border-input, #007bff);--le-input-radius:var(--le-radius-sm, 4px);--le-input-padding:2px 6px;--le-input-height:1.5rem;--le-input-label-color:var(--le-color-text-primary, #333333);--le-input-desc-color:var(--le-color-text-secondary, #666666);--le-input-placeholder-color:#999999}.le-input-wrapper{display:flex;flex-direction:column;gap:2px}.le-input-label{display:block;font-size:0.9em;font-weight:500;color:var(--le-input-label-color);margin-bottom:2px}.le-input-container{position:relative;display:flex;align-items:center;background:var(--le-input-bg);border:var(--le-input-border);border-radius:var(--le-input-radius);transition:border-color 0.2s}.le-input-container:focus-within{outline:2px solid var(--le-color-focus);outline-offset:2px}:host([disabled]) .le-input-container{opacity:0.6;background-color:rgba(0,0,0,0.05);cursor:not-allowed}input{flex:1;min-height:var(--le-input-height);padding:var(--le-input-padding);border:none;background:transparent;color:var(--le-input-color);font-family:inherit;font-size:inherit;outline:none;width:100%}input::placeholder{color:var(--le-input-placeholder-color)}.icon-start,.icon-end{display:flex;align-items:center;justify-content:center;padding:0 8px;color:var(--le-input-desc-color)}.le-input-description{font-size:0.85em;color:var(--le-input-desc-color);margin-top:2px}.le-input-description::has(le-slot>slot[name=description]:empty){display:none}";
5
6
 
6
- const LeButton = class {
7
- constructor(hostRef) {
8
- registerInstance(this, hostRef);
9
- this.leClick = createEvent(this, "click");
7
+ const LeStringInput = /*@__PURE__*/ proxyCustomElement(class LeStringInput extends HTMLElement {
8
+ constructor(registerHost) {
9
+ super();
10
+ if (registerHost !== false) {
11
+ this.__registerHost();
12
+ }
13
+ this.__attachShadow();
14
+ this.leChange = createEvent(this, "change", 7);
15
+ this.leInput = createEvent(this, "input", 7);
10
16
  }
11
- get el() { return getElement(this); }
17
+ get el() { return this; }
12
18
  /**
13
19
  * Mode of the popover should be 'default' for internal use
14
20
  */
15
21
  mode;
16
22
  /**
17
- * Button variant style
18
- * @allowedValues solid | outlined | clear
23
+ * The value of the input
19
24
  */
20
- variant = 'solid';
25
+ value;
21
26
  /**
22
- * Button color theme (uses theme semantic colors)
23
- * @allowedValues primary | secondary | success | warning | danger | info
27
+ * The name of the input
24
28
  */
25
- color = 'primary';
29
+ name;
26
30
  /**
27
- * Button size
28
- * @allowedValues small | medium | large
31
+ * The type of the input (text, email, password, etc.)
29
32
  */
30
- size = 'medium';
33
+ type = 'text';
31
34
  /**
32
- * Whether the button is in a selected/active state
35
+ * Label for the input
33
36
  */
34
- selected = false;
37
+ label;
35
38
  /**
36
- * Whether the button takes full width of its container
39
+ * Icon for the start icon
37
40
  */
38
- fullWidth = false;
41
+ iconStart;
39
42
  /**
40
- * Whether the button displays only an icon (square aspect ratio)
43
+ * Icon for the end icon
41
44
  */
42
- iconOnly = false;
45
+ iconEnd;
43
46
  /**
44
- * Whether the button is disabled
47
+ * Placeholder text
48
+ */
49
+ placeholder;
50
+ /**
51
+ * Whether the input is disabled
45
52
  */
46
53
  disabled = false;
47
54
  /**
48
- * The button type attribute
49
- * @allowedValues button | submit | reset
55
+ * Whether the input is read-only
50
56
  */
51
- type = 'button';
57
+ readonly = false;
52
58
  /**
53
- * Optional href to make the button act as a link
59
+ * External ID for linking with external systems
54
60
  */
55
- href;
61
+ externalId;
56
62
  /**
57
- * Link target when href is set
63
+ * Emitted when the value changes (on blur or Enter)
58
64
  */
59
- target;
65
+ leChange;
60
66
  /**
61
- * Emitted when the button is clicked.
62
- * This is a custom event that wraps the native click but ensures the target is the le-button.
67
+ * Emitted when the input value changes (on keystroke)
63
68
  */
64
- leClick;
65
- handleClick = (event) => {
66
- // We stop the internal button click from bubbling up
67
- event.stopPropagation();
68
- if (this.disabled) {
69
- event.preventDefault();
70
- return;
71
- }
72
- // And emit our own click event from the host element
73
- this.leClick.emit(event);
69
+ leInput;
70
+ handleInput = (ev) => {
71
+ const input = ev.target;
72
+ this.value = input.value;
73
+ this.leInput.emit({
74
+ value: this.value,
75
+ name: this.name,
76
+ externalId: this.externalId
77
+ });
74
78
  };
75
- render() {
76
- const classes = classnames(`variant-${this.variant}`, `color-${this.color}`, `size-${this.size}`, {
77
- 'selected': this.selected,
78
- 'full-width': this.fullWidth,
79
- 'icon-only': this.iconOnly,
80
- 'disabled': this.disabled,
79
+ handleChange = (ev) => {
80
+ const input = ev.target;
81
+ this.value = input.value;
82
+ this.leChange.emit({
83
+ value: this.value,
84
+ name: this.name,
85
+ externalId: this.externalId
81
86
  });
82
- const TagType = this.href ? 'a' : 'button';
83
- const attrs = this.href ? { href: this.href, target: this.target, role: 'button' } : { type: this.type, disabled: this.disabled };
84
- return (h("le-component", { key: '363dbfddf4a765bfd6f36ed16d0912e281153806', component: "le-button", hostClass: classes }, h(TagType, { key: 'e112acdff4278e976ad767bd1ea7c9ced5e85f43', class: "button", part: "button", ...attrs, onClick: this.handleClick }, this.iconOnly ? (h("span", { class: "icon-start" }, h("slot", { name: "icon-only" }))) : (h(Fragment, null, h("span", { class: "icon-start" }, h("slot", { name: "icon-start" })), h("le-slot", { name: "", description: "Button text", type: "text", class: "content", part: "content" }, h("slot", null)), h("span", { class: "icon-end" }, h("slot", { name: "icon-end" })))))));
87
+ };
88
+ handleClick = (ev) => {
89
+ ev.stopPropagation();
90
+ };
91
+ render() {
92
+ return (h("le-component", { key: 'd0c69370dae2d1fee5700954e4823d2a03a51331', component: "le-string-input", hostClass: classnames({ 'disabled': this.disabled }) }, h("div", { key: '4acae8d3c34da2a86970a616c493ff210d561f5f', class: "le-input-wrapper" }, this.label && (h("label", { key: '609191b45187b6b1a65d05cd594b149760ac6882', class: "le-input-label", htmlFor: this.name }, this.label)), h("div", { key: '36b4caff4468ac7421db03f811cb3ef4a622b001', class: "le-input-container" }, this.iconStart && (h("span", { key: '344f88887fe8270bbef7e26ec1ad5da9fae1f8e4', class: "icon-start" }, this.iconStart)), h("input", { key: '4ba7beeddd7fb3cf23d03e029d11a804764cdd6e', id: this.name, type: this.type, name: this.name, value: this.value, placeholder: this.placeholder, disabled: this.disabled, readOnly: this.readonly, onInput: this.handleInput, onChange: this.handleChange, onClick: this.handleClick }), this.iconEnd && (h("span", { key: '7cdd4b52c3e1a1b18b19e697bdb42431941bba01', class: "icon-end" }, this.iconEnd))), h("div", { key: '113a75aa413e4d95300aeaa97d1ce7a75cf68c7a', class: "le-input-description" }, h("le-slot", { key: '0b37fc14e6df68f6c44cf9001d63a70f019e1cc3', name: "description", type: "text", tag: "p", label: "Description" }, h("slot", { key: '2674056dc915fabdb4fcbcaa13294a116b9509a6', name: "description" }))))));
93
+ }
94
+ static get style() { return leStringInputCss; }
95
+ }, [769, "le-string-input", {
96
+ "mode": [1537],
97
+ "value": [1537],
98
+ "name": [1],
99
+ "type": [1],
100
+ "label": [1],
101
+ "iconStart": [1, "icon-start"],
102
+ "iconEnd": [1, "icon-end"],
103
+ "placeholder": [1],
104
+ "disabled": [4],
105
+ "readonly": [4],
106
+ "externalId": [1, "external-id"]
107
+ }]);
108
+ function defineCustomElement$4() {
109
+ if (typeof customElements === "undefined") {
110
+ return;
85
111
  }
86
- };
87
- LeButton.style = leButtonDefaultCss;
112
+ const components = ["le-string-input", "le-button", "le-checkbox", "le-component", "le-popover", "le-slot", "le-string-input"];
113
+ components.forEach(tagName => { switch (tagName) {
114
+ case "le-string-input":
115
+ if (!customElements.get(tagName)) {
116
+ customElements.define(tagName, LeStringInput);
117
+ }
118
+ break;
119
+ case "le-button":
120
+ if (!customElements.get(tagName)) {
121
+ defineCustomElement();
122
+ }
123
+ break;
124
+ case "le-checkbox":
125
+ if (!customElements.get(tagName)) {
126
+ defineCustomElement$1();
127
+ }
128
+ break;
129
+ case "le-component":
130
+ if (!customElements.get(tagName)) {
131
+ defineCustomElement$2();
132
+ }
133
+ break;
134
+ case "le-popover":
135
+ if (!customElements.get(tagName)) {
136
+ defineCustomElement$5();
137
+ }
138
+ break;
139
+ case "le-slot":
140
+ if (!customElements.get(tagName)) {
141
+ defineCustomElement$3();
142
+ }
143
+ break;
144
+ case "le-string-input":
145
+ if (!customElements.get(tagName)) {
146
+ defineCustomElement$4();
147
+ }
148
+ break;
149
+ } });
150
+ }
88
151
 
89
- const leCheckboxCss = ":host{display:block;--le-checkbox-size:18px;--le-checkbox-color:var(--le-color-primary, #007bff);--le-checkbox-label-color:var(--le-color-text-primary, #333);--le-checkbox-desc-color:var(--le-color-text-secondary, #666);--le-checkbox-border-radius:var(--le-radius-sm, 2px);--le-checkbox-marker-color:var(--le-color-surface, #fff)}.le-checkbox-wrapper{display:flex;flex-direction:column;gap:4px}.le-checkbox-label{display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;user-select:none}:host([disabled]) .le-checkbox-label{cursor:not-allowed;opacity:0.6}.le-checkbox-input{display:flex;align-items:center;justify-content:center;min-height:1.4em}input[type=\"checkbox\"]{appearance:none;-webkit-appearance:none;width:var(--le-checkbox-size);height:var(--le-checkbox-size);border:var(--le-border-width, 2px) solid var(--le-checkbox-color);border-radius:var(--le-checkbox-border-radius);margin:0;margin-top:2px;position:relative;cursor:inherit;background-color:transparent;transition:background-color 0.2s, border-color 0.2s}input[type=\"checkbox\"]:checked{background-color:var(--le-checkbox-color)}input[type=\"checkbox\"]:checked::after{content:'';position:absolute;left:0;top:0;bottom:calc(var(--le-checkbox-size) / 5);right:0;margin:auto;width:calc(var(--le-checkbox-size) / 4);height:calc(var(--le-checkbox-size) / 2);border:solid var(--le-checkbox-marker-color, #fff);border-width:0 calc(var(--le-checkbox-size) / 10) calc(var(--le-checkbox-size) / 10) 0;transform:rotate(45deg)}input[type=\"checkbox\"]:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.le-checkbox-text{flex:1;flex-wrap:wrap;color:var(--le-checkbox-label-color);line-height:1.5;text-align:start}.le-checkbox-description{margin-left:calc(var(--le-checkbox-size) + 8px);font-size:0.875em;color:var(--le-checkbox-desc-color);line-height:1.4}:host [slot=\"description\"]{margin:0}";
152
+ const leSlotDefaultCss = ":host{display:contents;--le-slot-border-color:#0088ff;--le-slot-bg-color:rgba(0, 136, 255, 0.05);--le-slot-header-bg:rgb(218, 238, 255);--le-slot-label-color:#0066cc;--le-slot-description-color:#666;--le-slot-required-color:#e53935;--le-slot-dropzone-min-height:20px;--le-slot-dropzone-border-color:#ccc}.le-slot-container,.le-slot-header,.le-slot-description,.le-slot-dropzone,.le-slot-input{display:none}.hidden-slot{display:none}:host(.admin-mode){display:block;flex:1}:host(.admin-mode) .le-slot-container{position:relative;display:flex;flex-direction:column;border:2px dashed var(--le-slot-border-color);border-radius:4px;background:var(--le-slot-bg-color);margin:4px 0}:host(.admin-mode) .le-slot-header{display:flex;align-items:center;gap:4px;padding:0 0 0 var(--le-spacing-1, 4px);background:var(--le-slot-header-bg);border-bottom:1px solid var(--le-slot-border-color);font-size:var(--le-font-size-xs, 11px);font-weight:400;text-transform:capitalize}:host(.admin-mode) .le-slot-header-no-label{justify-content:flex-end;height:16px;border:none;background-color:transparent}.le-slot-label{color:var(--le-slot-label-color);text-align:start;overflow:hidden;width:0;flex:1 1 0%}.le-slot-required{color:var(--le-slot-required-color);font-weight:bold}:host(.admin-mode) .le-slot-description{display:block;padding:4px 8px;font-size:12px;color:var(--le-slot-description-color);font-style:italic}:host(.admin-mode) .le-slot-description-icon{display:inline-block;font-size:9px;line-height:1;cursor:pointer;color:var(--le-slot-description-color)}:host(.admin-mode) .le-slot-dropzone{display:block;min-height:var(--le-slot-dropzone-min-height);padding:var(--le-spacing-1, 4px);position:relative}:host(.admin-mode) .le-slot-dropzone:empty::before{content:'Drop content here';display:flex;align-items:center;justify-content:center;position:absolute;inset:8px;border:2px dashed var(--le-slot-dropzone-border-color);border-radius:4px;color:#999;font-size:12px;pointer-events:none}:host(.admin-mode.drag-over) .le-slot-container{border-color:#00cc66;background:rgba(0, 204, 102, 0.1)}:host(.admin-mode.drag-over) .le-slot-dropzone:empty::before{border-color:#00cc66;color:#00cc66;content:'Release to drop'}:host(.admin-mode) .le-slot-input{display:block;padding:var(--le-spacing-1, 4px)}:host(.admin-mode) .le-slot-input input,:host(.admin-mode) .le-slot-input textarea{display:block;width:100%;padding:8px 10px;border:1px solid var(--le-slot-dropzone-border-color);border-radius:4px;font-family:inherit;font-size:14px;line-height:1.4;background:#fff;color:#333;box-sizing:border-box;transition:border-color 0.2s, box-shadow 0.2s}:host(.admin-mode) .le-slot-input input:focus,:host(.admin-mode) .le-slot-input textarea:focus{outline:none;border-color:var(--le-slot-border-color);box-shadow:0 0 0 3px rgba(0, 136, 255, 0.15)}:host(.admin-mode) .le-slot-input input::placeholder,:host(.admin-mode) .le-slot-input textarea::placeholder{color:#999}:host(.admin-mode) .le-slot-input textarea{resize:vertical;min-height:60px}:host(.admin-mode) .le-slot-input slot{display:none}.le-slot-invalid{color:var(--le-slot-required-color);font-size:10px;margin-left:auto;font-weight:normal;text-transform:none}:host(.admin-mode) .le-slot-input.has-error input,:host(.admin-mode) .le-slot-input.has-error textarea{border-color:var(--le-slot-required-color);background:rgba(229, 57, 53, 0.05)}:host(.admin-mode) .le-slot-input.has-error input:focus,:host(.admin-mode) .le-slot-input.has-error textarea:focus{border-color:var(--le-slot-required-color);box-shadow:0 0 0 3px rgba(229, 57, 53, 0.15)}.le-slot-add-btn{font-size:24px;line-height:0px;width:12px;height:12px}.le-slot-header-no-label .le-slot-add-btn{font-size:16px}.le-slot-button{width:20px;height:20px}:host(.admin-mode) .le-slot-header-no-label.le-slot-header-text{height:0}";
90
153
 
91
- const LeCheckbox = class {
92
- constructor(hostRef) {
93
- registerInstance(this, hostRef);
94
- this.leChange = createEvent(this, "change");
154
+ const LeSlot = /*@__PURE__*/ proxyCustomElement(class LeSlot extends HTMLElement {
155
+ constructor(registerHost) {
156
+ super();
157
+ if (registerHost !== false) {
158
+ this.__registerHost();
159
+ }
160
+ this.__attachShadow();
161
+ this.leSlotChange = createEvent(this, "leSlotChange", 7);
95
162
  }
96
- get el() { return getElement(this); }
163
+ get el() { return this; }
97
164
  /**
98
- * Whether the checkbox is checked
99
- */
100
- checked = false;
101
- /**
102
- * Whether the checkbox is disabled
165
+ * The type of slot content.
166
+ * - `slot`: Default, shows a dropzone for components (default)
167
+ * - `text`: Shows a single-line text input
168
+ * - `textarea`: Shows a multi-line text area
103
169
  */
104
- disabled = false;
170
+ type = 'slot';
105
171
  /**
106
- * The name of the checkbox input
172
+ * The name of the slot this placeholder represents.
173
+ * Should match the slot name in the parent component.
107
174
  */
108
- name;
175
+ name = '';
109
176
  /**
110
- * The value of the checkbox input
177
+ * Label to display in admin mode.
178
+ * If not provided, the slot name will be used.
111
179
  */
112
- value;
180
+ label;
113
181
  /**
114
- * External ID for linking with external systems (e.g. database ID, PDF form field ID)
182
+ * Description of what content this slot accepts.
183
+ * Shown in admin mode to guide content editors.
115
184
  */
116
- externalId;
185
+ description;
117
186
  /**
118
- * Emitted when the checked state changes
187
+ * Comma-separated list of allowed component tags for this slot.
188
+ * Used by CMS to filter available components.
189
+ *
190
+ * @example "le-card,le-button,le-text"
119
191
  */
120
- leChange;
121
- handleChange = (event) => {
122
- // We stop the internal button click from bubbling up
123
- event.stopPropagation();
124
- if (this.disabled) {
125
- event.preventDefault();
126
- return;
127
- }
128
- const input = event.target;
129
- this.checked = input.checked;
130
- this.leChange.emit({
131
- checked: this.checked,
132
- value: this.value,
133
- name: this.name,
134
- externalId: this.externalId
135
- });
136
- };
137
- render() {
138
- return (h("le-component", { key: '43399929e07835e0019d509803e50a151921fa72', component: "le-checkbox", hostClass: classnames({ 'disabled': this.disabled }) }, h("div", { key: '7ddbf2ac1690bb09082adfea70b9767c972d007a', class: "le-checkbox-wrapper" }, h("label", { key: '8eec4055c713e8b3b155695751b10bff64c9f903', class: "le-checkbox-label" }, h("span", { key: '2118b1cbe7911ff1674e522d723949d81cade185', class: "le-checkbox-input" }, h("input", { key: 'd0a30af5c14497fa6fa294c07ba74ae2e032481f', type: "checkbox", name: this.name, value: this.value, checked: this.checked, disabled: this.disabled, onChange: this.handleChange })), h("span", { key: '02cf9588431240039a53ee50e02b08ba5d63b974', class: "le-checkbox-text" }, h("le-slot", { key: 'e7d7b253deab72e627164eb72fc06109abfca6a5', name: "", type: "text", tag: "span" }, h("slot", { key: '1d8c443073e48848513a8a6d04cd7805a394e54e' })))), h("div", { key: '16c2c927dc0c0f7844a203a0628bf0e561009bd0', class: "le-checkbox-description" }, h("le-slot", { key: 'c6898ecc8992dce4786e68ab4b136bf5c3a4d3aa', name: "description", type: "text", tag: "div", label: "Description" }, h("slot", { key: '3342add8ed1400ab74681e445163eeb3dd415941', name: "description" }))))));
139
- }
140
- };
141
- LeCheckbox.style = leCheckboxCss;
142
-
143
- const leComponentCss = ":host{display:contents}:host(.admin-mode){display:block}.le-component-wrapper{position:relative;border:2px dashed var(--le-admin-border-color, #90caf9);border-radius:var(--le-radius-md, 8px);background:var(--le-admin-bg, rgba(144, 202, 249, 0.05));transition:border-color 0.2s ease, box-shadow 0.2s ease}.le-component-wrapper:hover{border-color:var(--le-admin-border-hover, #42a5f5);box-shadow:0 0 0 2px var(--le-admin-glow, rgba(66, 165, 245, 0.2))}.le-component-header{display:flex;align-items:center;justify-content:space-between;gap:var(--le-spacing-1, 4px);padding:0 0 0 var(--le-spacing-1, 4px);background:var(--le-admin-header-bg, rgba(144, 202, 249, 0.15));border-bottom:1px solid var(--le-admin-border-color, #90caf9);border-radius:var(--le-radius-md, 8px) var(--le-radius-md, 8px) 0 0;font-size:var(--le-font-size-xs, 11px)}.le-component-name{font-weight:var(--le-font-weight-medium, 500);color:var(--le-admin-text, #1976d2);text-transform:capitalize;text-align:start;overflow:hidden;width:0;flex:1 1 0%}.le-component-content{padding:var(--le-space-xs, 4px)}.le-component-trigger{font-size:24px;line-height:0px;width:12px;height:12px}.le-component-button{width:20px}.property-editor{display:flex;flex-direction:column;gap:var(--le-space-sm, 8px);max-width:380px}.property-field{display:flex;flex-direction:column;gap:var(--le-space-xs, 4px)}.property-field label{display:flex;flex-direction:column;gap:2px;font-size:var(--le-font-size-sm, 13px);font-weight:var(--le-font-weight-medium, 500);color:var(--le-color-text, #333)}.property-hint{font-size:var(--le-font-size-xs, 11px);font-weight:normal;color:var(--le-color-text-secondary, #666);line-height:1.3}.property-field input[type=\"text\"],.property-field input[type=\"number\"],.property-field select{padding:var(--le-space-xs, 4px) var(--le-space-sm, 8px);border:1px solid var(--le-color-border, #ddd);border-radius:var(--le-radius-md, 7px);font-size:var(--le-font-size-sm, 13px);font-family:inherit;background:var(--le-color-surface, #fff);color:var(--le-color-text, #333);transition:border-color 0.15s ease, box-shadow 0.15s ease}.property-field input:focus,.property-field select:focus{outline:none;border-color:var(--le-color-primary, #1976d2);box-shadow:0 0 0 2px var(--le-color-primary-light, rgba(25, 118, 210, 0.2))}.property-field--checkbox{flex-direction:column}.property-field--checkbox label{flex-direction:row;align-items:center;gap:var(--le-space-sm, 8px);cursor:pointer}.property-field--checkbox input[type=\"checkbox\"]{width:16px;height:16px;margin:0;cursor:pointer;accent-color:var(--le-color-primary, #1976d2)}.property-field--checkbox .property-hint{margin-left:24px}.no-properties{margin:0;padding:var(--le-space-sm, 8px);font-size:var(--le-font-size-sm, 13px);color:var(--le-color-text-secondary, #666);text-align:center}.property-editor-container{display:flex;flex-direction:column;gap:var(--le-space-md, 12px)}.property-editor-actions{padding-top:var(--le-space-sm, 8px);border-top:1px solid var(--le-color-border, #e5e5e5)}.delete-component-btn{display:flex;align-items:center;justify-content:center;gap:var(--le-space-xs, 4px);width:100%;padding:var(--le-space-sm, 8px) var(--le-space-md, 12px);border:1px solid var(--le-color-danger, #e53935);border-radius:var(--le-radius-md, 6px);background:transparent;color:var(--le-color-danger, #e53935);font-size:var(--le-font-size-sm, 13px);font-weight:500;cursor:pointer;transition:background-color 0.15s, color 0.15s}.delete-component-btn:hover{background:var(--le-color-danger, #e53935);color:white}.delete-component-btn:active{opacity:0.9}";
144
-
145
- const LeComponent = class {
146
- constructor(hostRef) {
147
- registerInstance(this, hostRef);
148
- }
149
- get el() { return getElement(this); }
192
+ allowedComponents;
150
193
  /**
151
- * The tag name of the component (e.g., 'le-card').
152
- * Used to look up property metadata and display the component name.
194
+ * Whether multiple components can be dropped in this slot.
153
195
  */
154
- component;
196
+ multiple = true;
155
197
  /**
156
- * Optional display name for the component.
157
- * If not provided, the tag name will be formatted as the display name.
198
+ * Whether this slot is required to have content.
158
199
  */
159
- displayName;
200
+ required = false;
160
201
  /**
161
- * Classes to apply to the host element.
162
- * Allows parent components to pass their styling classes.
202
+ * Placeholder text for text/textarea inputs in admin mode.
163
203
  */
164
- hostClass;
204
+ placeholder;
165
205
  /**
166
- * Inline styles to apply to the host element.
167
- * Allows parent components to pass dynamic styles (e.g., flex properties).
206
+ * The HTML tag to create when there's no slotted element.
207
+ * Used with type="text" or type="textarea" to auto-create elements.
208
+ *
209
+ * @example "h3" - creates <h3 slot="header">content</h3>
210
+ * @example "p" - creates <p slot="content">content</p>
168
211
  */
169
- hostStyle;
212
+ tag;
170
213
  /**
171
- * Reference to the host element (found automatically from parent)
214
+ * CSS styles for the slot dropzone container.
215
+ * Useful for layouts - e.g., "flex-direction: row" for horizontal stacks.
216
+ * Only applies in admin mode for type="slot".
172
217
  */
173
- hostElement;
218
+ slotStyle;
174
219
  /**
175
220
  * Internal state to track admin mode
176
221
  */
177
222
  adminMode = false;
178
223
  /**
179
- * Component metadata loaded from Custom Elements Manifest
224
+ * Internal state for text input value (synced from slot content)
180
225
  */
181
- componentMeta = null;
226
+ textValue = '';
182
227
  /**
183
- * Current property values of the host component
228
+ * Whether the current textValue contains valid HTML
184
229
  */
185
- propertyValues = {};
230
+ isValidHtml = true;
231
+ /**
232
+ * Available components loaded from Custom Elements Manifest
233
+ */
234
+ availableComponents = [];
235
+ /**
236
+ * Whether the component picker popover is open
237
+ */
238
+ pickerOpen = false;
239
+ /**
240
+ * Reference to the slot element to access assignedNodes
241
+ */
242
+ slotRef;
243
+ /**
244
+ * The original slotted element (e.g., <h3 slot="header">)
245
+ */
246
+ slottedElement;
247
+ /**
248
+ * Emitted when text content changes in admin mode.
249
+ * The event detail contains the new text value and validity.
250
+ */
251
+ leSlotChange;
186
252
  disconnectModeObserver;
187
253
  connectedCallback() {
188
- // Find the host element - le-component is rendered inside the component's shadow DOM,
189
- // so we need to find the shadow root's host element
190
- this.findHostElement();
191
254
  this.disconnectModeObserver = observeModeChanges(this.el, mode => {
255
+ const wasAdmin = this.adminMode;
192
256
  this.adminMode = mode === 'admin';
193
- // Load metadata and refresh property values only when entering admin mode
194
- if (this.adminMode) {
195
- if (!this.componentMeta) {
196
- this.loadComponentMetadata();
197
- }
198
- else {
199
- this.readPropertyValues();
257
+ // When entering admin mode, read content from slotted elements
258
+ if (this.adminMode && !wasAdmin) {
259
+ // Need to wait for render to access slot ref
260
+ requestAnimationFrame(() => this.readSlottedContent());
261
+ // Load available components for the component picker
262
+ if (this.type === 'slot') {
263
+ this.loadAvailableComponents();
200
264
  }
201
265
  }
202
266
  });
203
267
  }
204
- /**
205
- * Find the host element by traversing up through shadow DOM
206
- */
207
- findHostElement() {
208
- // Get the shadow root that contains this le-component
209
- const rootNode = this.el.getRootNode();
210
- if (rootNode instanceof ShadowRoot) {
211
- // The host of this shadow root is our target component (e.g., le-card)
212
- this.hostElement = rootNode.host;
213
- }
214
- }
215
- componentDidLoad() {
216
- // Read initial property values from the host element
217
- this.readPropertyValues();
218
- }
219
268
  disconnectedCallback() {
220
269
  this.disconnectModeObserver?.();
221
270
  }
222
271
  /**
223
- * Formats a tag name into a display name
224
- * e.g., 'le-card' -> 'Card'
272
+ * Flag to prevent re-reading content right after we updated it
225
273
  */
226
- formatDisplayName(tagName) {
227
- return tagName
228
- .replace(/^le-/, '') // Remove 'le-' prefix
229
- .split('-')
230
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
231
- .join(' ');
232
- }
274
+ isUpdating = false;
233
275
  /**
234
- * Load component metadata from the Custom Elements Manifest
276
+ * Read content from slotted elements via assignedNodes()
235
277
  */
236
- async loadComponentMetadata() {
237
- try {
238
- // Fetch the manifest from configured URL
239
- const { manifestUrl } = getLeKitConfig();
240
- const manifestUrlResolved = manifestUrl.startsWith('/')
241
- ? getAssetPath(`./assets${manifestUrl}`)
242
- : manifestUrl;
243
- const response = await fetch(manifestUrlResolved);
244
- const manifest = await response.json();
245
- // Find the component definition
246
- for (const module of manifest.modules) {
247
- for (const declaration of module.declarations || []) {
248
- if (declaration.tagName === this.component) {
249
- const attributes = (declaration.attributes || []).filter((attr) => !this.isInternalAttribute(attr.name));
250
- this.componentMeta = {
251
- tagName: declaration.tagName,
252
- description: declaration.description,
253
- attributes,
254
- };
255
- // console.log(`[le-component] Loaded metadata for ${this.component}:`, this.componentMeta);
256
- // Read property values after metadata is loaded
257
- this.readPropertyValues();
258
- return;
259
- }
278
+ readSlottedContent() {
279
+ if (!this.slotRef)
280
+ return;
281
+ // Skip if we just updated the content ourselves
282
+ if (this.isUpdating) {
283
+ this.isUpdating = false;
284
+ return;
285
+ }
286
+ const assignedNodes = this.slotRef.assignedNodes({ flatten: true });
287
+ // For text/textarea types, we want to edit the innerHTML of slotted elements
288
+ if (this.type === 'text' || this.type === 'textarea') {
289
+ // Find the first element node (skip text nodes that are just whitespace)
290
+ const elementNode = assignedNodes.find(node => node.nodeType === Node.ELEMENT_NODE);
291
+ if (elementNode) {
292
+ // Only update textValue if slotted element changed or we don't have one yet
293
+ if (this.slottedElement !== elementNode) {
294
+ this.slottedElement = elementNode;
295
+ this.textValue = elementNode.innerHTML?.trim() || '';
296
+ // console.log(`[le-slot "${this.name}"] Read slotted content:`, this.textValue);
297
+ }
298
+ }
299
+ else {
300
+ // No element, check for direct text content
301
+ const textContent = assignedNodes
302
+ .filter(node => node.nodeType === Node.TEXT_NODE)
303
+ .map(node => node.textContent)
304
+ .join('')
305
+ .trim();
306
+ if (textContent && !this.textValue) {
307
+ this.textValue = textContent;
308
+ // console.log(`[le-slot "${this.name}"] Read text content:`, this.textValue);
260
309
  }
261
310
  }
262
- // console.warn(`[le-component] No metadata found for component: ${this.component}`);
263
- }
264
- catch (error) {
265
- // console.warn(`[le-component] Failed to load metadata for component: ${this.component}`, error);
266
311
  }
267
312
  }
268
313
  /**
269
- * Check if an attribute is internal (should not be shown in editor)
314
+ * Validates if a string contains valid HTML
270
315
  */
271
- isInternalAttribute(name) {
272
- const internalAttrs = ['mode', 'theme', 'class', 'style', 'id', 'slot'];
273
- return internalAttrs.includes(name);
316
+ validateHtml(html) {
317
+ // Empty string is valid
318
+ if (!html.trim())
319
+ return true;
320
+ // Create a template element to parse the HTML
321
+ const template = document.createElement('template');
322
+ template.innerHTML = html;
323
+ // Check that we don't have obviously broken HTML
324
+ // Count opening and closing tags for common elements
325
+ const openTags = (html.match(/<[a-z][^>]*(?<!\/)>/gi) || []).length;
326
+ const closeTags = (html.match(/<\/[a-z][^>]*>/gi) || []).length;
327
+ const selfClosing = (html.match(/<[a-z][^>]*\/>/gi) || []).length;
328
+ // Simple validation: opening tags (minus self-closing) should roughly match closing tags
329
+ // Allow some tolerance for void elements like <br>, <img>, etc.
330
+ const voidElements = (html.match(/<(br|hr|img|input|meta|link|area|base|col|embed|param|source|track|wbr)[^>]*>/gi) || []).length;
331
+ const effectiveOpenTags = openTags - selfClosing - voidElements;
332
+ // If difference is too large, HTML is likely broken
333
+ if (Math.abs(effectiveOpenTags - closeTags) > 1) {
334
+ return false;
335
+ }
336
+ return true;
274
337
  }
338
+ handleTextInput = (event) => {
339
+ const target = event.target;
340
+ this.textValue = target.value;
341
+ this.isValidHtml = this.validateHtml(this.textValue);
342
+ if (this.isValidHtml) {
343
+ // Set flag to prevent slotchange from re-reading what we just wrote
344
+ this.isUpdating = true;
345
+ console.log('Updating text value:', this.textValue, 'slottedElement:', this.slottedElement);
346
+ if (this.slottedElement) {
347
+ // Update existing slotted element's innerHTML
348
+ this.slottedElement.innerHTML = this.textValue;
349
+ }
350
+ else if (this.tag && this.textValue) {
351
+ // No slotted element exists
352
+ // If the slot doesn't have a name, then it's the default slot
353
+ // remove the existing non-slotted content (text nodes and elements without slot attribute)
354
+ const rootNode = this.el.getRootNode();
355
+ if (!this.name && rootNode instanceof ShadowRoot) {
356
+ const hostComponent = rootNode.host;
357
+ Array.from(hostComponent.childNodes).forEach(node => {
358
+ if (node.nodeType === Node.TEXT_NODE || (node.nodeType === Node.ELEMENT_NODE && !node.hasAttribute('slot'))) {
359
+ node.remove();
360
+ }
361
+ });
362
+ }
363
+ // create one using the specified tag
364
+ this.createSlottedElement();
365
+ }
366
+ else if (this.textValue) {
367
+ // no tag specified - just replace everything in the host component
368
+ const rootNode = this.el.getRootNode();
369
+ if (rootNode instanceof ShadowRoot) {
370
+ const hostComponent = rootNode.host;
371
+ hostComponent.innerHTML = this.textValue;
372
+ }
373
+ }
374
+ }
375
+ this.leSlotChange.emit({
376
+ name: this.name,
377
+ value: this.textValue,
378
+ isValid: this.isValidHtml,
379
+ });
380
+ };
275
381
  /**
276
- * Read current property values from the host element
382
+ * Create a new slotted element when none exists.
383
+ * The element is appended to the host component's light DOM.
277
384
  */
278
- readPropertyValues() {
279
- if (!this.hostElement || !this.componentMeta)
385
+ createSlottedElement() {
386
+ if (!this.tag)
280
387
  return;
281
- const values = {};
282
- for (const attr of this.componentMeta.attributes) {
283
- const value = this.hostElement.getAttribute(attr.name);
284
- values[attr.name] = this.parseAttributeValue(value, attr.type?.text);
388
+ // Find the host component (le-card, etc.) by traversing up through shadow DOM
389
+ // le-slot is inside le-card's shadow DOM, so we need to find le-card's host
390
+ const rootNode = this.el.getRootNode();
391
+ if (!(rootNode instanceof ShadowRoot))
392
+ return;
393
+ const hostComponent = rootNode.host;
394
+ if (!hostComponent)
395
+ return;
396
+ // Create the new element
397
+ const newElement = document.createElement(this.tag);
398
+ newElement.innerHTML = this.textValue;
399
+ // Set the slot attribute if this is a named slot
400
+ if (this.name) {
401
+ newElement.setAttribute('slot', this.name);
285
402
  }
286
- this.propertyValues = values;
403
+ // Append to the host component's light DOM
404
+ hostComponent.appendChild(newElement);
405
+ // Store reference to the new element
406
+ this.slottedElement = newElement;
407
+ // console.log(`[le-slot "${this.name}"] Created new <${this.tag}> element`);
287
408
  }
288
409
  /**
289
- * Parse an attribute value based on its type
410
+ * Load available components from Custom Elements Manifest
290
411
  */
291
- parseAttributeValue(value, type) {
292
- if (value === null)
293
- return undefined;
294
- if (type === 'boolean') {
295
- return value !== null && value !== 'false';
412
+ async loadAvailableComponents() {
413
+ try {
414
+ const { manifestFile } = getLeKitConfig();
415
+ const manifestFileResolved = getAssetPath(`./assets/${manifestFile}`);
416
+ const response = await fetch(manifestFileResolved);
417
+ const manifest = await response.json();
418
+ const components = [];
419
+ const allowedList = this.allowedComponents?.split(',').map(s => s.trim()) || [];
420
+ for (const module of manifest.modules) {
421
+ for (const declaration of module.declarations || []) {
422
+ if (declaration.tagName && declaration.customElement) {
423
+ // Skip internal components (le-slot, le-component, le-popover)
424
+ const isInternal = ['le-slot', 'le-component', 'le-popover'].includes(declaration.tagName);
425
+ if (isInternal)
426
+ continue;
427
+ // If allowedComponents is specified, filter by it
428
+ if (allowedList.length > 0 && !allowedList.includes(declaration.tagName)) {
429
+ continue;
430
+ }
431
+ components.push({
432
+ tagName: declaration.tagName,
433
+ name: this.formatComponentName(declaration.tagName),
434
+ description: declaration.description || '',
435
+ });
436
+ }
437
+ }
438
+ }
439
+ this.availableComponents = components || [];
296
440
  }
297
- if (type === 'number') {
298
- return parseFloat(value);
441
+ catch (error) {
442
+ console.warn('[le-slot] Failed to load component manifest:', error);
299
443
  }
300
- return value;
301
444
  }
302
445
  /**
303
- * Handle property value changes from the editor
446
+ * Format a tag name into a display name
447
+ * e.g., 'le-card' -> 'Card'
304
448
  */
305
- handlePropertyChange(attrName, value, type) {
306
- if (!this.hostElement)
307
- return;
308
- // Update the host element's attribute
309
- if (type === 'boolean') {
310
- if (value) {
311
- this.hostElement.setAttribute(attrName, '');
312
- }
313
- else {
314
- this.hostElement.removeAttribute(attrName);
315
- }
316
- }
317
- else if (value === undefined || value === '') {
318
- this.hostElement.removeAttribute(attrName);
319
- }
320
- else {
321
- this.hostElement.setAttribute(attrName, String(value));
322
- }
323
- // Update local state
324
- this.propertyValues = { ...this.propertyValues, [attrName]: value };
449
+ formatComponentName(tagName) {
450
+ return tagName
451
+ .replace(/^le-/, '')
452
+ .split('-')
453
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
454
+ .join(' ');
325
455
  }
326
456
  /**
327
- * Delete this component from the DOM
457
+ * Add a new component to the slot
328
458
  */
329
- deleteComponent() {
330
- if (!this.hostElement)
459
+ addComponent(tagName) {
460
+ // Find the host component by traversing up through shadow DOM
461
+ const rootNode = this.el.getRootNode();
462
+ if (!(rootNode instanceof ShadowRoot))
331
463
  return;
332
- // Confirm deletion
333
- const name = this.displayName || this.formatDisplayName(this.component);
334
- if (!confirm(`Delete this ${name}?`))
464
+ const hostComponent = rootNode.host;
465
+ if (!hostComponent)
335
466
  return;
336
- // Remove the host element from its parent
337
- const parent = this.hostElement.parentElement;
338
- if (parent) {
339
- this.hostElement.remove();
467
+ // Create the new component element
468
+ const newElement = document.createElement(tagName);
469
+ // Set the slot attribute if this is a named slot
470
+ if (this.name) {
471
+ newElement.setAttribute('slot', this.name);
340
472
  }
473
+ // Append to the host component's light DOM
474
+ hostComponent.appendChild(newElement);
475
+ // Emit change event so the page can save
476
+ this.leSlotChange.emit({
477
+ name: this.name,
478
+ value: hostComponent.innerHTML,
479
+ isValid: true,
480
+ });
341
481
  }
342
482
  /**
343
- * Render the property editor form
344
- */
345
- renderPropertyEditor() {
346
- const hasProperties = this.componentMeta && this.componentMeta.attributes.length > 0;
347
- return (h("div", { class: "property-editor-container" }, hasProperties ? (h("form", { class: "property-editor", onSubmit: e => e.preventDefault() }, this.componentMeta.attributes.map(attr => this.renderPropertyField(attr)))) : (h("p", { class: "no-properties" }, "No editable properties")), h("div", { class: "property-editor-actions" }, h("le-button", { type: "button", variant: "outlined", color: "danger", "full-width": true, onClick: () => this.deleteComponent() }, h("span", { slot: "icon-start" }, "\uD83D\uDDD1\uFE0F"), h("span", null, "Delete Component")))));
348
- }
349
- /**
350
- * Render a single property field based on its type
483
+ * Handle slot change event to re-read content when nodes are assigned
351
484
  */
352
- renderPropertyField(attr) {
353
- const value = this.propertyValues[attr.name];
354
- const type = attr.type?.text || 'string';
355
- // Check if type is a union of string literals (e.g., "'default' | 'outlined' | 'elevated'")
356
- const enumMatch = type.match(/^'[^']+'/);
357
- if (enumMatch) {
358
- const options = type.split('|').map(opt => opt.trim().replace(/'/g, ''));
359
- return (h("div", { class: "property-field" }, h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && h("span", { class: "property-hint" }, attr.description)), h("select", { id: `prop-${attr.name}`, onChange: e => this.handlePropertyChange(attr.name, e.target.value, type) }, options.map(opt => (h("option", { value: opt, selected: value === opt || (!value && attr.default?.replace(/'/g, '') === opt) }, opt))))));
360
- }
361
- // Boolean type
362
- if (type === 'boolean') {
363
- return (h("div", { class: "property-field property-field--checkbox" }, h("le-checkbox", { name: `prop-${attr.name}`, checked: value === true || value === '', onChange: e => this.handlePropertyChange(attr.name, e.target.checked, type) }, attr.name, attr.description && h("div", { slot: "description" }, attr.description))));
364
- }
365
- // Number type
366
- if (type === 'number') {
367
- return (h("div", { class: "property-field" }, h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && h("span", { class: "property-hint" }, attr.description)), h("input", { type: "number", id: `prop-${attr.name}`, value: value ?? '', placeholder: attr.default, onChange: e => this.handlePropertyChange(attr.name, e.target.value, type) })));
368
- }
369
- // Default: string/text input
370
- return (h("div", { class: "property-field" }, h("le-string-input", { name: `prop-${attr.name}`, label: attr.name, value: value ?? '', placeholder: attr.default?.replace(/'/g, ''), onChange: (e) => this.handlePropertyChange(attr.name, e.detail.value, type) }, h("span", { slot: "description" }, attr.description))));
371
- }
485
+ handleSlotChange = () => {
486
+ this.readSlottedContent();
487
+ };
372
488
  render() {
373
- const name = this.displayName || this.formatDisplayName(this.component);
374
- // In default mode, just pass through content with host classes
375
- if (!this.adminMode) {
376
- return (h(Host, { class: classnames(this.component, this.hostClass), style: this.hostStyle }, h("slot", null)));
489
+ const displayLabel = this.label || this.name;
490
+ // Always render the same structure, CSS handles visibility via .admin-mode class
491
+ return (h(Host, { key: '0ffbcff05009d390a4de52aac1395c4c769ed948', class: {
492
+ 'admin-mode': this.adminMode,
493
+ 'invalid-html': !this.isValidHtml,
494
+ }, role: this.adminMode ? 'region' : undefined, "aria-label": this.adminMode ? `Slot: ${displayLabel}` : undefined, "data-slot-name": this.name, "data-slot-type": this.type, "data-allowed": this.allowedComponents, "data-multiple": this.multiple, "data-required": this.required }, this.adminMode ? (h("div", { class: "le-slot-container" }, h("div", { class: classnames('le-slot-header', {
495
+ 'le-slot-header-no-label': !displayLabel,
496
+ 'le-slot-header-text': this.type === 'text',
497
+ 'le-slot-header-error': !this.isValidHtml,
498
+ }) }, displayLabel && (h("span", { class: "le-slot-label" }, displayLabel, this.required && h("span", { class: "le-slot-required" }, "*"))), !this.isValidHtml && h("span", { class: "le-slot-invalid" }, "\u26A0 Invalid HTML"), this.type === 'slot' && this.adminMode && (h("le-popover", { mode: "default", showClose: true, align: "start", position: "right", popoverTitle: "Add Component", open: this.pickerOpen, onLePopoverOpen: () => (this.pickerOpen = true), onLePopoverClose: () => (this.pickerOpen = false) }, h("le-button", { type: "button", class: "le-slot-button", slot: "trigger", variant: "clear", size: "small", "aria-label": "Add component", "icon-only": true }, h("span", { class: "le-slot-add-btn", slot: "icon-only" }, "+")), h("div", { class: "le-slot-picker" }, this.availableComponents.length > 0 ? (h("ul", { class: "le-slot-picker-list" }, this.availableComponents.map(component => (h("li", { key: component.tagName }, h("button", { class: "le-slot-picker-item", onClick: () => {
499
+ this.addComponent(component.tagName);
500
+ this.pickerOpen = false;
501
+ } }, h("span", { class: "le-slot-picker-name" }, component.name), component.description && h("span", { class: "le-slot-picker-desc" }, component.description))))))) : (h("div", { class: "le-slot-picker-empty" }, "No components available")))))), this.renderContent())) : (
502
+ // In default mode, just pass through the slot - slotted content renders naturally
503
+ // Note: We use unnamed slot here because named slots from parent component
504
+ // are passed as le-slot's light DOM children
505
+ h("slot", null))));
506
+ }
507
+ renderContent() {
508
+ // Create the slot element with ref for reading assignedNodes
509
+ // Wrap in a hidden div since slot elements can't have style prop in Stencil
510
+ // Note: We use unnamed slot here because named slots from parent component
511
+ // are passed as le-slot's light DOM children
512
+ const slotElement = (h("div", { class: "hidden-slot" }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
513
+ switch (this.type) {
514
+ case 'text':
515
+ return (h("div", { class: { 'le-slot-input': true, 'has-error': !this.isValidHtml } }, h("le-string-input", { mode: "default", value: this.textValue, placeholder: this.placeholder || `Enter ${this.label || this.name || 'text'}...`, onChange: this.handleTextInput }), slotElement));
516
+ case 'textarea':
517
+ return (h("div", { class: { 'le-slot-input': true, 'has-error': !this.isValidHtml } }, h("textarea", { value: this.textValue, placeholder: this.placeholder || `Enter ${this.label || this.name || 'text'}...`, onInput: this.handleTextInput, required: this.required, rows: 3 }), slotElement));
518
+ case 'slot':
519
+ default:
520
+ // Parse slotStyle string into style object if provided
521
+ const dropzoneStyle = {};
522
+ if (this.slotStyle) {
523
+ this.slotStyle.split(';').forEach(rule => {
524
+ const [prop, value] = rule.split(':').map(s => s.trim());
525
+ if (prop && value) {
526
+ // Convert kebab-case to camelCase for style object
527
+ const camelProp = prop.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
528
+ dropzoneStyle[camelProp] = value;
529
+ }
530
+ });
531
+ }
532
+ return (h("div", { class: "le-slot-dropzone", style: dropzoneStyle }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
377
533
  }
378
- // In admin mode, show wrapper with header and settings
379
- return (h(Host, { class: classnames(this.component, this.hostClass, 'admin-mode'), style: this.hostStyle }, h("div", { class: "le-component-wrapper" }, h("div", { class: "le-component-header" }, h("span", { class: "le-component-name" }, name), h("le-popover", { popoverTitle: `${name} Settings`, position: "right", align: "start", "min-width": "300px", mode: "default" }, h("le-button", { type: "button", class: "le-component-button", slot: "trigger", variant: "clear", size: "small", "aria-label": "Edit component properties", "icon-only": true }, h("span", { class: "le-component-trigger", slot: "icon-only" }, "\u2699")), this.renderPropertyEditor())), h("div", { class: "le-component-content" }, h("slot", null)))));
380
534
  }
381
- };
382
- LeComponent.style = leComponentCss;
535
+ static get style() { return leSlotDefaultCss; }
536
+ }, [769, "le-slot", {
537
+ "type": [1],
538
+ "name": [1],
539
+ "label": [1],
540
+ "description": [1],
541
+ "allowedComponents": [1, "allowed-components"],
542
+ "multiple": [4],
543
+ "required": [4],
544
+ "placeholder": [1],
545
+ "tag": [1],
546
+ "slotStyle": [1, "slot-style"],
547
+ "adminMode": [32],
548
+ "textValue": [32],
549
+ "isValidHtml": [32],
550
+ "availableComponents": [32],
551
+ "pickerOpen": [32]
552
+ }]);
553
+ function defineCustomElement$3() {
554
+ if (typeof customElements === "undefined") {
555
+ return;
556
+ }
557
+ const components = ["le-slot", "le-button", "le-checkbox", "le-component", "le-popover", "le-slot", "le-string-input"];
558
+ components.forEach(tagName => { switch (tagName) {
559
+ case "le-slot":
560
+ if (!customElements.get(tagName)) {
561
+ customElements.define(tagName, LeSlot);
562
+ }
563
+ break;
564
+ case "le-button":
565
+ if (!customElements.get(tagName)) {
566
+ defineCustomElement();
567
+ }
568
+ break;
569
+ case "le-checkbox":
570
+ if (!customElements.get(tagName)) {
571
+ defineCustomElement$1();
572
+ }
573
+ break;
574
+ case "le-component":
575
+ if (!customElements.get(tagName)) {
576
+ defineCustomElement$2();
577
+ }
578
+ break;
579
+ case "le-popover":
580
+ if (!customElements.get(tagName)) {
581
+ defineCustomElement$5();
582
+ }
583
+ break;
584
+ case "le-slot":
585
+ if (!customElements.get(tagName)) {
586
+ defineCustomElement$3();
587
+ }
588
+ break;
589
+ case "le-string-input":
590
+ if (!customElements.get(tagName)) {
591
+ defineCustomElement$4();
592
+ }
593
+ break;
594
+ } });
595
+ }
383
596
 
384
- const lePopoverCss = "/* ============================================\n le-popover.css\n Popover using native HTML Popover API\n ============================================ */\n\n:host {\n display: inline-block;\n position: relative;\n}\n\n/* ============================================\n Trigger\n ============================================ */\n\n.le-popover-trigger {\n display: inline-flex;\n cursor: pointer;\n}\n\n.le-popover-default-trigger {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 1px solid var(--le-color-border, #e0e0e0);\n border-radius: var(--le-radius-md, 6px);\n background: var(--le-color-surface, #fff);\n color: var(--le-color-text-secondary, #666);\n font-size: 16px;\n cursor: pointer;\n transition: all var(--le-transition-fast, 0.15s ease);\n}\n\n.le-popover-default-trigger:hover {\n border-color: var(--le-color-primary, #2196f3);\n color: var(--le-color-primary, #2196f3);\n background: var(--le-color-primary-light, rgba(33, 150, 243, 0.1));\n}\n\n/* ============================================\n Popover Content (native popover)\n ============================================ */\n\n.le-popover-content {\n /* Reset native popover defaults */\n margin: 0;\n padding: 0;\n border: none;\n background: transparent;\n \n /* Positioning - will be set via JS */\n position: fixed;\n inset: unset;\n \n /* Styling */\n background: var(--le-color-surface, #ffffff);\n border: 1px solid var(--le-color-border, #e0e0e0);\n border-radius: var(--le-radius-lg, 8px);\n box-shadow: var(--le-shadow-lg, 0 4px 12px rgba(0, 0, 0, 0.15));\n overflow: hidden;\n font-family: var(--le-font-family, system-ui, -apple-system, sans-serif);\n font-size: var(--le-font-size-sm, 0.875rem);\n color: var(--le-color-text, #333);\n \n /* Animation */\n opacity: 0;\n transform: scale(0.95);\n transition: opacity 0.15s ease, transform 0.15s ease, display 0.15s ease allow-discrete;\n}\n\n/* When popover is open */\n.le-popover-content:popover-open {\n opacity: 1;\n transform: scale(1);\n}\n\n/* Starting style for animation (CSS Anchor Positioning spec) */\n@starting-style {\n .le-popover-content:popover-open {\n opacity: 0;\n transform: scale(0.95);\n }\n}\n\n/* ============================================\n Header\n ============================================ */\n\n.le-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--le-space-xs, 4px) var(--le-space-xs, 4px) var(--le-space-xs, 4px) var(--le-space-sm, 8px);\n border-bottom: 1px solid var(--le-color-border, #e0e0e0);\n background: var(--le-color-surface-alt, #f9f9f9);\n min-height: 32px;\n}\n\n.le-popover-title {\n font-weight: var(--le-font-weight-semibold, 600);\n font-size: var(--le-font-size-sm, 0.875rem);\n color: var(--le-color-text, #333);\n}\n\n.le-popover-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--le-color-text-secondary, #666);\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n border-radius: var(--le-radius-sm, 4px);\n transition: background-color 0.15s, color 0.15s;\n}\n\n.le-popover-close:hover {\n background: var(--le-color-surface-hover, rgba(0, 0, 0, 0.05));\n color: var(--le-color-text, #333);\n}\n\n/* ============================================\n Body\n ============================================ */\n\n.le-popover-body {\n padding: var(--le-space-md, 12px);\n}\n\n/* ============================================\n Scrollable content\n ============================================ */\n\n.le-popover-content[style*=\"overflow-y: auto\"] .le-popover-body {\n overflow-y: auto;\n}\n";
597
+ const leComponentCss = ":host{display:contents}:host(.admin-mode){display:block}.le-component-wrapper{position:relative;border:2px dashed var(--le-admin-border-color, #90caf9);border-radius:var(--le-radius-md, 8px);background:var(--le-admin-bg, rgba(144, 202, 249, 0.05));transition:border-color 0.2s ease, box-shadow 0.2s ease}.le-component-wrapper:hover{border-color:var(--le-admin-border-hover, #42a5f5);box-shadow:0 0 0 2px var(--le-admin-glow, rgba(66, 165, 245, 0.2))}.le-component-header{display:flex;align-items:center;justify-content:space-between;gap:var(--le-spacing-1, 4px);padding:0 0 0 var(--le-spacing-1, 4px);background:var(--le-admin-header-bg, rgba(144, 202, 249, 0.15));border-bottom:1px solid var(--le-admin-border-color, #90caf9);border-radius:var(--le-radius-md, 8px) var(--le-radius-md, 8px) 0 0;font-size:var(--le-font-size-xs, 11px)}.le-component-name{font-weight:var(--le-font-weight-medium, 500);color:var(--le-admin-text, #1976d2);text-transform:capitalize;text-align:start;overflow:hidden;width:0;flex:1 1 0%}.le-component-content{padding:var(--le-space-xs, 4px)}.le-component-trigger{font-size:24px;line-height:0px;width:12px;height:12px}.le-component-button{width:20px}.property-editor{display:flex;flex-direction:column;gap:var(--le-space-sm, 8px);max-width:380px}.property-field{display:flex;flex-direction:column;gap:var(--le-space-xs, 4px)}.property-field label{display:flex;flex-direction:column;gap:2px;font-size:var(--le-font-size-sm, 13px);font-weight:var(--le-font-weight-medium, 500);color:var(--le-color-text, #333)}.property-hint{font-size:var(--le-font-size-xs, 11px);font-weight:normal;color:var(--le-color-text-secondary, #666);line-height:1.3}.property-field input[type=\"text\"],.property-field input[type=\"number\"],.property-field select{padding:var(--le-space-xs, 4px) var(--le-space-sm, 8px);border:1px solid var(--le-color-border, #ddd);border-radius:var(--le-radius-md, 7px);font-size:var(--le-font-size-sm, 13px);font-family:inherit;background:var(--le-color-surface, #fff);color:var(--le-color-text, #333);transition:border-color 0.15s ease, box-shadow 0.15s ease}.property-field input:focus,.property-field select:focus{outline:none;border-color:var(--le-color-primary, #1976d2);box-shadow:0 0 0 2px var(--le-color-primary-light, rgba(25, 118, 210, 0.2))}.property-field--checkbox{flex-direction:column}.property-field--checkbox label{flex-direction:row;align-items:center;gap:var(--le-space-sm, 8px);cursor:pointer}.property-field--checkbox input[type=\"checkbox\"]{width:16px;height:16px;margin:0;cursor:pointer;accent-color:var(--le-color-primary, #1976d2)}.property-field--checkbox .property-hint{margin-left:24px}.no-properties{margin:0;padding:var(--le-space-sm, 8px);font-size:var(--le-font-size-sm, 13px);color:var(--le-color-text-secondary, #666);text-align:center}.property-editor-container{display:flex;flex-direction:column;gap:var(--le-space-md, 12px)}.property-editor-actions{padding-top:var(--le-space-sm, 8px);border-top:1px solid var(--le-color-border, #e5e5e5)}.delete-component-btn{display:flex;align-items:center;justify-content:center;gap:var(--le-space-xs, 4px);width:100%;padding:var(--le-space-sm, 8px) var(--le-space-md, 12px);border:1px solid var(--le-color-danger, #e53935);border-radius:var(--le-radius-md, 6px);background:transparent;color:var(--le-color-danger, #e53935);font-size:var(--le-font-size-sm, 13px);font-weight:500;cursor:pointer;transition:background-color 0.15s, color 0.15s}.delete-component-btn:hover{background:var(--le-color-danger, #e53935);color:white}.delete-component-btn:active{opacity:0.9}";
385
598
 
386
- const LePopover = class {
387
- constructor(hostRef) {
388
- registerInstance(this, hostRef);
389
- this.lePopoverOpen = createEvent(this, "lePopoverOpen");
390
- this.lePopoverClose = createEvent(this, "lePopoverClose");
599
+ const LeComponent = /*@__PURE__*/ proxyCustomElement(class LeComponent extends HTMLElement {
600
+ constructor(registerHost) {
601
+ super();
602
+ if (registerHost !== false) {
603
+ this.__registerHost();
604
+ }
605
+ this.__attachShadow();
391
606
  }
392
- get el() { return getElement(this); }
393
- /**
394
- * Mode of the popover should be 'default' for internal use
395
- */
396
- mode;
397
- /**
398
- * Whether the popover is currently open
399
- */
400
- open = false;
401
- /**
402
- * Position of the popover relative to its trigger
403
- */
404
- position = 'bottom';
405
- /**
406
- * Alignment of the popover
407
- */
408
- align = 'start';
607
+ get el() { return this; }
409
608
  /**
410
- * Optional title for the popover header
411
- */
412
- popoverTitle;
413
- /**
414
- * Whether to show a close button in the header
609
+ * The tag name of the component (e.g., 'le-card').
610
+ * Used to look up property metadata and display the component name.
415
611
  */
416
- showClose = true;
612
+ component;
417
613
  /**
418
- * Whether clicking outside closes the popover
614
+ * Optional display name for the component.
615
+ * If not provided, the tag name will be formatted as the display name.
419
616
  */
420
- closeOnClickOutside = true;
617
+ displayName;
421
618
  /**
422
- * Whether pressing Escape closes the popover
619
+ * Classes to apply to the host element.
620
+ * Allows parent components to pass their styling classes.
423
621
  */
424
- closeOnEscape = true;
622
+ hostClass;
425
623
  /**
426
- * Offset from the trigger element (in pixels)
624
+ * Inline styles to apply to the host element.
625
+ * Allows parent components to pass dynamic styles (e.g., flex properties).
427
626
  */
428
- offset = 8;
627
+ hostStyle;
429
628
  /**
430
- * Fixed width for the popover (e.g., '300px', '20rem')
629
+ * Reference to the host element (found automatically from parent)
431
630
  */
432
- width;
631
+ hostElement;
433
632
  /**
434
- * Minimum width for the popover (e.g., '200px', '15rem')
633
+ * Internal state to track admin mode
435
634
  */
436
- minWidth = '200px';
635
+ adminMode = false;
437
636
  /**
438
- * Maximum width for the popover (e.g., '400px', '25rem')
637
+ * Component metadata loaded from Custom Elements Manifest
439
638
  */
440
- maxWidth;
639
+ componentMeta = null;
441
640
  /**
442
- * Emitted when the popover opens
641
+ * Current property values of the host component
443
642
  */
444
- lePopoverOpen;
643
+ propertyValues = {};
644
+ disconnectModeObserver;
645
+ connectedCallback() {
646
+ // Find the host element - le-component is rendered inside the component's shadow DOM,
647
+ // so we need to find the shadow root's host element
648
+ this.findHostElement();
649
+ this.disconnectModeObserver = observeModeChanges(this.el, mode => {
650
+ this.adminMode = mode === 'admin';
651
+ // Load metadata and refresh property values only when entering admin mode
652
+ if (this.adminMode) {
653
+ if (!this.componentMeta) {
654
+ this.loadComponentMetadata();
655
+ }
656
+ else {
657
+ this.readPropertyValues();
658
+ }
659
+ }
660
+ });
661
+ }
445
662
  /**
446
- * Emitted when the popover closes
663
+ * Find the host element by traversing up through shadow DOM
447
664
  */
448
- lePopoverClose;
449
- isPositioned = false;
450
- triggerEl;
451
- popoverEl;
452
- uniqueId = `le-popover-${Math.random().toString(36).substr(2, 9)}`;
453
- scrollParents = [];
665
+ findHostElement() {
666
+ // Get the shadow root that contains this le-component
667
+ const rootNode = this.el.getRootNode();
668
+ if (rootNode instanceof ShadowRoot) {
669
+ // The host of this shadow root is our target component (e.g., le-card)
670
+ this.hostElement = rootNode.host;
671
+ }
672
+ }
454
673
  componentDidLoad() {
455
- // Listen for toggle events from the native popover API
456
- this.popoverEl?.addEventListener('toggle', this.handlePopoverToggle);
457
- // Listen for other popovers opening to close this one
458
- document.addEventListener('le-popover-will-open', this.handleOtherPopoverOpen);
674
+ // Read initial property values from the host element
675
+ this.readPropertyValues();
459
676
  }
460
677
  disconnectedCallback() {
461
- this.popoverEl?.removeEventListener('toggle', this.handlePopoverToggle);
462
- document.removeEventListener('le-popover-will-open', this.handleOtherPopoverOpen);
463
- this.removeScrollListeners();
464
- }
465
- /**
466
- * Find all scrollable parent elements
467
- */
468
- getScrollParents(element) {
469
- const scrollParents = [];
470
- let parent = element.parentElement;
471
- while (parent) {
472
- const style = getComputedStyle(parent);
473
- const overflow = style.overflow + style.overflowY + style.overflowX;
474
- if (/(auto|scroll)/.test(overflow)) {
475
- scrollParents.push(parent);
476
- }
477
- parent = parent.parentElement;
478
- }
479
- // Always include window for page scroll
480
- return scrollParents;
678
+ this.disconnectModeObserver?.();
481
679
  }
482
680
  /**
483
- * Add scroll listeners to all scrollable parents
681
+ * Formats a tag name into a display name
682
+ * e.g., 'le-card' -> 'Card'
484
683
  */
485
- addScrollListeners() {
486
- if (!this.triggerEl)
487
- return;
488
- this.scrollParents = this.getScrollParents(this.triggerEl);
489
- // Listen to each scroll parent
490
- this.scrollParents.forEach(parent => {
491
- parent.addEventListener('scroll', this.handleScroll, { passive: true });
492
- });
493
- // Also listen to window scroll and resize
494
- window.addEventListener('scroll', this.handleScroll, { passive: true });
495
- window.addEventListener('resize', this.handleScroll, { passive: true });
684
+ formatDisplayName(tagName) {
685
+ return tagName
686
+ .replace(/^le-/, '') // Remove 'le-' prefix
687
+ .split('-')
688
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
689
+ .join(' ');
496
690
  }
497
691
  /**
498
- * Remove scroll listeners
692
+ * Load component metadata from the Custom Elements Manifest
499
693
  */
500
- removeScrollListeners() {
501
- this.scrollParents.forEach(parent => {
502
- parent.removeEventListener('scroll', this.handleScroll);
503
- });
504
- window.removeEventListener('scroll', this.handleScroll);
505
- window.removeEventListener('resize', this.handleScroll);
506
- this.scrollParents = [];
507
- }
508
- handleScroll = () => {
509
- if (this.open) {
510
- this.updatePosition();
511
- }
512
- };
513
- handlePopoverToggle = (event) => {
514
- if (event.newState === 'open') {
515
- this.open = true;
516
- this.addScrollListeners();
517
- this.updatePosition();
518
- this.lePopoverOpen.emit();
519
- }
520
- else {
521
- this.open = false;
522
- this.isPositioned = false;
523
- this.removeScrollListeners();
524
- this.lePopoverClose.emit();
694
+ async loadComponentMetadata() {
695
+ try {
696
+ // Fetch the manifest from configured URL
697
+ const { manifestFile } = getLeKitConfig();
698
+ const manifestFileResolved = getAssetPath(`./assets/${manifestFile}`);
699
+ const response = await fetch(manifestFileResolved);
700
+ const manifest = await response.json();
701
+ // Find the component definition
702
+ for (const module of manifest.modules) {
703
+ for (const declaration of module.declarations || []) {
704
+ if (declaration.tagName === this.component) {
705
+ const attributes = (declaration.attributes || []).filter((attr) => !this.isInternalAttribute(attr.name));
706
+ this.componentMeta = {
707
+ tagName: declaration.tagName,
708
+ description: declaration.description,
709
+ attributes,
710
+ };
711
+ // console.log(`[le-component] Loaded metadata for ${this.component}:`, this.componentMeta);
712
+ // Read property values after metadata is loaded
713
+ this.readPropertyValues();
714
+ return;
715
+ }
716
+ }
717
+ }
718
+ // console.warn(`[le-component] No metadata found for component: ${this.component}`);
525
719
  }
526
- };
527
- handleOtherPopoverOpen = (event) => {
528
- const customEvent = event;
529
- if (customEvent.detail?.popover === this.el)
530
- return;
531
- if (this.open) {
532
- this.hide();
720
+ catch (error) {
721
+ // console.warn(`[le-component] Failed to load metadata for component: ${this.component}`, error);
533
722
  }
534
- };
723
+ }
535
724
  /**
536
- * Opens the popover
725
+ * Check if an attribute is internal (should not be shown in editor)
537
726
  */
538
- async show() {
539
- document.dispatchEvent(new CustomEvent('le-popover-will-open', {
540
- detail: { popover: this.el }
541
- }));
542
- this.popoverEl?.showPopover();
727
+ isInternalAttribute(name) {
728
+ const internalAttrs = ['mode', 'theme', 'class', 'style', 'id', 'slot'];
729
+ return internalAttrs.includes(name);
543
730
  }
544
731
  /**
545
- * Closes the popover
732
+ * Read current property values from the host element
546
733
  */
547
- async hide() {
548
- this.popoverEl?.hidePopover();
734
+ readPropertyValues() {
735
+ if (!this.hostElement || !this.componentMeta)
736
+ return;
737
+ const values = {};
738
+ for (const attr of this.componentMeta.attributes) {
739
+ const value = this.hostElement.getAttribute(attr.name);
740
+ values[attr.name] = this.parseAttributeValue(value, attr.type?.text);
741
+ }
742
+ this.propertyValues = values;
549
743
  }
550
744
  /**
551
- * Toggles the popover
745
+ * Parse an attribute value based on its type
552
746
  */
553
- async toggle() {
554
- if (this.open) {
555
- await this.hide();
747
+ parseAttributeValue(value, type) {
748
+ if (value === null)
749
+ return undefined;
750
+ if (type === 'boolean') {
751
+ return value !== null && value !== 'false';
556
752
  }
557
- else {
558
- await this.show();
753
+ if (type === 'number') {
754
+ return parseFloat(value);
559
755
  }
756
+ return value;
560
757
  }
561
- handleTriggerClick = (event) => {
562
- event.stopPropagation();
563
- this.toggle();
564
- };
565
- updatePosition() {
566
- if (!this.triggerEl || !this.popoverEl)
758
+ /**
759
+ * Handle property value changes from the editor
760
+ */
761
+ handlePropertyChange(attrName, value, type) {
762
+ if (!this.hostElement)
567
763
  return;
568
- const triggerRect = this.triggerEl.getBoundingClientRect();
569
- const popoverRect = this.popoverEl.getBoundingClientRect();
570
- const viewportWidth = window.innerWidth;
571
- const viewportHeight = window.innerHeight;
572
- const viewportPadding = 8;
573
- let position = this.position;
574
- let align = this.align;
575
- // Auto-position logic
576
- const spaceBelow = viewportHeight - triggerRect.bottom - viewportPadding;
577
- const spaceAbove = triggerRect.top - viewportPadding;
578
- const spaceRight = viewportWidth - triggerRect.right - viewportPadding;
579
- const spaceLeft = triggerRect.left - viewportPadding;
580
- if (position === 'auto') {
581
- if (spaceBelow >= popoverRect.height + this.offset) {
582
- position = 'bottom';
583
- }
584
- else if (spaceAbove >= popoverRect.height + this.offset) {
585
- position = 'top';
586
- }
587
- else if (spaceRight >= popoverRect.width + this.offset) {
588
- position = 'right';
589
- }
590
- else if (spaceLeft >= popoverRect.width + this.offset) {
591
- position = 'left';
764
+ // Update the host element's attribute
765
+ if (type === 'boolean') {
766
+ if (value) {
767
+ this.hostElement.setAttribute(attrName, '');
592
768
  }
593
769
  else {
594
- const maxSpace = Math.max(spaceBelow, spaceAbove, spaceRight, spaceLeft);
595
- if (maxSpace === spaceBelow)
596
- position = 'bottom';
597
- else if (maxSpace === spaceAbove)
598
- position = 'top';
599
- else if (maxSpace === spaceRight)
600
- position = 'right';
601
- else
602
- position = 'left';
603
- }
604
- }
605
- // Adjust alignment for horizontal overflow
606
- if (position === 'top' || position === 'bottom') {
607
- if (align === 'start' && triggerRect.left + popoverRect.width > viewportWidth - viewportPadding) {
608
- align = 'end';
609
- }
610
- else if (align === 'end' && triggerRect.right - popoverRect.width < viewportPadding) {
611
- align = 'start';
612
- }
613
- else if (align === 'center') {
614
- const triggerCenter = triggerRect.left + triggerRect.width / 2;
615
- if (triggerCenter - popoverRect.width / 2 < viewportPadding) {
616
- align = 'start';
617
- }
618
- else if (triggerCenter + popoverRect.width / 2 > viewportWidth - viewportPadding) {
619
- align = 'end';
620
- }
770
+ this.hostElement.removeAttribute(attrName);
621
771
  }
622
772
  }
623
- // Calculate position
624
- let top = 0;
625
- let left = 0;
626
- let maxHeight = null;
627
- switch (position) {
628
- case 'top':
629
- top = triggerRect.top - popoverRect.height - this.offset;
630
- if (top < viewportPadding) {
631
- maxHeight = triggerRect.top - this.offset - viewportPadding * 2;
632
- top = viewportPadding;
633
- }
634
- break;
635
- case 'bottom':
636
- top = triggerRect.bottom + this.offset;
637
- if (top + popoverRect.height > viewportHeight - viewportPadding) {
638
- maxHeight = viewportHeight - top - viewportPadding;
639
- }
640
- break;
641
- case 'left':
642
- left = triggerRect.left - popoverRect.width - this.offset;
643
- top = triggerRect.top;
644
- if (left < viewportPadding)
645
- left = viewportPadding;
646
- break;
647
- case 'right':
648
- left = triggerRect.right + this.offset;
649
- top = triggerRect.top;
650
- if (left + popoverRect.width > viewportWidth - viewportPadding) {
651
- left = viewportWidth - popoverRect.width - viewportPadding;
652
- }
653
- break;
654
- }
655
- // Calculate horizontal alignment for top/bottom
656
- if (position === 'top' || position === 'bottom') {
657
- switch (align) {
658
- case 'start':
659
- left = triggerRect.left;
660
- break;
661
- case 'center':
662
- left = triggerRect.left + triggerRect.width / 2 - popoverRect.width / 2;
663
- break;
664
- case 'end':
665
- left = triggerRect.right - popoverRect.width;
666
- break;
667
- }
668
- // Constrain to viewport
669
- if (left < viewportPadding) {
670
- left = viewportPadding;
671
- }
672
- else if (left + popoverRect.width > viewportWidth - viewportPadding) {
673
- left = viewportWidth - popoverRect.width - viewportPadding;
674
- }
675
- }
676
- // Calculate vertical alignment for left/right
677
- if (position === 'left' || position === 'right') {
678
- switch (align) {
679
- case 'start':
680
- top = triggerRect.top;
681
- break;
682
- case 'center':
683
- top = triggerRect.top + triggerRect.height / 2 - popoverRect.height / 2;
684
- break;
685
- case 'end':
686
- top = triggerRect.bottom - popoverRect.height;
687
- break;
688
- }
689
- if (top < viewportPadding)
690
- top = viewportPadding;
691
- if (top + popoverRect.height > viewportHeight - viewportPadding) {
692
- maxHeight = viewportHeight - top - viewportPadding;
693
- }
694
- }
695
- // Apply styles
696
- this.popoverEl.style.top = `${top}px`;
697
- this.popoverEl.style.left = `${left}px`;
698
- if (maxHeight !== null && maxHeight > 100) {
699
- this.popoverEl.style.maxHeight = `${maxHeight}px`;
700
- this.popoverEl.style.overflowY = 'auto';
773
+ else if (value === undefined || value === '') {
774
+ this.hostElement.removeAttribute(attrName);
701
775
  }
702
776
  else {
703
- this.popoverEl.style.maxHeight = '';
704
- this.popoverEl.style.overflowY = '';
777
+ this.hostElement.setAttribute(attrName, String(value));
705
778
  }
706
- this.isPositioned = true;
707
- }
708
- render() {
709
- const popoverStyles = {
710
- visibility: this.isPositioned ? 'visible' : 'hidden',
711
- };
712
- if (this.width)
713
- popoverStyles.width = this.width;
714
- if (this.minWidth)
715
- popoverStyles.minWidth = this.minWidth;
716
- if (this.maxWidth)
717
- popoverStyles.maxWidth = this.maxWidth;
718
- return [
719
- h("div", { key: '3d2a3b86ddb3be577bd0e976a5a00f25396a97fb', class: "le-popover-trigger", ref: (el) => (this.triggerEl = el), onClick: this.handleTriggerClick }, h("slot", { key: '9db2e9e2b0bdb25c5a2361115d2094292fe692ec', name: "trigger" }, h("button", { key: '88d78b192f72731f00d6131b92b8d6a4b445d7f9', type: "button", class: "le-popover-default-trigger" }, h("span", { key: '0f2913f160cda5dcbeb20c714219d587196e230b' }, "\u2295")))),
720
- h("div", { key: 'b65d2de900ff6e67a62d92d7452db34afde9f257', id: this.uniqueId, class: "le-popover-content", popover: this.closeOnClickOutside ? 'auto' : 'manual', ref: (el) => (this.popoverEl = el), style: popoverStyles }, (this.popoverTitle || this.showClose) && (h("div", { key: '323061fc49c8e0fc9ae541dfc576e551b0a83818', class: "le-popover-header" }, this.popoverTitle && h("span", { key: 'b1d9f4203966ae6a0bb14186824596643954d6f8', class: "le-popover-title" }, this.popoverTitle), this.showClose && (h("button", { key: 'd0d335d8c9897ed9ba7bd0370572a8cafa72b044', type: "button", class: "le-popover-close", onClick: () => this.hide(), "aria-label": "Close" }, "\u00D7")))), h("div", { key: '52d3294394b0e1fd49f8c361414e228feed68ea9', class: "le-popover-body" }, h("slot", { key: '16d8691545f2eaa44f136bfea33a1f1d71d18cd7' })))
721
- ];
722
- }
723
- };
724
- LePopover.style = lePopoverCss;
725
-
726
- const leSlotDefaultCss = ":host{display:contents;--le-slot-border-color:#0088ff;--le-slot-bg-color:rgba(0, 136, 255, 0.05);--le-slot-header-bg:rgb(218, 238, 255);--le-slot-label-color:#0066cc;--le-slot-description-color:#666;--le-slot-required-color:#e53935;--le-slot-dropzone-min-height:20px;--le-slot-dropzone-border-color:#ccc}.le-slot-container,.le-slot-header,.le-slot-description,.le-slot-dropzone,.le-slot-input{display:none}.hidden-slot{display:none}:host(.admin-mode){display:block;flex:1}:host(.admin-mode) .le-slot-container{position:relative;display:flex;flex-direction:column;border:2px dashed var(--le-slot-border-color);border-radius:4px;background:var(--le-slot-bg-color);margin:4px 0}:host(.admin-mode) .le-slot-header{display:flex;align-items:center;gap:4px;padding:0 0 0 var(--le-spacing-1, 4px);background:var(--le-slot-header-bg);border-bottom:1px solid var(--le-slot-border-color);font-size:var(--le-font-size-xs, 11px);font-weight:400;text-transform:capitalize}:host(.admin-mode) .le-slot-header-no-label{justify-content:flex-end;height:16px;border:none;background-color:transparent}.le-slot-label{color:var(--le-slot-label-color);text-align:start;overflow:hidden;width:0;flex:1 1 0%}.le-slot-required{color:var(--le-slot-required-color);font-weight:bold}:host(.admin-mode) .le-slot-description{display:block;padding:4px 8px;font-size:12px;color:var(--le-slot-description-color);font-style:italic}:host(.admin-mode) .le-slot-description-icon{display:inline-block;font-size:9px;line-height:1;cursor:pointer;color:var(--le-slot-description-color)}:host(.admin-mode) .le-slot-dropzone{display:block;min-height:var(--le-slot-dropzone-min-height);padding:var(--le-spacing-1, 4px);position:relative}:host(.admin-mode) .le-slot-dropzone:empty::before{content:'Drop content here';display:flex;align-items:center;justify-content:center;position:absolute;inset:8px;border:2px dashed var(--le-slot-dropzone-border-color);border-radius:4px;color:#999;font-size:12px;pointer-events:none}:host(.admin-mode.drag-over) .le-slot-container{border-color:#00cc66;background:rgba(0, 204, 102, 0.1)}:host(.admin-mode.drag-over) .le-slot-dropzone:empty::before{border-color:#00cc66;color:#00cc66;content:'Release to drop'}:host(.admin-mode) .le-slot-input{display:block;padding:var(--le-spacing-1, 4px)}:host(.admin-mode) .le-slot-input input,:host(.admin-mode) .le-slot-input textarea{display:block;width:100%;padding:8px 10px;border:1px solid var(--le-slot-dropzone-border-color);border-radius:4px;font-family:inherit;font-size:14px;line-height:1.4;background:#fff;color:#333;box-sizing:border-box;transition:border-color 0.2s, box-shadow 0.2s}:host(.admin-mode) .le-slot-input input:focus,:host(.admin-mode) .le-slot-input textarea:focus{outline:none;border-color:var(--le-slot-border-color);box-shadow:0 0 0 3px rgba(0, 136, 255, 0.15)}:host(.admin-mode) .le-slot-input input::placeholder,:host(.admin-mode) .le-slot-input textarea::placeholder{color:#999}:host(.admin-mode) .le-slot-input textarea{resize:vertical;min-height:60px}:host(.admin-mode) .le-slot-input slot{display:none}.le-slot-invalid{color:var(--le-slot-required-color);font-size:10px;margin-left:auto;font-weight:normal;text-transform:none}:host(.admin-mode) .le-slot-input.has-error input,:host(.admin-mode) .le-slot-input.has-error textarea{border-color:var(--le-slot-required-color);background:rgba(229, 57, 53, 0.05)}:host(.admin-mode) .le-slot-input.has-error input:focus,:host(.admin-mode) .le-slot-input.has-error textarea:focus{border-color:var(--le-slot-required-color);box-shadow:0 0 0 3px rgba(229, 57, 53, 0.15)}.le-slot-add-btn{font-size:24px;line-height:0px;width:12px;height:12px}.le-slot-header-no-label .le-slot-add-btn{font-size:16px}.le-slot-button{width:20px;height:20px}:host(.admin-mode) .le-slot-header-no-label.le-slot-header-text{height:0}";
727
-
728
- const LeSlot = class {
729
- constructor(hostRef) {
730
- registerInstance(this, hostRef);
731
- this.leSlotChange = createEvent(this, "leSlotChange");
779
+ // Update local state
780
+ this.propertyValues = { ...this.propertyValues, [attrName]: value };
732
781
  }
733
- get el() { return getElement(this); }
734
- /**
735
- * The type of slot content.
736
- * - `slot`: Default, shows a dropzone for components (default)
737
- * - `text`: Shows a single-line text input
738
- * - `textarea`: Shows a multi-line text area
739
- */
740
- type = 'slot';
741
- /**
742
- * The name of the slot this placeholder represents.
743
- * Should match the slot name in the parent component.
744
- */
745
- name = '';
746
- /**
747
- * Label to display in admin mode.
748
- * If not provided, the slot name will be used.
749
- */
750
- label;
751
- /**
752
- * Description of what content this slot accepts.
753
- * Shown in admin mode to guide content editors.
754
- */
755
- description;
756
- /**
757
- * Comma-separated list of allowed component tags for this slot.
758
- * Used by CMS to filter available components.
759
- *
760
- * @example "le-card,le-button,le-text"
761
- */
762
- allowedComponents;
763
- /**
764
- * Whether multiple components can be dropped in this slot.
765
- */
766
- multiple = true;
767
- /**
768
- * Whether this slot is required to have content.
769
- */
770
- required = false;
771
- /**
772
- * Placeholder text for text/textarea inputs in admin mode.
773
- */
774
- placeholder;
775
- /**
776
- * The HTML tag to create when there's no slotted element.
777
- * Used with type="text" or type="textarea" to auto-create elements.
778
- *
779
- * @example "h3" - creates <h3 slot="header">content</h3>
780
- * @example "p" - creates <p slot="content">content</p>
781
- */
782
- tag;
783
- /**
784
- * CSS styles for the slot dropzone container.
785
- * Useful for layouts - e.g., "flex-direction: row" for horizontal stacks.
786
- * Only applies in admin mode for type="slot".
787
- */
788
- slotStyle;
789
782
  /**
790
- * Internal state to track admin mode
791
- */
792
- adminMode = false;
793
- /**
794
- * Internal state for text input value (synced from slot content)
795
- */
796
- textValue = '';
797
- /**
798
- * Whether the current textValue contains valid HTML
799
- */
800
- isValidHtml = true;
801
- /**
802
- * Available components loaded from Custom Elements Manifest
803
- */
804
- availableComponents = [];
805
- /**
806
- * Whether the component picker popover is open
807
- */
808
- pickerOpen = false;
809
- /**
810
- * Reference to the slot element to access assignedNodes
811
- */
812
- slotRef;
813
- /**
814
- * The original slotted element (e.g., <h3 slot="header">)
815
- */
816
- slottedElement;
817
- /**
818
- * Emitted when text content changes in admin mode.
819
- * The event detail contains the new text value and validity.
783
+ * Delete this component from the DOM
820
784
  */
821
- leSlotChange;
822
- disconnectModeObserver;
823
- connectedCallback() {
824
- this.disconnectModeObserver = observeModeChanges(this.el, mode => {
825
- const wasAdmin = this.adminMode;
826
- this.adminMode = mode === 'admin';
827
- // When entering admin mode, read content from slotted elements
828
- if (this.adminMode && !wasAdmin) {
829
- // Need to wait for render to access slot ref
830
- requestAnimationFrame(() => this.readSlottedContent());
831
- // Load available components for the component picker
832
- if (this.type === 'slot') {
833
- this.loadAvailableComponents();
834
- }
835
- }
836
- });
837
- }
838
- disconnectedCallback() {
839
- this.disconnectModeObserver?.();
785
+ deleteComponent() {
786
+ if (!this.hostElement)
787
+ return;
788
+ // Confirm deletion
789
+ const name = this.displayName || this.formatDisplayName(this.component);
790
+ if (!confirm(`Delete this ${name}?`))
791
+ return;
792
+ // Remove the host element from its parent
793
+ const parent = this.hostElement.parentElement;
794
+ if (parent) {
795
+ this.hostElement.remove();
796
+ }
840
797
  }
841
798
  /**
842
- * Flag to prevent re-reading content right after we updated it
799
+ * Render the property editor form
843
800
  */
844
- isUpdating = false;
801
+ renderPropertyEditor() {
802
+ const hasProperties = this.componentMeta && this.componentMeta.attributes.length > 0;
803
+ return (h("div", { class: "property-editor-container" }, hasProperties ? (h("form", { class: "property-editor", onSubmit: e => e.preventDefault() }, this.componentMeta.attributes.map(attr => this.renderPropertyField(attr)))) : (h("p", { class: "no-properties" }, "No editable properties")), h("div", { class: "property-editor-actions" }, h("le-button", { type: "button", variant: "outlined", color: "danger", "full-width": true, onClick: () => this.deleteComponent() }, h("span", { slot: "icon-start" }, "\uD83D\uDDD1\uFE0F"), h("span", null, "Delete Component")))));
804
+ }
845
805
  /**
846
- * Read content from slotted elements via assignedNodes()
806
+ * Render a single property field based on its type
847
807
  */
848
- readSlottedContent() {
849
- if (!this.slotRef)
850
- return;
851
- // Skip if we just updated the content ourselves
852
- if (this.isUpdating) {
853
- this.isUpdating = false;
854
- return;
808
+ renderPropertyField(attr) {
809
+ const value = this.propertyValues[attr.name];
810
+ const type = attr.type?.text || 'string';
811
+ // Check if type is a union of string literals (e.g., "'default' | 'outlined' | 'elevated'")
812
+ const enumMatch = type.match(/^'[^']+'/);
813
+ if (enumMatch) {
814
+ const options = type.split('|').map(opt => opt.trim().replace(/'/g, ''));
815
+ return (h("div", { class: "property-field" }, h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && h("span", { class: "property-hint" }, attr.description)), h("select", { id: `prop-${attr.name}`, onChange: e => this.handlePropertyChange(attr.name, e.target.value, type) }, options.map(opt => (h("option", { value: opt, selected: value === opt || (!value && attr.default?.replace(/'/g, '') === opt) }, opt))))));
855
816
  }
856
- const assignedNodes = this.slotRef.assignedNodes({ flatten: true });
857
- // For text/textarea types, we want to edit the innerHTML of slotted elements
858
- if (this.type === 'text' || this.type === 'textarea') {
859
- // Find the first element node (skip text nodes that are just whitespace)
860
- const elementNode = assignedNodes.find(node => node.nodeType === Node.ELEMENT_NODE);
861
- if (elementNode) {
862
- // Only update textValue if slotted element changed or we don't have one yet
863
- if (this.slottedElement !== elementNode) {
864
- this.slottedElement = elementNode;
865
- this.textValue = elementNode.innerHTML?.trim() || '';
866
- // console.log(`[le-slot "${this.name}"] Read slotted content:`, this.textValue);
867
- }
868
- }
869
- else {
870
- // No element, check for direct text content
871
- const textContent = assignedNodes
872
- .filter(node => node.nodeType === Node.TEXT_NODE)
873
- .map(node => node.textContent)
874
- .join('')
875
- .trim();
876
- if (textContent && !this.textValue) {
877
- this.textValue = textContent;
878
- // console.log(`[le-slot "${this.name}"] Read text content:`, this.textValue);
879
- }
880
- }
817
+ // Boolean type
818
+ if (type === 'boolean') {
819
+ return (h("div", { class: "property-field property-field--checkbox" }, h("le-checkbox", { name: `prop-${attr.name}`, checked: value === true || value === '', onChange: e => this.handlePropertyChange(attr.name, e.target.checked, type) }, attr.name, attr.description && h("div", { slot: "description" }, attr.description))));
820
+ }
821
+ // Number type
822
+ if (type === 'number') {
823
+ return (h("div", { class: "property-field" }, h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && h("span", { class: "property-hint" }, attr.description)), h("input", { type: "number", id: `prop-${attr.name}`, value: value ?? '', placeholder: attr.default, onChange: e => this.handlePropertyChange(attr.name, e.target.value, type) })));
881
824
  }
825
+ // Default: string/text input
826
+ return (h("div", { class: "property-field" }, h("le-string-input", { name: `prop-${attr.name}`, label: attr.name, value: value ?? '', placeholder: attr.default?.replace(/'/g, ''), onChange: (e) => this.handlePropertyChange(attr.name, e.detail.value, type) }, h("span", { slot: "description" }, attr.description))));
882
827
  }
883
- /**
884
- * Validates if a string contains valid HTML
885
- */
886
- validateHtml(html) {
887
- // Empty string is valid
888
- if (!html.trim())
889
- return true;
890
- // Create a template element to parse the HTML
891
- const template = document.createElement('template');
892
- template.innerHTML = html;
893
- // Check that we don't have obviously broken HTML
894
- // Count opening and closing tags for common elements
895
- const openTags = (html.match(/<[a-z][^>]*(?<!\/)>/gi) || []).length;
896
- const closeTags = (html.match(/<\/[a-z][^>]*>/gi) || []).length;
897
- const selfClosing = (html.match(/<[a-z][^>]*\/>/gi) || []).length;
898
- // Simple validation: opening tags (minus self-closing) should roughly match closing tags
899
- // Allow some tolerance for void elements like <br>, <img>, etc.
900
- const voidElements = (html.match(/<(br|hr|img|input|meta|link|area|base|col|embed|param|source|track|wbr)[^>]*>/gi) || []).length;
901
- const effectiveOpenTags = openTags - selfClosing - voidElements;
902
- // If difference is too large, HTML is likely broken
903
- if (Math.abs(effectiveOpenTags - closeTags) > 1) {
904
- return false;
828
+ render() {
829
+ const name = this.displayName || this.formatDisplayName(this.component);
830
+ // In default mode, just pass through content with host classes
831
+ if (!this.adminMode) {
832
+ return (h(Host, { class: classnames(this.component, this.hostClass), style: this.hostStyle }, h("slot", null)));
905
833
  }
906
- return true;
834
+ // In admin mode, show wrapper with header and settings
835
+ return (h(Host, { class: classnames(this.component, this.hostClass, 'admin-mode'), style: this.hostStyle }, h("div", { class: "le-component-wrapper" }, h("div", { class: "le-component-header" }, h("span", { class: "le-component-name" }, name), h("le-popover", { popoverTitle: `${name} Settings`, position: "right", align: "start", "min-width": "300px", mode: "default" }, h("le-button", { type: "button", class: "le-component-button", slot: "trigger", variant: "clear", size: "small", "aria-label": "Edit component properties", "icon-only": true }, h("span", { class: "le-component-trigger", slot: "icon-only" }, "\u2699")), this.renderPropertyEditor())), h("div", { class: "le-component-content" }, h("slot", null)))));
907
836
  }
908
- handleTextInput = (event) => {
909
- const target = event.target;
910
- this.textValue = target.value;
911
- this.isValidHtml = this.validateHtml(this.textValue);
912
- if (this.isValidHtml) {
913
- // Set flag to prevent slotchange from re-reading what we just wrote
914
- this.isUpdating = true;
915
- console.log('Updating text value:', this.textValue, 'slottedElement:', this.slottedElement);
916
- if (this.slottedElement) {
917
- // Update existing slotted element's innerHTML
918
- this.slottedElement.innerHTML = this.textValue;
837
+ static get assetsDirs() { return ["assets"]; }
838
+ static get style() { return leComponentCss; }
839
+ }, [769, "le-component", {
840
+ "component": [1],
841
+ "displayName": [1, "display-name"],
842
+ "hostClass": [1, "host-class"],
843
+ "hostStyle": [16],
844
+ "adminMode": [32],
845
+ "componentMeta": [32],
846
+ "propertyValues": [32]
847
+ }]);
848
+ function defineCustomElement$2() {
849
+ if (typeof customElements === "undefined") {
850
+ return;
851
+ }
852
+ const components = ["le-component", "le-button", "le-checkbox", "le-component", "le-popover", "le-slot", "le-string-input"];
853
+ components.forEach(tagName => { switch (tagName) {
854
+ case "le-component":
855
+ if (!customElements.get(tagName)) {
856
+ customElements.define(tagName, LeComponent);
919
857
  }
920
- else if (this.tag && this.textValue) {
921
- // No slotted element exists
922
- // If the slot doesn't have a name, then it's the default slot
923
- // remove the existing non-slotted content (text nodes and elements without slot attribute)
924
- const rootNode = this.el.getRootNode();
925
- if (!this.name && rootNode instanceof ShadowRoot) {
926
- const hostComponent = rootNode.host;
927
- Array.from(hostComponent.childNodes).forEach(node => {
928
- if (node.nodeType === Node.TEXT_NODE || (node.nodeType === Node.ELEMENT_NODE && !node.hasAttribute('slot'))) {
929
- node.remove();
930
- }
931
- });
932
- }
933
- // create one using the specified tag
934
- this.createSlottedElement();
858
+ break;
859
+ case "le-button":
860
+ if (!customElements.get(tagName)) {
861
+ defineCustomElement();
935
862
  }
936
- else if (this.textValue) {
937
- // no tag specified - just replace everything in the host component
938
- const rootNode = this.el.getRootNode();
939
- if (rootNode instanceof ShadowRoot) {
940
- const hostComponent = rootNode.host;
941
- hostComponent.innerHTML = this.textValue;
942
- }
863
+ break;
864
+ case "le-checkbox":
865
+ if (!customElements.get(tagName)) {
866
+ defineCustomElement$1();
943
867
  }
868
+ break;
869
+ case "le-component":
870
+ if (!customElements.get(tagName)) {
871
+ defineCustomElement$2();
872
+ }
873
+ break;
874
+ case "le-popover":
875
+ if (!customElements.get(tagName)) {
876
+ defineCustomElement$5();
877
+ }
878
+ break;
879
+ case "le-slot":
880
+ if (!customElements.get(tagName)) {
881
+ defineCustomElement$3();
882
+ }
883
+ break;
884
+ case "le-string-input":
885
+ if (!customElements.get(tagName)) {
886
+ defineCustomElement$4();
887
+ }
888
+ break;
889
+ } });
890
+ }
891
+
892
+ const leCheckboxCss = ":host{display:block;--le-checkbox-size:18px;--le-checkbox-color:var(--le-color-primary, #007bff);--le-checkbox-label-color:var(--le-color-text-primary, #333);--le-checkbox-desc-color:var(--le-color-text-secondary, #666);--le-checkbox-border-radius:var(--le-radius-sm, 2px);--le-checkbox-marker-color:var(--le-color-surface, #fff)}.le-checkbox-wrapper{display:flex;flex-direction:column;gap:4px}.le-checkbox-label{display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;user-select:none}:host([disabled]) .le-checkbox-label{cursor:not-allowed;opacity:0.6}.le-checkbox-input{display:flex;align-items:center;justify-content:center;min-height:1.4em}input[type=\"checkbox\"]{appearance:none;-webkit-appearance:none;width:var(--le-checkbox-size);height:var(--le-checkbox-size);border:var(--le-border-width, 2px) solid var(--le-checkbox-color);border-radius:var(--le-checkbox-border-radius);margin:0;margin-top:2px;position:relative;cursor:inherit;background-color:transparent;transition:background-color 0.2s, border-color 0.2s}input[type=\"checkbox\"]:checked{background-color:var(--le-checkbox-color)}input[type=\"checkbox\"]:checked::after{content:'';position:absolute;left:0;top:0;bottom:calc(var(--le-checkbox-size) / 5);right:0;margin:auto;width:calc(var(--le-checkbox-size) / 4);height:calc(var(--le-checkbox-size) / 2);border:solid var(--le-checkbox-marker-color, #fff);border-width:0 calc(var(--le-checkbox-size) / 10) calc(var(--le-checkbox-size) / 10) 0;transform:rotate(45deg)}input[type=\"checkbox\"]:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.le-checkbox-text{flex:1;flex-wrap:wrap;color:var(--le-checkbox-label-color);line-height:1.5;text-align:start}.le-checkbox-description{margin-left:calc(var(--le-checkbox-size) + 8px);font-size:0.875em;color:var(--le-checkbox-desc-color);line-height:1.4}:host [slot=\"description\"]{margin:0}";
893
+
894
+ const LeCheckbox = /*@__PURE__*/ proxyCustomElement(class LeCheckbox extends HTMLElement {
895
+ constructor(registerHost) {
896
+ super();
897
+ if (registerHost !== false) {
898
+ this.__registerHost();
944
899
  }
945
- this.leSlotChange.emit({
946
- name: this.name,
947
- value: this.textValue,
948
- isValid: this.isValidHtml,
949
- });
950
- };
951
- /**
952
- * Create a new slotted element when none exists.
953
- * The element is appended to the host component's light DOM.
954
- */
955
- createSlottedElement() {
956
- if (!this.tag)
957
- return;
958
- // Find the host component (le-card, etc.) by traversing up through shadow DOM
959
- // le-slot is inside le-card's shadow DOM, so we need to find le-card's host
960
- const rootNode = this.el.getRootNode();
961
- if (!(rootNode instanceof ShadowRoot))
962
- return;
963
- const hostComponent = rootNode.host;
964
- if (!hostComponent)
965
- return;
966
- // Create the new element
967
- const newElement = document.createElement(this.tag);
968
- newElement.innerHTML = this.textValue;
969
- // Set the slot attribute if this is a named slot
970
- if (this.name) {
971
- newElement.setAttribute('slot', this.name);
972
- }
973
- // Append to the host component's light DOM
974
- hostComponent.appendChild(newElement);
975
- // Store reference to the new element
976
- this.slottedElement = newElement;
977
- // console.log(`[le-slot "${this.name}"] Created new <${this.tag}> element`);
900
+ this.__attachShadow();
901
+ this.leChange = createEvent(this, "change", 7);
978
902
  }
903
+ get el() { return this; }
979
904
  /**
980
- * Load available components from Custom Elements Manifest
905
+ * Whether the checkbox is checked
981
906
  */
982
- async loadAvailableComponents() {
983
- try {
984
- const { manifestUrl } = getLeKitConfig();
985
- const manifestUrlResolved = manifestUrl.startsWith('/')
986
- ? getAssetPath(`./assets${manifestUrl}`)
987
- : manifestUrl;
988
- const response = await fetch(manifestUrlResolved);
989
- const manifest = await response.json();
990
- const components = [];
991
- const allowedList = this.allowedComponents?.split(',').map(s => s.trim()) || [];
992
- for (const module of manifest.modules) {
993
- for (const declaration of module.declarations || []) {
994
- if (declaration.tagName && declaration.customElement) {
995
- // Skip internal components (le-slot, le-component, le-popover)
996
- const isInternal = ['le-slot', 'le-component', 'le-popover'].includes(declaration.tagName);
997
- if (isInternal)
998
- continue;
999
- // If allowedComponents is specified, filter by it
1000
- if (allowedList.length > 0 && !allowedList.includes(declaration.tagName)) {
1001
- continue;
1002
- }
1003
- components.push({
1004
- tagName: declaration.tagName,
1005
- name: this.formatComponentName(declaration.tagName),
1006
- description: declaration.description || '',
1007
- });
1008
- }
1009
- }
1010
- }
1011
- this.availableComponents = components || [];
1012
- }
1013
- catch (error) {
1014
- console.warn('[le-slot] Failed to load component manifest:', error);
1015
- }
1016
- }
907
+ checked = false;
1017
908
  /**
1018
- * Format a tag name into a display name
1019
- * e.g., 'le-card' -> 'Card'
909
+ * Whether the checkbox is disabled
1020
910
  */
1021
- formatComponentName(tagName) {
1022
- return tagName
1023
- .replace(/^le-/, '')
1024
- .split('-')
1025
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
1026
- .join(' ');
1027
- }
911
+ disabled = false;
1028
912
  /**
1029
- * Add a new component to the slot
913
+ * The name of the checkbox input
1030
914
  */
1031
- addComponent(tagName) {
1032
- // Find the host component by traversing up through shadow DOM
1033
- const rootNode = this.el.getRootNode();
1034
- if (!(rootNode instanceof ShadowRoot))
1035
- return;
1036
- const hostComponent = rootNode.host;
1037
- if (!hostComponent)
915
+ name;
916
+ /**
917
+ * The value of the checkbox input
918
+ */
919
+ value;
920
+ /**
921
+ * External ID for linking with external systems (e.g. database ID, PDF form field ID)
922
+ */
923
+ externalId;
924
+ /**
925
+ * Emitted when the checked state changes
926
+ */
927
+ leChange;
928
+ handleChange = (event) => {
929
+ // We stop the internal button click from bubbling up
930
+ event.stopPropagation();
931
+ if (this.disabled) {
932
+ event.preventDefault();
1038
933
  return;
1039
- // Create the new component element
1040
- const newElement = document.createElement(tagName);
1041
- // Set the slot attribute if this is a named slot
1042
- if (this.name) {
1043
- newElement.setAttribute('slot', this.name);
1044
934
  }
1045
- // Append to the host component's light DOM
1046
- hostComponent.appendChild(newElement);
1047
- // Emit change event so the page can save
1048
- this.leSlotChange.emit({
935
+ const input = event.target;
936
+ this.checked = input.checked;
937
+ this.leChange.emit({
938
+ checked: this.checked,
939
+ value: this.value,
1049
940
  name: this.name,
1050
- value: hostComponent.innerHTML,
1051
- isValid: true,
941
+ externalId: this.externalId
1052
942
  });
1053
- }
1054
- /**
1055
- * Handle slot change event to re-read content when nodes are assigned
1056
- */
1057
- handleSlotChange = () => {
1058
- this.readSlottedContent();
1059
943
  };
1060
944
  render() {
1061
- const displayLabel = this.label || this.name;
1062
- // Always render the same structure, CSS handles visibility via .admin-mode class
1063
- return (h(Host, { key: 'e89effa647f07ae271cffc05aad6730b51da6447', class: {
1064
- 'admin-mode': this.adminMode,
1065
- 'invalid-html': !this.isValidHtml,
1066
- }, role: this.adminMode ? 'region' : undefined, "aria-label": this.adminMode ? `Slot: ${displayLabel}` : undefined, "data-slot-name": this.name, "data-slot-type": this.type, "data-allowed": this.allowedComponents, "data-multiple": this.multiple, "data-required": this.required }, this.adminMode ? (h("div", { class: "le-slot-container" }, h("div", { class: classnames('le-slot-header', {
1067
- 'le-slot-header-no-label': !displayLabel,
1068
- 'le-slot-header-text': this.type === 'text',
1069
- 'le-slot-header-error': !this.isValidHtml,
1070
- }) }, displayLabel && (h("span", { class: "le-slot-label" }, displayLabel, this.required && h("span", { class: "le-slot-required" }, "*"))), !this.isValidHtml && h("span", { class: "le-slot-invalid" }, "\u26A0 Invalid HTML"), this.type === 'slot' && this.adminMode && (h("le-popover", { mode: "default", showClose: true, align: "start", position: "right", popoverTitle: "Add Component", open: this.pickerOpen, onLePopoverOpen: () => (this.pickerOpen = true), onLePopoverClose: () => (this.pickerOpen = false) }, h("le-button", { type: "button", class: "le-slot-button", slot: "trigger", variant: "clear", size: "small", "aria-label": "Add component", "icon-only": true }, h("span", { class: "le-slot-add-btn", slot: "icon-only" }, "+")), h("div", { class: "le-slot-picker" }, this.availableComponents.length > 0 ? (h("ul", { class: "le-slot-picker-list" }, this.availableComponents.map(component => (h("li", { key: component.tagName }, h("button", { class: "le-slot-picker-item", onClick: () => {
1071
- this.addComponent(component.tagName);
1072
- this.pickerOpen = false;
1073
- } }, h("span", { class: "le-slot-picker-name" }, component.name), component.description && h("span", { class: "le-slot-picker-desc" }, component.description))))))) : (h("div", { class: "le-slot-picker-empty" }, "No components available")))))), this.renderContent())) : (
1074
- // In default mode, just pass through the slot - slotted content renders naturally
1075
- // Note: We use unnamed slot here because named slots from parent component
1076
- // are passed as le-slot's light DOM children
1077
- h("slot", null))));
945
+ return (h("le-component", { key: '43399929e07835e0019d509803e50a151921fa72', component: "le-checkbox", hostClass: classnames({ 'disabled': this.disabled }) }, h("div", { key: '7ddbf2ac1690bb09082adfea70b9767c972d007a', class: "le-checkbox-wrapper" }, h("label", { key: '8eec4055c713e8b3b155695751b10bff64c9f903', class: "le-checkbox-label" }, h("span", { key: '2118b1cbe7911ff1674e522d723949d81cade185', class: "le-checkbox-input" }, h("input", { key: 'd0a30af5c14497fa6fa294c07ba74ae2e032481f', type: "checkbox", name: this.name, value: this.value, checked: this.checked, disabled: this.disabled, onChange: this.handleChange })), h("span", { key: '02cf9588431240039a53ee50e02b08ba5d63b974', class: "le-checkbox-text" }, h("le-slot", { key: 'e7d7b253deab72e627164eb72fc06109abfca6a5', name: "", type: "text", tag: "span" }, h("slot", { key: '1d8c443073e48848513a8a6d04cd7805a394e54e' })))), h("div", { key: '16c2c927dc0c0f7844a203a0628bf0e561009bd0', class: "le-checkbox-description" }, h("le-slot", { key: 'c6898ecc8992dce4786e68ab4b136bf5c3a4d3aa', name: "description", type: "text", tag: "div", label: "Description" }, h("slot", { key: '3342add8ed1400ab74681e445163eeb3dd415941', name: "description" }))))));
1078
946
  }
1079
- renderContent() {
1080
- // Create the slot element with ref for reading assignedNodes
1081
- // Wrap in a hidden div since slot elements can't have style prop in Stencil
1082
- // Note: We use unnamed slot here because named slots from parent component
1083
- // are passed as le-slot's light DOM children
1084
- const slotElement = (h("div", { class: "hidden-slot" }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
1085
- switch (this.type) {
1086
- case 'text':
1087
- return (h("div", { class: { 'le-slot-input': true, 'has-error': !this.isValidHtml } }, h("le-string-input", { mode: "default", value: this.textValue, placeholder: this.placeholder || `Enter ${this.label || this.name || 'text'}...`, onChange: this.handleTextInput }), slotElement));
1088
- case 'textarea':
1089
- return (h("div", { class: { 'le-slot-input': true, 'has-error': !this.isValidHtml } }, h("textarea", { value: this.textValue, placeholder: this.placeholder || `Enter ${this.label || this.name || 'text'}...`, onInput: this.handleTextInput, required: this.required, rows: 3 }), slotElement));
1090
- case 'slot':
1091
- default:
1092
- // Parse slotStyle string into style object if provided
1093
- const dropzoneStyle = {};
1094
- if (this.slotStyle) {
1095
- this.slotStyle.split(';').forEach(rule => {
1096
- const [prop, value] = rule.split(':').map(s => s.trim());
1097
- if (prop && value) {
1098
- // Convert kebab-case to camelCase for style object
1099
- const camelProp = prop.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
1100
- dropzoneStyle[camelProp] = value;
1101
- }
1102
- });
1103
- }
1104
- return (h("div", { class: "le-slot-dropzone", style: dropzoneStyle }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
1105
- }
947
+ static get style() { return leCheckboxCss; }
948
+ }, [769, "le-checkbox", {
949
+ "checked": [1540],
950
+ "disabled": [4],
951
+ "name": [1],
952
+ "value": [1],
953
+ "externalId": [1, "external-id"]
954
+ }]);
955
+ function defineCustomElement$1() {
956
+ if (typeof customElements === "undefined") {
957
+ return;
1106
958
  }
1107
- };
1108
- LeSlot.style = leSlotDefaultCss;
959
+ const components = ["le-checkbox", "le-button", "le-checkbox", "le-component", "le-popover", "le-slot", "le-string-input"];
960
+ components.forEach(tagName => { switch (tagName) {
961
+ case "le-checkbox":
962
+ if (!customElements.get(tagName)) {
963
+ customElements.define(tagName, LeCheckbox);
964
+ }
965
+ break;
966
+ case "le-button":
967
+ if (!customElements.get(tagName)) {
968
+ defineCustomElement();
969
+ }
970
+ break;
971
+ case "le-checkbox":
972
+ if (!customElements.get(tagName)) {
973
+ defineCustomElement$1();
974
+ }
975
+ break;
976
+ case "le-component":
977
+ if (!customElements.get(tagName)) {
978
+ defineCustomElement$2();
979
+ }
980
+ break;
981
+ case "le-popover":
982
+ if (!customElements.get(tagName)) {
983
+ defineCustomElement$5();
984
+ }
985
+ break;
986
+ case "le-slot":
987
+ if (!customElements.get(tagName)) {
988
+ defineCustomElement$3();
989
+ }
990
+ break;
991
+ case "le-string-input":
992
+ if (!customElements.get(tagName)) {
993
+ defineCustomElement$4();
994
+ }
995
+ break;
996
+ } });
997
+ }
1109
998
 
1110
- const leStringInputCss = ":host{display:block;--le-input-bg:var(--le-color-surface, #ffffff);--le-input-color:var(--le-color-text-primary, #333333);--le-input-border:var(--le-border-width, 2px) solid var(--le-color-border-input, #007bff);--le-input-radius:var(--le-radius-sm, 4px);--le-input-padding:2px 6px;--le-input-height:1.5rem;--le-input-label-color:var(--le-color-text-primary, #333333);--le-input-desc-color:var(--le-color-text-secondary, #666666);--le-input-placeholder-color:#999999}.le-input-wrapper{display:flex;flex-direction:column;gap:2px}.le-input-label{display:block;font-size:0.9em;font-weight:500;color:var(--le-input-label-color);margin-bottom:2px}.le-input-container{position:relative;display:flex;align-items:center;background:var(--le-input-bg);border:var(--le-input-border);border-radius:var(--le-input-radius);transition:border-color 0.2s}.le-input-container:focus-within{outline:2px solid var(--le-color-focus);outline-offset:2px}:host([disabled]) .le-input-container{opacity:0.6;background-color:rgba(0,0,0,0.05);cursor:not-allowed}input{flex:1;min-height:var(--le-input-height);padding:var(--le-input-padding);border:none;background:transparent;color:var(--le-input-color);font-family:inherit;font-size:inherit;outline:none;width:100%}input::placeholder{color:var(--le-input-placeholder-color)}.icon-start,.icon-end{display:flex;align-items:center;justify-content:center;padding:0 8px;color:var(--le-input-desc-color)}.le-input-description{font-size:0.85em;color:var(--le-input-desc-color);margin-top:2px}.le-input-description::has(le-slot>slot[name=description]:empty){display:none}";
999
+ const leButtonDefaultCss = ":host{display:inline-block;--le-button-border-radius:var(--le-radius-md);--le-button-padding-x:0.4rem;--le-button-padding-y:0.4rem;--le-button-small-padding:0.25rem;--le-button-font-size:var(--le-font-size-md);--le-button-font-weight:var(--le-font-weight-medium);--le-button-transition:var(--le-transition-fast);--le-button-icon-aspect-ratio:1;--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-bg-system:var(--le-color-black);--_btn-color:var(--le-color-primary-contrast);--_btn-border-color:var(--le-color-primary)}:host([full-width]){display:block;width:100%}.button{display:inline-flex;align-items:center;justify-content:center;gap:var(--le-spacing-3);width:100%;padding:var(--le-button-padding-y) var(--le-button-padding-x);border:1px solid var(--_btn-border-color);border-radius:var(--le-button-border-radius);background:var(--_btn-bg);color:var(--_btn-color);font-family:var(--le-font-family-base);font-size:var(--le-button-font-size);font-weight:var(--le-button-font-weight);line-height:var(--le-line-height-tight);text-decoration:none;cursor:pointer;transition:background-color var(--le-button-transition) var(--le-transition-easing),\n border-color var(--le-button-transition) var(--le-transition-easing),\n box-shadow var(--le-button-transition) var(--le-transition-easing),\n transform var(--le-button-transition) var(--le-transition-easing)}.button:hover:not(:disabled){background:var(--_btn-bg-hover);border-color:var(--_btn-bg-hover)}.button:active:not(:disabled){transform:translateY(1px)}.button:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.button:disabled{opacity:0.5;cursor:not-allowed}:host>le-component.color-primary{--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-color:var(--le-color-primary-contrast);--_btn-border-color:var(--le-color-primary)}:host>le-component.color-secondary{--_btn-bg:var(--le-color-secondary);--_btn-bg-hover:var(--le-color-secondary-dark);--_btn-color:var(--le-color-secondary-contrast);--_btn-border-color:var(--le-color-secondary)}:host>le-component.color-success{--_btn-bg:var(--le-color-success);--_btn-bg-hover:var(--le-color-success-dark);--_btn-color:var(--le-color-success-contrast);--_btn-border-color:var(--le-color-success)}:host>le-component.color-warning{--_btn-bg:var(--le-color-warning);--_btn-bg-hover:var(--le-color-warning-dark);--_btn-color:var(--le-color-warning-contrast);--_btn-border-color:var(--le-color-warning)}:host>le-component.color-danger{--_btn-bg:var(--le-color-danger);--_btn-bg-hover:var(--le-color-danger-dark);--_btn-color:var(--le-color-danger-contrast);--_btn-border-color:var(--le-color-danger)}:host>le-component.color-info{--_btn-bg:var(--le-color-info);--_btn-bg-hover:var(--le-color-info-dark);--_btn-color:var(--le-color-info-contrast);--_btn-border-color:var(--le-color-info)}:host>le-component.variant-solid .button{box-shadow:var(--le-shadow-sm)}:host>le-component.variant-solid .button:hover:not(:disabled){box-shadow:var(--le-shadow-md)}:host>le-component.variant-outlined .button{background:transparent;color:var(--_btn-bg);border-color:var(--_btn-border-color)}:host>le-component.variant-outlined .button:hover:not(:disabled){background:var(--_btn-bg);color:var(--_btn-color)}:host>le-component.variant-clear .button{background:transparent;color:var(--_btn-bg);border-color:transparent}:host>le-component.variant-clear .button:hover:not(:disabled){background:var(--le-color-gray-100);border-color:transparent}:host>le-component.variant-system .button{background:transparent;color:var(--_btn-bg-system);border-color:transparent}:host>le-component.size-small .button{--le-button-padding-x:0.4rem;--le-button-padding-y:0.3rem;--le-button-padding-top:0.35rem;--le-button-font-size:var(--le-button-small-font-size, var(--le-font-size-xs))}:host>le-component.size-large .button{--le-button-padding-x:0.9rem;--le-button-padding-y:0.6rem;--le-button-font-size:var(--le-font-size-xl)}:host>le-component.full-width{display:block;width:100%}:host>le-component.selected .button{box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.2)}:host>le-component.variant-outlined.selected .button,:host>le-component.variant-clear.selected .button{background:var(--_btn-bg);color:var(--_btn-color)}:host>le-component.icon-only .button{padding:0.5rem;padding-bottom:0.6rem;aspect-ratio:var(--le-button-icon-aspect-ratio, 1)}:host>le-component.icon-only.size-small .button{padding:var(--le-button-small-padding, 0.25rem)}:host>le-component.icon-only.size-large .button{padding:0.75rem}:host>le-component.icon-only .content{display:none}.content{display:inline}.content:empty{display:none}.icon-start,.icon-only,.icon-end{display:flex;align-items:center;justify-content:center}.icon-start:empty,.icon-only:empty,.icon-end:empty{display:none}::slotted([slot=\"icon-start\"]),::slotted([slot=\"icon-only\"]),::slotted([slot=\"icon-end\"]){display:flex;align-items:center;justify-content:center;width:1.125em;height:1.125em}";
1111
1000
 
1112
- const LeStringInput = class {
1113
- constructor(hostRef) {
1114
- registerInstance(this, hostRef);
1115
- this.leChange = createEvent(this, "change");
1116
- this.leInput = createEvent(this, "input");
1001
+ const LeButton = /*@__PURE__*/ proxyCustomElement(class LeButton extends HTMLElement {
1002
+ constructor(registerHost) {
1003
+ super();
1004
+ if (registerHost !== false) {
1005
+ this.__registerHost();
1006
+ }
1007
+ this.__attachShadow();
1008
+ this.leClick = createEvent(this, "click", 7);
1117
1009
  }
1118
- get el() { return getElement(this); }
1010
+ get el() { return this; }
1119
1011
  /**
1120
1012
  * Mode of the popover should be 'default' for internal use
1121
1013
  */
1122
1014
  mode;
1123
1015
  /**
1124
- * The value of the input
1125
- */
1126
- value;
1127
- /**
1128
- * The name of the input
1016
+ * Button variant style
1017
+ * @allowedValues solid | outlined | clear
1129
1018
  */
1130
- name;
1019
+ variant = 'solid';
1131
1020
  /**
1132
- * The type of the input (text, email, password, etc.)
1021
+ * Button color theme (uses theme semantic colors)
1022
+ * @allowedValues primary | secondary | success | warning | danger | info
1133
1023
  */
1134
- type = 'text';
1024
+ color = 'primary';
1135
1025
  /**
1136
- * Label for the input
1026
+ * Button size
1027
+ * @allowedValues small | medium | large
1137
1028
  */
1138
- label;
1029
+ size = 'medium';
1139
1030
  /**
1140
- * Icon for the start icon
1031
+ * Whether the button is in a selected/active state
1141
1032
  */
1142
- iconStart;
1033
+ selected = false;
1143
1034
  /**
1144
- * Icon for the end icon
1035
+ * Whether the button takes full width of its container
1145
1036
  */
1146
- iconEnd;
1037
+ fullWidth = false;
1147
1038
  /**
1148
- * Placeholder text
1039
+ * Whether the button displays only an icon (square aspect ratio)
1149
1040
  */
1150
- placeholder;
1041
+ iconOnly = false;
1151
1042
  /**
1152
- * Whether the input is disabled
1043
+ * Whether the button is disabled
1153
1044
  */
1154
1045
  disabled = false;
1155
1046
  /**
1156
- * Whether the input is read-only
1047
+ * The button type attribute
1048
+ * @allowedValues button | submit | reset
1157
1049
  */
1158
- readonly = false;
1050
+ type = 'button';
1159
1051
  /**
1160
- * External ID for linking with external systems
1052
+ * Optional href to make the button act as a link
1161
1053
  */
1162
- externalId;
1054
+ href;
1163
1055
  /**
1164
- * Emitted when the value changes (on blur or Enter)
1056
+ * Link target when href is set
1165
1057
  */
1166
- leChange;
1058
+ target;
1167
1059
  /**
1168
- * Emitted when the input value changes (on keystroke)
1060
+ * Emitted when the button is clicked.
1061
+ * This is a custom event that wraps the native click but ensures the target is the le-button.
1169
1062
  */
1170
- leInput;
1171
- handleInput = (ev) => {
1172
- const input = ev.target;
1173
- this.value = input.value;
1174
- this.leInput.emit({
1175
- value: this.value,
1176
- name: this.name,
1177
- externalId: this.externalId
1178
- });
1179
- };
1180
- handleChange = (ev) => {
1181
- const input = ev.target;
1182
- this.value = input.value;
1183
- this.leChange.emit({
1184
- value: this.value,
1185
- name: this.name,
1186
- externalId: this.externalId
1187
- });
1188
- };
1189
- handleClick = (ev) => {
1190
- ev.stopPropagation();
1063
+ leClick;
1064
+ handleClick = (event) => {
1065
+ // We stop the internal button click from bubbling up
1066
+ event.stopPropagation();
1067
+ if (this.disabled) {
1068
+ event.preventDefault();
1069
+ return;
1070
+ }
1071
+ // And emit our own click event from the host element
1072
+ this.leClick.emit(event);
1191
1073
  };
1192
1074
  render() {
1193
- return (h("le-component", { key: 'd0c69370dae2d1fee5700954e4823d2a03a51331', component: "le-string-input", hostClass: classnames({ 'disabled': this.disabled }) }, h("div", { key: '4acae8d3c34da2a86970a616c493ff210d561f5f', class: "le-input-wrapper" }, this.label && (h("label", { key: '609191b45187b6b1a65d05cd594b149760ac6882', class: "le-input-label", htmlFor: this.name }, this.label)), h("div", { key: '36b4caff4468ac7421db03f811cb3ef4a622b001', class: "le-input-container" }, this.iconStart && (h("span", { key: '344f88887fe8270bbef7e26ec1ad5da9fae1f8e4', class: "icon-start" }, this.iconStart)), h("input", { key: '4ba7beeddd7fb3cf23d03e029d11a804764cdd6e', id: this.name, type: this.type, name: this.name, value: this.value, placeholder: this.placeholder, disabled: this.disabled, readOnly: this.readonly, onInput: this.handleInput, onChange: this.handleChange, onClick: this.handleClick }), this.iconEnd && (h("span", { key: '7cdd4b52c3e1a1b18b19e697bdb42431941bba01', class: "icon-end" }, this.iconEnd))), h("div", { key: '113a75aa413e4d95300aeaa97d1ce7a75cf68c7a', class: "le-input-description" }, h("le-slot", { key: '0b37fc14e6df68f6c44cf9001d63a70f019e1cc3', name: "description", type: "text", tag: "p", label: "Description" }, h("slot", { key: '2674056dc915fabdb4fcbcaa13294a116b9509a6', name: "description" }))))));
1075
+ const classes = classnames(`variant-${this.variant}`, `color-${this.color}`, `size-${this.size}`, {
1076
+ 'selected': this.selected,
1077
+ 'full-width': this.fullWidth,
1078
+ 'icon-only': this.iconOnly,
1079
+ 'disabled': this.disabled,
1080
+ });
1081
+ const TagType = this.href ? 'a' : 'button';
1082
+ const attrs = this.href ? { href: this.href, target: this.target, role: 'button' } : { type: this.type, disabled: this.disabled };
1083
+ return (h("le-component", { key: '363dbfddf4a765bfd6f36ed16d0912e281153806', component: "le-button", hostClass: classes }, h(TagType, { key: 'e112acdff4278e976ad767bd1ea7c9ced5e85f43', class: "button", part: "button", ...attrs, onClick: this.handleClick }, this.iconOnly ? (h("span", { class: "icon-start" }, h("slot", { name: "icon-only" }))) : (h(Fragment, null, h("span", { class: "icon-start" }, h("slot", { name: "icon-start" })), h("le-slot", { name: "", description: "Button text", type: "text", class: "content", part: "content" }, h("slot", null)), h("span", { class: "icon-end" }, h("slot", { name: "icon-end" })))))));
1084
+ }
1085
+ static get style() { return leButtonDefaultCss; }
1086
+ }, [769, "le-button", {
1087
+ "mode": [1537],
1088
+ "variant": [1],
1089
+ "color": [1],
1090
+ "size": [1],
1091
+ "selected": [4],
1092
+ "fullWidth": [516, "full-width"],
1093
+ "iconOnly": [4, "icon-only"],
1094
+ "disabled": [4],
1095
+ "type": [1],
1096
+ "href": [1],
1097
+ "target": [1]
1098
+ }]);
1099
+ function defineCustomElement() {
1100
+ if (typeof customElements === "undefined") {
1101
+ return;
1194
1102
  }
1195
- };
1196
- LeStringInput.style = leStringInputCss;
1103
+ const components = ["le-button", "le-button", "le-checkbox", "le-component", "le-popover", "le-slot", "le-string-input"];
1104
+ components.forEach(tagName => { switch (tagName) {
1105
+ case "le-button":
1106
+ if (!customElements.get(tagName)) {
1107
+ customElements.define(tagName, LeButton);
1108
+ }
1109
+ break;
1110
+ case "le-button":
1111
+ if (!customElements.get(tagName)) {
1112
+ defineCustomElement();
1113
+ }
1114
+ break;
1115
+ case "le-checkbox":
1116
+ if (!customElements.get(tagName)) {
1117
+ defineCustomElement$1();
1118
+ }
1119
+ break;
1120
+ case "le-component":
1121
+ if (!customElements.get(tagName)) {
1122
+ defineCustomElement$2();
1123
+ }
1124
+ break;
1125
+ case "le-popover":
1126
+ if (!customElements.get(tagName)) {
1127
+ defineCustomElement$5();
1128
+ }
1129
+ break;
1130
+ case "le-slot":
1131
+ if (!customElements.get(tagName)) {
1132
+ defineCustomElement$3();
1133
+ }
1134
+ break;
1135
+ case "le-string-input":
1136
+ if (!customElements.get(tagName)) {
1137
+ defineCustomElement$4();
1138
+ }
1139
+ break;
1140
+ } });
1141
+ }
1142
+
1143
+ export { LeButton as L, defineCustomElement$3 as a, defineCustomElement$2 as b, defineCustomElement$1 as c, defineCustomElement$4 as d, defineCustomElement as e, LeCheckbox as f, LeComponent as g, LeSlot as h, LeStringInput as i };
1144
+ //# sourceMappingURL=le-button2.js.map
1197
1145
 
1198
- export { LeButton as le_button, LeCheckbox as le_checkbox, LeComponent as le_component, LePopover as le_popover, LeSlot as le_slot, LeStringInput as le_string_input };
1199
- //# sourceMappingURL=le-button.le-checkbox.le-component.le-popover.le-slot.le-string-input.entry.js.map
1146
+ //# sourceMappingURL=le-button2.js.map