le-kit 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/LLM_CONTEXT.md +95 -34
  2. package/package.json +3 -1
  3. package/readme.md +2 -0
  4. package/dist/cjs/index-BzadfLTc.js +0 -1864
  5. package/dist/cjs/index-BzadfLTc.js.map +0 -1
  6. package/dist/cjs/index.cjs.js +0 -124
  7. package/dist/cjs/index.cjs.js.map +0 -1
  8. package/dist/cjs/le-bar_16.cjs.entry.js +0 -3397
  9. package/dist/cjs/le-box.cjs.entry.js +0 -136
  10. package/dist/cjs/le-breadcrumbs.cjs.entry.js +0 -223
  11. package/dist/cjs/le-card.cjs.entry.js +0 -29
  12. package/dist/cjs/le-code-input.cjs.entry.js +0 -147
  13. package/dist/cjs/le-combobox.cjs.entry.js +0 -210
  14. package/dist/cjs/le-header-placeholder.cjs.entry.js +0 -18
  15. package/dist/cjs/le-kit.cjs.js +0 -27
  16. package/dist/cjs/le-kit.cjs.js.map +0 -1
  17. package/dist/cjs/le-multiselect.cjs.entry.js +0 -284
  18. package/dist/cjs/le-number-input.cjs.entry.js +0 -162
  19. package/dist/cjs/le-round-progress.cjs.entry.js +0 -101
  20. package/dist/cjs/le-segmented-control.cjs.entry.js +0 -235
  21. package/dist/cjs/le-side-panel-toggle.cjs.entry.js +0 -213
  22. package/dist/cjs/le-side-panel.cjs.entry.js +0 -539
  23. package/dist/cjs/le-stack.cjs.entry.js +0 -122
  24. package/dist/cjs/le-tab-bar.cjs.entry.js +0 -233
  25. package/dist/cjs/le-tab-panel.cjs.entry.js +0 -82
  26. package/dist/cjs/le-tab.cjs.entry.js +0 -98
  27. package/dist/cjs/le-tabs.cjs.entry.js +0 -297
  28. package/dist/cjs/le-tag.cjs.entry.js +0 -51
  29. package/dist/cjs/le-text.cjs.entry.js +0 -318
  30. package/dist/cjs/le-turntable.cjs.entry.js +0 -131
  31. package/dist/cjs/loader.cjs.js +0 -15
  32. package/dist/cjs/loader.cjs.js.map +0 -1
  33. package/dist/cjs/utils-Dxx9WhWK.js +0 -152
  34. package/dist/cjs/utils-Dxx9WhWK.js.map +0 -1
  35. package/dist/collection/collection-manifest.json +0 -48
  36. package/dist/collection/components/le-bar/le-bar.css +0 -255
  37. package/dist/collection/components/le-bar/le-bar.js +0 -673
  38. package/dist/collection/components/le-bar/le-bar.js.map +0 -1
  39. package/dist/collection/components/le-box/le-box.css +0 -37
  40. package/dist/collection/components/le-box/le-box.js +0 -567
  41. package/dist/collection/components/le-box/le-box.js.map +0 -1
  42. package/dist/collection/components/le-breadcrumbs/le-breadcrumbs.css +0 -72
  43. package/dist/collection/components/le-breadcrumbs/le-breadcrumbs.js +0 -372
  44. package/dist/collection/components/le-breadcrumbs/le-breadcrumbs.js.map +0 -1
  45. package/dist/collection/components/le-button/le-button.css +0 -290
  46. package/dist/collection/components/le-button/le-button.js +0 -431
  47. package/dist/collection/components/le-button/le-button.js.map +0 -1
  48. package/dist/collection/components/le-card/le-card.css +0 -74
  49. package/dist/collection/components/le-card/le-card.js +0 -103
  50. package/dist/collection/components/le-card/le-card.js.map +0 -1
  51. package/dist/collection/components/le-checkbox/le-checkbox.css +0 -93
  52. package/dist/collection/components/le-checkbox/le-checkbox.js +0 -177
  53. package/dist/collection/components/le-checkbox/le-checkbox.js.map +0 -1
  54. package/dist/collection/components/le-code-input/le-code-input.css +0 -106
  55. package/dist/collection/components/le-code-input/le-code-input.js +0 -433
  56. package/dist/collection/components/le-code-input/le-code-input.js.map +0 -1
  57. package/dist/collection/components/le-collapse/le-collapse.css +0 -31
  58. package/dist/collection/components/le-collapse/le-collapse.js +0 -185
  59. package/dist/collection/components/le-collapse/le-collapse.js.map +0 -1
  60. package/dist/collection/components/le-combobox/le-combobox.css +0 -144
  61. package/dist/collection/components/le-combobox/le-combobox.js +0 -633
  62. package/dist/collection/components/le-combobox/le-combobox.js.map +0 -1
  63. package/dist/collection/components/le-component/le-component.css +0 -189
  64. package/dist/collection/components/le-component/le-component.js +0 -343
  65. package/dist/collection/components/le-component/le-component.js.map +0 -1
  66. package/dist/collection/components/le-current-heading/le-current-heading.css +0 -13
  67. package/dist/collection/components/le-current-heading/le-current-heading.js +0 -131
  68. package/dist/collection/components/le-current-heading/le-current-heading.js.map +0 -1
  69. package/dist/collection/components/le-dropdown-base/le-dropdown-base.css +0 -167
  70. package/dist/collection/components/le-dropdown-base/le-dropdown-base.js +0 -735
  71. package/dist/collection/components/le-dropdown-base/le-dropdown-base.js.map +0 -1
  72. package/dist/collection/components/le-header/le-header.css +0 -120
  73. package/dist/collection/components/le-header/le-header.js +0 -485
  74. package/dist/collection/components/le-header/le-header.js.map +0 -1
  75. package/dist/collection/components/le-header-placeholder/le-header-placeholder.js +0 -21
  76. package/dist/collection/components/le-header-placeholder/le-header-placeholder.js.map +0 -1
  77. package/dist/collection/components/le-icon/le-icon.css +0 -13
  78. package/dist/collection/components/le-icon/le-icon.js +0 -185
  79. package/dist/collection/components/le-icon/le-icon.js.map +0 -1
  80. package/dist/collection/components/le-multiselect/le-multiselect.css +0 -163
  81. package/dist/collection/components/le-multiselect/le-multiselect.js +0 -713
  82. package/dist/collection/components/le-multiselect/le-multiselect.js.map +0 -1
  83. package/dist/collection/components/le-navigation/le-navigation.css +0 -330
  84. package/dist/collection/components/le-navigation/le-navigation.js +0 -690
  85. package/dist/collection/components/le-navigation/le-navigation.js.map +0 -1
  86. package/dist/collection/components/le-number-input/le-number-input.css +0 -135
  87. package/dist/collection/components/le-number-input/le-number-input.js +0 -476
  88. package/dist/collection/components/le-number-input/le-number-input.js.map +0 -1
  89. package/dist/collection/components/le-popover/le-popover.css +0 -164
  90. package/dist/collection/components/le-popover/le-popover.js +0 -828
  91. package/dist/collection/components/le-popover/le-popover.js.map +0 -1
  92. package/dist/collection/components/le-popup/le-popup.api.js +0 -102
  93. package/dist/collection/components/le-popup/le-popup.api.js.map +0 -1
  94. package/dist/collection/components/le-popup/le-popup.css +0 -222
  95. package/dist/collection/components/le-popup/le-popup.js +0 -600
  96. package/dist/collection/components/le-popup/le-popup.js.map +0 -1
  97. package/dist/collection/components/le-round-progress/le-round-progress.css +0 -34
  98. package/dist/collection/components/le-round-progress/le-round-progress.js +0 -179
  99. package/dist/collection/components/le-round-progress/le-round-progress.js.map +0 -1
  100. package/dist/collection/components/le-scroll-progress/le-scroll-progress.css +0 -29
  101. package/dist/collection/components/le-scroll-progress/le-scroll-progress.js +0 -185
  102. package/dist/collection/components/le-scroll-progress/le-scroll-progress.js.map +0 -1
  103. package/dist/collection/components/le-segmented-control/le-segmented-control.css +0 -78
  104. package/dist/collection/components/le-segmented-control/le-segmented-control.js +0 -436
  105. package/dist/collection/components/le-segmented-control/le-segmented-control.js.map +0 -1
  106. package/dist/collection/components/le-select/le-select.css +0 -121
  107. package/dist/collection/components/le-select/le-select.js +0 -556
  108. package/dist/collection/components/le-select/le-select.js.map +0 -1
  109. package/dist/collection/components/le-side-panel/le-side-panel.css +0 -202
  110. package/dist/collection/components/le-side-panel/le-side-panel.js +0 -948
  111. package/dist/collection/components/le-side-panel/le-side-panel.js.map +0 -1
  112. package/dist/collection/components/le-side-panel-toggle/le-side-panel-toggle.js +0 -595
  113. package/dist/collection/components/le-side-panel-toggle/le-side-panel-toggle.js.map +0 -1
  114. package/dist/collection/components/le-slot/le-slot.default.css +0 -222
  115. package/dist/collection/components/le-slot/le-slot.js +0 -590
  116. package/dist/collection/components/le-slot/le-slot.js.map +0 -1
  117. package/dist/collection/components/le-stack/le-stack.default.css +0 -37
  118. package/dist/collection/components/le-stack/le-stack.js +0 -377
  119. package/dist/collection/components/le-stack/le-stack.js.map +0 -1
  120. package/dist/collection/components/le-string-input/le-string-input.css +0 -83
  121. package/dist/collection/components/le-string-input/le-string-input.js +0 -370
  122. package/dist/collection/components/le-string-input/le-string-input.js.map +0 -1
  123. package/dist/collection/components/le-tab/le-tab.css +0 -289
  124. package/dist/collection/components/le-tab/le-tab.js +0 -528
  125. package/dist/collection/components/le-tab/le-tab.js.map +0 -1
  126. package/dist/collection/components/le-tab-bar/le-tab-bar.css +0 -89
  127. package/dist/collection/components/le-tab-bar/le-tab-bar.js +0 -459
  128. package/dist/collection/components/le-tab-bar/le-tab-bar.js.map +0 -1
  129. package/dist/collection/components/le-tab-panel/le-tab-panel.css +0 -30
  130. package/dist/collection/components/le-tab-panel/le-tab-panel.js +0 -285
  131. package/dist/collection/components/le-tab-panel/le-tab-panel.js.map +0 -1
  132. package/dist/collection/components/le-tabs/le-tabs.css +0 -146
  133. package/dist/collection/components/le-tabs/le-tabs.js +0 -579
  134. package/dist/collection/components/le-tabs/le-tabs.js.map +0 -1
  135. package/dist/collection/components/le-tag/le-tag.css +0 -139
  136. package/dist/collection/components/le-tag/le-tag.js +0 -251
  137. package/dist/collection/components/le-tag/le-tag.js.map +0 -1
  138. package/dist/collection/components/le-text/le-text.css +0 -169
  139. package/dist/collection/components/le-text/le-text.js +0 -459
  140. package/dist/collection/components/le-text/le-text.js.map +0 -1
  141. package/dist/collection/components/le-turntable/le-turntable.css +0 -10
  142. package/dist/collection/components/le-turntable/le-turntable.js +0 -202
  143. package/dist/collection/components/le-turntable/le-turntable.js.map +0 -1
  144. package/dist/collection/dist/components/assets/custom-elements.json +0 -12263
  145. package/dist/collection/dist/components/assets/icons/arrow-left.json +0 -21
  146. package/dist/collection/dist/components/assets/icons/arrow-right.json +0 -21
  147. package/dist/collection/dist/components/assets/icons/check.json +0 -12
  148. package/dist/collection/dist/components/assets/icons/chevron-down.json +0 -12
  149. package/dist/collection/dist/components/assets/icons/chevron-left.json +0 -12
  150. package/dist/collection/dist/components/assets/icons/chevron-right.json +0 -12
  151. package/dist/collection/dist/components/assets/icons/chevron-up.json +0 -12
  152. package/dist/collection/dist/components/assets/icons/ellipsis-horizontal.json +0 -14
  153. package/dist/collection/dist/components/assets/icons/ellipsis-vertical.json +0 -14
  154. package/dist/collection/dist/components/assets/icons/hamburger.json +0 -14
  155. package/dist/collection/dist/components/assets/icons/side-panel.json +0 -61
  156. package/dist/collection/dist/themes/base.css +0 -89
  157. package/dist/collection/dist/themes/dark.css +0 -104
  158. package/dist/collection/dist/themes/default.css +0 -112
  159. package/dist/collection/dist/themes/gradient.css +0 -104
  160. package/dist/collection/dist/themes/index.css +0 -76
  161. package/dist/collection/dist/themes/minimal.css +0 -104
  162. package/dist/collection/dist/themes/warm.css +0 -104
  163. package/dist/collection/global/app.js +0 -177
  164. package/dist/collection/global/app.js.map +0 -1
  165. package/dist/collection/index.js +0 -16
  166. package/dist/collection/index.js.map +0 -1
  167. package/dist/collection/types/blocks.js +0 -115
  168. package/dist/collection/types/blocks.js.map +0 -1
  169. package/dist/collection/types/options.js +0 -2
  170. package/dist/collection/types/options.js.map +0 -1
  171. package/dist/collection/utils/utils.js +0 -141
  172. package/dist/collection/utils/utils.js.map +0 -1
  173. package/dist/components/app.js +0 -180
  174. package/dist/components/app.js.map +0 -1
  175. package/dist/components/assets/custom-elements.json +0 -12263
  176. package/dist/components/assets/icons/arrow-left.json +0 -21
  177. package/dist/components/assets/icons/arrow-right.json +0 -21
  178. package/dist/components/assets/icons/check.json +0 -12
  179. package/dist/components/assets/icons/chevron-down.json +0 -12
  180. package/dist/components/assets/icons/chevron-left.json +0 -12
  181. package/dist/components/assets/icons/chevron-right.json +0 -12
  182. package/dist/components/assets/icons/chevron-up.json +0 -12
  183. package/dist/components/assets/icons/ellipsis-horizontal.json +0 -14
  184. package/dist/components/assets/icons/ellipsis-vertical.json +0 -14
  185. package/dist/components/assets/icons/hamburger.json +0 -14
  186. package/dist/components/assets/icons/side-panel.json +0 -61
  187. package/dist/components/index.d.ts +0 -33
  188. package/dist/components/index.js +0 -12
  189. package/dist/components/index.js.map +0 -1
  190. package/dist/components/le-bar.d.ts +0 -11
  191. package/dist/components/le-bar.js +0 -9
  192. package/dist/components/le-bar.js.map +0 -1
  193. package/dist/components/le-bar2.js +0 -498
  194. package/dist/components/le-bar2.js.map +0 -1
  195. package/dist/components/le-box.d.ts +0 -11
  196. package/dist/components/le-box.js +0 -225
  197. package/dist/components/le-box.js.map +0 -1
  198. package/dist/components/le-breadcrumbs.d.ts +0 -11
  199. package/dist/components/le-breadcrumbs.js +0 -327
  200. package/dist/components/le-breadcrumbs.js.map +0 -1
  201. package/dist/components/le-button.d.ts +0 -11
  202. package/dist/components/le-button.js +0 -9
  203. package/dist/components/le-button.js.map +0 -1
  204. package/dist/components/le-button2.js +0 -1577
  205. package/dist/components/le-button2.js.map +0 -1
  206. package/dist/components/le-card.d.ts +0 -11
  207. package/dist/components/le-card.js +0 -100
  208. package/dist/components/le-card.js.map +0 -1
  209. package/dist/components/le-checkbox.d.ts +0 -11
  210. package/dist/components/le-checkbox.js +0 -9
  211. package/dist/components/le-checkbox.js.map +0 -1
  212. package/dist/components/le-code-input.d.ts +0 -11
  213. package/dist/components/le-code-input.js +0 -231
  214. package/dist/components/le-code-input.js.map +0 -1
  215. package/dist/components/le-collapse.d.ts +0 -11
  216. package/dist/components/le-collapse.js +0 -9
  217. package/dist/components/le-collapse.js.map +0 -1
  218. package/dist/components/le-collapse2.js +0 -138
  219. package/dist/components/le-collapse2.js.map +0 -1
  220. package/dist/components/le-combobox.d.ts +0 -11
  221. package/dist/components/le-combobox.js +0 -299
  222. package/dist/components/le-combobox.js.map +0 -1
  223. package/dist/components/le-component.d.ts +0 -11
  224. package/dist/components/le-component.js +0 -9
  225. package/dist/components/le-component.js.map +0 -1
  226. package/dist/components/le-current-heading.d.ts +0 -11
  227. package/dist/components/le-current-heading.js +0 -93
  228. package/dist/components/le-current-heading.js.map +0 -1
  229. package/dist/components/le-dropdown-base.d.ts +0 -11
  230. package/dist/components/le-dropdown-base.js +0 -9
  231. package/dist/components/le-dropdown-base.js.map +0 -1
  232. package/dist/components/le-dropdown-base2.js +0 -366
  233. package/dist/components/le-dropdown-base2.js.map +0 -1
  234. package/dist/components/le-header-placeholder.d.ts +0 -11
  235. package/dist/components/le-header-placeholder.js +0 -37
  236. package/dist/components/le-header-placeholder.js.map +0 -1
  237. package/dist/components/le-header.d.ts +0 -11
  238. package/dist/components/le-header.js +0 -325
  239. package/dist/components/le-header.js.map +0 -1
  240. package/dist/components/le-icon.d.ts +0 -11
  241. package/dist/components/le-icon.js +0 -9
  242. package/dist/components/le-icon.js.map +0 -1
  243. package/dist/components/le-icon2.js +0 -149
  244. package/dist/components/le-icon2.js.map +0 -1
  245. package/dist/components/le-multiselect.d.ts +0 -11
  246. package/dist/components/le-multiselect.js +0 -383
  247. package/dist/components/le-multiselect.js.map +0 -1
  248. package/dist/components/le-navigation.d.ts +0 -11
  249. package/dist/components/le-navigation.js +0 -9
  250. package/dist/components/le-navigation.js.map +0 -1
  251. package/dist/components/le-navigation2.js +0 -488
  252. package/dist/components/le-navigation2.js.map +0 -1
  253. package/dist/components/le-number-input.d.ts +0 -11
  254. package/dist/components/le-number-input.js +0 -248
  255. package/dist/components/le-number-input.js.map +0 -1
  256. package/dist/components/le-popover.d.ts +0 -11
  257. package/dist/components/le-popover.js +0 -9
  258. package/dist/components/le-popover.js.map +0 -1
  259. package/dist/components/le-popover2.js +0 -642
  260. package/dist/components/le-popover2.js.map +0 -1
  261. package/dist/components/le-popup.api.js +0 -106
  262. package/dist/components/le-popup.api.js.map +0 -1
  263. package/dist/components/le-popup.d.ts +0 -11
  264. package/dist/components/le-popup.js +0 -9
  265. package/dist/components/le-popup.js.map +0 -1
  266. package/dist/components/le-round-progress.d.ts +0 -11
  267. package/dist/components/le-round-progress.js +0 -130
  268. package/dist/components/le-round-progress.js.map +0 -1
  269. package/dist/components/le-scroll-progress.d.ts +0 -11
  270. package/dist/components/le-scroll-progress.js +0 -140
  271. package/dist/components/le-scroll-progress.js.map +0 -1
  272. package/dist/components/le-segmented-control.d.ts +0 -11
  273. package/dist/components/le-segmented-control.js +0 -321
  274. package/dist/components/le-segmented-control.js.map +0 -1
  275. package/dist/components/le-select.d.ts +0 -11
  276. package/dist/components/le-select.js +0 -9
  277. package/dist/components/le-select.js.map +0 -1
  278. package/dist/components/le-side-panel-toggle.d.ts +0 -11
  279. package/dist/components/le-side-panel-toggle.js +0 -9
  280. package/dist/components/le-side-panel-toggle.js.map +0 -1
  281. package/dist/components/le-side-panel-toggle2.js +0 -295
  282. package/dist/components/le-side-panel-toggle2.js.map +0 -1
  283. package/dist/components/le-side-panel.d.ts +0 -11
  284. package/dist/components/le-side-panel.js +0 -654
  285. package/dist/components/le-side-panel.js.map +0 -1
  286. package/dist/components/le-slot.d.ts +0 -11
  287. package/dist/components/le-slot.js +0 -9
  288. package/dist/components/le-slot.js.map +0 -1
  289. package/dist/components/le-stack.d.ts +0 -11
  290. package/dist/components/le-stack.js +0 -202
  291. package/dist/components/le-stack.js.map +0 -1
  292. package/dist/components/le-string-input.d.ts +0 -11
  293. package/dist/components/le-string-input.js +0 -9
  294. package/dist/components/le-string-input.js.map +0 -1
  295. package/dist/components/le-tab-bar.d.ts +0 -11
  296. package/dist/components/le-tab-bar.js +0 -321
  297. package/dist/components/le-tab-bar.js.map +0 -1
  298. package/dist/components/le-tab-panel.d.ts +0 -11
  299. package/dist/components/le-tab-panel.js +0 -164
  300. package/dist/components/le-tab-panel.js.map +0 -1
  301. package/dist/components/le-tab.d.ts +0 -11
  302. package/dist/components/le-tab.js +0 -9
  303. package/dist/components/le-tab.js.map +0 -1
  304. package/dist/components/le-tab2.js +0 -182
  305. package/dist/components/le-tab2.js.map +0 -1
  306. package/dist/components/le-tabs.d.ts +0 -11
  307. package/dist/components/le-tabs.js +0 -387
  308. package/dist/components/le-tabs.js.map +0 -1
  309. package/dist/components/le-tag.d.ts +0 -11
  310. package/dist/components/le-tag.js +0 -9
  311. package/dist/components/le-tag.js.map +0 -1
  312. package/dist/components/le-tag2.js +0 -124
  313. package/dist/components/le-tag2.js.map +0 -1
  314. package/dist/components/le-text.d.ts +0 -11
  315. package/dist/components/le-text.js +0 -398
  316. package/dist/components/le-text.js.map +0 -1
  317. package/dist/components/le-turntable.d.ts +0 -11
  318. package/dist/components/le-turntable.js +0 -156
  319. package/dist/components/le-turntable.js.map +0 -1
  320. package/dist/components/utils.js +0 -146
  321. package/dist/components/utils.js.map +0 -1
  322. package/dist/docs.d.ts +0 -443
  323. package/dist/docs.json +0 -14581
  324. package/dist/esm/index-DFTm5BqT.js +0 -1844
  325. package/dist/esm/index-DFTm5BqT.js.map +0 -1
  326. package/dist/esm/index.js +0 -109
  327. package/dist/esm/index.js.map +0 -1
  328. package/dist/esm/le-bar_16.entry.js +0 -3380
  329. package/dist/esm/le-box.entry.js +0 -134
  330. package/dist/esm/le-box.entry.js.map +0 -1
  331. package/dist/esm/le-breadcrumbs.entry.js +0 -221
  332. package/dist/esm/le-breadcrumbs.entry.js.map +0 -1
  333. package/dist/esm/le-card.entry.js +0 -27
  334. package/dist/esm/le-card.entry.js.map +0 -1
  335. package/dist/esm/le-code-input.entry.js +0 -145
  336. package/dist/esm/le-code-input.entry.js.map +0 -1
  337. package/dist/esm/le-combobox.entry.js +0 -208
  338. package/dist/esm/le-combobox.entry.js.map +0 -1
  339. package/dist/esm/le-header-placeholder.entry.js +0 -16
  340. package/dist/esm/le-header-placeholder.entry.js.map +0 -1
  341. package/dist/esm/le-kit.js +0 -23
  342. package/dist/esm/le-kit.js.map +0 -1
  343. package/dist/esm/le-multiselect.entry.js +0 -282
  344. package/dist/esm/le-multiselect.entry.js.map +0 -1
  345. package/dist/esm/le-number-input.entry.js +0 -160
  346. package/dist/esm/le-number-input.entry.js.map +0 -1
  347. package/dist/esm/le-round-progress.entry.js +0 -99
  348. package/dist/esm/le-round-progress.entry.js.map +0 -1
  349. package/dist/esm/le-segmented-control.entry.js +0 -233
  350. package/dist/esm/le-segmented-control.entry.js.map +0 -1
  351. package/dist/esm/le-side-panel-toggle.entry.js +0 -211
  352. package/dist/esm/le-side-panel-toggle.entry.js.map +0 -1
  353. package/dist/esm/le-side-panel.entry.js +0 -537
  354. package/dist/esm/le-side-panel.entry.js.map +0 -1
  355. package/dist/esm/le-stack.entry.js +0 -120
  356. package/dist/esm/le-stack.entry.js.map +0 -1
  357. package/dist/esm/le-tab-bar.entry.js +0 -231
  358. package/dist/esm/le-tab-bar.entry.js.map +0 -1
  359. package/dist/esm/le-tab-panel.entry.js +0 -80
  360. package/dist/esm/le-tab-panel.entry.js.map +0 -1
  361. package/dist/esm/le-tab.entry.js +0 -96
  362. package/dist/esm/le-tab.entry.js.map +0 -1
  363. package/dist/esm/le-tabs.entry.js +0 -295
  364. package/dist/esm/le-tabs.entry.js.map +0 -1
  365. package/dist/esm/le-tag.entry.js +0 -49
  366. package/dist/esm/le-tag.entry.js.map +0 -1
  367. package/dist/esm/le-text.entry.js +0 -316
  368. package/dist/esm/le-text.entry.js.map +0 -1
  369. package/dist/esm/le-turntable.entry.js +0 -129
  370. package/dist/esm/le-turntable.entry.js.map +0 -1
  371. package/dist/esm/loader.js +0 -13
  372. package/dist/esm/loader.js.map +0 -1
  373. package/dist/esm/utils-DZYCZLrF.js +0 -146
  374. package/dist/esm/utils-DZYCZLrF.js.map +0 -1
  375. package/dist/index.cjs.js +0 -1
  376. package/dist/index.js +0 -1
  377. package/dist/le-kit/dist/components/assets/custom-elements.json +0 -12263
  378. package/dist/le-kit/dist/components/assets/icons/arrow-left.json +0 -21
  379. package/dist/le-kit/dist/components/assets/icons/arrow-right.json +0 -21
  380. package/dist/le-kit/dist/components/assets/icons/check.json +0 -12
  381. package/dist/le-kit/dist/components/assets/icons/chevron-down.json +0 -12
  382. package/dist/le-kit/dist/components/assets/icons/chevron-left.json +0 -12
  383. package/dist/le-kit/dist/components/assets/icons/chevron-right.json +0 -12
  384. package/dist/le-kit/dist/components/assets/icons/chevron-up.json +0 -12
  385. package/dist/le-kit/dist/components/assets/icons/ellipsis-horizontal.json +0 -14
  386. package/dist/le-kit/dist/components/assets/icons/ellipsis-vertical.json +0 -14
  387. package/dist/le-kit/dist/components/assets/icons/hamburger.json +0 -14
  388. package/dist/le-kit/dist/components/assets/icons/side-panel.json +0 -61
  389. package/dist/le-kit/dist/themes/base.css +0 -89
  390. package/dist/le-kit/dist/themes/dark.css +0 -104
  391. package/dist/le-kit/dist/themes/default.css +0 -112
  392. package/dist/le-kit/dist/themes/gradient.css +0 -104
  393. package/dist/le-kit/dist/themes/index.css +0 -76
  394. package/dist/le-kit/dist/themes/minimal.css +0 -104
  395. package/dist/le-kit/dist/themes/warm.css +0 -104
  396. package/dist/le-kit/index.esm.js +0 -2
  397. package/dist/le-kit/index.esm.js.map +0 -1
  398. package/dist/le-kit/le-kit.css +0 -1
  399. package/dist/le-kit/le-kit.esm.js +0 -2
  400. package/dist/le-kit/le-kit.esm.js.map +0 -1
  401. package/dist/le-kit/loader.esm.js.map +0 -1
  402. package/dist/le-kit/p-3067b18f.entry.js +0 -2
  403. package/dist/le-kit/p-3067b18f.entry.js.map +0 -1
  404. package/dist/le-kit/p-34c4d97d.entry.js +0 -2
  405. package/dist/le-kit/p-34c4d97d.entry.js.map +0 -1
  406. package/dist/le-kit/p-45182541.entry.js +0 -2
  407. package/dist/le-kit/p-45182541.entry.js.map +0 -1
  408. package/dist/le-kit/p-52a41c96.entry.js +0 -2
  409. package/dist/le-kit/p-52a41c96.entry.js.map +0 -1
  410. package/dist/le-kit/p-55fb5dd2.entry.js +0 -2
  411. package/dist/le-kit/p-55fb5dd2.entry.js.map +0 -1
  412. package/dist/le-kit/p-649025f4.entry.js +0 -2
  413. package/dist/le-kit/p-649025f4.entry.js.map +0 -1
  414. package/dist/le-kit/p-67930309.entry.js +0 -2
  415. package/dist/le-kit/p-67930309.entry.js.map +0 -1
  416. package/dist/le-kit/p-6d222705.entry.js +0 -2
  417. package/dist/le-kit/p-6d222705.entry.js.map +0 -1
  418. package/dist/le-kit/p-8049e0c2.entry.js +0 -2
  419. package/dist/le-kit/p-8049e0c2.entry.js.map +0 -1
  420. package/dist/le-kit/p-884f57bd.entry.js +0 -2
  421. package/dist/le-kit/p-884f57bd.entry.js.map +0 -1
  422. package/dist/le-kit/p-88c70f9d.entry.js +0 -2
  423. package/dist/le-kit/p-88c70f9d.entry.js.map +0 -1
  424. package/dist/le-kit/p-96610729.entry.js +0 -2
  425. package/dist/le-kit/p-96610729.entry.js.map +0 -1
  426. package/dist/le-kit/p-D8RYDS9p.js +0 -2
  427. package/dist/le-kit/p-D8RYDS9p.js.map +0 -1
  428. package/dist/le-kit/p-DFTm5BqT.js +0 -3
  429. package/dist/le-kit/p-DFTm5BqT.js.map +0 -1
  430. package/dist/le-kit/p-a34054e0.entry.js +0 -2
  431. package/dist/le-kit/p-a34054e0.entry.js.map +0 -1
  432. package/dist/le-kit/p-a388e46a.entry.js +0 -2
  433. package/dist/le-kit/p-a388e46a.entry.js.map +0 -1
  434. package/dist/le-kit/p-c0c53650.entry.js +0 -2
  435. package/dist/le-kit/p-c0c53650.entry.js.map +0 -1
  436. package/dist/le-kit/p-cbf17514.entry.js +0 -2
  437. package/dist/le-kit/p-cbf17514.entry.js.map +0 -1
  438. package/dist/le-kit/p-d934de74.entry.js +0 -2
  439. package/dist/le-kit/p-d934de74.entry.js.map +0 -1
  440. package/dist/le-kit/p-de72c8b5.entry.js +0 -2
  441. package/dist/le-kit/p-de72c8b5.entry.js.map +0 -1
  442. package/dist/le-kit/p-e3dd0f2a.entry.js +0 -2
  443. package/dist/le-kit/p-e3dd0f2a.entry.js.map +0 -1
  444. package/dist/le-kit/p-ee170967.entry.js +0 -2
  445. package/dist/le-kit/p-ee170967.entry.js.map +0 -1
  446. package/dist/le-kit/p-eedb2f75.entry.js +0 -2
  447. package/dist/le-kit/p-eedb2f75.entry.js.map +0 -1
  448. package/dist/themes/base.css +0 -89
  449. package/dist/themes/dark.css +0 -104
  450. package/dist/themes/default.css +0 -112
  451. package/dist/themes/gradient.css +0 -104
  452. package/dist/themes/index.css +0 -76
  453. package/dist/themes/minimal.css +0 -104
  454. package/dist/themes/warm.css +0 -104
  455. package/dist/types/components/le-bar/le-bar.d.ts +0 -131
  456. package/dist/types/components/le-box/le-box.d.ts +0 -111
  457. package/dist/types/components/le-breadcrumbs/le-breadcrumbs.d.ts +0 -57
  458. package/dist/types/components/le-button/le-button.d.ts +0 -93
  459. package/dist/types/components/le-card/le-card.d.ts +0 -37
  460. package/dist/types/components/le-checkbox/le-checkbox.d.ts +0 -46
  461. package/dist/types/components/le-code-input/le-code-input.d.ts +0 -102
  462. package/dist/types/components/le-collapse/le-collapse.d.ts +0 -43
  463. package/dist/types/components/le-combobox/le-combobox.d.ts +0 -128
  464. package/dist/types/components/le-component/le-component.d.ts +0 -115
  465. package/dist/types/components/le-current-heading/le-current-heading.d.ts +0 -25
  466. package/dist/types/components/le-dropdown-base/le-dropdown-base.d.ts +0 -118
  467. package/dist/types/components/le-header/le-header.d.ts +0 -115
  468. package/dist/types/components/le-header-placeholder/le-header-placeholder.d.ts +0 -13
  469. package/dist/types/components/le-icon/le-icon.d.ts +0 -28
  470. package/dist/types/components/le-multiselect/le-multiselect.d.ts +0 -143
  471. package/dist/types/components/le-navigation/le-navigation.d.ts +0 -125
  472. package/dist/types/components/le-number-input/le-number-input.d.ts +0 -106
  473. package/dist/types/components/le-popover/le-popover.d.ts +0 -129
  474. package/dist/types/components/le-popup/le-popup.api.d.ts +0 -73
  475. package/dist/types/components/le-popup/le-popup.d.ts +0 -127
  476. package/dist/types/components/le-round-progress/le-round-progress.d.ts +0 -37
  477. package/dist/types/components/le-scroll-progress/le-scroll-progress.d.ts +0 -40
  478. package/dist/types/components/le-segmented-control/le-segmented-control.d.ts +0 -82
  479. package/dist/types/components/le-select/le-select.d.ts +0 -125
  480. package/dist/types/components/le-side-panel/le-side-panel.d.ts +0 -102
  481. package/dist/types/components/le-side-panel-toggle/le-side-panel-toggle.d.ts +0 -48
  482. package/dist/types/components/le-slot/le-slot.d.ts +0 -149
  483. package/dist/types/components/le-stack/le-stack.d.ts +0 -73
  484. package/dist/types/components/le-string-input/le-string-input.d.ts +0 -91
  485. package/dist/types/components/le-tab/le-tab.d.ts +0 -116
  486. package/dist/types/components/le-tab-bar/le-tab-bar.d.ts +0 -88
  487. package/dist/types/components/le-tab-panel/le-tab-panel.d.ts +0 -75
  488. package/dist/types/components/le-tabs/le-tabs.d.ts +0 -108
  489. package/dist/types/components/le-tag/le-tag.d.ts +0 -78
  490. package/dist/types/components/le-text/le-text.d.ts +0 -141
  491. package/dist/types/components/le-turntable/le-turntable.d.ts +0 -55
  492. package/dist/types/components.d.ts +0 -5800
  493. package/dist/types/global/app.d.ts +0 -96
  494. package/dist/types/index.d.ts +0 -16
  495. package/dist/types/stencil-public-runtime.d.ts +0 -1799
  496. package/dist/types/types/blocks.d.ts +0 -136
  497. package/dist/types/types/options.d.ts +0 -143
  498. package/dist/types/utils/utils.d.ts +0 -54
  499. package/loader/cdn.js +0 -1
  500. package/loader/index.cjs.js +0 -1
  501. package/loader/index.d.ts +0 -24
  502. package/loader/index.es2017.js +0 -1
  503. package/loader/index.js +0 -2
@@ -1,3380 +0,0 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host, a as getElement, F as Fragment, e as getLeKitConfig, f as getAssetPath, i as getAssetBasePath } from './index-DFTm5BqT.js';
2
- import { g as generateId, c as classnames, o as observeModeChanges } from './utils-DZYCZLrF.js';
3
- import { leConfirm } from './index.js';
4
-
5
- const leBarCss = () => `:host{display:block;--le-bar-gap:var(--le-spacing-2);--le-bar-padding:var(--le-spacing-2);--le-bar-min-height:2.5rem;--le-bar-background:transparent;--le-bar-border-color:var(--le-color-border);--le-bar-border-radius:var(--le-radius-md);--le-bar-button-size:2rem;--le-bar-button-color:var(--le-color-text-primary);--le-bar-button-hover-bg:var(--le-color-gray-100);--le-bar-button-border-radius:var(--le-radius-sm);--le-bar-arrow-size:1.5rem;--le-bar-popover-min-width:200px;--le-bar-popover-gap:var(--le-spacing-1)}.bar-container{display:flex;align-items:center;gap:var(--le-bar-gap);min-height:var(--le-bar-min-height);background:var(--le-bar-background);border-radius:var(--le-bar-border-radius);padding:var(--le-bar-padding)}.bar-container.align-start{justify-content:flex-start}.bar-container.align-end .bar-items{justify-content:flex-end}.bar-container.align-center .bar-items{justify-content:center}.bar-container.align-stretch .bar-items{justify-content:space-evenly}.bar-items{display:flex;flex-wrap:wrap;align-items:center;gap:var(--le-bar-gap);overflow:hidden;min-width:0;flex:1 1 0%;position:relative}.bar-items[style*="height"]{overflow:hidden}.bar-items.is-scrollable{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;-ms-overflow-style:none}.bar-items.is-scrollable::-webkit-scrollbar{display:none}.bar-items.is-scrollable ::slotted(*){scroll-snap-align:start;flex-shrink:0}.bar-items.is-wrapping{flex-wrap:wrap;overflow:visible;height:auto !important}.bar-controls{display:flex;align-items:center;gap:var(--le-spacing-1);flex-shrink:0}.bar-controls-start{order:-1}.bar-controls-end{order:1}.bar-more-button,.bar-hamburger-button,.bar-all-menu-button{display:inline-flex;align-items:center;justify-content:center;width:var(--le-bar-button-size);height:var(--le-bar-button-size);padding:0;border:none;background:transparent;color:var(--le-bar-button-color);border-radius:var(--le-bar-button-border-radius);cursor:pointer;transition:background-color 0.15s ease}.bar-more-button:hover,.bar-hamburger-button:hover,.bar-all-menu-button:hover{background:var(--le-bar-button-hover-bg)}.bar-more-button:focus-visible,.bar-hamburger-button:focus-visible,.bar-all-menu-button:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.bar-arrow{display:inline-flex;align-items:center;justify-content:center;width:var(--le-bar-arrow-size);height:var(--le-bar-arrow-size);padding:0;border:none;background:transparent;color:var(--le-bar-button-color);border-radius:var(--le-bar-button-border-radius);cursor:pointer;transition:background-color 0.15s ease, opacity 0.15s ease}.bar-arrow:hover:not(:disabled){background:var(--le-bar-button-hover-bg)}.bar-arrow:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.bar-arrow:disabled,.bar-arrow.disabled{opacity:0.3;cursor:not-allowed}.arrow-icon-start{transform:rotate(90deg)}.arrow-icon-end{transform:rotate(-90deg)}.bar-overflow-trigger,.bar-all-menu-trigger{display:inline-flex}.bar-popover-content{display:flex;flex-direction:column;gap:var(--le-bar-popover-gap);min-width:var(--le-bar-popover-min-width);padding:var(--le-spacing-2)}.bar-popover-item{cursor:pointer}.bar-popover-item:hover{background:var(--le-bar-button-hover-bg);border-radius:var(--le-bar-button-border-radius)}:host(.hamburger-active) .bar-items{visibility:hidden;pointer-events:none}`;
6
-
7
- const LeBar = class {
8
- constructor(hostRef) {
9
- registerInstance(this, hostRef);
10
- this.leBarOverflowChange = createEvent(this, "leBarOverflowChange");
11
- /**
12
- * Overflow behavior when items don't fit on one row.
13
- * - `more`: Overflow items appear in a "more" dropdown
14
- * - `scroll`: Items scroll horizontally with optional arrows
15
- * - `hamburger`: All items go into a hamburger menu if any overflow
16
- * - `wrap`: Items wrap to additional rows
17
- */
18
- this.overflow = 'more';
19
- /**
20
- * Alignment of items within the bar (maps to justify-content).
21
- */
22
- this.alignItems = 'start';
23
- /**
24
- * Show scroll arrows when overflow is "scroll".
25
- */
26
- this.arrows = false;
27
- /**
28
- * Disable the internal overflow popover.
29
- * When true, the bar still detects overflow and hides items,
30
- * but doesn't render its own popover. Use this when providing
31
- * custom overflow handling via the leBarOverflowChange event.
32
- */
33
- this.disablePopover = false;
34
- /**
35
- * Minimum number of visible items required when using "more" overflow mode.
36
- * If fewer items would be visible, the bar falls back to hamburger mode.
37
- * Only applies when overflow is "more".
38
- */
39
- this.minVisibleItems = 0;
40
- /**
41
- * Show an "all items" menu button.
42
- * - `false`: Don't show
43
- * - `true` or `'end'`: Show at end
44
- * - `'start'`: Show at start
45
- */
46
- this.showAllMenu = false;
47
- /** Whether the hamburger/more popover is open */
48
- this.popoverOpen = false;
49
- /** Whether hamburger mode is active (for hamburger overflow) */
50
- this.hamburgerActive = false;
51
- /** IDs of items that are overflowing */
52
- this.overflowingIds = new Set();
53
- /** Whether we can scroll left */
54
- this.canScrollStart = false;
55
- /** Whether we can scroll right */
56
- this.canScrollEnd = false;
57
- /** Whether the all-menu popover is open */
58
- this.allMenuOpen = false;
59
- /** Current height of the items container (for overflow handling) */
60
- this.containerHeight = null;
61
- this.instanceId = generateId('le-bar');
62
- // Map to track item elements and their IDs
63
- this.itemMap = new Map();
64
- // Prevent multiple recalculations in the same frame
65
- this.pendingRecalc = null;
66
- this.handleScroll = () => {
67
- this.updateScrollState();
68
- };
69
- this.scrollToStart = () => {
70
- if (!this.itemsContainerEl)
71
- return;
72
- const items = this.getSlottedItems();
73
- const container = this.itemsContainerEl;
74
- // Find the scroll position of the previous item
75
- const currentScroll = container.scrollLeft;
76
- let targetScroll = 0;
77
- for (let i = items.length - 1; i >= 0; i--) {
78
- const item = items[i];
79
- // Calculate item's left edge relative to container's scroll position
80
- const itemLeft = item.offsetLeft - container.offsetLeft;
81
- // If this item starts before current scroll position, scroll to it
82
- if (itemLeft < currentScroll - 1) {
83
- targetScroll = itemLeft;
84
- break;
85
- }
86
- }
87
- container.scrollTo({ left: targetScroll, behavior: 'smooth' });
88
- // Update scroll state after animation
89
- setTimeout(() => this.updateScrollState(), 300);
90
- };
91
- this.scrollToEnd = () => {
92
- if (!this.itemsContainerEl)
93
- return;
94
- const container = this.itemsContainerEl;
95
- const items = this.getSlottedItems();
96
- if (items.length === 0)
97
- return;
98
- const containerWidth = container.clientWidth;
99
- const currentScroll = container.scrollLeft;
100
- let targetScroll = container.scrollWidth - containerWidth;
101
- for (const item of items) {
102
- // Calculate item's right edge relative to container
103
- const itemLeft = item.offsetLeft - container.offsetLeft;
104
- // If this is the next item to scroll to from left to right then scroll to it
105
- if (itemLeft > currentScroll + 1) {
106
- targetScroll = itemLeft;
107
- break;
108
- }
109
- }
110
- container.scrollTo({ left: Math.max(0, targetScroll), behavior: 'smooth' });
111
- // Update scroll state after animation
112
- setTimeout(() => this.updateScrollState(), 300);
113
- };
114
- this.togglePopover = () => {
115
- this.popoverOpen = !this.popoverOpen;
116
- };
117
- this.closePopover = () => {
118
- this.popoverOpen = false;
119
- };
120
- this.toggleAllMenu = () => {
121
- this.allMenuOpen = !this.allMenuOpen;
122
- };
123
- this.closeAllMenu = () => {
124
- this.allMenuOpen = false;
125
- };
126
- this.handleItemClick = (_e, id) => {
127
- // Close popover when an item inside is clicked
128
- const originalItem = this.itemMap.get(id);
129
- if (originalItem) {
130
- // Clone the click to the original item
131
- const cloneEvent = new MouseEvent('click', {
132
- bubbles: true,
133
- cancelable: true,
134
- view: window,
135
- });
136
- originalItem.dispatchEvent(cloneEvent);
137
- }
138
- this.closePopover();
139
- this.closeAllMenu();
140
- };
141
- }
142
- handleOverflowChange() {
143
- this.resetOverflowState();
144
- this.scheduleOverflowRecalc();
145
- }
146
- handleSlotChange() {
147
- this.scheduleOverflowRecalc();
148
- }
149
- connectedCallback() {
150
- this.setupObservers();
151
- }
152
- componentDidLoad() {
153
- this.scheduleOverflowRecalc();
154
- }
155
- componentDidRender() {
156
- // Recalculate after render in case children changed
157
- this.scheduleOverflowRecalc();
158
- }
159
- disconnectedCallback() {
160
- this.resizeObserver?.disconnect();
161
- this.mutationObserver?.disconnect();
162
- }
163
- /**
164
- * Force recalculation of overflow state.
165
- */
166
- async recalculate() {
167
- this.computeOverflow();
168
- }
169
- setupObservers() {
170
- // ResizeObserver for container size changes
171
- if (typeof ResizeObserver !== 'undefined') {
172
- this.resizeObserver = new ResizeObserver(() => {
173
- this.computeOverflow();
174
- this.updateScrollState();
175
- });
176
- }
177
- // MutationObserver for child changes
178
- this.mutationObserver = new MutationObserver(() => {
179
- this.scheduleOverflowRecalc();
180
- });
181
- this.mutationObserver.observe(this.el, {
182
- childList: true,
183
- subtree: false,
184
- });
185
- }
186
- observeContainer(el) {
187
- if (!this.resizeObserver)
188
- return;
189
- this.resizeObserver.disconnect();
190
- if (el)
191
- this.resizeObserver.observe(el);
192
- }
193
- scheduleOverflowRecalc() {
194
- // Debounce recalculations to prevent infinite loops
195
- if (this.pendingRecalc !== null) {
196
- cancelAnimationFrame(this.pendingRecalc);
197
- }
198
- this.pendingRecalc = requestAnimationFrame(() => {
199
- this.pendingRecalc = null;
200
- this.computeOverflow();
201
- });
202
- }
203
- resetOverflowState() {
204
- this.hamburgerActive = false;
205
- this.overflowingIds = new Set();
206
- this.containerHeight = null;
207
- this.popoverOpen = false;
208
- }
209
- getSlottedItems() {
210
- // Get direct children from the light DOM (excluding named slot elements)
211
- return Array.from(this.el.children).filter((el) => el instanceof HTMLElement && !el.hasAttribute('slot'));
212
- }
213
- getItemId(el, index) {
214
- return el.id || el.dataset.barId || `${this.instanceId}-item-${index}`;
215
- }
216
- computeOverflow() {
217
- if (this.overflow === 'wrap' || this.overflow === 'scroll') {
218
- // No overflow handling needed for wrap/scroll modes
219
- this.resetOverflowState();
220
- this.updateScrollState();
221
- return;
222
- }
223
- const container = this.itemsContainerEl;
224
- if (!container)
225
- return;
226
- const items = this.getSlottedItems();
227
- if (items.length === 0) {
228
- this.resetOverflowState();
229
- return;
230
- }
231
- // Build item map
232
- this.itemMap.clear();
233
- items.forEach((item, index) => {
234
- const id = this.getItemId(item, index);
235
- this.itemMap.set(id, item);
236
- });
237
- // Get the position of items to determine which are on the first row
238
- const itemRects = items.map((item, index) => ({
239
- item,
240
- id: this.getItemId(item, index),
241
- rect: item.getBoundingClientRect(),
242
- }));
243
- if (itemRects.length === 0) {
244
- return;
245
- }
246
- // Find the first row's top position (accounting for vertical alignment)
247
- const containerRect = container.getBoundingClientRect();
248
- const topValues = itemRects.map(i => i.rect.top - containerRect.top);
249
- const minTop = Math.min(...topValues);
250
- // Items are on the first row if their top is close to minTop
251
- // Allow some tolerance for alignment differences
252
- const tolerance = 15;
253
- const firstRowItems = itemRects.filter(i => i.rect.top - containerRect.top <= minTop + tolerance);
254
- const overflowItems = itemRects.filter(i => i.rect.top - containerRect.top > minTop + tolerance);
255
- // Calculate the height of the first row
256
- const firstRowBottom = firstRowItems.length > 0
257
- ? Math.max(...firstRowItems.map(i => i.rect.bottom - containerRect.top))
258
- : 0;
259
- if (this.overflow === 'hamburger') {
260
- // In hamburger mode, if ANY item overflows, all go into the menu
261
- const shouldHamburger = overflowItems.length > 0;
262
- if (shouldHamburger !== this.hamburgerActive) {
263
- this.hamburgerActive = shouldHamburger;
264
- this.emitOverflowChange();
265
- }
266
- // Set height to show only first row (or hide all if hamburger is active)
267
- if (shouldHamburger && firstRowBottom > 0) {
268
- this.containerHeight = firstRowBottom;
269
- }
270
- else {
271
- this.containerHeight = null;
272
- }
273
- }
274
- else {
275
- // 'more' mode
276
- let newOverflowingIds = new Set(overflowItems.map(i => i.id));
277
- // Check if we need to make room for the "more" button
278
- if (newOverflowingIds.size > 0 && this.moreButtonEl) {
279
- const moreRect = this.moreButtonEl.getBoundingClientRect();
280
- const moreTop = moreRect.top - containerRect.top;
281
- // If "more" button is not on the first row, we need to hide one more item
282
- if (moreTop > minTop + tolerance) {
283
- // Find the last visible item and move it to overflow
284
- const lastVisible = firstRowItems[firstRowItems.length - 1];
285
- if (lastVisible) {
286
- newOverflowingIds.add(lastVisible.id);
287
- }
288
- }
289
- }
290
- // Check if we should fallback to hamburger mode
291
- // This happens when minVisibleItems is set and fewer items would be visible
292
- const visibleCount = items.length - newOverflowingIds.size;
293
- const shouldFallbackToHamburger = this.minVisibleItems > 0 &&
294
- newOverflowingIds.size > 0 &&
295
- visibleCount < this.minVisibleItems;
296
- if (shouldFallbackToHamburger) {
297
- // Switch to hamburger mode - all items go into the menu
298
- if (!this.hamburgerActive) {
299
- this.hamburgerActive = true;
300
- this.overflowingIds = new Set();
301
- this.emitOverflowChange();
302
- }
303
- // Set height to show only first row
304
- if (firstRowBottom > 0) {
305
- this.containerHeight = firstRowBottom;
306
- }
307
- else {
308
- this.containerHeight = null;
309
- }
310
- return;
311
- }
312
- // Not falling back to hamburger - ensure hamburgerActive is false
313
- if (this.hamburgerActive) {
314
- this.hamburgerActive = false;
315
- }
316
- // Check if overflow state changed
317
- const hasChanged = (newOverflowingIds?.size ?? 0) !== (this.overflowingIds?.size ?? 0) ||
318
- ![...newOverflowingIds].every(id => this.overflowingIds?.has(id));
319
- if (hasChanged) {
320
- this.overflowingIds = newOverflowingIds;
321
- this.emitOverflowChange();
322
- }
323
- // Set container height to show only first row
324
- if ((newOverflowingIds?.size ?? 0) > 0 && firstRowBottom > 0) {
325
- this.containerHeight = firstRowBottom;
326
- }
327
- else {
328
- this.containerHeight = null;
329
- }
330
- }
331
- }
332
- emitOverflowChange() {
333
- this.leBarOverflowChange.emit({
334
- overflowingIds: [...(this.overflowingIds ?? [])],
335
- hamburgerActive: this.hamburgerActive,
336
- });
337
- }
338
- updateScrollState() {
339
- if (this.overflow !== 'scroll' || !this.itemsContainerEl) {
340
- this.canScrollStart = false;
341
- this.canScrollEnd = false;
342
- return;
343
- }
344
- const el = this.itemsContainerEl;
345
- this.canScrollStart = el.scrollLeft > 0;
346
- this.canScrollEnd = el.scrollLeft < el.scrollWidth - el.clientWidth - 1;
347
- }
348
- renderMoreButton() {
349
- const hasSlottedMore = this.el.querySelector('[slot="more"]');
350
- return (h("button", { class: "bar-more-button", part: "more-button", ref: el => (this.moreButtonEl = el), onClick: this.togglePopover, "aria-expanded": String(this.popoverOpen), "aria-haspopup": "true" }, hasSlottedMore ? h("slot", { name: "more" }) : h("le-icon", { name: "ellipsis-horizontal" })));
351
- }
352
- renderHamburgerButton() {
353
- const hasSlottedHamburger = this.el.querySelector('[slot="hamburger"]');
354
- return (h("button", { class: "bar-hamburger-button", part: "hamburger-button", onClick: this.togglePopover, "aria-expanded": String(this.popoverOpen), "aria-haspopup": "true" }, hasSlottedHamburger ? h("slot", { name: "hamburger" }) : h("le-icon", { name: "hamburger" })));
355
- }
356
- renderScrollArrows() {
357
- if (!this.arrows || this.overflow !== 'scroll')
358
- return null;
359
- const hasSlottedStartArrow = this.el.querySelector('[slot="start-arrow"]');
360
- const hasSlottedEndArrow = this.el.querySelector('[slot="end-arrow"]');
361
- return [
362
- h("button", { class: classnames('bar-arrow', 'bar-arrow-start', {
363
- disabled: !this.canScrollStart,
364
- }), part: "arrow-start", onClick: this.scrollToStart, disabled: !this.canScrollStart, "aria-label": "Scroll to start" }, hasSlottedStartArrow ? (h("slot", { name: "start-arrow" })) : (h("le-icon", { name: "chevron-down", class: "arrow-icon-start" }))),
365
- h("button", { class: classnames('bar-arrow', 'bar-arrow-end', {
366
- disabled: !this.canScrollEnd,
367
- }), part: "arrow-end", onClick: this.scrollToEnd, disabled: !this.canScrollEnd, "aria-label": "Scroll to end" }, hasSlottedEndArrow ? (h("slot", { name: "end-arrow" })) : (h("le-icon", { name: "chevron-down", class: "arrow-icon-end" }))),
368
- ];
369
- }
370
- renderAllMenuButton() {
371
- if (!this.showAllMenu)
372
- return null;
373
- const hasSlottedAllMenu = this.el.querySelector('[slot="all-menu"]');
374
- return (h("button", { class: "bar-all-menu-button", part: "all-menu-button", onClick: this.toggleAllMenu, "aria-expanded": String(this.allMenuOpen), "aria-haspopup": "true" }, hasSlottedAllMenu ? h("slot", { name: "all-menu" }) : h("le-icon", { name: "hamburger" })));
375
- }
376
- renderPopoverContent(itemsToShow) {
377
- return (h("div", { class: "bar-popover-content", part: "popover-content" }, itemsToShow.map(({ id, item }) => (h("div", { class: "bar-popover-item", key: id, onClick: (e) => this.handleItemClick(e, id), innerHTML: item.outerHTML })))));
378
- }
379
- renderOverflowPopover() {
380
- if (this.overflow !== 'more' && this.overflow !== 'hamburger')
381
- return null;
382
- const items = this.getSlottedItems();
383
- let itemsToShow = [];
384
- if (this.overflow === 'hamburger' && this.hamburgerActive) {
385
- // Show all items in hamburger mode
386
- itemsToShow = items.map((item, index) => ({
387
- id: this.getItemId(item, index),
388
- item,
389
- }));
390
- }
391
- else if (this.overflow === 'more' && (this.overflowingIds?.size ?? 0) > 0) {
392
- // Show only overflowing items
393
- itemsToShow = items
394
- .map((item, index) => ({
395
- id: this.getItemId(item, index),
396
- item,
397
- }))
398
- .filter(({ id }) => this.overflowingIds?.has(id));
399
- }
400
- if (itemsToShow.length === 0)
401
- return null;
402
- return (h("le-popover", { mode: "default", open: this.popoverOpen, position: "bottom", align: "end", showClose: false, closeOnClickOutside: true, closeOnEscape: true, onLePopoverClose: this.closePopover }, h("div", { slot: "trigger", class: "bar-overflow-trigger" }, this.overflow === 'hamburger' ? this.renderHamburgerButton() : this.renderMoreButton()), this.renderPopoverContent(itemsToShow)));
403
- }
404
- renderAllMenuPopover() {
405
- if (!this.showAllMenu)
406
- return null;
407
- const items = this.getSlottedItems();
408
- const itemsToShow = items.map((item, index) => ({
409
- id: this.getItemId(item, index),
410
- item,
411
- }));
412
- const position = this.showAllMenu === 'start' ? 'start' : 'end';
413
- return (h("le-popover", { mode: "default", open: this.allMenuOpen, position: "bottom", align: position, showClose: false, closeOnClickOutside: true, closeOnEscape: true, onLePopoverClose: this.closeAllMenu }, h("div", { slot: "trigger", class: "bar-all-menu-trigger" }, this.renderAllMenuButton()), this.renderPopoverContent(itemsToShow)));
414
- }
415
- render() {
416
- const showOverflowButton = !this.disablePopover &&
417
- ((this.overflow === 'more' && (this.overflowingIds?.size ?? 0) > 0) ||
418
- (this.overflow === 'hamburger' && this.hamburgerActive));
419
- const containerStyle = {};
420
- if (this.containerHeight !== null &&
421
- (this.overflow === 'more' || this.overflow === 'hamburger')) {
422
- containerStyle.height = `${this.containerHeight}px`;
423
- }
424
- const showAllMenuAtStart = this.showAllMenu === 'start';
425
- const showAllMenuAtEnd = this.showAllMenu === true || this.showAllMenu === 'end';
426
- return (h(Host, { key: '56d04e4504ed7ce1d8e78a825c71c71c074d0b62', class: classnames({
427
- 'overflow-more': this.overflow === 'more',
428
- 'overflow-scroll': this.overflow === 'scroll',
429
- 'overflow-hamburger': this.overflow === 'hamburger',
430
- 'overflow-wrap': this.overflow === 'wrap',
431
- 'hamburger-active': this.hamburgerActive,
432
- 'has-overflow': (this.overflowingIds?.size ?? 0) > 0 || this.hamburgerActive,
433
- }) }, h("div", { key: '4e7aeb4c84a9964e19012c3d05827fa8406988b0', class: classnames('bar-container', {
434
- [`align-${this.alignItems}`]: true,
435
- }), part: "container" }, this.overflow === 'scroll' && this.arrows && (h("div", { key: '2e3ae04c00e88e5055216dbc5b6d53574c450470', class: "bar-controls bar-controls-start" }, this.renderScrollArrows()?.[0])), showAllMenuAtStart && (h("div", { key: '9628c8dc2b15d9358baad63b19c75fd933eeb19a', class: "bar-controls bar-controls-start" }, this.renderAllMenuPopover())), h("div", { key: 'd1feb9603d0ff4247852aadb62cb920a5f5a1921', class: classnames('bar-items', {
436
- 'is-scrollable': this.overflow === 'scroll',
437
- 'is-wrapping': this.overflow === 'wrap',
438
- }), style: containerStyle, ref: el => {
439
- this.itemsContainerEl = el;
440
- this.observeContainer(el);
441
- }, onScroll: this.overflow === 'scroll' ? this.handleScroll : undefined }, h("slot", { key: '338698e038b9df4c7b163017ceb0675b834160e4' })), showOverflowButton && (h("div", { key: 'd619fcda1b0c28247af60899f73cc076b0517787', class: "bar-controls bar-controls-end" }, this.renderOverflowPopover())), showAllMenuAtEnd && (h("div", { key: 'fd9fef90194aabb8d48e77c8f7615daa5d7297ac', class: "bar-controls bar-controls-end" }, this.renderAllMenuPopover())), this.overflow === 'scroll' && this.arrows && (h("div", { key: 'bcffb914e2788767c3765351a3eeae771f3e115f', class: "bar-controls bar-controls-end" }, this.renderScrollArrows()?.[1])))));
442
- }
443
- get el() { return getElement(this); }
444
- static get watchers() { return {
445
- "overflow": ["handleOverflowChange"]
446
- }; }
447
- };
448
- LeBar.style = leBarCss();
449
-
450
- const leButtonCss = () => `:host{display:inline-block;--le-button-border-radius:var(--le-radius-md);--le-button-padding-x:var(--le-spacing-3);--le-button-padding-y:var(--le-spacing-1);--le-button-padding:var(--le-button-padding-y) var(--le-button-padding-x);--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-transition-easing:ease-in-out;--le-button-icon-aspect-ratio:1;--le-button-color:var(--le-color-primary-contrast);--_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-button-color);--_btn-border-color:var(--le-color-primary)}:host([full-width]){display:block;width:100%}.le-button-container{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;gap:var(--le-spacing-3);width:100%;padding:var(--le-button-padding);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),
451
- border-color var(--le-button-transition) var(--le-transition-easing),
452
- box-shadow var(--le-button-transition) var(--le-transition-easing),
453
- transform var(--le-button-transition) var(--le-transition-easing)}.le-button-container:hover:not(:disabled){background:var(--_btn-bg-hover);border-color:var(--_btn-bg-hover)}.le-button-container:active:not(:disabled){box-shadow:inset 0 0 5px color-mix(in srgb, var(--_btn-bg) 50%, transparent)}.le-button-container:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.le-button-container:disabled{opacity:0.5;cursor:not-allowed}.le-button-label{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;gap:var(--le-spacing-2)}:host(.color-primary){--_btn-bg:var(--le-color-primary);--_btn-bg-hover:var(--le-color-primary-dark);--_btn-color:var(--le-button-color);--_btn-border-color:var(--le-color-primary)}:host(.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(.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(.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(.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(.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(.variant-solid) .le-button-container{box-shadow:var(--le-shadow-sm)}:host(.variant-solid) .le-button-container:hover:not(:disabled){box-shadow:var(--le-shadow-md)}:host(.variant-outlined) .le-button-container{background:transparent;color:var(--_btn-bg);border-color:color-mix(in srgb, var(--_btn-border-color) 33%, transparent)}:host(.variant-outlined) .le-button-container:hover:not(:disabled){border-color:var(--_btn-border-color)}:host(.variant-clear) .le-button-container{background:transparent;color:var(--_btn-bg);border-color:transparent}:host(.variant-clear) .le-button-container:hover:not(:disabled){background:var(--le-color-gray-100);border-color:transparent}:host(.variant-system) .le-button-container{background:transparent;color:var(--_btn-bg-system);border-color:transparent}:host(.size-small){--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(.size-large){--le-button-padding-x:0.9rem;--le-button-padding-y:0.6rem;--le-button-font-size:var(--le-font-size-xl)}:host(.full-width){display:block;width:100%}:host(.selected) .le-button-container{box-shadow:inset 0 0 4px var(--le-color-shadow)}:host(.variant-outlined.selected) .le-button-container,:host(.variant-clear.selected) .le-button-container{background:var(--_btn-bg);color:var(--_btn-color)}:host(.icon-only) .le-button-container{padding:var(--le-button-icon-only-padding, 0.5rem);padding-bottom:var(--le-button-icon-only-padding, 0.6rem);aspect-ratio:var(--le-button-icon-aspect-ratio, 1)}:host(.icon-only.size-small) .le-button-container{padding:var(--le-button-small-padding, 0.25rem)}:host(.icon-only.size-large) .le-button-container{padding:0.75rem}:host(.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}.le-button-align-start{justify-content:flex-start}.le-button-align-center{justify-content:center}.le-button-align-space-between{justify-content:space-between}.le-button-align-end{justify-content:flex-end}`;
454
-
455
- const LeButton = class {
456
- constructor(hostRef) {
457
- registerInstance(this, hostRef);
458
- this.leClick = createEvent(this, "click");
459
- /**
460
- * Button variant style
461
- * @allowedValues solid | outlined | clear
462
- */
463
- this.variant = 'solid';
464
- /**
465
- * Button color theme (uses theme semantic colors)
466
- * @allowedValues primary | secondary | success | warning | danger | info
467
- */
468
- this.color = 'primary';
469
- /**
470
- * Button size
471
- * @allowedValues small | medium | large
472
- */
473
- this.size = 'medium';
474
- /**
475
- * Whether the button is in a selected/active state
476
- */
477
- this.selected = false;
478
- /**
479
- * Whether the button takes full width of its container
480
- */
481
- this.fullWidth = false;
482
- /**
483
- * Whether the button is disabled
484
- */
485
- this.disabled = false;
486
- /**
487
- * The button type attribute
488
- * @allowedValues button | submit | reset
489
- */
490
- this.type = 'button';
491
- /**
492
- * Alignment of the button label without the end icon
493
- * @allowedValues start | center | space-between | end
494
- */
495
- this.align = 'center';
496
- this.handleClick = (event) => {
497
- // We stop the internal button click from bubbling up
498
- event.stopPropagation();
499
- if (this.disabled) {
500
- event.preventDefault();
501
- return;
502
- }
503
- // And emit our own click event from the host element
504
- this.leClick.emit(event);
505
- };
506
- }
507
- render() {
508
- const classes = classnames(`variant-${this.variant}`, `color-${this.color}`, `size-${this.size}`, {
509
- 'selected': this.selected,
510
- 'full-width': this.fullWidth,
511
- 'icon-only': this.iconOnly,
512
- 'disabled': this.disabled,
513
- });
514
- const TagType = this.href ? 'a' : 'button';
515
- const attrs = this.href
516
- ? { href: this.href, target: this.target, role: 'button' }
517
- : { type: this.type, disabled: this.disabled };
518
- return (h(Host, { key: '4bf9fb21e9bf0ca5a19193d977ad9fab90b519a0', class: classes }, h("le-component", { key: '8e0edefabbe9196eba935a1e8cce788c686c170c', component: "le-button" }, h(TagType, { key: '30f88ea834a9029c0f8ec24819107ba318dc6397', class: classnames('le-button-container', `le-button-align-${this.align}`), part: "button", ...attrs, onClick: this.handleClick }, this.iconOnly !== undefined ? (h("slot", { name: "icon-only" }, typeof this.iconOnly === 'string' ? this.iconOnly : null)) : (h(Fragment, null, h("span", { class: "le-button-label" }, this.iconStart && (h("span", { class: "icon-start", part: "icon-start" }, this.iconStart)), h("le-slot", { name: "", description: "Button text", type: "text", class: "content", part: "content" }, h("slot", null))), this.iconEnd && (h("span", { class: "icon-end", part: "icon-end" }, this.iconEnd))))))));
519
- }
520
- get el() { return getElement(this); }
521
- };
522
- LeButton.style = leButtonCss();
523
-
524
- 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}`;
525
-
526
- const LeCheckbox = class {
527
- constructor(hostRef) {
528
- registerInstance(this, hostRef);
529
- this.leChange = createEvent(this, "change");
530
- /**
531
- * Whether the checkbox is checked
532
- */
533
- this.checked = false;
534
- /**
535
- * Whether the checkbox is disabled
536
- */
537
- this.disabled = false;
538
- this.handleChange = (event) => {
539
- // We stop the internal button click from bubbling up
540
- event.stopPropagation();
541
- if (this.disabled) {
542
- event.preventDefault();
543
- return;
544
- }
545
- const input = event.target;
546
- this.checked = input.checked;
547
- this.leChange.emit({
548
- checked: this.checked,
549
- value: this.value,
550
- name: this.name,
551
- externalId: this.externalId
552
- });
553
- };
554
- }
555
- render() {
556
- return (h("le-component", { key: '8b4541e96816b6e69ee790779971981b9d112484', component: "le-checkbox", hostClass: classnames({ 'disabled': this.disabled }) }, h("div", { key: 'c5e3a8692e59fa59a46bc90302e80f20dc700f04', class: "le-checkbox-wrapper" }, h("label", { key: 'b72abfbd39434a2c8be951a933e57ce70e9c922c', class: "le-checkbox-label" }, h("span", { key: '624ebbd37e6ea6a0800d702cbcea5ab8fe78b59e', class: "le-checkbox-input" }, h("input", { key: '182dc9549cc3494fc61e7779242ff14c304c3d97', type: "checkbox", name: this.name, value: this.value, checked: this.checked, disabled: this.disabled, onChange: this.handleChange })), h("span", { key: 'f14dc486329d8375b47ca75bedd2ac31f04273a7', class: "le-checkbox-text" }, h("le-slot", { key: '3be69ca148e121e8970bd3950fcbdee12613c775', name: "", type: "text", tag: "span" }, h("slot", { key: '2a258f7ce0331b9d08df5ac23a5ec492493974ca' })))), h("div", { key: '2deeab5d1d7c6b4046b5b4f54cd92061fc5f7383', class: "le-checkbox-description" }, h("le-slot", { key: '3ec3ca85d9f472d209084c4d95d46d2c114133e8', name: "description", type: "text", tag: "div", label: "Description" }, h("slot", { key: 'e1043ec4613df078446e7a6a5550646bbbe7d8be', name: "description" }))))));
557
- }
558
- get el() { return getElement(this); }
559
- };
560
- LeCheckbox.style = leCheckboxCss();
561
-
562
- const leCollapseCss = () => `:host{--le-collapse-duration:var(--le-transition-normal);display:grid;grid-template-rows:1fr;opacity:1;transition:grid-template-rows var(--le-collapse-duration),
563
- opacity var(--le-collapse-duration)}:host([data-open="false"]),:host([closed]){grid-template-rows:0fr;opacity:0}:host([no-fading][data-open="false"]),:host([no-fading][closed]){opacity:1}.region{display:flex;flex-direction:column;justify-content:flex-end;overflow:hidden}.region.scroll-down{justify-content:flex-start}`;
564
-
565
- const LeCollapse = class {
566
- constructor(hostRef) {
567
- registerInstance(this, hostRef);
568
- /**
569
- * Since Stencil boolean props default to `false` when the attribute is missing.
570
- * instead of `open` defaulting to `true`, using a `closed` prop.
571
- */
572
- this.closed = false;
573
- /** Whether the content should scroll down from the top when open. */
574
- this.scrollDown = false;
575
- /** Stop fading the content when collapsing/expanding. */
576
- this.noFading = false;
577
- /** If true, collapse/expand based on the nearest header shrink event. */
578
- this.collapseOnHeaderShrink = false;
579
- this.headerShrunk = false;
580
- }
581
- /**
582
- * Handles `leHeaderShrinkChange` events from the `le-header`.
583
- * In case multiple headers are present, only the nearest one in the DOM tree is used.
584
- */
585
- handleHeaderShrink(ev) {
586
- const e = ev;
587
- this.headerShrunk = !!e.detail?.shrunk;
588
- }
589
- componentDidLoad() {
590
- this.applyOpenState();
591
- }
592
- onOpenChange() {
593
- this.applyOpenState();
594
- }
595
- onDrivenStateChange() {
596
- this.applyOpenState();
597
- }
598
- shouldBeOpen() {
599
- if (this.closed)
600
- return false;
601
- if (this.collapseOnHeaderShrink && this.headerShrunk)
602
- return false;
603
- return true;
604
- }
605
- applyOpenState() {
606
- const nextOpen = this.shouldBeOpen();
607
- this.el.toggleAttribute('data-open', nextOpen);
608
- }
609
- render() {
610
- return (h(Host, { key: '81a03bdd47d7c6e7d4491f4ee6be2e2f7af66334', "data-open": this.shouldBeOpen() ? 'true' : 'false' }, h("le-component", { key: '14cbe57c5cee1a3a7565175528d32b5d1be47919', component: "le-collapse" }, h("div", { key: 'c669a8d9f20776dba9d5ba162aaa6a58a31ad5b5', class: { 'region': true, 'scroll-down': this.scrollDown }, part: "region" }, h("slot", { key: 'd56fd4c71032da7935800874c13a2ba5b7427c83' })))));
611
- }
612
- get el() { return getElement(this); }
613
- static get watchers() { return {
614
- "open": ["onOpenChange"],
615
- "headerShrunk": ["onDrivenStateChange"]
616
- }; }
617
- };
618
- LeCollapse.style = leCollapseCss();
619
-
620
- 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}`;
621
-
622
- const LeComponent = class {
623
- constructor(hostRef) {
624
- registerInstance(this, hostRef);
625
- /**
626
- * Internal state to track admin mode
627
- */
628
- this.adminMode = false;
629
- /**
630
- * Component metadata loaded from Custom Elements Manifest
631
- */
632
- this.componentMeta = null;
633
- /**
634
- * Current property values of the host component
635
- */
636
- this.propertyValues = {};
637
- }
638
- connectedCallback() {
639
- // Find the host element - le-component is rendered inside the component's shadow DOM,
640
- // so we need to find the shadow root's host element
641
- this.findHostElement();
642
- this.disconnectModeObserver = observeModeChanges(this.el, mode => {
643
- this.adminMode = mode === 'admin';
644
- // Load metadata and refresh property values only when entering admin mode
645
- if (this.adminMode) {
646
- if (!this.componentMeta) {
647
- this.loadComponentMetadata();
648
- }
649
- else {
650
- this.readPropertyValues();
651
- }
652
- }
653
- });
654
- }
655
- /**
656
- * Find the host element by traversing up through shadow DOM
657
- */
658
- findHostElement() {
659
- // Get the shadow root that contains this le-component
660
- const rootNode = this.el.getRootNode();
661
- if (rootNode instanceof ShadowRoot) {
662
- // The host of this shadow root is our target component (e.g., le-card)
663
- this.hostElement = rootNode.host;
664
- }
665
- }
666
- componentDidLoad() {
667
- // Read initial property values from the host element
668
- this.readPropertyValues();
669
- }
670
- disconnectedCallback() {
671
- this.disconnectModeObserver?.();
672
- }
673
- /**
674
- * Formats a tag name into a display name
675
- * e.g., 'le-card' -> 'Card'
676
- */
677
- formatDisplayName(tagName) {
678
- if (!tagName || typeof tagName !== 'string')
679
- return 'unknown';
680
- return tagName
681
- .replace(/^le-/, '') // Remove 'le-' prefix
682
- .split('-')
683
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
684
- .join(' ');
685
- }
686
- /**
687
- * Load component metadata from the Custom Elements Manifest
688
- */
689
- async loadComponentMetadata() {
690
- try {
691
- // Fetch the manifest from configured URL
692
- const { manifestFile } = getLeKitConfig();
693
- const manifestFileResolved = getAssetPath(`./assets/${manifestFile}`);
694
- const response = await fetch(manifestFileResolved);
695
- const manifest = await response.json();
696
- // Find the component definition
697
- for (const module of manifest.modules) {
698
- for (const declaration of module.declarations || []) {
699
- if (declaration.tagName === this.component) {
700
- const attributes = (declaration.attributes || []).filter((attr) => !this.isInternalAttribute(attr.name));
701
- this.componentMeta = {
702
- tagName: declaration.tagName,
703
- description: declaration.description,
704
- attributes,
705
- };
706
- // console.log(`[le-component] Loaded metadata for ${this.component}:`, this.componentMeta);
707
- // Read property values after metadata is loaded
708
- this.readPropertyValues();
709
- return;
710
- }
711
- }
712
- }
713
- // console.warn(`[le-component] No metadata found for component: ${this.component}`);
714
- }
715
- catch (error) {
716
- // console.warn(`[le-component] Failed to load metadata for component: ${this.component}`, error);
717
- }
718
- }
719
- /**
720
- * Check if an attribute is internal (should not be shown in editor)
721
- */
722
- isInternalAttribute(name) {
723
- const internalAttrs = ['mode', 'theme', 'class', 'style', 'id', 'slot'];
724
- return internalAttrs.includes(name);
725
- }
726
- /**
727
- * Read current property values from the host element
728
- */
729
- readPropertyValues() {
730
- if (!this.hostElement || !this.componentMeta)
731
- return;
732
- const values = {};
733
- for (const attr of this.componentMeta.attributes) {
734
- const value = this.hostElement.getAttribute(attr.name);
735
- values[attr.name] = this.parseAttributeValue(value, attr.type?.text);
736
- }
737
- this.propertyValues = values;
738
- }
739
- /**
740
- * Parse an attribute value based on its type
741
- */
742
- parseAttributeValue(value, type) {
743
- if (value === null)
744
- return undefined;
745
- if (type === 'boolean') {
746
- return value !== null && value !== 'false';
747
- }
748
- if (type === 'number') {
749
- return parseFloat(value);
750
- }
751
- return value;
752
- }
753
- /**
754
- * Handle property value changes from the editor
755
- */
756
- handlePropertyChange(attrName, value, type) {
757
- if (!this.hostElement)
758
- return;
759
- // Update the host element's attribute
760
- if (type === 'boolean') {
761
- if (value) {
762
- this.hostElement.setAttribute(attrName, '');
763
- }
764
- else {
765
- this.hostElement.removeAttribute(attrName);
766
- }
767
- }
768
- else if (value === undefined || value === '') {
769
- this.hostElement.removeAttribute(attrName);
770
- }
771
- else {
772
- this.hostElement.setAttribute(attrName, String(value));
773
- }
774
- // Update local state
775
- this.propertyValues = { ...this.propertyValues, [attrName]: value };
776
- // update the host element the way the parent element mutation observer would catch it?
777
- }
778
- /**
779
- * Delete this component from the DOM
780
- */
781
- deleteComponent() {
782
- if (!this.hostElement)
783
- return;
784
- // Confirm deletion
785
- const name = this.displayName || this.formatDisplayName(this.component);
786
- if (!leConfirm(`Delete this ${name}?`))
787
- return;
788
- // Remove the host element from its parent
789
- const parent = this.hostElement.parentElement;
790
- if (parent) {
791
- this.hostElement.remove();
792
- }
793
- }
794
- /**
795
- * Render the property editor form
796
- */
797
- renderPropertyEditor() {
798
- const hasProperties = this.componentMeta && this.componentMeta.attributes.length > 0;
799
- 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")))));
800
- }
801
- /**
802
- * Render a single property field based on its type
803
- */
804
- renderPropertyField(attr) {
805
- const value = this.propertyValues[attr.name];
806
- const type = attr.type?.text || 'string';
807
- // Check if type is a union of string literals (e.g., "'default' | 'outlined' | 'elevated'")
808
- const enumMatch = type.match(/^'[^']+'/);
809
- if (enumMatch) {
810
- const options = type.split('|').map(opt => opt.trim().replace(/'/g, ''));
811
- return (h("div", { class: "property-field" }, h("label", { htmlFor: `prop-${attr.name}` }, attr.name, attr.description && h("span", { class: "property-hint" }, attr.description)), h("le-select", { options: [...options.map(opt => ({ label: opt, value: opt }))], "full-width": true, value: value ?? attr.default?.replace(/'/g, ''), placeholder: attr.default?.replace(/'/g, ''), onChange: (e) => this.handlePropertyChange(attr.name, e.detail.value, type) })));
812
- }
813
- // Boolean type
814
- if (type === 'boolean') {
815
- 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))));
816
- }
817
- // Number type
818
- if (type === 'number') {
819
- 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) })));
820
- }
821
- // Default: string/text input
822
- 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))));
823
- }
824
- render() {
825
- const name = this.displayName || this.formatDisplayName(this.component);
826
- // In default mode, just pass through content with host classes
827
- if (!this.adminMode) {
828
- return (h(Host, { class: classnames(this.component, this.hostClass), style: this.hostStyle }, h("slot", null)));
829
- }
830
- // In admin mode, show wrapper with header and settings
831
- 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)))));
832
- }
833
- static get assetsDirs() { return ["assets"]; }
834
- get el() { return getElement(this); }
835
- };
836
- LeComponent.style = leComponentCss();
837
-
838
- const leCurrentHeadingCss = () => `:host{display:inline-flex;min-width:0}.title{font:inherit;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--le-current-heading-color, var(--le-color-text-primary))}`;
839
-
840
- const LeCurrentHeading = class {
841
- constructor(hostRef) {
842
- registerInstance(this, hostRef);
843
- /** CSS selector for page title/headings to watch (e.g. `.page-title`, `main h2`). */
844
- this.selector = '';
845
- this.activeText = null;
846
- }
847
- componentWillLoad() {
848
- this.updateActiveTitle();
849
- }
850
- onSelectorChange() {
851
- this.updateActiveTitle();
852
- }
853
- onScroll() {
854
- this.updateActiveTitle();
855
- }
856
- onResize() {
857
- this.updateActiveTitle();
858
- }
859
- updateActiveTitle() {
860
- if (typeof window === 'undefined')
861
- return;
862
- const selector = (this.selector ?? '').trim();
863
- if (!selector) {
864
- this.activeText = null;
865
- return;
866
- }
867
- let elements = [];
868
- try {
869
- elements = Array.from(document.querySelectorAll(selector));
870
- }
871
- catch {
872
- this.activeText = null;
873
- return;
874
- }
875
- // Pick the last element that is fully above the viewport.
876
- let nextText = null;
877
- for (const element of elements) {
878
- const rect = element.getBoundingClientRect();
879
- if (rect.height > 0 && rect.bottom <= 0) {
880
- const t = (element.textContent ?? '').trim();
881
- if (t)
882
- nextText = t;
883
- }
884
- }
885
- // Do not create oscillations: update only when the computed title changes.
886
- if (nextText !== this.activeText) {
887
- this.activeText = nextText;
888
- }
889
- }
890
- render() {
891
- return (h(Host, { key: '72903f20413e002efaef27210a1dedfdc4065404' }, this.activeText ? (h("span", { class: "title", part: "title" }, this.activeText)) : (h("slot", null))));
892
- }
893
- get el() { return getElement(this); }
894
- static get watchers() { return {
895
- "selector": ["onSelectorChange"]
896
- }; }
897
- };
898
- LeCurrentHeading.style = leCurrentHeadingCss();
899
-
900
- const leDropdownBaseCss = () => `:host{display:block;--le-dropdown-list-padding:var(--le-spacing-1);--le-dropdown-empty-padding:var(--le-spacing-4);--le-dropdown-option-radius:var(--le-radius-md);--le-dropdown-font-size:var(--le-font-size-sm);--le-dropdown-option-padding:var(--le-spacing-1) var(--le-spacing-2);--le-dropdown-group-padding:var(--le-spacing-2) var(--le-spacing-2) var(--le-spacing-1);--le-dropdown-group-font-size:var(--le-font-size-xs)}:host([disabled]){pointer-events:none;opacity:0.5}le-popover::part(content){overflow-y:auto;overflow-x:hidden;padding:var(--le-dropdown-list-padding, 0.25rem)}.dropdown-empty{padding:var(--le-dropdown-empty-padding);text-align:center;color:var(--le-color-text-secondary, #9ca3af);font-size:var(--le-dropdown-font-size)}.dropdown-group-header{padding:var(--le-dropdown-group-padding);font-size:var(--le-dropdown-group-font-size);font-weight:700;color:var(--le-color-text-secondary, #9ca3af);letter-spacing:0.05em}.dropdown-list{text-align:initial}.dropdown-separator{height:1px;margin:var(--le-dropdown-separator-margin, 0.25rem 0);background:var(--le-color-border, #e5e7eb)}.dropdown-option{display:flex;align-items:center;gap:var(--le-dropdown-option-gap, 0.5rem);padding:var(--le-dropdown-option-padding);font-size:var(--le-dropdown-font-size, 0.875rem);line-height:1.4;color:var(--le-color-text, #1f2937);border:1px solid transparent;border-radius:var(--le-dropdown-option-radius, 0.25rem);cursor:pointer;user-select:none;transition:background-color 0.1s ease}.dropdown-option:hover,.dropdown-option.is-focused{border-color:var(--le-color-border-hover, #d1d5db)}.dropdown-option.is-disabled{opacity:0.5;cursor:not-allowed}.dropdown-option.is-disabled:hover{background:transparent}.option-checkbox{display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;border:2px solid var(--le-color-border, #d1d5db);border-radius:0.25rem;background:var(--le-color-surface, #fff);flex-shrink:0}.is-selected .option-checkbox{background:var(--le-color-primary, #3b82f6);border-color:var(--le-color-primary, #3b82f6);color:white}.option-checkbox svg{width:0.75rem;height:0.75rem}.option-icon-start,.option-icon-end{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem}.option-icon-start img,.option-icon-end img{width:100%;height:100%;object-fit:contain}.option-content{flex:1;min-width:0;display:flex;flex-direction:column}.option-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.option-description{font-size:0.75rem;color:var(--le-color-text-muted, #6b7280);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.option-check{display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;color:var(--le-color-primary, #3b82f6);flex-shrink:0}.option-check svg{width:1rem;height:1rem}`;
901
-
902
- const LeDropdownBase = class {
903
- constructor(hostRef) {
904
- registerInstance(this, hostRef);
905
- this.leOptionSelect = createEvent(this, "leOptionSelect");
906
- this.leDropdownOpen = createEvent(this, "leDropdownOpen");
907
- this.leDropdownClose = createEvent(this, "leDropdownClose");
908
- /**
909
- * The options to display in the dropdown.
910
- */
911
- this.options = [];
912
- /**
913
- * Whether multiple selection is allowed.
914
- */
915
- this.multiple = false;
916
- /**
917
- * Whether the dropdown is open.
918
- */
919
- this.open = false;
920
- /**
921
- * Whether the dropdown is disabled.
922
- */
923
- this.disabled = false;
924
- /**
925
- * Current filter query string.
926
- */
927
- this.filterQuery = '';
928
- /**
929
- * Placeholder text when no options match filter.
930
- */
931
- this.emptyText = 'No options';
932
- /**
933
- * Whether to show checkboxes for multiselect mode.
934
- */
935
- this.showCheckboxes = true;
936
- /**
937
- * Maximum height of the dropdown list.
938
- */
939
- this.maxHeight = '300px';
940
- /**
941
- * Sets the dropdown to full width of the trigger.
942
- */
943
- this.fullWidth = false;
944
- /**
945
- * Whether to close the dropdown when clicking outside.
946
- * (used to support combobox with input focus)
947
- */
948
- this.closeOnClickOutside = true;
949
- this.focusedIndex = -1;
950
- this.filteredOptions = [];
951
- this.triggerWidth = 0;
952
- this.handleKeyDown = (e) => {
953
- if (!this.open)
954
- return;
955
- const optionCount = this.filteredOptions.length;
956
- switch (e.key) {
957
- case 'ArrowDown':
958
- e.preventDefault();
959
- // check for the next non-disabled option and focus
960
- let nextIndex = this.focusedIndex < optionCount - 1 ? this.focusedIndex + 1 : 0;
961
- while (this.filteredOptions[nextIndex].disabled) {
962
- nextIndex = ++nextIndex < optionCount ? nextIndex : 0;
963
- }
964
- this.focusedIndex = nextIndex;
965
- this.scrollToFocused();
966
- break;
967
- case 'ArrowUp':
968
- e.preventDefault();
969
- // check for the previous non-disabled option and focus
970
- let prevIndex = this.focusedIndex > 0 ? this.focusedIndex - 1 : optionCount - 1;
971
- while (this.filteredOptions[prevIndex].disabled) {
972
- prevIndex = --prevIndex >= 0 ? prevIndex : optionCount - 1;
973
- }
974
- this.focusedIndex = prevIndex;
975
- this.scrollToFocused();
976
- break;
977
- case 'Home':
978
- e.preventDefault();
979
- // check for the first non-disabled option and focus
980
- let firstIndex = 0;
981
- while (this.filteredOptions[firstIndex].disabled) {
982
- firstIndex++;
983
- if (firstIndex >= optionCount) {
984
- firstIndex = -1;
985
- break;
986
- }
987
- }
988
- this.focusedIndex = firstIndex;
989
- this.scrollToFocused();
990
- break;
991
- case 'End':
992
- e.preventDefault();
993
- // check for the last non-disabled option and focus
994
- let lastIndex = optionCount - 1;
995
- while (this.filteredOptions[lastIndex].disabled) {
996
- lastIndex--;
997
- if (lastIndex < 0) {
998
- lastIndex = -1;
999
- break;
1000
- }
1001
- }
1002
- this.focusedIndex = lastIndex;
1003
- this.scrollToFocused();
1004
- break;
1005
- case 'Enter':
1006
- case ' ':
1007
- e.preventDefault();
1008
- if (this.focusedIndex >= 0 && this.focusedIndex < optionCount) {
1009
- const option = this.filteredOptions[this.focusedIndex];
1010
- if (!option || option.disabled)
1011
- return;
1012
- this.leOptionSelect.emit({
1013
- value: option.value ?? option.label,
1014
- option,
1015
- });
1016
- if (!this.multiple) {
1017
- this.hide();
1018
- }
1019
- }
1020
- break;
1021
- case 'Escape':
1022
- e.preventDefault();
1023
- this.hide();
1024
- break;
1025
- case 'Tab':
1026
- this.hide();
1027
- break;
1028
- }
1029
- };
1030
- this.handlePopoverOpen = () => {
1031
- this.open = true;
1032
- this.focusedIndex = this.getInitialFocusIndex();
1033
- this.leDropdownOpen.emit();
1034
- // Add keyboard listener
1035
- document.addEventListener('keydown', this.handleKeyDown);
1036
- };
1037
- this.handlePopoverClose = () => {
1038
- this.open = false;
1039
- this.focusedIndex = -1;
1040
- this.leDropdownClose.emit();
1041
- // Remove keyboard listener
1042
- document.removeEventListener('keydown', this.handleKeyDown);
1043
- };
1044
- }
1045
- handleOptionsChange() {
1046
- this.updateFilteredOptions();
1047
- }
1048
- componentWillLoad() {
1049
- this.updateFilteredOptions();
1050
- }
1051
- updateFilteredOptions() {
1052
- // Remember previously focused option
1053
- const focusedOption = this.filteredOptions[this.focusedIndex];
1054
- if (!this.filterQuery || !this.filterFn) {
1055
- this.filteredOptions = this.options;
1056
- }
1057
- else {
1058
- this.filteredOptions = this.options.filter(opt => this.filterFn(opt, this.filterQuery));
1059
- }
1060
- // try to maintain focus on same option if still present
1061
- if (focusedOption) {
1062
- const newIndex = this.filteredOptions.indexOf(focusedOption);
1063
- this.focusedIndex = newIndex >= 0 ? newIndex : this.getInitialFocusIndex();
1064
- }
1065
- else {
1066
- this.focusedIndex = -1;
1067
- }
1068
- }
1069
- getSelectableOptions() {
1070
- return this.filteredOptions.filter(opt => !opt.disabled);
1071
- }
1072
- isSelected(option) {
1073
- const optValue = option.value ?? option.label;
1074
- if (this.multiple && Array.isArray(this.value)) {
1075
- setTimeout(() => {
1076
- this.popoverEl?.updatePosition();
1077
- }, 50);
1078
- return this.value.includes(optValue);
1079
- }
1080
- return this.value === optValue;
1081
- }
1082
- handleOptionClick(option, e) {
1083
- e.preventDefault();
1084
- e.stopPropagation();
1085
- if (option.disabled)
1086
- return;
1087
- this.leOptionSelect.emit({
1088
- value: option.value ?? option.label,
1089
- option,
1090
- });
1091
- // Close dropdown for single select
1092
- if (!this.multiple) {
1093
- this.hide();
1094
- }
1095
- }
1096
- scrollToFocused() {
1097
- if (!this.listEl || this.focusedIndex < 0)
1098
- return;
1099
- const focusedEl = this.listEl.querySelector(`[data-index="${this.focusedIndex}"]`);
1100
- if (focusedEl) {
1101
- focusedEl.scrollIntoView({ block: 'nearest' });
1102
- }
1103
- }
1104
- getInitialFocusIndex() {
1105
- // Focus on first selected option, or first option
1106
- const selectableOptions = this.getSelectableOptions();
1107
- const selectedIndex = selectableOptions.findIndex(opt => this.isSelected(opt));
1108
- return selectedIndex >= 0 ? selectedIndex : 0;
1109
- }
1110
- /**
1111
- * Opens the dropdown.
1112
- */
1113
- async show() {
1114
- if (this.disabled)
1115
- return;
1116
- // Capture trigger width for matching dropdown width
1117
- const trigger = this.el.querySelector('[slot="trigger"]');
1118
- if (trigger) {
1119
- this.triggerWidth = trigger.offsetWidth;
1120
- }
1121
- await this.popoverEl?.show();
1122
- }
1123
- /**
1124
- * Closes the dropdown.
1125
- */
1126
- async hide() {
1127
- await this.popoverEl?.hide();
1128
- }
1129
- /**
1130
- * Toggles the dropdown.
1131
- */
1132
- async toggle() {
1133
- if (this.open) {
1134
- await this.hide();
1135
- }
1136
- else {
1137
- await this.show();
1138
- }
1139
- }
1140
- renderIcon(icon, className) {
1141
- if (!icon)
1142
- return null;
1143
- if (icon.startsWith('http') || icon.startsWith('/')) {
1144
- return h("img", { class: className, src: icon, alt: "" });
1145
- }
1146
- return h("span", { class: className }, icon);
1147
- }
1148
- renderOption(option, index) {
1149
- const isSelected = this.isSelected(option);
1150
- const isFocused = index === this.focusedIndex;
1151
- const optionId = option.id || generateId();
1152
- return (h("div", { class: {
1153
- 'dropdown-option': true,
1154
- 'is-selected': isSelected,
1155
- 'is-focused': isFocused,
1156
- 'is-disabled': !!option.disabled,
1157
- }, role: "option", id: optionId, "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": option.disabled ? 'true' : undefined, "data-index": index, onClick: e => this.handleOptionClick(option, e), onMouseEnter: () => {
1158
- if (!option.disabled) {
1159
- this.focusedIndex = index;
1160
- }
1161
- } }, this.renderIcon(option.iconStart, 'option-icon-start'), h("div", { class: "option-content" }, h("span", { class: "option-label" }, option.label), option.description && h("span", { class: "option-description" }, option.description)), this.renderIcon(option.iconEnd, 'option-icon-end'), (!this.multiple || this.showCheckboxes) && isSelected && (h("span", { class: "option-check" }, h("svg", { viewBox: "0 0 16 16", fill: "currentColor" }, h("path", { d: "M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z" }))))));
1162
- }
1163
- renderOptions() {
1164
- if (this.filteredOptions.length === 0) {
1165
- return h("div", { class: "dropdown-empty" }, this.emptyText);
1166
- }
1167
- // Group options if they have group property
1168
- const grouped = new Map();
1169
- const ungrouped = [];
1170
- this.filteredOptions.forEach(opt => {
1171
- if (opt.group) {
1172
- const group = grouped.get(opt.group) || [];
1173
- group.push(opt);
1174
- grouped.set(opt.group, group);
1175
- }
1176
- else {
1177
- ungrouped.push(opt);
1178
- }
1179
- });
1180
- // Build flat list with group headers for index tracking
1181
- let globalIndex = 0;
1182
- const elements = [];
1183
- // Render ungrouped options first
1184
- ungrouped.forEach(opt => {
1185
- if (opt.separator === 'before') {
1186
- elements.push(h("div", { class: "dropdown-separator", role: "separator" }));
1187
- }
1188
- elements.push(this.renderOption(opt, globalIndex++));
1189
- if (opt.separator === 'after') {
1190
- elements.push(h("div", { class: "dropdown-separator", role: "separator" }));
1191
- }
1192
- });
1193
- // Render grouped options
1194
- grouped.forEach((options, groupLabel) => {
1195
- elements.push(h("div", { class: "dropdown-group-header", role: "presentation" }, groupLabel));
1196
- options.forEach(opt => {
1197
- elements.push(this.renderOption(opt, globalIndex++));
1198
- });
1199
- });
1200
- return elements;
1201
- }
1202
- render() {
1203
- const dropdownWidth = this.width || (this.triggerWidth ? `${this.triggerWidth}px` : undefined);
1204
- return (h(Host, { key: '71c3537d6234aebb8c18fb6c07e5a751568a4b87' }, h("le-popover", { key: 'e02fcd7454cae5a9c197a509d18cd7b91e49fc9e', ref: el => (this.popoverEl = el), position: "bottom", align: "start", showClose: false, closeOnClickOutside: this.closeOnClickOutside, closeOnEscape: true, offset: 4, width: dropdownWidth, minWidth: "150px", "trigger-full-width": this.fullWidth, onLePopoverOpen: this.handlePopoverOpen, onLePopoverClose: this.handlePopoverClose }, h("slot", { key: 'f1a9e3145119f1cfc1b8a535b98b0858758c6265', name: "trigger", slot: "trigger" }), h("slot", { key: '8dd6126a610e167fb2b3c2593677f70c387bd275', name: "header" }), h("div", { key: '708b3916132c36f736f8a88e3408d482a50610fb', class: "dropdown-list", role: "listbox", "aria-multiselectable": this.multiple ? 'true' : undefined, ref: el => (this.listEl = el), style: { maxHeight: this.maxHeight } }, this.renderOptions()))));
1205
- }
1206
- get el() { return getElement(this); }
1207
- static get watchers() { return {
1208
- "options": ["handleOptionsChange"],
1209
- "filterQuery": ["handleOptionsChange"]
1210
- }; }
1211
- };
1212
- LeDropdownBase.style = leDropdownBaseCss();
1213
-
1214
- const leHeaderCss = () => `:host{display:block;width:100%;--le-header-top-offset:0;--le-header-bg:var(--le-color-surface);--le-header-max-width:var(--le-header-max-width, auto);--le-header-margin:0 auto;--le-header-border:1px solid var(--le-color-border);--le-header-border-radius:0px;--le-header-shadow:var(--le-header-shadow, none);--le-header-color:var(--le-color-text);--le-header-content-max-width:800px;--le-header-padding-x:var(--le-space-md);--le-header-padding-y:var(--le-space-sm);--le-header-gap:var(--le-space-sm);--le-header-transition:var(--le-transition-normal);--le-header-z:1000}.header{width:100%;max-width:var(--le-header-max-width);margin:var(--le-header-margin);background:var(--le-header-bg);color:var(--le-header-color);border-bottom:var(--le-header-border);border-radius:var(--le-header-border-radius);box-shadow:var(--le-header-shadow)}:host(.is-fixed){position:fixed;top:var(--le-header-top-offset);left:0;right:0;z-index:var(--le-header-z)}:host(.is-sticky){position:sticky;top:var(--le-header-top-offset);z-index:var(--le-header-z)}:host(.is-static){position:relative}.inner{max-width:var(--le-header-content-max-width);margin:0 auto;padding:var(--le-header-padding-y) var(--le-header-padding-x)}.row{display:grid;grid-template-columns:minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr);align-items:center;gap:var(--le-header-gap);transition:height var(--le-header-transition),
1215
- padding var(--le-header-transition),
1216
- transform var(--le-header-transition)}:host(.is-shrunk) .row{height:var(--le-header-height-condensed)}:host(.is-sticky.is-hidden){transform:translateY(-150%);transition:transform var(--le-header-transition)}:host(.is-sticky.is-revealed){transform:translateY(0);transition:transform var(--le-header-transition)}.start,.title,.end{min-width:0;display:flex;align-items:center}.start{justify-content:flex-start}.end{justify-content:flex-end}.title{justify-content:center;text-align:center}.title-slot ::slotted(*){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.compact-title{font:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}`;
1217
-
1218
- const LeHeader = class {
1219
- constructor(hostRef) {
1220
- registerInstance(this, hostRef);
1221
- this.leHeaderState = createEvent(this, "leHeaderState");
1222
- this.leHeaderShrinkChange = createEvent(this, "leHeaderShrinkChange");
1223
- this.leHeaderVisibilityChange = createEvent(this, "leHeaderVisibilityChange");
1224
- /** Force static positioning (default). Ignored if `sticky` or `fixed` are true. */
1225
- this.isStatic = false;
1226
- /** Sticky positioning (in-flow). Ignored if `fixed` is true. */
1227
- this.sticky = false;
1228
- /** Fixed positioning (out-of-flow). Takes precedence over `sticky`/`static`. */
1229
- this.fixed = false;
1230
- /**
1231
- * If true, expand the header when hovered
1232
- */
1233
- this.expandOnHover = false;
1234
- this.revealed = true;
1235
- this.shrunk = false;
1236
- this.placeholderHeight = null;
1237
- this.hoverActive = false;
1238
- this.rafId = null;
1239
- this.measureRafId = null;
1240
- this.lastY = 0;
1241
- this.lastEmittedDirection = 'down';
1242
- }
1243
- setShrunk(next, y) {
1244
- if (next === this.shrunk)
1245
- return;
1246
- this.shrunk = next;
1247
- this.leHeaderShrinkChange.emit({ shrunk: this.shrunk, y });
1248
- }
1249
- componentDidLoad() {
1250
- if (typeof window === 'undefined')
1251
- return;
1252
- this.lastY = window.scrollY || 0;
1253
- this.scheduleMeasure(true);
1254
- this.scheduleUpdate(true);
1255
- }
1256
- disconnectedCallback() {
1257
- this.disconnectModeObserver?.();
1258
- if (this.rafId != null) {
1259
- cancelAnimationFrame(this.rafId);
1260
- this.rafId = null;
1261
- }
1262
- if (this.measureRafId != null) {
1263
- cancelAnimationFrame(this.measureRafId);
1264
- this.measureRafId = null;
1265
- }
1266
- }
1267
- onBehaviorPropsChange() {
1268
- this.scheduleUpdate(true);
1269
- this.scheduleMeasure(true);
1270
- }
1271
- onWindowScroll() {
1272
- this.scheduleUpdate();
1273
- }
1274
- onWindowResize() {
1275
- this.scheduleMeasure(true);
1276
- this.scheduleUpdate(true);
1277
- }
1278
- getPosition() {
1279
- if (this.fixed)
1280
- return 'fixed';
1281
- if (this.sticky)
1282
- return 'sticky';
1283
- return 'static';
1284
- }
1285
- parseRevealThreshold() {
1286
- // Only applies in sticky mode.
1287
- if (!this.sticky || this.fixed)
1288
- return null;
1289
- if (this.revealOnScroll == null)
1290
- return null;
1291
- const raw = String(this.revealOnScroll).trim();
1292
- if (raw === '' || raw === 'true')
1293
- return 16;
1294
- if (raw === 'false')
1295
- return null;
1296
- const n = Number(raw);
1297
- return Number.isFinite(n) ? Math.max(0, n) : 16;
1298
- }
1299
- resolveShrinkStartPx() {
1300
- const raw = (this.shrinkOffset ?? '').trim();
1301
- if (!raw || raw === '0')
1302
- return null;
1303
- // Numeric
1304
- const numeric = Number(raw);
1305
- if (Number.isFinite(numeric))
1306
- return Math.max(0, numeric);
1307
- // CSS variable name
1308
- if (raw.startsWith('--')) {
1309
- const value = getComputedStyle(document.documentElement).getPropertyValue(raw).trim();
1310
- const v = Number(value.replace('px', '').trim());
1311
- return Number.isFinite(v) ? Math.max(0, v) : null;
1312
- }
1313
- // Selector
1314
- try {
1315
- const el = document.querySelector(raw);
1316
- this.shrinkSelectorEl = el;
1317
- return null;
1318
- }
1319
- catch {
1320
- this.shrinkSelectorEl = null;
1321
- return null;
1322
- }
1323
- }
1324
- scheduleUpdate(force = false) {
1325
- if (this.rafId != null) {
1326
- if (!force)
1327
- return;
1328
- cancelAnimationFrame(this.rafId);
1329
- this.rafId = null;
1330
- }
1331
- this.rafId = requestAnimationFrame(() => {
1332
- this.rafId = null;
1333
- this.updateFromScroll();
1334
- });
1335
- }
1336
- scheduleMeasure(force = false) {
1337
- if (this.measureRafId != null && !force)
1338
- return;
1339
- this.measureRafId = requestAnimationFrame(() => {
1340
- this.measureRafId = null;
1341
- this.measurePlaceholderHeight();
1342
- });
1343
- }
1344
- measurePlaceholderHeight() {
1345
- // Measure the rendered header height once (and on resize/mode change).
1346
- // This intentionally ignores scroll/shrink behavior; it should reserve the full header height.
1347
- if (!this.headerEl)
1348
- return;
1349
- const next = Math.ceil(this.headerEl.getBoundingClientRect().height);
1350
- if (!Number.isFinite(next) || next <= 0)
1351
- return;
1352
- if (next !== this.placeholderHeight) {
1353
- this.placeholderHeight = next;
1354
- // Publish to global root so placeholders anywhere can read it.
1355
- if (typeof document !== 'undefined') {
1356
- document.documentElement.style.setProperty('--le-header-height', `${next}px`);
1357
- }
1358
- }
1359
- }
1360
- updateFromScroll() {
1361
- const y = typeof window !== 'undefined' ? window.scrollY || 0 : 0;
1362
- const delta = y - this.lastY;
1363
- const direction = delta < 0 ? 'up' : 'down';
1364
- // Shrink behavior
1365
- let computedShrunk = false;
1366
- const headerHeight = Math.max(0, this.placeholderHeight ?? 0);
1367
- const shrinkStartPx = typeof window !== 'undefined' ? this.resolveShrinkStartPx() : null;
1368
- if (this.shrinkSelectorEl) {
1369
- const rect = this.shrinkSelectorEl.getBoundingClientRect();
1370
- computedShrunk = rect.bottom <= 0;
1371
- }
1372
- else if (shrinkStartPx != null) {
1373
- const effectiveStart = Math.max(shrinkStartPx, headerHeight);
1374
- computedShrunk = y >= effectiveStart;
1375
- }
1376
- // Hover override: when enabled and hovered, force expanded.
1377
- const nextShrunk = this.expandOnHover && this.hoverActive ? false : computedShrunk;
1378
- this.setShrunk(nextShrunk, y);
1379
- // Reveal-on-scroll (sticky-only)
1380
- const revealThreshold = this.parseRevealThreshold();
1381
- if (revealThreshold != null) {
1382
- // Always show the header near the top of the page.
1383
- const topLock = Math.max(0, this.placeholderHeight ?? 0);
1384
- if (y <= topLock) {
1385
- if (!this.revealed) {
1386
- this.revealed = true;
1387
- this.leHeaderVisibilityChange.emit({ visible: true, y });
1388
- }
1389
- }
1390
- else if (Math.abs(delta) >= revealThreshold) {
1391
- const nextRevealed = direction === 'up' || y <= 0;
1392
- if (nextRevealed !== this.revealed) {
1393
- this.revealed = nextRevealed;
1394
- this.leHeaderVisibilityChange.emit({ visible: this.revealed, y });
1395
- }
1396
- this.lastEmittedDirection = direction;
1397
- }
1398
- }
1399
- else {
1400
- if (!this.revealed) {
1401
- this.revealed = true;
1402
- this.leHeaderVisibilityChange.emit({ visible: true, y });
1403
- }
1404
- }
1405
- this.lastY = y;
1406
- this.leHeaderState.emit({
1407
- y,
1408
- direction: this.lastEmittedDirection,
1409
- revealed: this.revealed,
1410
- shrunk: this.shrunk,
1411
- });
1412
- }
1413
- render() {
1414
- const position = this.getPosition();
1415
- const hostClass = classnames('le-header', {
1416
- 'header-is-shrunk': this.shrunk,
1417
- 'is-fixed': position === 'fixed',
1418
- 'is-sticky': position === 'sticky',
1419
- 'is-static': position === 'static',
1420
- 'is-revealed': this.revealed,
1421
- 'is-hidden': !this.revealed,
1422
- 'is-shrunk': this.shrunk,
1423
- });
1424
- return (h(Host, { key: 'ade87accbc122a0eb84422598646da357570d7d0', class: hostClass, onMouseEnter: () => {
1425
- if (!this.expandOnHover)
1426
- return;
1427
- this.hoverActive = true;
1428
- this.scheduleUpdate(true);
1429
- }, onMouseLeave: () => {
1430
- if (!this.expandOnHover)
1431
- return;
1432
- this.hoverActive = false;
1433
- this.scheduleUpdate(true);
1434
- } }, h("le-component", { key: 'dfe9a341d0f8ec702775ff68f2f7afb42bc878dc', component: "le-header" }, h("header", { key: '3239f73706082a6dfc5f7637f5ee8c793debd28f', class: "header", part: "header", role: "banner", ref: el => (this.headerEl = el) }, h("div", { key: '7e4b99e4b1a8bde81c340086d947598ff7bfd9a6', class: "inner", part: "inner" }, h("div", { key: 'b8fb2a8d42a07b35482de7553cd2f3bb608169d2', class: "row", part: "row" }, h("div", { key: '89cd5b7707ccb0626c0ecdf1c07494b184fdda1b', class: "start", part: "start" }, h("le-slot", { key: 'ee442e5f097bd3dcbc5b8376eb5eed024fe474b4', name: "start", label: "Start", description: "Logo / back button / nav", "allowed-components": "le-button,le-text,le-tag,le-box,le-stack" }, h("slot", { key: 'fbf43302c87d9e15cb6e848c1f2e7a30d37ee8f0', name: "start" }))), h("div", { key: '295165dbf2b29744d0687e426cd91665a320944f', class: "title", part: "title" }, h("le-slot", { key: '96aa340f844a15042a17c98610fd4da7e771f61a', name: "title", label: "Title", description: "Header title", type: "text", tag: "span" }, h("span", { key: 'f12cee8413e02e18d3a30a203f61165c4efce673', class: "title-slot", part: "title" }, h("slot", { key: 'dddb32fcf70ec8f16017626056668f325c701b99', name: "title" })))), h("div", { key: 'bc1c9d0deb4120d335de476211e41d86ea408621', class: "end", part: "end" }, h("le-slot", { key: '804482ee7e47f93147899cab94eedbdedc1ba63f', name: "end", label: "End", description: "Actions", "allowed-components": "le-button,le-text,le-tag,le-box,le-stack" }, h("slot", { key: '11bc31fd9875f1d38393606833328c31ac651ece', name: "end" })))), h("div", { key: '8351339444b373d88d9ac0cc4487b67a8c5267cd', class: "secondary", part: "secondary" }, h("le-slot", { key: 'ee99b61af146d91bfb0a84b1fac64ab8e077b85e', name: "", label: "Secondary", description: "Secondary row content", "allowed-components": "le-tabs,le-tab-bar,le-select,le-combobox,le-text,le-stack,le-box" }, h("slot", { key: '77fabff83384d721715bd0ba6efe129dad285875' }))))))));
1435
- }
1436
- get el() { return getElement(this); }
1437
- static get watchers() { return {
1438
- "revealOnScroll": ["onBehaviorPropsChange"],
1439
- "shrinkOffset": ["onBehaviorPropsChange"],
1440
- "fixed": ["onBehaviorPropsChange"],
1441
- "sticky": ["onBehaviorPropsChange"],
1442
- "isStatic": ["onBehaviorPropsChange"]
1443
- }; }
1444
- };
1445
- LeHeader.style = leHeaderCss();
1446
-
1447
- const leIconCss = () => `:host{display:inline-block;width:var(--le-icon-size, var(--le-size-4));height:var(--le-icon-size, var(--le-size-4));color:var(--le-icon-color, var(--le-color-text-primary))}:host svg{display:block;fill:currentColor}`;
1448
-
1449
- const iconCache = {};
1450
- const requestCache = {};
1451
- /**
1452
- * Get the URL for loading an icon.
1453
- * Uses configurable assetBasePath if set, otherwise falls back to Stencil's getAssetPath.
1454
- */
1455
- function getIconUrl(name) {
1456
- const basePath = getAssetBasePath();
1457
- if (basePath) {
1458
- // Use configured base path - normalize by removing trailing slash
1459
- const normalizedBase = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
1460
- return `${normalizedBase}/icons/${name}.json`;
1461
- }
1462
- // Fall back to Stencil's getAssetPath for local development
1463
- return getAssetPath(`./assets/icons/${name}.json`);
1464
- }
1465
- async function fetchIcon({ name }) {
1466
- if (iconCache[name]) {
1467
- return iconCache[name];
1468
- }
1469
- if (!requestCache[name]) {
1470
- const iconUrl = getIconUrl(name);
1471
- requestCache[name] = fetch(iconUrl)
1472
- .then(resp => resp.json())
1473
- .catch(() => {
1474
- console.error(`Icon "${name}" could not be loaded from: ${iconUrl}`);
1475
- return '';
1476
- });
1477
- }
1478
- const path = await requestCache[name];
1479
- iconCache[name] = path;
1480
- return path;
1481
- }
1482
- const LeIcon = class {
1483
- constructor(hostRef) {
1484
- registerInstance(this, hostRef);
1485
- /**
1486
- * Name of the icon to display. Corresponds to a JSON file in the assets folder.
1487
- * For example, "search" will load the "search.json" file.
1488
- */
1489
- this.name = null;
1490
- /**
1491
- * Size of the icon in pixels. Default is 16.
1492
- */
1493
- this.size = 16;
1494
- this.iconData = null;
1495
- this.visible = false;
1496
- }
1497
- async loadIconData() {
1498
- const { name, visible } = this;
1499
- if (!name || !visible) {
1500
- return;
1501
- }
1502
- this.iconData = await fetchIcon({ name });
1503
- }
1504
- connectedCallback() {
1505
- this.waitUntilVisible(() => {
1506
- this.visible = true;
1507
- this.loadIconData();
1508
- });
1509
- }
1510
- disconnectedCallback() {
1511
- if (this.intersectionObserver) {
1512
- this.intersectionObserver.disconnect();
1513
- this.intersectionObserver = null;
1514
- }
1515
- }
1516
- async componentWillLoad() {
1517
- this.loadIconData();
1518
- }
1519
- waitUntilVisible(callback) {
1520
- if (typeof window === 'undefined' ||
1521
- !window.IntersectionObserver) {
1522
- callback();
1523
- return;
1524
- }
1525
- this.intersectionObserver = new IntersectionObserver(entries => {
1526
- entries.forEach(entry => {
1527
- if (entry.isIntersecting) {
1528
- this.intersectionObserver.disconnect();
1529
- this.intersectionObserver = null;
1530
- callback();
1531
- }
1532
- });
1533
- }, { rootMargin: '50px' });
1534
- this.intersectionObserver.observe(this.el);
1535
- }
1536
- /**
1537
- * Renders the SVG content out of a JSON data in a format:
1538
- * { "viewBox": "...", children: [{ "tag": "g", ""children": [ ... ], ...attrs }, ...] }
1539
- *
1540
- * @returns JSX.Element | null
1541
- */
1542
- renderSVGContent(children) {
1543
- if (!children || children.length === 0) {
1544
- return null;
1545
- }
1546
- const createElement = node => {
1547
- const { tag, children, ...attrs } = node;
1548
- return h(tag, attrs, children ? children.map(createElement) : null);
1549
- };
1550
- const svgElements = children.map(createElement);
1551
- return svgElements;
1552
- }
1553
- render() {
1554
- return (h("svg", { key: '15ae743268ab99a174f669436778c2305f4d65df', xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", height: this.size || 16, width: this.size || 16, viewBox: this.iconData?.viewBox || `0 0 ${this.size || 16} ${this.size || 16}` }, this.renderSVGContent(this.iconData?.children)));
1555
- }
1556
- static get assetsDirs() { return ["assets/icons"]; }
1557
- get el() { return getElement(this); }
1558
- static get watchers() { return {
1559
- "name": ["loadIconData"]
1560
- }; }
1561
- };
1562
- LeIcon.style = leIconCss();
1563
-
1564
- const leNavigationCss = () => `:host{display:block;--le-nav-radius:var(--le-radius-md);--le-nav-gap:var(--le-spacing-2);--le-nav-item-padding-x:var(--le-spacing-1);--le-nav-item-padding-y:var(--le-spacing-2);--le-nav-item-gap:var(--le-spacing-2);--le-nav-link-padding-x:var(--le-spacing-2);--le-nav-link-padding-y:var(--le-spacing-1);--le-nav-link-gap:var(--le-spacing-1);--le-nav-color:var(--le-color-text-primary);--le-nav-muted:var(--le-color-text-secondary);--le-nav-hover-bg:var(--le-color-gray-100);--le-nav-selected-bg:var(--le-color-primary);--le-nav-selected-color:var(--le-color-primary-contrast)}:host([orientation='horizontal']:not([wrap])){flex:1 1 0%;min-width:0}.nav-vertical{display:flex;flex-direction:column;gap:var(--le-nav-gap)}.nav-search{width:100%}.nav-search-input{--le-input-radius:var(--le-radius-md)}.nav-empty{padding:var(--le-spacing-2);color:var(--le-nav-muted);font-size:var(--le-font-size-sm)}.nav-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--le-spacing-1)}.nav-row{display:flex;align-items:stretch;gap:var(--le-spacing-1);border-radius:var(--le-nav-radius)}.nav-row:hover{background:var(--le-nav-hover-bg)}.nav-toggle,.nav-toggle-spacer{box-sizing:border-box;width:var(--le-spacing-4);min-width:var(--le-spacing-4);display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:var(--le-nav-radius);color:inherit}.nav-toggle{background:transparent;cursor:pointer;opacity:0.4}.nav-toggle:hover:not(:disabled){opacity:1}.nav-toggle:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px;opacity:1}.nav-chevron{display:inline-block;transition:transform var(--le-transition-fast)}.nav-chevron svg{display:block;width:var(--le-spacing-4);height:var(--le-spacing-4)}.nav-node>div>button>.nav-chevron{transform:rotate(-90deg)}.nav-node.open>div>button>.nav-chevron{transform:rotate(0deg)}.nav-item{flex:1;display:inline-flex;align-items:center;gap:var(--le-nav-item-gap);padding:var(--le-nav-item-padding-y) var(--le-nav-item-padding-x) var(--le-nav-item-padding-y) 0;border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;text-decoration:none;color:var(--le-nav-color);font-family:var(--le-font-family-base);font-size:var(--le-font-size-md);line-height:var(--le-line-height-tight);cursor:pointer}.nav-item:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.nav-node.selected>.nav-row{background:var(--le-nav-selected-bg);color:var(--le-nav-selected-color)}.nav-node.selected>.nav-row>.nav-item{color:inherit}.nav-node.disabled>.nav-row>.nav-item{opacity:0.5;cursor:not-allowed}.nav-text{display:flex;flex-direction:column;min-width:0}.nav-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav-description{color:color-mix(in srgb, var(--le-nav-muted) 90%, transparent);font-size:var(--le-font-size-sm);line-height:var(--le-line-height-tight)}.nav-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.nav-icon-end{margin-left:auto}.nav-children{margin-top:var(--le-spacing-1)}.nav-horizontal-wrapper{display:flex;align-items:center;gap:var(--le-nav-gap)}.nav-bar{flex:1 1 0%;min-width:0;--le-bar-gap:var(--le-nav-gap)}.nav-bar.align-end{--le-bar-justify:flex-end}.nav-bar.align-center{--le-bar-justify:center}.nav-bar.align-space-between{--le-bar-justify:space-between}.nav-bar.overflow-more.has-overflow,.nav-bar.overflow-hamburger.has-overflow{margin-inline-end:calc((var(--le-nav-gap) + (var(--le-nav-link-padding-x) * 2)) * -1)}.h-item{display:flex;align-items:center}.h-link{display:inline-flex;align-items:center;gap:var(--le-nav-link-gap);padding:var(--le-nav-link-padding-y) var(--le-nav-link-padding-x);border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;text-decoration:none;color:var(--le-nav-color);font-family:var(--le-font-family-base);font-size:var(--le-font-size-md);cursor:pointer}.h-link:hover{background:var(--le-nav-hover-bg)}.h-link:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.h-link.disabled,.h-trigger.disabled{opacity:0.5;pointer-events:none}.h-link.selected,.h-trigger.selected{background:var(--le-nav-selected-bg);color:var(--le-nav-selected-color)}.h-label{white-space:nowrap}.h-trigger{display:inline-flex;align-items:center;gap:var(--le-spacing-1);border-radius:var(--le-nav-radius)}.h-submenu-toggle{width:var(--le-spacing-3);height:var(--le-spacing-3);display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:var(--le-nav-radius);background:transparent;color:currentColor;cursor:pointer}.h-submenu-toggle:hover{background:var(--le-nav-hover-bg)}.overflow-trigger{display:inline-flex;align-items:center;justify-content:center;gap:var(--le-nav-link-gap);padding:var(--le-nav-link-padding-y) var(--le-nav-link-padding-x);border-radius:var(--le-nav-radius);border:1px solid transparent;background:transparent;color:var(--le-nav-color);cursor:pointer;font-family:var(--le-font-family-base);font-size:var(--le-font-size-md)}.overflow-trigger:hover{background:var(--le-nav-hover-bg)}.overflow-trigger:focus-visible{outline:2px solid var(--le-color-focus);outline-offset:2px}.nav-overflow-trigger{display:flex;align-items:center}le-popover::part(content){padding:var(--le-spacing-1)}`;
1565
-
1566
- const LeNavigation = class {
1567
- constructor(hostRef) {
1568
- registerInstance(this, hostRef);
1569
- this.leNavItemSelect = createEvent(this, "leNavItemSelect");
1570
- this.leNavItemToggle = createEvent(this, "leNavItemToggle");
1571
- /**
1572
- * Navigation items.
1573
- * Can be passed as an array or JSON string (same pattern as le-select).
1574
- */
1575
- this.items = [];
1576
- /**
1577
- * Layout orientation.
1578
- */
1579
- this.orientation = 'horizontal';
1580
- /**
1581
- * Horizontal wrapping behavior.
1582
- * If false, overflow behavior depends on `overflowMode`.
1583
- */
1584
- this.wrap = false;
1585
- /**
1586
- * Overflow behavior for horizontal, non-wrapping menus.
1587
- * - more: moves overflow items into a "More" popover
1588
- * - hamburger: turns the whole nav into a hamburger popover
1589
- */
1590
- this.overflowMode = 'more';
1591
- /**
1592
- * Minimum number of visible top-level items required to use the "More" overflow.
1593
- * If fewer would be visible, the navigation falls back to hamburger.
1594
- */
1595
- this.minVisibleItemsForMore = 2;
1596
- /**
1597
- * Alignment of the menu items within the navigation bar.
1598
- */
1599
- this.align = 'start';
1600
- /**
1601
- * Active url for automatic selection.
1602
- */
1603
- this.activeUrl = '';
1604
- /**
1605
- * Enables a search input for the vertical navigation.
1606
- */
1607
- this.searchable = false;
1608
- /**
1609
- * Placeholder text for the search input.
1610
- */
1611
- this.searchPlaceholder = 'Search...';
1612
- /**
1613
- * Text shown when no items match the filter.
1614
- */
1615
- this.emptyText = 'No results found';
1616
- /**
1617
- * Whether submenu popovers should include a filter input.
1618
- */
1619
- this.submenuSearchable = false;
1620
- this.searchQuery = '';
1621
- this.openState = {};
1622
- /** IDs of items currently in overflow (from le-bar) */
1623
- this.overflowIds = [];
1624
- /** Whether hamburger mode is active (from le-bar) */
1625
- this.hamburgerActive = false;
1626
- this.submenuQueries = {};
1627
- /** Whether the overflow popover is open */
1628
- this.overflowPopoverOpen = false;
1629
- this.popoverRefs = new Map();
1630
- this.instanceId = generateId('le-nav');
1631
- this.handleItemSelect = (e, item, id) => {
1632
- if (item.disabled) {
1633
- e.preventDefault();
1634
- e.stopPropagation();
1635
- return;
1636
- }
1637
- const emitted = this.leNavItemSelect.emit({
1638
- item,
1639
- id,
1640
- href: item.href,
1641
- originalEvent: e,
1642
- });
1643
- if (emitted.defaultPrevented) {
1644
- e.preventDefault();
1645
- }
1646
- };
1647
- this.handleToggle = (e, item, id) => {
1648
- e.preventDefault();
1649
- e.stopPropagation();
1650
- if (item.disabled)
1651
- return;
1652
- const next = !this.isOpen(item, id);
1653
- this.setOpen(id, next);
1654
- this.leNavItemToggle.emit({
1655
- item,
1656
- id,
1657
- open: next,
1658
- originalEvent: e,
1659
- });
1660
- };
1661
- this.handleSearchInput = (e) => {
1662
- const target = e.target;
1663
- this.searchQuery = target.value;
1664
- };
1665
- this.handleSubmenuSearchInput = (submenuId, e) => {
1666
- const target = e.target;
1667
- const value = target.value;
1668
- if (this.submenuQueries[submenuId] === value)
1669
- return;
1670
- this.submenuQueries = {
1671
- ...this.submenuQueries,
1672
- [submenuId]: value,
1673
- };
1674
- // Position may change as items filter.
1675
- requestAnimationFrame(() => this.popoverRefs.get(submenuId)?.updatePosition());
1676
- };
1677
- this.handleBarOverflowChange = (e) => {
1678
- this.overflowIds = e.detail.overflowingIds || [];
1679
- this.hamburgerActive = e.detail.hamburgerActive || false;
1680
- };
1681
- this.openOverflowPopover = () => {
1682
- this.overflowPopoverOpen = true;
1683
- };
1684
- this.closeOverflowPopover = () => {
1685
- this.overflowPopoverOpen = false;
1686
- };
1687
- }
1688
- partFromOptionPart(base, part) {
1689
- const raw = (part ?? '').trim();
1690
- if (!raw)
1691
- return base;
1692
- const tokens = raw
1693
- .split(/\s+/)
1694
- .map(t => t.replace(/[^a-zA-Z0-9_-]/g, ''))
1695
- .filter(Boolean);
1696
- if (tokens.length === 0)
1697
- return base;
1698
- return [base, ...tokens.map(t => `${base}-${t}`)].join(' ');
1699
- }
1700
- handleLayoutInputsChange() {
1701
- // Reset overflow state when layout inputs change
1702
- this.overflowIds = [];
1703
- this.hamburgerActive = false;
1704
- }
1705
- disconnectedCallback() {
1706
- // Cleanup if needed
1707
- }
1708
- get parsedItems() {
1709
- if (typeof this.items === 'string') {
1710
- try {
1711
- return JSON.parse(this.items);
1712
- }
1713
- catch {
1714
- return [];
1715
- }
1716
- }
1717
- return this.items;
1718
- }
1719
- getItemId(item, path) {
1720
- return item.id ?? `${this.instanceId}:${path}`;
1721
- }
1722
- getChildItems(item) {
1723
- return Array.isArray(item.children) ? item.children : [];
1724
- }
1725
- isOpen(item, id) {
1726
- const fromState = this.openState[id];
1727
- if (typeof fromState === 'boolean')
1728
- return fromState;
1729
- return !!item.open;
1730
- }
1731
- setOpen(id, open) {
1732
- if (this.openState[id] === open)
1733
- return;
1734
- this.openState = {
1735
- ...this.openState,
1736
- [id]: open,
1737
- };
1738
- }
1739
- matchesQuery(option, query) {
1740
- if (!query)
1741
- return true;
1742
- const q = query.toLowerCase();
1743
- return (option.label.toLowerCase().includes(q) ||
1744
- (option.description?.toLowerCase().includes(q) ?? false));
1745
- }
1746
- filterTree(items, query, pathPrefix, autoOpen) {
1747
- if (!query)
1748
- return items;
1749
- const result = [];
1750
- items.forEach((item, index) => {
1751
- const path = pathPrefix ? `${pathPrefix}.${index}` : String(index);
1752
- const id = this.getItemId(item, path);
1753
- const children = this.getChildItems(item);
1754
- const filteredChildren = this.filterTree(children, query, path, autoOpen);
1755
- const selfMatch = this.matchesQuery(item, query);
1756
- const childMatch = filteredChildren.length > 0;
1757
- if (selfMatch || childMatch) {
1758
- if (childMatch) {
1759
- autoOpen.add(id);
1760
- }
1761
- if (childMatch && filteredChildren !== children) {
1762
- result.push({
1763
- ...item,
1764
- children: filteredChildren,
1765
- });
1766
- }
1767
- else {
1768
- result.push(item);
1769
- }
1770
- }
1771
- });
1772
- return result;
1773
- }
1774
- renderVerticalList(items, { depth, pathPrefix, autoOpenIds, searchable, searchQuery, searchPlaceholder, emptyText, submenuId, closePopover, }) {
1775
- const query = searchQuery ?? '';
1776
- const openFromSearch = autoOpenIds ?? new Set();
1777
- const filtered = query ? this.filterTree(items, query, pathPrefix, openFromSearch) : items;
1778
- return (h("div", { class: classnames('nav-vertical', { 'is-submenu': !!submenuId }) }, searchable && (h("div", { class: "nav-search" }, h("le-string-input", { mode: "default", class: "nav-search-input", placeholder: searchPlaceholder ?? 'Search...', value: query, onInput: (e) => submenuId ? this.handleSubmenuSearchInput(submenuId, e) : this.handleSearchInput(e) }))), filtered.length === 0 ? (h("div", { class: "nav-empty" }, emptyText ?? this.emptyText)) : (h("ul", { class: "nav-list", role: "tree" }, filtered.map((item, index) => {
1779
- const path = pathPrefix ? `${pathPrefix}.${index}` : String(index);
1780
- const id = this.getItemId(item, path);
1781
- const children = this.getChildItems(item);
1782
- const hasChildren = children.length > 0;
1783
- const open = hasChildren && (this.isOpen(item, id) || openFromSearch.has(id));
1784
- const paddingLeft = `calc(var(--le-nav-item-padding-x) + ${depth} * var(--le-spacing-4))`;
1785
- const TagType = item.href && !item.disabled ? 'a' : 'button';
1786
- const attrs = TagType === 'a'
1787
- ? { href: item.href, role: 'treeitem' }
1788
- : { type: 'button', role: 'treeitem' };
1789
- const itemPart = this.partFromOptionPart('item', item.part);
1790
- return (h("li", { class: classnames('nav-node', {
1791
- 'disabled': item.disabled,
1792
- 'selected': item.selected || (this.activeUrl && item.href === this.activeUrl),
1793
- open,
1794
- 'has-children': hasChildren,
1795
- }), key: id, role: "none" }, h("div", { class: "nav-row", style: { paddingLeft } }, hasChildren ? (h("button", { type: "button", class: "nav-toggle", "aria-label": open ? 'Collapse' : 'Expand', "aria-expanded": open ? 'true' : 'false', onClick: (e) => this.handleToggle(e, item, id), disabled: item.disabled }, h("le-icon", { name: "chevron-down", class: "nav-chevron", "aria-hidden": "true" }))) : (h("span", { class: "nav-toggle-spacer", "aria-hidden": "true" })), h(TagType, { class: "nav-item", part: itemPart, ...attrs, "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => {
1796
- // For buttons, also toggle if this is a purely structural node.
1797
- this.handleItemSelect(e, item, id);
1798
- if (!item.href && hasChildren && !item.disabled) {
1799
- this.handleToggle(e, item, id);
1800
- return;
1801
- }
1802
- if (!item.disabled && closePopover) {
1803
- closePopover();
1804
- }
1805
- } }, item.iconStart && (h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), h("span", { class: "nav-text" }, h("span", { class: "nav-label" }, item.label), item.description && (h("span", { class: "nav-description" }, item.description))), item.iconEnd && (h("span", { class: "nav-icon nav-icon-end", "aria-hidden": "true" }, item.iconEnd)))), hasChildren && (h("le-collapse", { class: "nav-children", closed: !open, noFading: true, role: "group" }, this.renderVerticalList(children, {
1806
- depth: depth + 1,
1807
- pathPrefix: path,
1808
- autoOpenIds: openFromSearch,
1809
- submenuId,
1810
- closePopover,
1811
- })))));
1812
- })))));
1813
- }
1814
- renderHorizontalItem(item, index) {
1815
- const id = this.getItemId(item, String(index));
1816
- const children = this.getChildItems(item);
1817
- const hasChildren = children.length > 0;
1818
- if (!hasChildren) {
1819
- const TagType = item.href && !item.disabled ? 'a' : 'button';
1820
- const attrs = TagType === 'a'
1821
- ? { href: item.href, role: 'menuitem' }
1822
- : { type: 'button', role: 'menuitem' };
1823
- const itemPart = this.partFromOptionPart('item', item.part);
1824
- return (h("div", { class: "h-item", "data-bar-id": id }, h(TagType, { class: classnames('h-link', {
1825
- disabled: item.disabled,
1826
- selected: item.selected || (this.activeUrl && item.href === this.activeUrl),
1827
- }), part: itemPart, ...attrs, "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => this.handleItemSelect(e, item, id) }, item.iconStart && (h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), h("span", { class: "h-label" }, item.label), item.iconEnd && (h("span", { class: "nav-icon nav-icon-end", "aria-hidden": "true" }, item.iconEnd)))));
1828
- }
1829
- const submenuId = id;
1830
- const itemPart = this.partFromOptionPart('item', item.part);
1831
- return (h("div", { class: "h-item", "data-bar-id": id }, h("le-popover", { ref: el => {
1832
- if (el)
1833
- this.popoverRefs.set(submenuId, el);
1834
- }, mode: "default", offset: 8, showClose: false, closeOnClickOutside: true, closeOnEscape: true, position: "bottom", align: "start", minWidth: "240px" }, h("div", { slot: "trigger", class: classnames('h-trigger', {
1835
- disabled: item.disabled,
1836
- selected: item.selected || (this.activeUrl && item.href === this.activeUrl),
1837
- }), part: itemPart, role: "menuitem", "aria-disabled": item.disabled ? 'true' : undefined, onClick: (e) => {
1838
- // Don’t let le-popover auto-toggle from its internal wrapper.
1839
- e.stopPropagation();
1840
- if (item.disabled)
1841
- return;
1842
- if (item.href) {
1843
- this.handleItemSelect(e, item, id);
1844
- this.popoverRefs.get(submenuId)?.hide();
1845
- }
1846
- else {
1847
- this.popoverRefs.get(submenuId)?.toggle();
1848
- }
1849
- } }, item.href ? (h("a", { class: "h-link", href: item.href, onClick: (e) => {
1850
- e.stopPropagation();
1851
- this.handleItemSelect(e, item, id);
1852
- } }, item.iconStart && (h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), h("span", { class: "h-label" }, item.label), h("span", { class: "nav-chevron", "aria-hidden": "true" }, h("le-icon", { name: "chevron-down" })))) : (h("button", { type: "button", class: "h-link", onClick: (e) => {
1853
- e.stopPropagation();
1854
- if (item.disabled)
1855
- return;
1856
- this.popoverRefs.get(submenuId)?.toggle();
1857
- } }, item.iconStart && (h("span", { class: "nav-icon", "aria-hidden": "true" }, item.iconStart)), h("span", { class: "h-label" }, item.label), h("span", { class: "nav-chevron", "aria-hidden": "true" }, h("le-icon", { name: "chevron-down" }))))), h("div", { class: "popover-menu" }, this.renderVerticalList(children, {
1858
- depth: 0,
1859
- pathPrefix: String(index),
1860
- searchable: this.submenuSearchable,
1861
- searchQuery: this.submenuQueries[submenuId] ?? '',
1862
- searchPlaceholder: this.searchPlaceholder,
1863
- emptyText: this.emptyText,
1864
- submenuId,
1865
- closePopover: () => this.popoverRefs.get(submenuId)?.hide(),
1866
- })))));
1867
- }
1868
- getOverflowMode() {
1869
- if (this.wrap)
1870
- return 'wrap';
1871
- return this.overflowMode;
1872
- }
1873
- getBarAlignment() {
1874
- // Map le-navigation align to le-bar alignItems
1875
- // 'space-between' doesn't map directly, use 'stretch' as closest
1876
- if (this.align === 'space-between')
1877
- return 'stretch';
1878
- return this.align;
1879
- }
1880
- renderOverflowPopover() {
1881
- const items = this.parsedItems;
1882
- const overflowSet = new Set(this.overflowIds || []);
1883
- // Determine which items to show in the popover
1884
- let itemsToShow;
1885
- if (this.hamburgerActive) {
1886
- // In hamburger mode, show all items
1887
- itemsToShow = items;
1888
- }
1889
- else {
1890
- // In "more" mode, show only overflow items
1891
- itemsToShow = items.filter((item, index) => {
1892
- const id = this.getItemId(item, String(index));
1893
- return overflowSet.has(id);
1894
- });
1895
- }
1896
- if (itemsToShow.length === 0)
1897
- return null;
1898
- const isHamburger = this.hamburgerActive;
1899
- return (h("le-popover", { mode: "default", offset: 8, open: this.overflowPopoverOpen, showClose: false, closeOnClickOutside: true, closeOnEscape: true, position: "bottom", align: "end", minWidth: "260px", onLePopoverClose: this.closeOverflowPopover }, h("button", { slot: "trigger", type: "button", class: "overflow-trigger", part: isHamburger ? 'hamburger-trigger' : 'more-trigger', "aria-label": isHamburger ? 'Open menu' : 'More', onClick: this.openOverflowPopover }, h("slot", { name: isHamburger ? 'hamburger-trigger' : 'more-trigger' }, h("le-icon", { name: isHamburger ? 'hamburger' : 'ellipsis-horizontal' }))), h("div", { class: "popover-menu" }, this.renderVerticalList(itemsToShow, {
1900
- depth: 0,
1901
- pathPrefix: '',
1902
- closePopover: this.closeOverflowPopover,
1903
- }))));
1904
- }
1905
- renderHorizontal() {
1906
- const items = this.parsedItems;
1907
- const overflowMode = this.getOverflowMode();
1908
- const showOverflowButton = (this.overflowIds?.length ?? 0) > 0 || this.hamburgerActive;
1909
- return (h("div", { class: "nav-horizontal-wrapper" }, h("le-bar", { class: classnames('nav-bar', {
1910
- 'align-end': this.align === 'end',
1911
- 'align-center': this.align === 'center',
1912
- 'align-space-between': this.align === 'space-between',
1913
- }), overflow: overflowMode, alignItems: this.getBarAlignment(), disablePopover: true, minVisibleItems: this.minVisibleItemsForMore, onLeBarOverflowChange: this.handleBarOverflowChange }, items.map((item, index) => this.renderHorizontalItem(item, index))), showOverflowButton && this.renderOverflowPopover()));
1914
- }
1915
- render() {
1916
- const items = this.parsedItems;
1917
- if (this.orientation === 'horizontal') {
1918
- return (h(Host, null, h("le-component", { component: "le-navigation" }, this.renderHorizontal())));
1919
- }
1920
- return (h(Host, null, h("le-component", { component: "le-navigation" }, this.renderVerticalList(items, {
1921
- depth: 0,
1922
- pathPrefix: '',
1923
- searchable: this.searchable,
1924
- searchQuery: this.searchQuery,
1925
- searchPlaceholder: this.searchPlaceholder,
1926
- emptyText: this.emptyText,
1927
- }))));
1928
- }
1929
- get el() { return getElement(this); }
1930
- static get watchers() { return {
1931
- "items": ["handleLayoutInputsChange"],
1932
- "orientation": ["handleLayoutInputsChange"],
1933
- "wrap": ["handleLayoutInputsChange"],
1934
- "overflowMode": ["handleLayoutInputsChange"]
1935
- }; }
1936
- };
1937
- LeNavigation.style = leNavigationCss();
1938
-
1939
- const lePopoverCss = () => `/* ============================================
1940
- le-popover.css
1941
- Popover using native HTML Popover API
1942
- ============================================ */
1943
-
1944
- :host {
1945
- display: inline-block;
1946
- position: relative;
1947
- --le-popover-padding: var(--le-space-md, 12px);
1948
- }
1949
-
1950
- :host([trigger-full-width]) {
1951
- display: block;
1952
- width: 100%;
1953
- }
1954
-
1955
- /* ============================================
1956
- Trigger
1957
- ============================================ */
1958
-
1959
- .le-popover-trigger {
1960
- display: inline-flex;
1961
- cursor: pointer;
1962
- }
1963
-
1964
- .le-popover-trigger-full-width {
1965
- display: flex;
1966
- width: 100%;
1967
- }
1968
-
1969
- .le-popover-default-trigger {
1970
- display: flex;
1971
- align-items: center;
1972
- justify-content: center;
1973
- width: 28px;
1974
- height: 28px;
1975
- padding: 0;
1976
- border: 1px solid var(--le-color-border, #e0e0e0);
1977
- border-radius: var(--le-radius-md, 6px);
1978
- background: var(--le-color-surface, #fff);
1979
- color: var(--le-color-text-secondary, #666);
1980
- font-size: 16px;
1981
- cursor: pointer;
1982
- transition: all var(--le-transition-fast, 0.15s ease);
1983
- }
1984
-
1985
- .le-popover-default-trigger:hover {
1986
- border-color: var(--le-color-primary, #2196f3);
1987
- color: var(--le-color-primary, #2196f3);
1988
- background: var(--le-color-primary-light, rgba(33, 150, 243, 0.1));
1989
- }
1990
-
1991
- /* ============================================
1992
- Popover Content (native popover)
1993
- ============================================ */
1994
-
1995
- .le-popover-content {
1996
- /* Reset native popover defaults */
1997
- margin: 0;
1998
- padding: 0;
1999
- border: none;
2000
- background: transparent;
2001
-
2002
- /* Positioning - will be set via JS */
2003
- position: fixed;
2004
- inset: unset;
2005
-
2006
- /* Styling */
2007
- background: var(--le-color-surface, #ffffff);
2008
- border: 1px solid var(--le-color-border, #e0e0e0);
2009
- border-radius: var(--le-radius-lg, 8px);
2010
- box-shadow: var(--le-shadow-lg, 0 4px 12px rgba(0, 0, 0, 0.15));
2011
- overflow: hidden;
2012
- font-family: var(--le-font-family, system-ui, -apple-system, sans-serif);
2013
- font-size: var(--le-font-size-sm, 0.875rem);
2014
- color: var(--le-color-text, #333);
2015
-
2016
- /* Animation */
2017
- opacity: 0;
2018
- transform: scale(0.95);
2019
- transition: opacity 0.15s ease, transform 0.15s ease, display 0.15s ease allow-discrete;
2020
- }
2021
-
2022
- /* When popover is open */
2023
- .le-popover-content:popover-open {
2024
- opacity: 1;
2025
- transform: scale(1);
2026
- }
2027
-
2028
- /* Fallback for browsers without the Popover API */
2029
- .le-popover-content[data-fallback-open="false"] {
2030
- display: none;
2031
- }
2032
-
2033
- .le-popover-content[data-fallback-open="true"] {
2034
- opacity: 1;
2035
- transform: scale(1);
2036
- }
2037
-
2038
- /* Starting style for animation (CSS Anchor Positioning spec) */
2039
- @starting-style {
2040
- .le-popover-content:popover-open {
2041
- opacity: 0;
2042
- transform: scale(0.95);
2043
- }
2044
- }
2045
-
2046
- /* ============================================
2047
- Header
2048
- ============================================ */
2049
-
2050
- .le-popover-header {
2051
- display: flex;
2052
- align-items: center;
2053
- justify-content: space-between;
2054
- padding: var(--le-space-xs, 4px) var(--le-space-xs, 4px) var(--le-space-xs, 4px) var(--le-space-sm, 8px);
2055
- border-bottom: 1px solid var(--le-color-border, #e0e0e0);
2056
- background: var(--le-color-surface-alt, #f9f9f9);
2057
- min-height: 32px;
2058
- }
2059
-
2060
- .le-popover-title {
2061
- font-weight: var(--le-font-weight-semibold, 600);
2062
- font-size: var(--le-font-size-sm, 0.875rem);
2063
- color: var(--le-color-text, #333);
2064
- }
2065
-
2066
- .le-popover-close {
2067
- display: flex;
2068
- align-items: center;
2069
- justify-content: center;
2070
- width: 24px;
2071
- height: 24px;
2072
- padding: 0;
2073
- border: none;
2074
- background: transparent;
2075
- color: var(--le-color-text-secondary, #666);
2076
- font-size: 18px;
2077
- line-height: 1;
2078
- cursor: pointer;
2079
- border-radius: var(--le-radius-sm, 4px);
2080
- transition: background-color 0.15s, color 0.15s;
2081
- }
2082
-
2083
- .le-popover-close:hover {
2084
- background: var(--le-color-surface-hover, rgba(0, 0, 0, 0.05));
2085
- color: var(--le-color-text, #333);
2086
- }
2087
-
2088
- /* ============================================
2089
- Body
2090
- ============================================ */
2091
-
2092
- .le-popover-body {
2093
- padding: var(--le-popover-padding);
2094
- }
2095
-
2096
- /* ============================================
2097
- Scrollable content
2098
- ============================================ */
2099
-
2100
- .le-popover-content[style*="overflow-y: auto"] .le-popover-body {
2101
- overflow-y: auto;
2102
- }
2103
- `;
2104
-
2105
- // Keep a simple stack so Escape closes the most recently opened popover first.
2106
- // This also helps nested popovers behave naturally.
2107
- const openPopoverStack = [];
2108
- const LePopover = class {
2109
- constructor(hostRef) {
2110
- registerInstance(this, hostRef);
2111
- this.lePopoverOpen = createEvent(this, "lePopoverOpen");
2112
- this.lePopoverClose = createEvent(this, "lePopoverClose");
2113
- /**
2114
- * Whether the popover is currently open
2115
- */
2116
- this.open = false;
2117
- /**
2118
- * Position of the popover relative to its trigger
2119
- */
2120
- this.position = 'bottom';
2121
- /**
2122
- * Alignment of the popover
2123
- */
2124
- this.align = 'start';
2125
- /**
2126
- * Whether to show a close button in the header
2127
- */
2128
- this.showClose = true;
2129
- /**
2130
- * Whether clicking outside closes the popover
2131
- */
2132
- this.closeOnClickOutside = true;
2133
- /**
2134
- * Whether pressing Escape closes the popover
2135
- */
2136
- this.closeOnEscape = true;
2137
- /**
2138
- * Offset from the trigger element (in pixels)
2139
- */
2140
- this.offset = 8;
2141
- /**
2142
- * Minimum width for the popover (e.g., '200px', '15rem')
2143
- */
2144
- this.minWidth = '200px';
2145
- /**
2146
- * Should the popover's trigger take full width of its container
2147
- */
2148
- this.triggerFullWidth = false;
2149
- this.isPositioned = false;
2150
- this.uniqueId = `le-popover-${Math.random().toString(36).substr(2, 9)}`;
2151
- this.scrollParents = [];
2152
- this.isListeningForDismiss = false;
2153
- this.handleDocumentPointerDown = (event) => {
2154
- if (!this.open || !this.closeOnClickOutside)
2155
- return;
2156
- // If the click happens inside this popover component (trigger OR content), don't close.
2157
- const path = (event.composedPath?.() ?? []);
2158
- if (path.includes(this.el))
2159
- return;
2160
- this.hide();
2161
- };
2162
- this.handleDocumentKeyDown = (event) => {
2163
- if (!this.open || !this.closeOnEscape)
2164
- return;
2165
- if (event.key !== 'Escape')
2166
- return;
2167
- // Only the top-most opened popover handles Escape.
2168
- const top = openPopoverStack[openPopoverStack.length - 1];
2169
- if (top !== this.el)
2170
- return;
2171
- event.preventDefault();
2172
- event.stopPropagation();
2173
- this.hide();
2174
- };
2175
- this.handleScroll = () => {
2176
- if (this.open) {
2177
- this._updatePosition();
2178
- }
2179
- };
2180
- this.handlePopoverToggle = (event) => {
2181
- if (event.newState === 'open') {
2182
- this.handleOpened();
2183
- }
2184
- else {
2185
- this.handleClosed();
2186
- }
2187
- };
2188
- this.handleOtherPopoverOpen = (event) => {
2189
- const customEvent = event;
2190
- const openingPopover = customEvent.detail?.popover;
2191
- if (!openingPopover)
2192
- return;
2193
- if (openingPopover === this.el)
2194
- return;
2195
- // Allow nested popovers (e.g., le-select inside another popover).
2196
- // Use a shadow-DOM-aware containment check.
2197
- if (this.shadowContains(this.el, openingPopover) ||
2198
- this.shadowContains(openingPopover, this.el)) {
2199
- return;
2200
- }
2201
- if (this.open) {
2202
- this.hide();
2203
- }
2204
- };
2205
- this.handleTriggerClick = (event) => {
2206
- event.stopPropagation();
2207
- this.toggle();
2208
- };
2209
- }
2210
- /**
2211
- * Method to update the popover position from a parent component
2212
- */
2213
- async updatePosition() {
2214
- this._updatePosition();
2215
- }
2216
- get supportsPopoverApi() {
2217
- return typeof HTMLElement.prototype.showPopover === 'function';
2218
- }
2219
- shadowContains(container, node) {
2220
- let current = node;
2221
- while (current) {
2222
- if (current === container)
2223
- return true;
2224
- if (current instanceof ShadowRoot) {
2225
- current = current.host;
2226
- continue;
2227
- }
2228
- if (current.parentNode) {
2229
- current = current.parentNode;
2230
- continue;
2231
- }
2232
- const root = current.getRootNode?.();
2233
- if (root instanceof ShadowRoot) {
2234
- current = root.host;
2235
- continue;
2236
- }
2237
- break;
2238
- }
2239
- return false;
2240
- }
2241
- componentDidLoad() {
2242
- // Listen for toggle events from the native popover API
2243
- this.popoverEl?.addEventListener('toggle', this.handlePopoverToggle);
2244
- // Listen for other popovers opening to close this one
2245
- document.addEventListener('le-popover-will-open', this.handleOtherPopoverOpen);
2246
- // If the popover is initially open (unlikely, but possible), wire listeners.
2247
- if (this.open) {
2248
- this.addDismissListeners();
2249
- }
2250
- }
2251
- disconnectedCallback() {
2252
- this.popoverEl?.removeEventListener('toggle', this.handlePopoverToggle);
2253
- document.removeEventListener('le-popover-will-open', this.handleOtherPopoverOpen);
2254
- this.removeScrollListeners();
2255
- this.removeDismissListeners();
2256
- }
2257
- addDismissListeners() {
2258
- if (this.isListeningForDismiss)
2259
- return;
2260
- // Use capture so clicks inside the trigger (which stops propagation) are still observed.
2261
- document.addEventListener('pointerdown', this.handleDocumentPointerDown, true);
2262
- document.addEventListener('keydown', this.handleDocumentKeyDown, true);
2263
- this.isListeningForDismiss = true;
2264
- }
2265
- removeDismissListeners() {
2266
- if (!this.isListeningForDismiss)
2267
- return;
2268
- document.removeEventListener('pointerdown', this.handleDocumentPointerDown, true);
2269
- document.removeEventListener('keydown', this.handleDocumentKeyDown, true);
2270
- this.isListeningForDismiss = false;
2271
- }
2272
- /**
2273
- * Find all scrollable parent elements
2274
- */
2275
- getScrollParents(element) {
2276
- const scrollParents = [];
2277
- let parent = element.parentElement;
2278
- while (parent) {
2279
- const style = getComputedStyle(parent);
2280
- const overflow = style.overflow + style.overflowY + style.overflowX;
2281
- if (/(auto|scroll)/.test(overflow)) {
2282
- scrollParents.push(parent);
2283
- }
2284
- parent = parent.parentElement;
2285
- }
2286
- // Always include window for page scroll
2287
- return scrollParents;
2288
- }
2289
- /**
2290
- * Add scroll listeners to all scrollable parents
2291
- */
2292
- addScrollListeners() {
2293
- if (!this.triggerEl)
2294
- return;
2295
- this.scrollParents = this.getScrollParents(this.triggerEl);
2296
- // Listen to each scroll parent
2297
- this.scrollParents.forEach(parent => {
2298
- parent.addEventListener('scroll', this.handleScroll, { passive: true });
2299
- });
2300
- // Also listen to window scroll and resize
2301
- window.addEventListener('scroll', this.handleScroll, { passive: true });
2302
- window.addEventListener('resize', this.handleScroll, { passive: true });
2303
- }
2304
- /**
2305
- * Remove scroll listeners
2306
- */
2307
- removeScrollListeners() {
2308
- this.scrollParents.forEach(parent => {
2309
- parent.removeEventListener('scroll', this.handleScroll);
2310
- });
2311
- window.removeEventListener('scroll', this.handleScroll);
2312
- window.removeEventListener('resize', this.handleScroll);
2313
- this.scrollParents = [];
2314
- }
2315
- handleOpened() {
2316
- this.open = true;
2317
- // Track stack order for Escape handling.
2318
- const existingIndex = openPopoverStack.indexOf(this.el);
2319
- if (existingIndex >= 0)
2320
- openPopoverStack.splice(existingIndex, 1);
2321
- openPopoverStack.push(this.el);
2322
- this.addDismissListeners();
2323
- this.addScrollListeners();
2324
- this._updatePosition();
2325
- this.lePopoverOpen.emit();
2326
- }
2327
- handleClosed() {
2328
- this.open = false;
2329
- this.isPositioned = false;
2330
- this.removeScrollListeners();
2331
- this.removeDismissListeners();
2332
- const index = openPopoverStack.indexOf(this.el);
2333
- if (index >= 0)
2334
- openPopoverStack.splice(index, 1);
2335
- this.lePopoverClose.emit();
2336
- }
2337
- /**
2338
- * Opens the popover
2339
- */
2340
- async show() {
2341
- document.dispatchEvent(new CustomEvent('le-popover-will-open', {
2342
- detail: { popover: this.el },
2343
- }));
2344
- if (this.supportsPopoverApi) {
2345
- this.popoverEl?.showPopover();
2346
- }
2347
- else {
2348
- this.handleOpened();
2349
- }
2350
- }
2351
- /**
2352
- * Closes the popover
2353
- */
2354
- async hide() {
2355
- if (this.supportsPopoverApi) {
2356
- this.popoverEl?.hidePopover();
2357
- }
2358
- else {
2359
- this.handleClosed();
2360
- }
2361
- }
2362
- /**
2363
- * Toggles the popover
2364
- */
2365
- async toggle() {
2366
- if (this.open) {
2367
- await this.hide();
2368
- }
2369
- else {
2370
- await this.show();
2371
- }
2372
- }
2373
- _updatePosition() {
2374
- if (!this.triggerEl || !this.popoverEl)
2375
- return;
2376
- const triggerRect = this.triggerEl.getBoundingClientRect();
2377
- const popoverRect = this.popoverEl.getBoundingClientRect();
2378
- const viewportWidth = window.innerWidth;
2379
- const viewportHeight = window.innerHeight;
2380
- const viewportPadding = 8;
2381
- let position = this.position;
2382
- let align = this.align;
2383
- // Auto-position logic
2384
- const spaceBelow = viewportHeight - triggerRect.bottom - viewportPadding;
2385
- const spaceAbove = triggerRect.top - viewportPadding;
2386
- const spaceRight = viewportWidth - triggerRect.right - viewportPadding;
2387
- const spaceLeft = triggerRect.left - viewportPadding;
2388
- if (position === 'auto') {
2389
- if (spaceBelow >= popoverRect.height + this.offset) {
2390
- position = 'bottom';
2391
- }
2392
- else if (spaceAbove >= popoverRect.height + this.offset) {
2393
- position = 'top';
2394
- }
2395
- else if (spaceRight >= popoverRect.width + this.offset) {
2396
- position = 'right';
2397
- }
2398
- else if (spaceLeft >= popoverRect.width + this.offset) {
2399
- position = 'left';
2400
- }
2401
- else {
2402
- const maxSpace = Math.max(spaceBelow, spaceAbove, spaceRight, spaceLeft);
2403
- if (maxSpace === spaceBelow)
2404
- position = 'bottom';
2405
- else if (maxSpace === spaceAbove)
2406
- position = 'top';
2407
- else if (maxSpace === spaceRight)
2408
- position = 'right';
2409
- else
2410
- position = 'left';
2411
- }
2412
- }
2413
- // Adjust alignment for horizontal overflow
2414
- if (position === 'top' || position === 'bottom') {
2415
- if (align === 'start' &&
2416
- triggerRect.left + popoverRect.width > viewportWidth - viewportPadding) {
2417
- align = 'end';
2418
- }
2419
- else if (align === 'end' && triggerRect.right - popoverRect.width < viewportPadding) {
2420
- align = 'start';
2421
- }
2422
- else if (align === 'center') {
2423
- const triggerCenter = triggerRect.left + triggerRect.width / 2;
2424
- if (triggerCenter - popoverRect.width / 2 < viewportPadding) {
2425
- align = 'start';
2426
- }
2427
- else if (triggerCenter + popoverRect.width / 2 > viewportWidth - viewportPadding) {
2428
- align = 'end';
2429
- }
2430
- }
2431
- }
2432
- // Calculate position
2433
- let top = 0;
2434
- let left = 0;
2435
- let maxHeight = null;
2436
- switch (position) {
2437
- case 'top':
2438
- top = triggerRect.top - popoverRect.height - this.offset;
2439
- if (top < viewportPadding) {
2440
- maxHeight = triggerRect.top - this.offset - viewportPadding * 2;
2441
- top = viewportPadding;
2442
- }
2443
- break;
2444
- case 'bottom':
2445
- top = triggerRect.bottom + this.offset;
2446
- if (top + popoverRect.height > viewportHeight - viewportPadding) {
2447
- maxHeight = viewportHeight - top - viewportPadding;
2448
- }
2449
- break;
2450
- case 'left':
2451
- left = triggerRect.left - popoverRect.width - this.offset;
2452
- top = triggerRect.top;
2453
- if (left < viewportPadding)
2454
- left = viewportPadding;
2455
- break;
2456
- case 'right':
2457
- left = triggerRect.right + this.offset;
2458
- top = triggerRect.top;
2459
- if (left + popoverRect.width > viewportWidth - viewportPadding) {
2460
- left = viewportWidth - popoverRect.width - viewportPadding;
2461
- }
2462
- break;
2463
- }
2464
- // Calculate horizontal alignment for top/bottom
2465
- if (position === 'top' || position === 'bottom') {
2466
- switch (align) {
2467
- case 'start':
2468
- left = triggerRect.left;
2469
- break;
2470
- case 'center':
2471
- left = triggerRect.left + triggerRect.width / 2 - popoverRect.width / 2;
2472
- break;
2473
- case 'end':
2474
- left = triggerRect.right - popoverRect.width;
2475
- break;
2476
- }
2477
- // Constrain to viewport
2478
- if (left < viewportPadding) {
2479
- left = viewportPadding;
2480
- }
2481
- else if (left + popoverRect.width > viewportWidth - viewportPadding) {
2482
- left = viewportWidth - popoverRect.width - viewportPadding;
2483
- }
2484
- }
2485
- // Calculate vertical alignment for left/right
2486
- if (position === 'left' || position === 'right') {
2487
- switch (align) {
2488
- case 'start':
2489
- top = triggerRect.top;
2490
- break;
2491
- case 'center':
2492
- top = triggerRect.top + triggerRect.height / 2 - popoverRect.height / 2;
2493
- break;
2494
- case 'end':
2495
- top = triggerRect.bottom - popoverRect.height;
2496
- break;
2497
- }
2498
- if (top < viewportPadding)
2499
- top = viewportPadding;
2500
- if (top + popoverRect.height > viewportHeight - viewportPadding) {
2501
- maxHeight = viewportHeight - top - viewportPadding;
2502
- }
2503
- }
2504
- // Apply styles
2505
- this.popoverEl.style.top = `${top}px`;
2506
- this.popoverEl.style.left = `${left}px`;
2507
- if (maxHeight !== null && maxHeight > 100) {
2508
- this.popoverEl.style.maxHeight = `${maxHeight}px`;
2509
- this.popoverEl.style.overflowY = 'auto';
2510
- }
2511
- else {
2512
- this.popoverEl.style.maxHeight = '';
2513
- this.popoverEl.style.overflowY = '';
2514
- }
2515
- this.isPositioned = true;
2516
- }
2517
- render() {
2518
- const popoverStyles = {
2519
- visibility: this.isPositioned ? 'visible' : 'hidden',
2520
- };
2521
- if (this.width)
2522
- popoverStyles.width = this.width;
2523
- if (this.minWidth)
2524
- popoverStyles.minWidth = this.minWidth;
2525
- if (this.maxWidth)
2526
- popoverStyles.maxWidth = this.maxWidth;
2527
- return (h(Host, { key: 'c9adf9fa285b33fca47bd2caa54c3ad62f2784e1', "trigger-full-width": this.triggerFullWidth }, h("div", { key: 'e3f6c1441ec018325400e2673e012ba2939d359b', class: classnames('le-popover-trigger', {
2528
- 'le-popover-trigger-full-width': this.triggerFullWidth,
2529
- }), ref: el => (this.triggerEl = el), onClick: this.handleTriggerClick, part: "trigger" }, h("slot", { key: '9ece065f14fedc62905406359f0b6ae25747403b', name: "trigger" }, h("button", { key: '816e450c49c441f315bd619c24a4c96ef3bbc164', type: "button", class: "le-popover-default-trigger" }, h("span", { key: '4408bf0edee9ccf6e3fa9147110793c94eed8a39' }, "\u2295")))), h("div", { key: '9061223ed8051dda88802b1fb54b455aafcd20a6', id: this.uniqueId, class: "le-popover-content",
2530
- // Always use manual mode so nested popovers can be open together.
2531
- // We implement click-outside and Escape handling ourselves.
2532
- popover: "manual", ref: el => (this.popoverEl = el), style: popoverStyles, "data-fallback-open": this.supportsPopoverApi ? undefined : String(this.open) }, (this.popoverTitle || this.showClose) && (h("div", { key: '92f61d207bfd18693d5e610cdfca708afecadf9d', class: "le-popover-header" }, this.popoverTitle && h("span", { key: 'caeb2cfc8b500061bad1e8dc9cf36eff298ba7ed', class: "le-popover-title" }, this.popoverTitle), this.showClose && (h("button", { key: '3fc53cc7c0ae0bce3330613ecc90003db5028d69', type: "button", class: "le-popover-close", onClick: () => this.hide(), "aria-label": "Close" }, "\u00D7")))), h("div", { key: '829a9d5d78cb8b5d19dfb7c2afeda55faafaa8ac', class: "le-popover-body", part: "content" }, h("slot", { key: '684b41952086d22e7d3d79f6db02f7cbfd32bbf5' })))));
2533
- }
2534
- get el() { return getElement(this); }
2535
- };
2536
- LePopover.style = lePopoverCss();
2537
-
2538
- const lePopupCss = () => `:host{display:contents}.le-popup-dialog{position:fixed;z-index:100;top:0;right:0;bottom:0;left:0;padding:0;border:none;background:transparent;max-width:none;max-height:none;overflow:visible;--_popup-min-width:var(--le-popup-min-width, 320px);--_popup-max-width:var(--le-popup-max-width, min(500px, 90vw));--_popup-min-height:var(--le-popup-min-height, auto)}.le-popup-dialog::backdrop{background:var(--le-popup-backdrop-color, rgba(0, 0, 0, 0.5));animation:le-popup-backdrop-fade 0.2s ease-out}@keyframes le-popup-backdrop-fade{from{opacity:0}to{opacity:1}}.le-popup-position-center{margin:auto}.le-popup-position-top{margin:var(--le-space-2xl, 48px) auto auto auto}.le-popup-position-top-left{margin:var(--le-space-lg, 24px) auto auto var(--le-space-lg, 24px)}.le-popup-position-top-right{margin:var(--le-space-lg, 24px) var(--le-space-lg, 24px) auto auto}.le-popup-position-bottom{margin:auto auto var(--le-space-2xl, 48px) auto}.le-popup-position-bottom-left{margin:auto auto var(--le-space-lg, 24px) var(--le-space-lg, 24px)}.le-popup-position-bottom-right{margin:auto var(--le-space-lg, 24px) var(--le-space-lg, 24px) auto}.le-popup-container{display:flex;flex-direction:column;min-width:var(--_popup-min-width);max-width:var(--_popup-max-width);min-height:var(--_popup-min-height);max-height:calc(100vh - var(--le-space-2xl, 48px) * 2);background:var(--le-color-surface, #ffffff);border:1px solid var(--le-color-border, #e0e0e0);border-radius:var(--le-radius-lg, 12px);box-shadow:var(--le-shadow-xl, 0 8px 32px rgba(0, 0, 0, 0.15));overflow:hidden;font-family:var(--le-font-family, system-ui, -apple-system, sans-serif);color:var(--le-color-text, #333);animation:le-popup-appear 0.2s ease-out}@keyframes le-popup-appear{from{opacity:0;transform:scale(0.95) translateY(-10px)}to{opacity:1;transform:scale(1) translateY(0)}}.le-popup-header{flex-shrink:0;padding:var(--le-space-md, 16px) var(--le-space-lg, 24px);border-bottom:1px solid var(--le-color-border, #e0e0e0);background:var(--le-color-surface-alt, #f9f9f9);font-size:var(--le-font-size-lg, 1.125rem);font-weight:var(--le-font-weight-semibold, 600);color:var(--le-color-text, #333)}.le-popup-body{flex:1;padding:var(--le-space-lg, 24px);overflow-y:auto}.le-popup-message{margin:0;font-size:var(--le-font-size-md, 1rem);line-height:var(--le-line-height-relaxed, 1.6);color:var(--le-color-text, #333)}.le-popup-message+::slotted(*){margin-top:var(--le-space-md, 16px)}.le-popup-input{display:block;width:100%;margin-top:var(--le-space-md, 16px);padding:var(--le-space-sm, 8px) var(--le-space-md, 16px);font-family:inherit;font-size:var(--le-font-size-md, 1rem);color:var(--le-color-text, #333);background:var(--le-color-background, #fff);border:1px solid var(--le-color-border, #e0e0e0);border-radius:var(--le-radius-md, 8px);outline:none;transition:border-color var(--le-transition-fast, 0.15s ease),
2539
- box-shadow var(--le-transition-fast, 0.15s ease);box-sizing:border-box}.le-popup-input:focus{border-color:var(--le-color-primary, #2196f3);box-shadow:0 0 0 3px var(--le-color-primary-light, rgba(33, 150, 243, 0.2))}.le-popup-input::placeholder{color:var(--le-color-text-muted, #999)}.le-popup-footer{flex-shrink:0;display:flex;justify-content:flex-end;gap:var(--le-space-sm, 8px);padding:var(--le-space-md, 16px) var(--le-space-lg, 24px);border-top:1px solid var(--le-color-border, #e0e0e0);background:var(--le-color-surface-alt, #f9f9f9)}.le-popup-btn{min-width:80px}@media (max-width: 480px){.le-popup-container{min-width:calc(100vw - var(--le-space-md, 16px) * 2);max-width:calc(100vw - var(--le-space-md, 16px) * 2)}.le-popup-footer{flex-direction:column-reverse}.le-popup-btn{width:100%}}`;
2540
-
2541
- const LePopup = class {
2542
- constructor(hostRef) {
2543
- registerInstance(this, hostRef);
2544
- this.leConfirm = createEvent(this, "leConfirm");
2545
- this.leCancel = createEvent(this, "leCancel");
2546
- this.leOpen = createEvent(this, "leOpen");
2547
- this.leClose = createEvent(this, "leClose");
2548
- /**
2549
- * The mode of the Le Kit (e.g., 'default' or 'admin')
2550
- */
2551
- this.mode = 'default';
2552
- /**
2553
- * Whether the popup is currently visible
2554
- */
2555
- this.open = false;
2556
- /**
2557
- * Type of popup: alert (OK only), confirm (OK/Cancel), prompt (input + OK/Cancel), custom
2558
- */
2559
- this.type = 'alert';
2560
- /**
2561
- * Whether the popup is modal (blocks interaction with page behind)
2562
- */
2563
- this.modal = true;
2564
- /**
2565
- * Position of the popup on screen
2566
- */
2567
- this.position = 'center';
2568
- /**
2569
- * Text for the confirm/OK button
2570
- */
2571
- this.confirmText = 'OK';
2572
- /**
2573
- * Text for the cancel button
2574
- */
2575
- this.cancelText = 'Cancel';
2576
- /**
2577
- * Placeholder text for prompt input
2578
- */
2579
- this.placeholder = '';
2580
- /**
2581
- * Default value for prompt input
2582
- */
2583
- this.defaultValue = '';
2584
- /**
2585
- * Whether clicking the backdrop closes the popup (modal only)
2586
- */
2587
- this.closeOnBackdrop = true;
2588
- /**
2589
- * Internal state for prompt input value
2590
- */
2591
- this.inputValue = '';
2592
- this.handleDialogCancel = (e) => {
2593
- e.preventDefault(); // Prevent default close to handle it ourselves
2594
- this.handleCancel();
2595
- };
2596
- this.handleConfirm = () => {
2597
- const result = {
2598
- confirmed: true,
2599
- value: this.type === 'prompt' ? this.inputValue : undefined,
2600
- };
2601
- this.leConfirm.emit(result);
2602
- this.hide(true);
2603
- };
2604
- this.handleCancel = () => {
2605
- const result = {
2606
- confirmed: false,
2607
- value: undefined,
2608
- };
2609
- this.leCancel.emit(result);
2610
- this.hide(false);
2611
- };
2612
- this.handleBackdropClick = (e) => {
2613
- // Check if click was on the dialog backdrop (outside the dialog box)
2614
- if (this.closeOnBackdrop && e.target === this.dialogEl) {
2615
- const rect = this.dialogEl.getBoundingClientRect();
2616
- const clickedInDialog = e.clientX >= rect.left &&
2617
- e.clientX <= rect.right &&
2618
- e.clientY >= rect.top &&
2619
- e.clientY <= rect.bottom;
2620
- if (!clickedInDialog) {
2621
- this.handleCancel();
2622
- }
2623
- }
2624
- };
2625
- this.handleInputChange = (e) => {
2626
- this.inputValue = e.target.value;
2627
- };
2628
- this.handleKeyDown = (e) => {
2629
- if (e.key === 'Enter' && this.type !== 'custom') {
2630
- e.preventDefault();
2631
- this.handleConfirm();
2632
- }
2633
- };
2634
- }
2635
- componentWillLoad() {
2636
- this.inputValue = this.defaultValue;
2637
- }
2638
- componentDidLoad() {
2639
- // Native dialog handles Escape key automatically when modal
2640
- // We just need to listen for the cancel event
2641
- this.dialogEl?.addEventListener('cancel', this.handleDialogCancel);
2642
- }
2643
- disconnectedCallback() {
2644
- this.dialogEl?.removeEventListener('cancel', this.handleDialogCancel);
2645
- }
2646
- /**
2647
- * Opens the popup and returns a promise that resolves when closed
2648
- */
2649
- async show() {
2650
- return new Promise(resolve => {
2651
- this.resolvePromise = resolve;
2652
- this.inputValue = this.defaultValue;
2653
- this.open = true;
2654
- // Use requestAnimationFrame to ensure the dialog element is rendered
2655
- requestAnimationFrame(() => {
2656
- if (this.dialogEl) {
2657
- if (this.modal) {
2658
- this.dialogEl.showModal();
2659
- }
2660
- else {
2661
- this.dialogEl.show();
2662
- }
2663
- this.leOpen.emit();
2664
- // Focus input for prompt type
2665
- if (this.type === 'prompt' && this.inputEl) {
2666
- this.inputEl.focus();
2667
- this.inputEl.select();
2668
- }
2669
- }
2670
- });
2671
- });
2672
- }
2673
- /**
2674
- * Closes the popup with a result
2675
- */
2676
- async hide(confirmed = false) {
2677
- const result = {
2678
- confirmed,
2679
- value: this.type === 'prompt' ? this.inputValue : undefined,
2680
- };
2681
- this.dialogEl?.close();
2682
- this.open = false;
2683
- this.leClose.emit(result);
2684
- if (this.resolvePromise) {
2685
- this.resolvePromise(result);
2686
- this.resolvePromise = undefined;
2687
- }
2688
- }
2689
- hasSlot(name) {
2690
- return !!this.el.querySelector(`[slot="${name}"]`);
2691
- }
2692
- renderHeader() {
2693
- if (this.hasSlot('header')) {
2694
- return (h("div", { class: "le-popup-header", part: "header" }, h("slot", { name: "header" })));
2695
- }
2696
- if (this.popupTitle) {
2697
- return (h("div", { class: "le-popup-header", part: "header" }, this.popupTitle));
2698
- }
2699
- return null;
2700
- }
2701
- renderBody() {
2702
- return (h("div", { class: "le-popup-body", part: "body" }, this.message && h("p", { class: "le-popup-message" }, this.message), this.type === 'prompt' && (h("input", { type: "text", class: "le-popup-input", part: "input", placeholder: this.placeholder, value: this.inputValue, onInput: this.handleInputChange, onKeyDown: this.handleKeyDown, ref: el => (this.inputEl = el) })), h("le-slot", { name: "", tag: "div", description: "Custom popup content", type: "slot" }, h("slot", null))));
2703
- }
2704
- renderFooter() {
2705
- if (this.hasSlot('footer')) {
2706
- return (h("div", { class: "le-popup-footer", part: "footer" }, h("slot", { name: "footer" })));
2707
- }
2708
- // For custom type without footer slot, don't render default buttons
2709
- if (this.type === 'custom') {
2710
- return null;
2711
- }
2712
- return (h("div", { class: "le-popup-footer", part: "footer" }, (this.type === 'confirm' || this.type === 'prompt') && (h("le-button", { variant: "outlined", part: "button-cancel", class: "le-popup-btn", onClick: this.handleCancel }, this.cancelText)), h("le-button", { variant: "solid", part: "button-confirm", class: "le-popup-btn", onClick: this.handleConfirm }, this.confirmText)));
2713
- }
2714
- render() {
2715
- const positionClass = `le-popup-position-${this.position}`;
2716
- return (h("dialog", { key: '9a42c63b24b521264654847ff45ea026000a642d', class: `le-popup-dialog ${positionClass}`, part: "dialog", ref: el => (this.dialogEl = el), onClick: this.handleBackdropClick }, h("le-component", { key: 'a3f086d20a9e611f3907f039bbcf9f7054927fa5', component: "le-popup" }, h("div", { key: 'b2ee2bc7d9eb42f457541c8ffb20af52b7cde8e9', class: "le-popup-container", part: "container" }, this.renderHeader(), this.renderBody(), this.renderFooter()))));
2717
- }
2718
- get el() { return getElement(this); }
2719
- };
2720
- LePopup.style = lePopupCss();
2721
-
2722
- const leScrollProgressCss = () => `:host{display:block}:host([sticky]){position:sticky;top:var(--le-scroll-progress-sticky-top, 0);z-index:var(--le-scroll-progress-z, calc(var(--le-header-z, 1000) + 1))}:host([fixed]){position:fixed;top:var(--le-scroll-progress-fixed-top, 0);left:var(--le-scroll-progress-fixed-left, 0);right:var(--le-scroll-progress-fixed-right, 0);z-index:var(--le-scroll-progress-z, calc(var(--le-header-z, 1000) + 1))}.track{width:100%;height:var(--le-scroll-progress-height, 4px);background:var(--le-scroll-progress-bg, transparent)}.fill{height:100%;width:0;background:var(--le-scroll-progress-fill, var(--le-color-primary, currentColor));border-radius:var(--le-scroll-progress-border-radius, 2px);transition:width var(--le-transition-fast, 120ms linear)}`;
2723
-
2724
- const LeScrollProgress = class {
2725
- constructor(hostRef) {
2726
- registerInstance(this, hostRef);
2727
- this.progress = 0;
2728
- this.rafId = null;
2729
- this.targetEl = null;
2730
- }
2731
- componentWillLoad() {
2732
- this.updateProgress();
2733
- }
2734
- componentDidLoad() {
2735
- this.resolveTarget();
2736
- this.updateProgress();
2737
- }
2738
- disconnectedCallback() {
2739
- if (this.rafId != null) {
2740
- cancelAnimationFrame(this.rafId);
2741
- this.rafId = null;
2742
- }
2743
- }
2744
- onTrackChange() {
2745
- this.resolveTarget();
2746
- this.updateProgress();
2747
- }
2748
- onScroll() {
2749
- this.scheduleUpdate();
2750
- }
2751
- onResize() {
2752
- this.resolveTarget();
2753
- this.scheduleUpdate(true);
2754
- }
2755
- scheduleUpdate(force = false) {
2756
- if (this.rafId != null && !force)
2757
- return;
2758
- this.rafId = requestAnimationFrame(() => {
2759
- this.rafId = null;
2760
- this.updateProgress();
2761
- });
2762
- }
2763
- resolveTarget() {
2764
- if (typeof document === 'undefined')
2765
- return;
2766
- const raw = this.trackScrollProgress;
2767
- // If attribute missing, default to enabled (full document).
2768
- // If user explicitly sets 'false', treat as disabled.
2769
- if (raw == null) {
2770
- this.targetEl = null;
2771
- return;
2772
- }
2773
- const val = String(raw).trim();
2774
- if (val === '' || val === 'true') {
2775
- this.targetEl = null;
2776
- return;
2777
- }
2778
- if (val === 'false') {
2779
- this.targetEl = null;
2780
- return;
2781
- }
2782
- try {
2783
- this.targetEl = document.querySelector(val);
2784
- }
2785
- catch {
2786
- this.targetEl = null;
2787
- }
2788
- }
2789
- clamp01(n) {
2790
- return Math.max(0, Math.min(1, n));
2791
- }
2792
- updateProgress() {
2793
- if (typeof window === 'undefined' || typeof document === 'undefined')
2794
- return;
2795
- // If explicitly disabled.
2796
- if (this.trackScrollProgress === 'false') {
2797
- if (this.progress !== 0)
2798
- this.progress = 0;
2799
- return;
2800
- }
2801
- const scrollY = window.scrollY || 0;
2802
- let p = 0;
2803
- if (this.targetEl) {
2804
- const rect = this.targetEl.getBoundingClientRect();
2805
- const top = scrollY + rect.top;
2806
- const height = rect.height;
2807
- const viewport = window.innerHeight || 1;
2808
- const denom = Math.max(1, height - viewport);
2809
- p = this.clamp01((scrollY - top) / denom);
2810
- }
2811
- else {
2812
- const doc = document.documentElement;
2813
- const denom = Math.max(1, doc.scrollHeight - doc.clientHeight);
2814
- p = this.clamp01(scrollY / denom);
2815
- }
2816
- const next = Math.round(p * 1000) / 1000;
2817
- if (next !== this.progress)
2818
- this.progress = next;
2819
- }
2820
- render() {
2821
- const width = `${this.progress * 100}%`;
2822
- return (h(Host, { key: '4521900e44e8226280a6fc1d7431e24832057be3' }, h("div", { key: 'a0daeec6b1c39fd4b5cc3ae90f27e615fa9828ef', class: "track", part: "track", "aria-hidden": "true" }, h("div", { key: 'd2c683765627c5eea27483ce00c3eff734e8c87a', class: "fill", part: "fill", style: { width } }))));
2823
- }
2824
- get el() { return getElement(this); }
2825
- static get watchers() { return {
2826
- "trackScrollProgress": ["onTrackChange"]
2827
- }; }
2828
- };
2829
- LeScrollProgress.style = leScrollProgressCss();
2830
-
2831
- const leSelectCss = () => `:host{display:inline-block;min-width:150px;--le-select-color:var(--le-color-text, #1f2937);--le-select-border-radius:var(--le-radius-md);--le-select-content-padding:var(--le-spacing-2)}:host([disabled]){opacity:0.5;pointer-events:none}:host([full-width]){width:100%}.select-trigger{display:flex;align-items:center;gap:0.5rem;width:100%;padding:0;--le-button-padding:var(--le-spacing-1) var(--le-spacing-1) var(--le-spacing-1) var(--le-spacing-2);font-size:var(--le-select-font-size, 0.875rem);font-family:inherit;line-height:1.4;color:var(--le-select-color);background:var(--le-select-bg, var(--le-color-surface, #fff));border-radius:var(--le-select-border-radius);cursor:pointer;text-align:left;transition:border-color 0.15s ease, box-shadow 0.15s ease}.select-trigger:focus{outline:2px solid var(--le-color-focus);outline-offset:2px}.select-trigger:not(.has-value) .trigger-label{color:color-mix(in srgb, var(--le-color-text-secondary) 66%, transparent)}.trigger-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem}.trigger-icon-end{width:16px;height:16px}.trigger-icon img{width:100%;height:100%;object-fit:contain}.trigger-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--le-color-text)}.trigger-label::not(.has-value){color:var(--le-color-text-disabled, #9ca3af)}le-button::part(icon-end){display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;transition:transform 0.2s ease}le-button::part(icon-end) svg{width:1rem;height:1rem}le-button.is-open::part(icon-end){transform:rotate(180deg)}.search-input::part(container):focus-within{outline:none !important}.search-input{--le-input-radius:var(--le-radius-md)}`;
2832
-
2833
- const LeSelect = class {
2834
- constructor(hostRef) {
2835
- registerInstance(this, hostRef);
2836
- this.leChange = createEvent(this, "change");
2837
- this.leOpen = createEvent(this, "leOpen");
2838
- this.leClose = createEvent(this, "leClose");
2839
- /**
2840
- * The options to display in the dropdown.
2841
- */
2842
- this.options = [];
2843
- /**
2844
- * Placeholder text when no option is selected.
2845
- */
2846
- this.placeholder = 'Select an option';
2847
- /**
2848
- * Whether the select is disabled.
2849
- */
2850
- this.disabled = false;
2851
- /**
2852
- * Whether selection is required.
2853
- */
2854
- this.required = false;
2855
- /**
2856
- * Whether the select should take full width of its container.
2857
- */
2858
- this.fullWidth = false;
2859
- /**
2860
- * Size variant of the select.
2861
- */
2862
- this.size = 'medium';
2863
- /**
2864
- * Visual variant of the select.
2865
- */
2866
- this.variant = 'default';
2867
- /**
2868
- * Whether the input is searchable.
2869
- */
2870
- this.searchable = false;
2871
- /**
2872
- * Text to show when no options match the search.
2873
- */
2874
- this.emptyText = 'No results found';
2875
- /**
2876
- * Whether the dropdown is currently open.
2877
- */
2878
- this.open = false;
2879
- this.searchQuery = '';
2880
- this.filterOption = (option, query) => {
2881
- if (!query)
2882
- return true;
2883
- const searchLower = query.toLowerCase();
2884
- return (option.label.toLowerCase().includes(searchLower) ||
2885
- (option.description?.toLowerCase().includes(searchLower) ?? false));
2886
- };
2887
- this.handleOptionSelect = (e) => {
2888
- this.value = e.detail.value;
2889
- this.selectedOption = e.detail.option;
2890
- this.leChange.emit(e.detail);
2891
- };
2892
- this.handleDropdownOpen = () => {
2893
- this.open = true;
2894
- this.leOpen.emit();
2895
- // Focus search input if searchable
2896
- if (this.searchable) {
2897
- setTimeout(() => {
2898
- this.inputEl?.focus();
2899
- }, 50);
2900
- }
2901
- };
2902
- this.handleDropdownClose = () => {
2903
- this.open = false;
2904
- this.leClose.emit();
2905
- };
2906
- this.handleTriggerClick = () => {
2907
- if (!this.disabled) {
2908
- this.dropdownEl?.toggle();
2909
- }
2910
- };
2911
- this.handleTriggerKeyDown = (e) => {
2912
- if (this.disabled)
2913
- return;
2914
- if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
2915
- e.preventDefault();
2916
- this.dropdownEl?.show();
2917
- }
2918
- };
2919
- this.handleSearchInput = (e) => {
2920
- const target = e.target;
2921
- this.searchQuery = target.value;
2922
- };
2923
- }
2924
- handleValueChange() {
2925
- this.updateSelectedOption();
2926
- }
2927
- handleOptionsChange() {
2928
- this.updateSelectedOption();
2929
- }
2930
- componentWillLoad() {
2931
- this.updateSelectedOption();
2932
- }
2933
- get parsedOptions() {
2934
- if (typeof this.options === 'string') {
2935
- try {
2936
- return JSON.parse(this.options);
2937
- }
2938
- catch {
2939
- return [];
2940
- }
2941
- }
2942
- return this.options;
2943
- }
2944
- updateSelectedOption() {
2945
- if (this.value !== undefined) {
2946
- this.selectedOption = this.parsedOptions.find(opt => (opt.value ?? opt.label) === this.value);
2947
- }
2948
- else {
2949
- this.selectedOption = undefined;
2950
- }
2951
- }
2952
- /**
2953
- * Opens the dropdown.
2954
- */
2955
- async showDropdown() {
2956
- await this.dropdownEl?.show();
2957
- }
2958
- /**
2959
- * Closes the dropdown.
2960
- */
2961
- async hideDropdown() {
2962
- await this.dropdownEl?.hide();
2963
- }
2964
- renderIcon(icon) {
2965
- if (!icon)
2966
- return null;
2967
- if (icon.startsWith('http') || icon.startsWith('/')) {
2968
- return h("img", { class: "trigger-icon", src: icon, alt: "" });
2969
- }
2970
- return h("span", { class: "trigger-icon" }, icon);
2971
- }
2972
- render() {
2973
- const hasValue = this.selectedOption !== undefined;
2974
- return (h("le-component", { key: 'cd0d10eb7ee1cc6f52fcb32bc3675e2f74219d9b', component: "le-select" }, h("le-dropdown-base", { key: '200e03a079caaa6c091f82d0384134a3e2d0154d', ref: el => (this.dropdownEl = el), options: this.parsedOptions, value: this.value, disabled: this.disabled, filterFn: this.searchable ? this.filterOption : undefined, filterQuery: this.searchQuery, onLeOptionSelect: this.handleOptionSelect, onLeDropdownOpen: this.handleDropdownOpen, onLeDropdownClose: this.handleDropdownClose, fullWidth: this.fullWidth }, h("le-button", { key: '0fa315cceaf6f18a5e370351027f27167fe64ce0', variant: this.variant && this.variant !== 'default' ? this.variant : 'outlined', slot: "trigger", align: "space-between", class: {
2975
- 'select-trigger': true,
2976
- 'has-value': hasValue,
2977
- 'is-open': this.open,
2978
- }, mode: "default", size: this.size, disabled: this.disabled, "aria-haspopup": "listbox", "aria-expanded": this.open ? 'true' : 'false', onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeyDown, fullWidth: this.fullWidth, iconStart: hasValue && this.selectedOption?.iconStart
2979
- ? this.renderIcon(this.selectedOption.iconStart)
2980
- : null, iconEnd: h("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { d: "M4 6l4 4 4-4" })) }, h("span", { key: 'aae9bb220fb206622dbf6959f125c78adfb13e00', class: "trigger-label" }, hasValue ? this.selectedOption.label : this.placeholder)), this.searchable && this.open && (h("div", { key: '0e7e360672e2e7ce7d32dc726a450ccff245cee0', class: "multiselect-search", slot: "header" }, h("le-string-input", { key: 'a2a36fc139d4b477d35910541fab6071eddc3de5', mode: "default", inputRef: el => (this.inputEl = el), class: "search-input", placeholder: "Search...", value: this.searchQuery, onInput: this.handleSearchInput })))), this.name && h("input", { key: '9555b72d2f433ce9ee3803d0bb3ceb0dae1c37e3', type: "hidden", name: this.name, value: this.value?.toString() ?? '' })));
2981
- }
2982
- get el() { return getElement(this); }
2983
- static get watchers() { return {
2984
- "value": ["handleValueChange"],
2985
- "options": ["handleOptionsChange"]
2986
- }; }
2987
- };
2988
- LeSelect.style = leSelectCss();
2989
-
2990
- 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}`;
2991
-
2992
- const LeSlot = class {
2993
- constructor(hostRef) {
2994
- registerInstance(this, hostRef);
2995
- this.leSlotChange = createEvent(this, "leSlotChange");
2996
- /**
2997
- * The type of slot content.
2998
- * - `slot`: Default, shows a dropzone for components (default)
2999
- * - `text`: Shows a single-line text input
3000
- * - `textarea`: Shows a multi-line text area
3001
- */
3002
- this.type = 'slot';
3003
- /**
3004
- * The name of the slot this placeholder represents.
3005
- * Should match the slot name in the parent component.
3006
- */
3007
- this.name = '';
3008
- /**
3009
- * Whether multiple components can be dropped in this slot.
3010
- */
3011
- this.multiple = true;
3012
- /**
3013
- * Whether this slot is required to have content.
3014
- */
3015
- this.required = false;
3016
- /**
3017
- * Internal state to track admin mode
3018
- */
3019
- this.adminMode = false;
3020
- /**
3021
- * Internal state for text input value (synced from slot content)
3022
- */
3023
- this.textValue = '';
3024
- /**
3025
- * Whether the current textValue contains valid HTML
3026
- */
3027
- this.isValidHtml = true;
3028
- /**
3029
- * Available components loaded from Custom Elements Manifest
3030
- */
3031
- this.availableComponents = [];
3032
- /**
3033
- * Whether the component picker popover is open
3034
- */
3035
- this.pickerOpen = false;
3036
- /**
3037
- * Flag to prevent re-reading content right after we updated it
3038
- */
3039
- this.isUpdating = false;
3040
- this.handleTextInput = (event) => {
3041
- const target = event.target;
3042
- this.textValue = target.value;
3043
- this.isValidHtml = this.validateHtml(this.textValue);
3044
- if (this.isValidHtml) {
3045
- // Set flag to prevent slotchange from re-reading what we just wrote
3046
- this.isUpdating = true;
3047
- console.log('Updating text value:', this.textValue, 'slottedElement:', this.slottedElement);
3048
- if (this.slottedElement) {
3049
- // Update existing slotted element's innerHTML
3050
- this.slottedElement.innerHTML = this.textValue;
3051
- }
3052
- else if (this.tag && this.textValue) {
3053
- // No slotted element exists
3054
- // If the slot doesn't have a name, then it's the default slot
3055
- // remove the existing non-slotted content (text nodes and elements without slot attribute)
3056
- const rootNode = this.el.getRootNode();
3057
- if (!this.name && rootNode instanceof ShadowRoot) {
3058
- const hostComponent = rootNode.host;
3059
- Array.from(hostComponent.childNodes).forEach(node => {
3060
- if (node.nodeType === Node.TEXT_NODE || (node.nodeType === Node.ELEMENT_NODE && !node.hasAttribute('slot'))) {
3061
- node.remove();
3062
- }
3063
- });
3064
- }
3065
- // create one using the specified tag
3066
- this.createSlottedElement();
3067
- }
3068
- else if (this.textValue) {
3069
- // no tag specified - just replace everything in the host component
3070
- const rootNode = this.el.getRootNode();
3071
- if (rootNode instanceof ShadowRoot) {
3072
- const hostComponent = rootNode.host;
3073
- hostComponent.innerHTML = this.textValue;
3074
- }
3075
- }
3076
- }
3077
- this.leSlotChange.emit({
3078
- name: this.name,
3079
- value: this.textValue,
3080
- isValid: this.isValidHtml,
3081
- });
3082
- };
3083
- /**
3084
- * Handle slot change event to re-read content when nodes are assigned
3085
- */
3086
- this.handleSlotChange = () => {
3087
- this.readSlottedContent();
3088
- };
3089
- }
3090
- connectedCallback() {
3091
- this.disconnectModeObserver = observeModeChanges(this.el, mode => {
3092
- const wasAdmin = this.adminMode;
3093
- this.adminMode = mode === 'admin';
3094
- // When entering admin mode, read content from slotted elements
3095
- if (this.adminMode && !wasAdmin) {
3096
- // Need to wait for render to access slot ref
3097
- requestAnimationFrame(() => this.readSlottedContent());
3098
- // Load available components for the component picker
3099
- if (this.type === 'slot') {
3100
- this.loadAvailableComponents();
3101
- }
3102
- }
3103
- });
3104
- }
3105
- disconnectedCallback() {
3106
- this.disconnectModeObserver?.();
3107
- }
3108
- /**
3109
- * Read content from slotted elements via assignedNodes()
3110
- */
3111
- readSlottedContent() {
3112
- if (!this.slotRef)
3113
- return;
3114
- // Skip if we just updated the content ourselves
3115
- if (this.isUpdating) {
3116
- this.isUpdating = false;
3117
- return;
3118
- }
3119
- const assignedNodes = this.slotRef.assignedNodes({ flatten: true });
3120
- // For text/textarea types, we want to edit the innerHTML of slotted elements
3121
- if (this.type === 'text' || this.type === 'textarea') {
3122
- // Find the first element node (skip text nodes that are just whitespace)
3123
- const elementNode = assignedNodes.find(node => node.nodeType === Node.ELEMENT_NODE);
3124
- if (elementNode) {
3125
- // Only update textValue if slotted element changed or we don't have one yet
3126
- if (this.slottedElement !== elementNode) {
3127
- this.slottedElement = elementNode;
3128
- this.textValue = elementNode.innerHTML?.trim() || '';
3129
- // console.log(`[le-slot "${this.name}"] Read slotted content:`, this.textValue);
3130
- }
3131
- }
3132
- else {
3133
- // No element, check for direct text content
3134
- const textContent = assignedNodes
3135
- .filter(node => node.nodeType === Node.TEXT_NODE)
3136
- .map(node => node.textContent)
3137
- .join('')
3138
- .trim();
3139
- if (textContent && !this.textValue) {
3140
- this.textValue = textContent;
3141
- // console.log(`[le-slot "${this.name}"] Read text content:`, this.textValue);
3142
- }
3143
- }
3144
- }
3145
- }
3146
- /**
3147
- * Validates if a string contains valid HTML
3148
- */
3149
- validateHtml(html) {
3150
- // Empty string is valid
3151
- if (!html.trim())
3152
- return true;
3153
- // Create a template element to parse the HTML
3154
- const template = document.createElement('template');
3155
- template.innerHTML = html;
3156
- // Check that we don't have obviously broken HTML
3157
- // Count opening and closing tags for common elements
3158
- const openTags = (html.match(/<[a-z][^>]*(?<!\/)>/gi) || []).length;
3159
- const closeTags = (html.match(/<\/[a-z][^>]*>/gi) || []).length;
3160
- const selfClosing = (html.match(/<[a-z][^>]*\/>/gi) || []).length;
3161
- // Simple validation: opening tags (minus self-closing) should roughly match closing tags
3162
- // Allow some tolerance for void elements like <br>, <img>, etc.
3163
- const voidElements = (html.match(/<(br|hr|img|input|meta|link|area|base|col|embed|param|source|track|wbr)[^>]*>/gi) || []).length;
3164
- const effectiveOpenTags = openTags - selfClosing - voidElements;
3165
- // If difference is too large, HTML is likely broken
3166
- if (Math.abs(effectiveOpenTags - closeTags) > 1) {
3167
- return false;
3168
- }
3169
- return true;
3170
- }
3171
- /**
3172
- * Create a new slotted element when none exists.
3173
- * The element is appended to the host component's light DOM.
3174
- */
3175
- createSlottedElement() {
3176
- if (!this.tag)
3177
- return;
3178
- // Find the host component (le-card, etc.) by traversing up through shadow DOM
3179
- // le-slot is inside le-card's shadow DOM, so we need to find le-card's host
3180
- const rootNode = this.el.getRootNode();
3181
- if (!(rootNode instanceof ShadowRoot))
3182
- return;
3183
- const hostComponent = rootNode.host;
3184
- if (!hostComponent)
3185
- return;
3186
- // Create the new element
3187
- const newElement = document.createElement(this.tag);
3188
- newElement.innerHTML = this.textValue;
3189
- // Set the slot attribute if this is a named slot
3190
- if (this.name) {
3191
- newElement.setAttribute('slot', this.name);
3192
- }
3193
- // Append to the host component's light DOM
3194
- hostComponent.appendChild(newElement);
3195
- // Store reference to the new element
3196
- this.slottedElement = newElement;
3197
- // console.log(`[le-slot "${this.name}"] Created new <${this.tag}> element`);
3198
- }
3199
- /**
3200
- * Load available components from Custom Elements Manifest
3201
- */
3202
- async loadAvailableComponents() {
3203
- try {
3204
- const { manifestFile } = getLeKitConfig();
3205
- const manifestFileResolved = getAssetPath(`./assets/${manifestFile}`);
3206
- const response = await fetch(manifestFileResolved);
3207
- const manifest = await response.json();
3208
- const components = [];
3209
- const allowedList = this.allowedComponents?.split(',').map(s => s.trim()) || [];
3210
- for (const module of manifest.modules) {
3211
- for (const declaration of module.declarations || []) {
3212
- if (declaration.tagName && declaration.customElement) {
3213
- // Skip internal components (le-slot, le-component, le-popover)
3214
- const isInternal = ['le-slot', 'le-component', 'le-popover'].includes(declaration.tagName);
3215
- if (isInternal)
3216
- continue;
3217
- // If allowedComponents is specified, filter by it
3218
- if (allowedList.length > 0 && !allowedList.includes(declaration.tagName)) {
3219
- continue;
3220
- }
3221
- components.push({
3222
- tagName: declaration.tagName,
3223
- name: this.formatComponentName(declaration.tagName),
3224
- description: declaration.description || '',
3225
- });
3226
- }
3227
- }
3228
- }
3229
- this.availableComponents = components || [];
3230
- }
3231
- catch (error) {
3232
- console.warn('[le-slot] Failed to load component manifest:', error);
3233
- }
3234
- }
3235
- /**
3236
- * Format a tag name into a display name
3237
- * e.g., 'le-card' -> 'Card'
3238
- */
3239
- formatComponentName(tagName) {
3240
- return tagName
3241
- .replace(/^le-/, '')
3242
- .split('-')
3243
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
3244
- .join(' ');
3245
- }
3246
- /**
3247
- * Add a new component to the slot
3248
- */
3249
- addComponent(tagName) {
3250
- // Find the host component by traversing up through shadow DOM
3251
- const rootNode = this.el.getRootNode();
3252
- if (!(rootNode instanceof ShadowRoot))
3253
- return;
3254
- const hostComponent = rootNode.host;
3255
- if (!hostComponent)
3256
- return;
3257
- // Create the new component element
3258
- const newElement = document.createElement(tagName);
3259
- // Set the slot attribute if this is a named slot
3260
- if (this.name) {
3261
- newElement.setAttribute('slot', this.name);
3262
- }
3263
- // Append to the host component's light DOM
3264
- hostComponent.appendChild(newElement);
3265
- // Emit change event so the page can save
3266
- this.leSlotChange.emit({
3267
- name: this.name,
3268
- value: hostComponent.innerHTML,
3269
- isValid: true,
3270
- });
3271
- }
3272
- render() {
3273
- const displayLabel = this.label || this.name;
3274
- // Always render the same structure, CSS handles visibility via .admin-mode class
3275
- return (h(Host, { key: 'fb2a01670291a714608bc59069991a8ef65dc3e9', class: {
3276
- 'admin-mode': this.adminMode,
3277
- 'invalid-html': !this.isValidHtml,
3278
- }, 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', {
3279
- 'le-slot-header-no-label': !displayLabel,
3280
- 'le-slot-header-text': this.type === 'text',
3281
- 'le-slot-header-error': !this.isValidHtml,
3282
- }) }, 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: () => {
3283
- this.addComponent(component.tagName);
3284
- this.pickerOpen = false;
3285
- } }, 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())) : (
3286
- // In default mode, just pass through the slot - slotted content renders naturally
3287
- // Note: We use unnamed slot here because named slots from parent component
3288
- // are passed as le-slot's light DOM children
3289
- h("slot", null))));
3290
- }
3291
- renderContent() {
3292
- // Create the slot element with ref for reading assignedNodes
3293
- // Wrap in a hidden div since slot elements can't have style prop in Stencil
3294
- // Note: We use unnamed slot here because named slots from parent component
3295
- // are passed as le-slot's light DOM children
3296
- const slotElement = (h("div", { class: "hidden-slot" }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
3297
- switch (this.type) {
3298
- case 'text':
3299
- 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));
3300
- case 'textarea':
3301
- 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));
3302
- case 'slot':
3303
- default:
3304
- // Parse slotStyle string into style object if provided
3305
- const dropzoneStyle = {};
3306
- if (this.slotStyle) {
3307
- this.slotStyle.split(';').forEach(rule => {
3308
- const [prop, value] = rule.split(':').map(s => s.trim());
3309
- if (prop && value) {
3310
- // Convert kebab-case to camelCase for style object
3311
- const camelProp = prop.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
3312
- dropzoneStyle[camelProp] = value;
3313
- }
3314
- });
3315
- }
3316
- return (h("div", { class: "le-slot-dropzone", style: dropzoneStyle }, h("slot", { ref: el => (this.slotRef = el), onSlotchange: this.handleSlotChange })));
3317
- }
3318
- }
3319
- get el() { return getElement(this); }
3320
- };
3321
- LeSlot.style = leSlotDefaultCss();
3322
-
3323
- 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}`;
3324
-
3325
- const LeStringInput = class {
3326
- constructor(hostRef) {
3327
- registerInstance(this, hostRef);
3328
- this.leChange = createEvent(this, "change");
3329
- this.leInput = createEvent(this, "input");
3330
- /**
3331
- * The type of the input (text, email, password, etc.)
3332
- */
3333
- this.type = 'text';
3334
- /**
3335
- * Hide description slot
3336
- */
3337
- this.hideDescription = false;
3338
- /**
3339
- * Whether the input is disabled
3340
- */
3341
- this.disabled = false;
3342
- /**
3343
- * Whether the input is read-only
3344
- */
3345
- this.readonly = false;
3346
- this.handleInput = (ev) => {
3347
- const input = ev.target;
3348
- this.value = input.value;
3349
- this.leInput.emit({
3350
- value: this.value,
3351
- name: this.name,
3352
- externalId: this.externalId,
3353
- });
3354
- };
3355
- this.handleChange = (ev) => {
3356
- const input = ev.target;
3357
- this.value = input.value;
3358
- this.leChange.emit({
3359
- value: this.value,
3360
- name: this.name,
3361
- externalId: this.externalId,
3362
- });
3363
- };
3364
- this.handleClick = (ev) => {
3365
- ev.stopPropagation();
3366
- };
3367
- }
3368
- render() {
3369
- return (h("le-component", { key: 'b7d315a0bbe587dae606fec9ee3da32c16b773cb', component: "le-string-input", hostClass: classnames({ disabled: this.disabled }) }, h("div", { key: 'cfefdea8ce0625417cef62d0f432e13df652ab44', class: "le-input-wrapper" }, this.label && (h("label", { key: 'bfc0f2c440e00f2212c1ae9b0d3dd5b484ed0c5d', class: "le-input-label", htmlFor: this.name }, this.label)), h("div", { key: '324d58a4e798c4cd4d44c4f23760e38a24bfa4f6', class: "le-input-container", part: "container" }, this.iconStart && h("span", { key: '7851e3d9a30a304f2472e8de3dea1d6ce703b9ea', class: "icon-start" }, this.iconStart), h("input", { key: 'e51b775e8a9f8f55279ea91f04efbb0c5fdb4d1a', ref: el => {
3370
- if (this.inputRef) {
3371
- this.inputRef(el);
3372
- }
3373
- }, 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: '7018ada874d6b1c85e88a93ba695d00c118c4a6a', class: "icon-end" }, this.iconEnd)), !this.hideDescription && (h("div", { key: '826a2853561ab428e82d879012bc7bfdad4b1dfe', class: "le-input-description" }, h("le-slot", { key: '3a6fc7a46fffacbef6e44fcaa7a80af365754d1c', name: "description", type: "text", tag: "p", label: "Description" }, h("slot", { key: 'b6bbe4efe29c88b1910a53f6704846bfd4280307', name: "description" })))))));
3374
- }
3375
- get el() { return getElement(this); }
3376
- };
3377
- LeStringInput.style = leStringInputCss();
3378
-
3379
- export { LeBar as le_bar, LeButton as le_button, LeCheckbox as le_checkbox, LeCollapse as le_collapse, LeComponent as le_component, LeCurrentHeading as le_current_heading, LeDropdownBase as le_dropdown_base, LeHeader as le_header, LeIcon as le_icon, LeNavigation as le_navigation, LePopover as le_popover, LePopup as le_popup, LeScrollProgress as le_scroll_progress, LeSelect as le_select, LeSlot as le_slot, LeStringInput as le_string_input };
3380
- //# sourceMappingURL=le-bar.le-button.le-checkbox.le-collapse.le-component.le-current-heading.le-dropdown-base.le-header.le-icon.le-navigation.le-popover.le-popup.le-scroll-progress.le-select.le-slot.le-string-input.entry.js.map