le-kit 0.1.3 → 0.1.5

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