luxen-ui 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +91 -0
  2. package/bin/cli.mjs +527 -0
  3. package/cdn/chunks/lit.js.map +1 -1
  4. package/cdn/config.d.ts +82 -0
  5. package/cdn/config.d.ts.map +1 -0
  6. package/cdn/config.js +0 -0
  7. package/cdn/custom-elements.json +3139 -3038
  8. package/cdn/define.d.ts +1 -1
  9. package/cdn/define.d.ts.map +1 -1
  10. package/cdn/define.js.map +1 -1
  11. package/cdn/elements/avatar/avatar.d.ts +1 -1
  12. package/cdn/elements/avatar/avatar.d.ts.map +1 -1
  13. package/cdn/elements/avatar/avatar.js.map +1 -1
  14. package/cdn/elements/avatar/index.d.ts +1 -7
  15. package/cdn/elements/avatar/index.d.ts.map +1 -1
  16. package/cdn/elements/avatar/index.js.map +1 -1
  17. package/cdn/elements/badge/badge.d.ts +7 -4
  18. package/cdn/elements/badge/badge.d.ts.map +1 -1
  19. package/cdn/elements/badge/badge.js.map +1 -1
  20. package/cdn/elements/badge/index.d.ts +1 -7
  21. package/cdn/elements/badge/index.d.ts.map +1 -1
  22. package/cdn/elements/badge/index.js.map +1 -1
  23. package/cdn/elements/carousel/carousel.d.ts +1 -1
  24. package/cdn/elements/carousel/carousel.d.ts.map +1 -1
  25. package/cdn/elements/carousel/carousel.js.map +1 -1
  26. package/cdn/elements/carousel/index.d.ts +1 -7
  27. package/cdn/elements/carousel/index.d.ts.map +1 -1
  28. package/cdn/elements/carousel/index.js.map +1 -1
  29. package/cdn/elements/carousel-item/carousel-item.d.ts +1 -1
  30. package/cdn/elements/carousel-item/carousel-item.d.ts.map +1 -1
  31. package/cdn/elements/carousel-item/carousel-item.js.map +1 -1
  32. package/cdn/elements/carousel-item/index.d.ts +1 -7
  33. package/cdn/elements/carousel-item/index.d.ts.map +1 -1
  34. package/cdn/elements/carousel-item/index.js.map +1 -1
  35. package/cdn/elements/dialog/dialog.d.ts +1 -1
  36. package/cdn/elements/dialog/dialog.d.ts.map +1 -1
  37. package/cdn/elements/dialog/dialog.js.map +1 -1
  38. package/cdn/elements/dialog/index.d.ts +1 -7
  39. package/cdn/elements/dialog/index.d.ts.map +1 -1
  40. package/cdn/elements/dialog/index.js.map +1 -1
  41. package/cdn/elements/divider/divider.d.ts +1 -1
  42. package/cdn/elements/divider/divider.d.ts.map +1 -1
  43. package/cdn/elements/divider/divider.js.map +1 -1
  44. package/cdn/elements/divider/index.d.ts +1 -7
  45. package/cdn/elements/divider/index.d.ts.map +1 -1
  46. package/cdn/elements/divider/index.js.map +1 -1
  47. package/cdn/elements/drawer/drawer.d.ts +1 -1
  48. package/cdn/elements/drawer/drawer.d.ts.map +1 -1
  49. package/cdn/elements/drawer/drawer.js.map +1 -1
  50. package/cdn/elements/drawer/index.d.ts +1 -7
  51. package/cdn/elements/drawer/index.d.ts.map +1 -1
  52. package/cdn/elements/drawer/index.js.map +1 -1
  53. package/cdn/elements/dropdown/dropdown.d.ts +1 -1
  54. package/cdn/elements/dropdown/dropdown.d.ts.map +1 -1
  55. package/cdn/elements/dropdown/dropdown.js.map +1 -1
  56. package/cdn/elements/dropdown/index.d.ts +1 -7
  57. package/cdn/elements/dropdown/index.d.ts.map +1 -1
  58. package/cdn/elements/dropdown/index.js.map +1 -1
  59. package/cdn/elements/dropdown-item/dropdown-item.d.ts +1 -1
  60. package/cdn/elements/dropdown-item/dropdown-item.d.ts.map +1 -1
  61. package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
  62. package/cdn/elements/dropdown-item/index.d.ts +1 -7
  63. package/cdn/elements/dropdown-item/index.d.ts.map +1 -1
  64. package/cdn/elements/dropdown-item/index.js.map +1 -1
  65. package/cdn/elements/icon/icon.d.ts +1 -1
  66. package/cdn/elements/icon/icon.d.ts.map +1 -1
  67. package/cdn/elements/icon/icon.js.map +1 -1
  68. package/cdn/elements/icon/index.d.ts +1 -7
  69. package/cdn/elements/icon/index.d.ts.map +1 -1
  70. package/cdn/elements/icon/index.js.map +1 -1
  71. package/cdn/elements/input-otp/index.d.ts +1 -7
  72. package/cdn/elements/input-otp/index.d.ts.map +1 -1
  73. package/cdn/elements/input-otp/index.js.map +1 -1
  74. package/cdn/elements/input-otp/input-otp.d.ts +1 -1
  75. package/cdn/elements/input-otp/input-otp.d.ts.map +1 -1
  76. package/cdn/elements/input-otp/input-otp.js.map +1 -1
  77. package/cdn/elements/input-stepper/index.d.ts +1 -7
  78. package/cdn/elements/input-stepper/index.d.ts.map +1 -1
  79. package/cdn/elements/input-stepper/index.js.map +1 -1
  80. package/cdn/elements/input-stepper/input-stepper.d.ts +1 -1
  81. package/cdn/elements/input-stepper/input-stepper.d.ts.map +1 -1
  82. package/cdn/elements/input-stepper/input-stepper.js.map +1 -1
  83. package/cdn/elements/popover/index.d.ts +1 -7
  84. package/cdn/elements/popover/index.d.ts.map +1 -1
  85. package/cdn/elements/popover/index.js.map +1 -1
  86. package/cdn/elements/popover/popover.d.ts +1 -1
  87. package/cdn/elements/popover/popover.d.ts.map +1 -1
  88. package/cdn/elements/popover/popover.js.map +1 -1
  89. package/cdn/elements/rating/index.d.ts +1 -7
  90. package/cdn/elements/rating/index.d.ts.map +1 -1
  91. package/cdn/elements/rating/index.js.map +1 -1
  92. package/cdn/elements/rating/rating.d.ts +1 -1
  93. package/cdn/elements/rating/rating.d.ts.map +1 -1
  94. package/cdn/elements/rating/rating.js.map +1 -1
  95. package/cdn/elements/skeleton/index.d.ts +1 -7
  96. package/cdn/elements/skeleton/index.d.ts.map +1 -1
  97. package/cdn/elements/skeleton/index.js.map +1 -1
  98. package/cdn/elements/skeleton/skeleton.d.ts +1 -1
  99. package/cdn/elements/skeleton/skeleton.d.ts.map +1 -1
  100. package/cdn/elements/skeleton/skeleton.js.map +1 -1
  101. package/cdn/elements/spinner/index.d.ts +1 -7
  102. package/cdn/elements/spinner/index.d.ts.map +1 -1
  103. package/cdn/elements/spinner/index.js.map +1 -1
  104. package/cdn/elements/spinner/spinner.d.ts +1 -1
  105. package/cdn/elements/spinner/spinner.d.ts.map +1 -1
  106. package/cdn/elements/spinner/spinner.js.map +1 -1
  107. package/cdn/elements/sticky-bar/index.d.ts +1 -7
  108. package/cdn/elements/sticky-bar/index.d.ts.map +1 -1
  109. package/cdn/elements/sticky-bar/index.js.map +1 -1
  110. package/cdn/elements/sticky-bar/sticky-bar.d.ts +1 -1
  111. package/cdn/elements/sticky-bar/sticky-bar.d.ts.map +1 -1
  112. package/cdn/elements/sticky-bar/sticky-bar.js.map +1 -1
  113. package/cdn/elements/stories/index.d.ts +1 -7
  114. package/cdn/elements/stories/index.d.ts.map +1 -1
  115. package/cdn/elements/stories/index.js.map +1 -1
  116. package/cdn/elements/stories/stories.d.ts +2 -7
  117. package/cdn/elements/stories/stories.d.ts.map +1 -1
  118. package/cdn/elements/stories/stories.js.map +1 -1
  119. package/cdn/elements/stories-viewer/index.d.ts +1 -7
  120. package/cdn/elements/stories-viewer/index.d.ts.map +1 -1
  121. package/cdn/elements/stories-viewer/index.js.map +1 -1
  122. package/cdn/elements/stories-viewer/stories-viewer.d.ts +3 -8
  123. package/cdn/elements/stories-viewer/stories-viewer.d.ts.map +1 -1
  124. package/cdn/elements/stories-viewer/stories-viewer.js.map +1 -1
  125. package/cdn/elements/story/index.d.ts +1 -7
  126. package/cdn/elements/story/index.d.ts.map +1 -1
  127. package/cdn/elements/story/index.js.map +1 -1
  128. package/cdn/elements/story/story.d.ts +2 -7
  129. package/cdn/elements/story/story.d.ts.map +1 -1
  130. package/cdn/elements/story/story.js.map +1 -1
  131. package/cdn/elements/tabs/index.d.ts +1 -7
  132. package/cdn/elements/tabs/index.d.ts.map +1 -1
  133. package/cdn/elements/tabs/index.js.map +1 -1
  134. package/cdn/elements/tabs/tabs.d.ts +1 -1
  135. package/cdn/elements/tabs/tabs.d.ts.map +1 -1
  136. package/cdn/elements/tabs/tabs.js.map +1 -1
  137. package/cdn/elements/toast/index.d.ts +1 -8
  138. package/cdn/elements/toast/index.d.ts.map +1 -1
  139. package/cdn/elements/toast/index.js.map +1 -1
  140. package/cdn/elements/toast/toast.d.ts +7 -5
  141. package/cdn/elements/toast/toast.d.ts.map +1 -1
  142. package/cdn/elements/toast/toast.js +1 -1
  143. package/cdn/elements/toast/toast.js.map +1 -1
  144. package/cdn/elements/tooltip/index.d.ts +1 -7
  145. package/cdn/elements/tooltip/index.d.ts.map +1 -1
  146. package/cdn/elements/tooltip/index.js.map +1 -1
  147. package/cdn/elements/tooltip/tooltip.d.ts +1 -1
  148. package/cdn/elements/tooltip/tooltip.d.ts.map +1 -1
  149. package/cdn/elements/tooltip/tooltip.js.map +1 -1
  150. package/cdn/elements/tree/index.d.ts +1 -7
  151. package/cdn/elements/tree/index.d.ts.map +1 -1
  152. package/cdn/elements/tree/index.js.map +1 -1
  153. package/cdn/elements/tree/tree.d.ts +2 -2
  154. package/cdn/elements/tree/tree.d.ts.map +1 -1
  155. package/cdn/elements/tree/tree.js.map +1 -1
  156. package/cdn/elements/tree-item/index.d.ts +1 -7
  157. package/cdn/elements/tree-item/index.d.ts.map +1 -1
  158. package/cdn/elements/tree-item/index.js.map +1 -1
  159. package/cdn/elements/tree-item/tree-item.d.ts +1 -1
  160. package/cdn/elements/tree-item/tree-item.d.ts.map +1 -1
  161. package/cdn/elements/tree-item/tree-item.js.map +1 -1
  162. package/cdn/index.d.ts +7 -5
  163. package/cdn/index.d.ts.map +1 -1
  164. package/cdn/index.js +1 -1
  165. package/cdn/shared/controllers/popover.js.map +1 -1
  166. package/cdn/shared/luxen-form-associated-element.d.ts +1 -1
  167. package/cdn/shared/luxen-form-associated-element.d.ts.map +1 -1
  168. package/cdn/shared/luxen-form-associated-element.js.map +1 -1
  169. package/cdn/standalone.css +3581 -0
  170. package/cdn/standalone.js +9301 -0
  171. package/cdn/standalone.js.map +1 -0
  172. package/cdn/styles/base.css +728 -0
  173. package/cdn/styles/elements/badge.css +6 -6
  174. package/cdn/styles/elements/button.css +9 -9
  175. package/cdn/styles/elements/close-button/circle.css +3 -3
  176. package/cdn/styles/elements/close-button/ring.css +1 -1
  177. package/cdn/styles/elements/close-button/square.css +3 -3
  178. package/cdn/styles/elements/disclosure.css +2 -2
  179. package/cdn/styles/elements/divider.css +3 -3
  180. package/cdn/styles/elements/input-otp.css +1 -1
  181. package/cdn/styles/elements/input-stepper/default.css +1 -1
  182. package/cdn/styles/elements/input-stepper/rounded.css +2 -2
  183. package/cdn/styles/elements/kbd.css +3 -3
  184. package/cdn/styles/elements/select.css +2 -2
  185. package/cdn/styles/elements/skeleton.css +4 -4
  186. package/cdn/styles/elements/stories.css +1 -1
  187. package/cdn/styles/elements/story.css +37 -37
  188. package/cdn/styles/elements/tabs/enclosed.css +6 -6
  189. package/cdn/styles/elements/tabs/line.css +4 -4
  190. package/cdn/styles/{index.css → preset.css} +223 -145
  191. package/cdn/styles/tailwind/preset.css +575 -0
  192. package/cdn/styles/tokens/aliases.css +103 -0
  193. package/cdn/styles/tokens/palette.css +250 -0
  194. package/cdn/styles/tokens/primitives.css +141 -0
  195. package/cdn/styles/tokens.css +239 -0
  196. package/dist/config.d.ts +82 -0
  197. package/dist/config.d.ts.map +1 -0
  198. package/dist/config.js +28 -0
  199. package/dist/css/base.css +728 -0
  200. package/dist/css/elements/badge.css +6 -6
  201. package/dist/css/elements/button.css +9 -9
  202. package/dist/css/elements/close-button/circle.css +3 -3
  203. package/dist/css/elements/close-button/ring.css +1 -1
  204. package/dist/css/elements/close-button/square.css +3 -3
  205. package/dist/css/elements/disclosure.css +2 -2
  206. package/dist/css/elements/divider.css +3 -3
  207. package/dist/css/elements/input-otp.css +1 -1
  208. package/dist/css/elements/input-stepper/default.css +1 -1
  209. package/dist/css/elements/input-stepper/rounded.css +2 -2
  210. package/dist/css/elements/kbd.css +3 -3
  211. package/dist/css/elements/select.css +2 -2
  212. package/dist/css/elements/skeleton.css +4 -4
  213. package/dist/css/elements/stories.css +1 -1
  214. package/dist/css/elements/story.css +37 -37
  215. package/dist/css/elements/tabs/enclosed.css +6 -6
  216. package/dist/css/elements/tabs/line.css +4 -4
  217. package/dist/css/{index.css → preset.css} +223 -145
  218. package/dist/css/tailwind/preset.css +575 -0
  219. package/dist/css/tokens/aliases.css +103 -0
  220. package/dist/css/tokens/palette.css +250 -0
  221. package/dist/css/tokens/primitives.css +141 -0
  222. package/dist/css/tokens.css +239 -0
  223. package/dist/custom-elements.json +3139 -3038
  224. package/dist/define.d.ts +1 -1
  225. package/dist/define.d.ts.map +1 -1
  226. package/dist/define.js +1 -1
  227. package/dist/elements/avatar/avatar.d.ts +1 -1
  228. package/dist/elements/avatar/avatar.d.ts.map +1 -1
  229. package/dist/elements/avatar/avatar.js +2 -2
  230. package/dist/elements/avatar/index.d.ts +1 -7
  231. package/dist/elements/avatar/index.d.ts.map +1 -1
  232. package/dist/elements/avatar/index.js +3 -3
  233. package/dist/elements/badge/badge.d.ts +7 -4
  234. package/dist/elements/badge/badge.d.ts.map +1 -1
  235. package/dist/elements/badge/badge.js +1 -1
  236. package/dist/elements/badge/index.d.ts +1 -7
  237. package/dist/elements/badge/index.d.ts.map +1 -1
  238. package/dist/elements/badge/index.js +3 -3
  239. package/dist/elements/carousel/carousel.d.ts +1 -1
  240. package/dist/elements/carousel/carousel.d.ts.map +1 -1
  241. package/dist/elements/carousel/carousel.js +2 -2
  242. package/dist/elements/carousel/index.d.ts +1 -7
  243. package/dist/elements/carousel/index.d.ts.map +1 -1
  244. package/dist/elements/carousel/index.js +3 -3
  245. package/dist/elements/carousel-item/carousel-item.d.ts +1 -1
  246. package/dist/elements/carousel-item/carousel-item.d.ts.map +1 -1
  247. package/dist/elements/carousel-item/carousel-item.js +2 -2
  248. package/dist/elements/carousel-item/index.d.ts +1 -7
  249. package/dist/elements/carousel-item/index.d.ts.map +1 -1
  250. package/dist/elements/carousel-item/index.js +3 -3
  251. package/dist/elements/dialog/dialog.d.ts +1 -1
  252. package/dist/elements/dialog/dialog.d.ts.map +1 -1
  253. package/dist/elements/dialog/dialog.js +3 -3
  254. package/dist/elements/dialog/index.d.ts +1 -7
  255. package/dist/elements/dialog/index.d.ts.map +1 -1
  256. package/dist/elements/dialog/index.js +3 -3
  257. package/dist/elements/divider/divider.d.ts +1 -1
  258. package/dist/elements/divider/divider.d.ts.map +1 -1
  259. package/dist/elements/divider/divider.js +1 -1
  260. package/dist/elements/divider/index.d.ts +1 -7
  261. package/dist/elements/divider/index.d.ts.map +1 -1
  262. package/dist/elements/divider/index.js +3 -3
  263. package/dist/elements/drawer/drawer.d.ts +1 -1
  264. package/dist/elements/drawer/drawer.d.ts.map +1 -1
  265. package/dist/elements/drawer/drawer.js +3 -3
  266. package/dist/elements/drawer/index.d.ts +1 -7
  267. package/dist/elements/drawer/index.d.ts.map +1 -1
  268. package/dist/elements/drawer/index.js +3 -3
  269. package/dist/elements/dropdown/dropdown.d.ts +1 -1
  270. package/dist/elements/dropdown/dropdown.d.ts.map +1 -1
  271. package/dist/elements/dropdown/dropdown.js +4 -4
  272. package/dist/elements/dropdown/index.d.ts +1 -7
  273. package/dist/elements/dropdown/index.d.ts.map +1 -1
  274. package/dist/elements/dropdown/index.js +3 -3
  275. package/dist/elements/dropdown-item/dropdown-item.d.ts +1 -1
  276. package/dist/elements/dropdown-item/dropdown-item.d.ts.map +1 -1
  277. package/dist/elements/dropdown-item/dropdown-item.js +2 -2
  278. package/dist/elements/dropdown-item/index.d.ts +1 -7
  279. package/dist/elements/dropdown-item/index.d.ts.map +1 -1
  280. package/dist/elements/dropdown-item/index.js +3 -3
  281. package/dist/elements/icon/icon.d.ts +1 -1
  282. package/dist/elements/icon/icon.d.ts.map +1 -1
  283. package/dist/elements/icon/icon.js +2 -2
  284. package/dist/elements/icon/index.d.ts +1 -7
  285. package/dist/elements/icon/index.d.ts.map +1 -1
  286. package/dist/elements/icon/index.js +3 -3
  287. package/dist/elements/input-otp/index.d.ts +1 -7
  288. package/dist/elements/input-otp/index.d.ts.map +1 -1
  289. package/dist/elements/input-otp/index.js +3 -3
  290. package/dist/elements/input-otp/input-otp.d.ts +1 -1
  291. package/dist/elements/input-otp/input-otp.d.ts.map +1 -1
  292. package/dist/elements/input-otp/input-otp.js +1 -1
  293. package/dist/elements/input-stepper/index.d.ts +1 -7
  294. package/dist/elements/input-stepper/index.d.ts.map +1 -1
  295. package/dist/elements/input-stepper/index.js +3 -3
  296. package/dist/elements/input-stepper/input-stepper.d.ts +1 -1
  297. package/dist/elements/input-stepper/input-stepper.d.ts.map +1 -1
  298. package/dist/elements/input-stepper/input-stepper.js +1 -1
  299. package/dist/elements/popover/index.d.ts +1 -7
  300. package/dist/elements/popover/index.d.ts.map +1 -1
  301. package/dist/elements/popover/index.js +3 -3
  302. package/dist/elements/popover/popover.d.ts +1 -1
  303. package/dist/elements/popover/popover.d.ts.map +1 -1
  304. package/dist/elements/popover/popover.js +4 -4
  305. package/dist/elements/rating/index.d.ts +1 -7
  306. package/dist/elements/rating/index.d.ts.map +1 -1
  307. package/dist/elements/rating/index.js +3 -3
  308. package/dist/elements/rating/rating.d.ts +1 -1
  309. package/dist/elements/rating/rating.d.ts.map +1 -1
  310. package/dist/elements/rating/rating.js +2 -2
  311. package/dist/elements/skeleton/index.d.ts +1 -7
  312. package/dist/elements/skeleton/index.d.ts.map +1 -1
  313. package/dist/elements/skeleton/index.js +3 -3
  314. package/dist/elements/skeleton/skeleton.d.ts +1 -1
  315. package/dist/elements/skeleton/skeleton.d.ts.map +1 -1
  316. package/dist/elements/skeleton/skeleton.js +1 -1
  317. package/dist/elements/spinner/index.d.ts +1 -7
  318. package/dist/elements/spinner/index.d.ts.map +1 -1
  319. package/dist/elements/spinner/index.js +3 -3
  320. package/dist/elements/spinner/spinner.d.ts +1 -1
  321. package/dist/elements/spinner/spinner.d.ts.map +1 -1
  322. package/dist/elements/spinner/spinner.js +2 -2
  323. package/dist/elements/sticky-bar/index.d.ts +1 -7
  324. package/dist/elements/sticky-bar/index.d.ts.map +1 -1
  325. package/dist/elements/sticky-bar/index.js +3 -3
  326. package/dist/elements/sticky-bar/sticky-bar.d.ts +1 -1
  327. package/dist/elements/sticky-bar/sticky-bar.d.ts.map +1 -1
  328. package/dist/elements/sticky-bar/sticky-bar.js +2 -2
  329. package/dist/elements/stories/index.d.ts +1 -7
  330. package/dist/elements/stories/index.d.ts.map +1 -1
  331. package/dist/elements/stories/index.js +3 -3
  332. package/dist/elements/stories/stories.d.ts +2 -7
  333. package/dist/elements/stories/stories.d.ts.map +1 -1
  334. package/dist/elements/stories/stories.js +1 -1
  335. package/dist/elements/stories-viewer/index.d.ts +1 -7
  336. package/dist/elements/stories-viewer/index.d.ts.map +1 -1
  337. package/dist/elements/stories-viewer/index.js +3 -3
  338. package/dist/elements/stories-viewer/stories-viewer.d.ts +3 -8
  339. package/dist/elements/stories-viewer/stories-viewer.d.ts.map +1 -1
  340. package/dist/elements/stories-viewer/stories-viewer.js +2 -2
  341. package/dist/elements/story/index.d.ts +1 -7
  342. package/dist/elements/story/index.d.ts.map +1 -1
  343. package/dist/elements/story/index.js +3 -3
  344. package/dist/elements/story/story.d.ts +2 -7
  345. package/dist/elements/story/story.d.ts.map +1 -1
  346. package/dist/elements/story/story.js +2 -2
  347. package/dist/elements/tabs/index.d.ts +1 -7
  348. package/dist/elements/tabs/index.d.ts.map +1 -1
  349. package/dist/elements/tabs/index.js +3 -3
  350. package/dist/elements/tabs/tabs.d.ts +1 -1
  351. package/dist/elements/tabs/tabs.d.ts.map +1 -1
  352. package/dist/elements/tabs/tabs.js +2 -2
  353. package/dist/elements/toast/index.d.ts +1 -8
  354. package/dist/elements/toast/index.d.ts.map +1 -1
  355. package/dist/elements/toast/index.js +3 -3
  356. package/dist/elements/toast/toast.d.ts +7 -5
  357. package/dist/elements/toast/toast.d.ts.map +1 -1
  358. package/dist/elements/toast/toast.js +2 -4
  359. package/dist/elements/tooltip/index.d.ts +1 -7
  360. package/dist/elements/tooltip/index.d.ts.map +1 -1
  361. package/dist/elements/tooltip/index.js +3 -3
  362. package/dist/elements/tooltip/tooltip.d.ts +1 -1
  363. package/dist/elements/tooltip/tooltip.d.ts.map +1 -1
  364. package/dist/elements/tooltip/tooltip.js +4 -4
  365. package/dist/elements/tree/index.d.ts +1 -7
  366. package/dist/elements/tree/index.d.ts.map +1 -1
  367. package/dist/elements/tree/index.js +3 -3
  368. package/dist/elements/tree/tree.d.ts +2 -2
  369. package/dist/elements/tree/tree.d.ts.map +1 -1
  370. package/dist/elements/tree/tree.js +3 -3
  371. package/dist/elements/tree-item/index.d.ts +1 -7
  372. package/dist/elements/tree-item/index.d.ts.map +1 -1
  373. package/dist/elements/tree-item/index.js +3 -3
  374. package/dist/elements/tree-item/tree-item.d.ts +1 -1
  375. package/dist/elements/tree-item/tree-item.d.ts.map +1 -1
  376. package/dist/elements/tree-item/tree-item.js +3 -3
  377. package/dist/index.d.ts +7 -5
  378. package/dist/index.d.ts.map +1 -1
  379. package/dist/index.js +5 -4
  380. package/dist/shared/luxen-form-associated-element.d.ts +1 -1
  381. package/dist/shared/luxen-form-associated-element.d.ts.map +1 -1
  382. package/dist/shared/luxen-form-associated-element.js +1 -1
  383. package/dist/{skills/luxen-ui/references → templates/elements}/badge.md +8 -8
  384. package/dist/{skills/luxen-ui/references → templates/elements}/button.md +1 -1
  385. package/elements.json +229 -0
  386. package/package.json +45 -16
  387. package/postcss-plugin-prefix.d.ts +9 -0
  388. package/templates/SKILL.md.tpl +34 -0
  389. package/templates/claude-design.md.tpl +42 -0
  390. package/templates/integration.md.tpl +53 -0
  391. package/templates/mockups.md.tpl +64 -0
  392. package/vite-plugin.ts +265 -3
  393. package/dist/skills/luxen-ui/SKILL.md +0 -83
  394. /package/dist/{skills/luxen-ui/references → templates/elements}/avatar.md +0 -0
  395. /package/dist/{skills/luxen-ui/references → templates/elements}/close-button.md +0 -0
  396. /package/dist/{skills/luxen-ui/references → templates/elements}/dialog.md +0 -0
  397. /package/dist/{skills/luxen-ui/references → templates/elements}/drawer.md +0 -0
  398. /package/dist/{skills/luxen-ui/references → templates/elements}/progress.md +0 -0
  399. /package/dist/{skills/luxen-ui/references → templates/elements}/select.md +0 -0
  400. /package/dist/{skills/luxen-ui/references → templates/elements}/sticky-bar.md +0 -0
  401. /package/dist/{skills/luxen-ui/references → templates/elements}/toast.md +0 -0
  402. /package/dist/{skills/luxen-ui/references → templates/elements}/tree.md +0 -0
package/README.md CHANGED
@@ -77,6 +77,97 @@ import 'luxen-ui/css/button';
77
77
  <l-tooltip for="my-button">Hello world</l-tooltip>
78
78
  ```
79
79
 
80
+ ## TypeScript (prefix-aware)
81
+
82
+ Element classes are exported under `luxen-ui/<name>/element` as side-effect-free
83
+ type entries:
84
+
85
+ ```ts
86
+ import type { Badge, BadgeVariant } from 'luxen-ui/badge/element';
87
+ ```
88
+
89
+ The package does **not** ship a `HTMLElementTagNameMap` augmentation by
90
+ default — consumers own that file so it always reflects the prefix they
91
+ actually use (default `l-*` or rebranded). The Vite plugin can write it for
92
+ you:
93
+
94
+ ```ts
95
+ // vite.config.ts (or nuxt.config.ts)
96
+ import luxen from 'luxen-ui/vite-plugin';
97
+
98
+ export default defineConfig({
99
+ plugins: [
100
+ luxen({
101
+ elementPrefix: 'pulse',
102
+ cssPrefix: 'pulse',
103
+ emitTypes: 'types/luxen.d.ts', // ← writes the file on first build
104
+ }),
105
+ ],
106
+ });
107
+ ```
108
+
109
+ The generated `types/luxen.d.ts` imports the class types from the
110
+ `*/element` subpaths and augments `HTMLElementTagNameMap` for every Luxen
111
+ element under your prefix. Once written:
112
+
113
+ - **You own the file.** Edit it freely — drop elements you don't use, or
114
+ add ones from your own custom element set.
115
+ - **The plugin never overwrites** an existing file silently. Pass
116
+ `emitTypes: { path: 'types/luxen.d.ts', force: true }` to regenerate.
117
+ - **Drift detection.** If your `elementPrefix` later changes, the plugin
118
+ logs a warning so you can regenerate.
119
+
120
+ Need a subset only?
121
+
122
+ ```ts
123
+ luxen({
124
+ elementPrefix: 'pulse',
125
+ emitTypes: { path: 'types/luxen.d.ts', elements: ['badge', 'dropdown', 'popover'] },
126
+ });
127
+ ```
128
+
129
+ ### Vue / Nuxt — strict template checking
130
+
131
+ `HTMLElementTagNameMap` types the DOM side (`document.querySelector`,
132
+ `el.variant = …`) but Vue's template checker treats custom elements as a
133
+ permissive surface — typos and bad prop values are **not** flagged. Use
134
+ `target: 'vue'` to additionally augment Vue's `GlobalComponents`:
135
+
136
+ ```ts
137
+ luxen({
138
+ elementPrefix: 'pulse',
139
+ cssPrefix: 'pulse',
140
+ emitTypes: { path: 'types/luxen.d.ts', target: 'vue' },
141
+ });
142
+ ```
143
+
144
+ Then enable strict templates in your tsconfig (for Nuxt, set it via
145
+ `nuxt.config.ts` → `typescript.tsConfig.vueCompilerOptions`):
146
+
147
+ ```jsonc
148
+ {
149
+ "vueCompilerOptions": { "strictTemplates": true },
150
+ }
151
+ ```
152
+
153
+ Now `<pulse-badge variant="bogus">` and `<pulse-badge typo="x">` are errors
154
+ in the editor and in `vue-tsc`, while autocomplete stays scoped to each
155
+ element's real props. The generated file also re-allows `data-*` and `slot`
156
+ on native elements (which `strictTemplates` would otherwise reject) and keeps
157
+ `@event` listeners permissive.
158
+
159
+ Installed under an npm alias? Pass `packageName` so the emitted imports
160
+ resolve:
161
+
162
+ ```jsonc
163
+ // package.json
164
+ { "dependencies": { "pulse-ui": "npm:luxen-ui@^0.5.0" } }
165
+ ```
166
+
167
+ ```ts
168
+ emitTypes: { path: 'types/luxen.d.ts', target: 'vue', packageName: 'pulse-ui' }
169
+ ```
170
+
80
171
  ## Local Development
81
172
 
82
173
  Requires **Node.js >= 24** and **pnpm**.
package/bin/cli.mjs ADDED
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * luxen-ui CLI — two subcommands:
4
+ *
5
+ * import <noun> Copy a CSS preset / token file into the project for
6
+ * customization (see IMPORTABLES below).
7
+ *
8
+ * generate-skill Produce an Agent Skill folder named after your design
9
+ * system, with prefix and brand tokens already applied.
10
+ * Output is meant to be committed to your repo (e.g.
11
+ * `.claude/skills/<name>/`).
12
+ *
13
+ * Run `luxen-ui --help` for usage.
14
+ */
15
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
16
+ import { dirname, join, relative, resolve } from 'node:path';
17
+ import { pathToFileURL, fileURLToPath } from 'node:url';
18
+
19
+ const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
20
+ const PKG_VERSION = JSON.parse(readFileSync(resolve(PKG_ROOT, 'package.json'), 'utf-8')).version;
21
+
22
+ // =============================================================================
23
+ // `import <noun>` — copies a Luxen preset / piece into your project.
24
+ // =============================================================================
25
+
26
+ const IMPORTABLES = {
27
+ preset: {
28
+ source: resolve(PKG_ROOT, 'dist/css/preset.css'),
29
+ defaultDest: './luxen-preset.css',
30
+ next: (importPath) => [
31
+ 'Next steps:',
32
+ ' 1. In your CSS entry, replace',
33
+ " @import 'luxen-ui/css/preset';",
34
+ ' with',
35
+ ` @import '${importPath}';`,
36
+ '',
37
+ ' 2. Edit the file freely — swap any layer for your own',
38
+ ' implementation, or import atomic pieces directly:',
39
+ " @import 'luxen-ui/css/base'; /* runtime only */",
40
+ " @import '@my-ds/colors'; /* your palette */",
41
+ " @import 'luxen-ui/css/tokens/aliases'; /* semantic aliases */",
42
+ ],
43
+ },
44
+ tailwind: {
45
+ source: resolve(PKG_ROOT, 'dist/css/tailwind/preset.css'),
46
+ defaultDest: './luxen-tailwind.css',
47
+ next: (importPath) => [
48
+ 'Next steps:',
49
+ ' 1. In your CSS entry, replace',
50
+ " @import 'luxen-ui/tailwind/preset';",
51
+ ' with',
52
+ ` @import '${importPath}';`,
53
+ '',
54
+ ' 2. Uncomment any extended Tailwind palette families you want to use.',
55
+ '',
56
+ ' 3. Add project-specific tokens (brand colors, custom fonts, etc.)',
57
+ ' in the same file — they coexist with Luxen tokens.',
58
+ ],
59
+ },
60
+ 'design-tokens': {
61
+ source: resolve(PKG_ROOT, 'dist/css/tokens/aliases.css'),
62
+ defaultDest: './luxen-design-tokens.css',
63
+ next: (importPath) => [
64
+ 'Next steps:',
65
+ ' 1. In your CSS entry, replace',
66
+ " @import 'luxen-ui/css/tokens/aliases';",
67
+ " or @import 'luxen-ui/css/preset'; (if you used the preset)",
68
+ ' with the new ordering:',
69
+ " @import 'luxen-ui/css/base';",
70
+ " @import 'luxen-ui/css/tokens/primitives'; /* or your own */",
71
+ ` @import '${importPath}';`,
72
+ '',
73
+ ' 2. Edit ./luxen-design-tokens.css — every semantic alias is yours to',
74
+ ' repurpose (text-primary, bg-fill-brand, focus-ring, …).',
75
+ '',
76
+ ' 3. Tokens reference primitives via `var(--l-color-*)`. Either keep the',
77
+ ' Luxen primitives, or remap them (e.g. to Radix UI colors) above this',
78
+ ' import so the aliases pick up your palette.',
79
+ ],
80
+ },
81
+ };
82
+
83
+ function cmdImport([noun, destArg]) {
84
+ if (!noun) {
85
+ console.error('✗ Missing noun after `import`. Try: luxen-ui import preset');
86
+ usageImport(1);
87
+ }
88
+ const recipe = IMPORTABLES[noun];
89
+ if (!recipe) {
90
+ console.error(`✗ Don't know how to import "${noun}".`);
91
+ console.error(` Available: ${Object.keys(IMPORTABLES).join(', ')}`);
92
+ process.exit(1);
93
+ }
94
+
95
+ const dest = destArg ?? recipe.defaultDest;
96
+ const destPath = resolve(process.cwd(), dest);
97
+
98
+ if (existsSync(destPath)) {
99
+ console.error(`✗ ${dest} already exists. Move it aside or pass a different path.`);
100
+ process.exit(1);
101
+ }
102
+ if (!existsSync(recipe.source)) {
103
+ console.error(`✗ Source not found at ${recipe.source}.`);
104
+ console.error(' Did luxen-ui finish installing? Try re-running install.');
105
+ process.exit(1);
106
+ }
107
+
108
+ const content = readFileSync(recipe.source, 'utf8');
109
+ writeFileSync(destPath, content, 'utf8');
110
+
111
+ const importPath = dest.startsWith('.') || dest.startsWith('/') ? dest : `./${dest}`;
112
+ console.log(`✓ Created ${relative(process.cwd(), destPath)}`);
113
+ console.log('');
114
+ for (const line of recipe.next(importPath)) console.log(line);
115
+ }
116
+
117
+ // =============================================================================
118
+ // `generate-skill` — produce a brand-aware Agent Skill folder.
119
+ // =============================================================================
120
+
121
+ const DEFAULT_CONFIG = {
122
+ name: 'luxen-ui',
123
+ displayName: 'Luxen UI',
124
+ description:
125
+ 'Generate UI with Luxen UI, a CSS-first web component library. Provides CSS classes for native HTML elements and custom elements (l-badge, l-dialog, l-toast). Use when building interfaces with Luxen UI.',
126
+ // Prefixes use the Vite plugin convention: bare identifier without trailing
127
+ // dash. `elementPrefix: 'pulse'` means tags are `<pulse-badge>`, type selectors
128
+ // are `pulse-badge`. `cssPrefix: 'pulse'` controls `.pulse-button` classes,
129
+ // `--pulse-*` custom properties, and `@keyframes pulse-*`.
130
+ elementPrefix: 'l',
131
+ cssPrefix: 'l',
132
+ cssImportPath: 'luxen-ui/css',
133
+ jsImportPath: 'luxen-ui',
134
+ themeCss: null,
135
+ out: null,
136
+ };
137
+
138
+ async function cmdGenerateSkill(args) {
139
+ const opts = parseFlags(args);
140
+ const config = await loadConfig(opts.config);
141
+ const ctx = buildContext(config, opts);
142
+
143
+ await runGenerateSkill(ctx);
144
+
145
+ console.log(`✓ Skill generated at ${relative(process.cwd(), ctx.outDir)}`);
146
+ console.log('');
147
+ console.log('Next steps:');
148
+ console.log(` • Commit ${ctx.outDir} so AI agents (and the rest of your team) can read it.`);
149
+ console.log(` • Re-run \`luxen-ui generate-skill\` whenever luxen-ui or your tokens change.`);
150
+ }
151
+
152
+ function parseFlags(argv) {
153
+ const opts = {};
154
+ for (let i = 0; i < argv.length; i++) {
155
+ const arg = argv[i];
156
+ if (arg === '--config') opts.config = argv[++i];
157
+ else if (arg === '--out') opts.out = argv[++i];
158
+ else if (arg === '--element-prefix') opts.elementPrefix = argv[++i];
159
+ else if (arg === '--css-prefix') opts.cssPrefix = argv[++i];
160
+ else if (arg === '--name') opts.name = argv[++i];
161
+ else if (arg === '--theme-css') opts.themeCss = argv[++i];
162
+ else if (arg === '-h' || arg === '--help') usageGenerateSkill(0);
163
+ else {
164
+ console.error(`✗ Unknown flag: ${arg}`);
165
+ usageGenerateSkill(1);
166
+ }
167
+ }
168
+ return opts;
169
+ }
170
+
171
+ async function loadConfig(configPath) {
172
+ const candidates = configPath
173
+ ? [resolve(process.cwd(), configPath)]
174
+ : [resolve(process.cwd(), 'luxen.config.mjs'), resolve(process.cwd(), 'luxen.config.js')];
175
+ for (const p of candidates) {
176
+ if (existsSync(p)) {
177
+ // eslint-disable-next-line no-await-in-loop -- early-return on first match, max 2 candidates
178
+ const mod = await import(pathToFileURL(p).href);
179
+ return mod.default ?? mod;
180
+ }
181
+ }
182
+ if (configPath) {
183
+ console.error(`✗ Config file not found: ${configPath}`);
184
+ process.exit(1);
185
+ }
186
+ return {};
187
+ }
188
+
189
+ function buildContext(config, opts) {
190
+ const merged = { ...DEFAULT_CONFIG, ...config, ...stripUndefined(opts) };
191
+ // Sanity: prefixes must NOT end with a dash (matches Vite plugin convention).
192
+ for (const k of ['elementPrefix', 'cssPrefix']) {
193
+ if (merged[k].endsWith('-')) {
194
+ console.error(
195
+ `✗ Invalid ${k} "${merged[k]}" — drop the trailing dash (e.g. "pulse", not "pulse-").`,
196
+ );
197
+ process.exit(1);
198
+ }
199
+ }
200
+ const outDir = resolve(process.cwd(), merged.out ?? `.claude/skills/${merged.name}`);
201
+ return {
202
+ ...merged,
203
+ outDir,
204
+ pkgRoot: PKG_ROOT,
205
+ sourceVersion: PKG_VERSION,
206
+ };
207
+ }
208
+
209
+ function stripUndefined(obj) {
210
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
211
+ }
212
+
213
+ // --- Pipeline -----------------------------------------------------------------
214
+
215
+ async function runGenerateSkill(ctx) {
216
+ ensureDir(ctx.outDir);
217
+ ensureDir(join(ctx.outDir, 'references'));
218
+ ensureDir(join(ctx.outDir, 'assets'));
219
+ ensureDir(join(ctx.outDir, 'assets', 'css'));
220
+
221
+ // 1. Read templates (hand-written) and pre-transformed element docs (build).
222
+ const tplDir = resolve(ctx.pkgRoot, 'templates');
223
+ const distTplDir = resolve(ctx.pkgRoot, 'dist/templates');
224
+
225
+ if (!existsSync(distTplDir)) {
226
+ console.error(`✗ Missing ${distTplDir}.`);
227
+ console.error(" This directory is generated by luxen-ui's build. Reinstall the package.");
228
+ process.exit(1);
229
+ }
230
+
231
+ const elements = JSON.parse(readFileSync(resolve(ctx.pkgRoot, 'elements.json'), 'utf-8'));
232
+ const skillElements = elements.elements.filter((e) => e.inSkill);
233
+
234
+ // 2. Compute template variables.
235
+ const vars = {
236
+ name: ctx.name,
237
+ displayName: ctx.displayName,
238
+ description: ctx.description.trim().replace(/\s+/g, ' '),
239
+ elementPrefix: ctx.elementPrefix,
240
+ cssPrefix: ctx.cssPrefix,
241
+ sourceVersion: ctx.sourceVersion,
242
+ cdnVersion: ctx.sourceVersion.split('.').slice(0, 2).join('.'),
243
+ cssImportPath: ctx.cssImportPath,
244
+ jsImportPath: ctx.jsImportPath,
245
+ elementsTable: buildElementsTable(skillElements, ctx),
246
+ elementsList: buildElementsList(skillElements),
247
+ tagsList: buildTagsList(elements.elements),
248
+ };
249
+
250
+ // 3. Render SKILL.md, integration.md, claude-design.md
251
+ await renderTemplate(join(tplDir, 'SKILL.md.tpl'), join(ctx.outDir, 'SKILL.md'), vars, ctx);
252
+ await renderTemplate(
253
+ join(tplDir, 'integration.md.tpl'),
254
+ join(ctx.outDir, 'references', 'integration.md'),
255
+ vars,
256
+ ctx,
257
+ );
258
+ await renderTemplate(
259
+ join(tplDir, 'claude-design.md.tpl'),
260
+ join(ctx.outDir, 'assets', 'claude-design.md'),
261
+ vars,
262
+ ctx,
263
+ );
264
+
265
+ // 4. Per-element references (with prefix + package-name substitution).
266
+ for (const el of skillElements) {
267
+ const src = join(distTplDir, 'elements', `${el.name}.md`);
268
+ const dst = join(ctx.outDir, 'references', `${el.name}.md`);
269
+ const content = readFileSync(src, 'utf-8');
270
+ const out = applyPackageName(applyPrefix(content, ctx), ctx);
271
+ writeFileSync(dst, out, 'utf-8');
272
+ }
273
+
274
+ // 5. mockups.md — rendered from template (local-assets paths, prefix-aware
275
+ // since assets/cdn/ has been substituted to the consumer's prefix).
276
+ await renderTemplate(
277
+ join(tplDir, 'mockups.md.tpl'),
278
+ join(ctx.outDir, 'references', 'mockups.md'),
279
+ vars,
280
+ ctx,
281
+ );
282
+
283
+ // 6. Standalone runtime bundle for mockup mode (assets/<name>-standalone.{js,css}).
284
+ // Two files instead of a 150-file tree: one <link> + one <script> in any
285
+ // mockup HTML loads the full library with the consumer's prefix and tokens.
286
+ const standaloneJsSrc = resolve(ctx.pkgRoot, 'cdn/standalone.js');
287
+ const standaloneCssSrc = resolve(ctx.pkgRoot, 'cdn/standalone.css');
288
+ if (!existsSync(standaloneJsSrc) || !existsSync(standaloneCssSrc)) {
289
+ console.error(
290
+ `✗ cdn/standalone.{js,css} not found in ${ctx.pkgRoot}. Run \`pnpm build:standalone\` in luxen-ui first.`,
291
+ );
292
+ process.exit(1);
293
+ }
294
+ const jsDst = join(ctx.outDir, 'assets', `${ctx.name}-standalone.js`);
295
+ const cssDst = join(ctx.outDir, 'assets', `${ctx.name}-standalone.css`);
296
+ writeFileSync(
297
+ jsDst,
298
+ applyPackageName(applyPrefixJs(readFileSync(standaloneJsSrc, 'utf-8'), ctx), ctx),
299
+ 'utf-8',
300
+ );
301
+ writeFileSync(
302
+ cssDst,
303
+ applyPackageName(applyPrefixCss(readFileSync(standaloneCssSrc, 'utf-8'), ctx), ctx),
304
+ 'utf-8',
305
+ );
306
+
307
+ // 7. Optional theme override CSS — appended to the standalone CSS so it
308
+ // overrides Luxen's default tokens. The consumer authored the file, so we
309
+ // copy verbatim without prefix substitution.
310
+ if (ctx.themeCss) {
311
+ const themePath = resolve(process.cwd(), ctx.themeCss);
312
+ if (!existsSync(themePath)) {
313
+ console.error(`✗ themeCss not found: ${ctx.themeCss}`);
314
+ process.exit(1);
315
+ }
316
+ const themeContent = readFileSync(themePath, 'utf-8');
317
+ writeFileSync(
318
+ cssDst,
319
+ readFileSync(cssDst, 'utf-8') + '\n\n/* Theme overrides */\n' + themeContent,
320
+ 'utf-8',
321
+ );
322
+ }
323
+ }
324
+
325
+ // --- Helpers ------------------------------------------------------------------
326
+
327
+ function ensureDir(p) {
328
+ mkdirSync(p, { recursive: true });
329
+ }
330
+
331
+ async function renderTemplate(srcPath, dstPath, vars, ctx) {
332
+ const raw = readFileSync(srcPath, 'utf-8');
333
+ const withVars = applyMustache(raw, vars);
334
+ const withPrefix = applyPrefix(withVars, ctx);
335
+ const final = applyPackageName(withPrefix, ctx);
336
+ writeFileSync(dstPath, final, 'utf-8');
337
+ }
338
+
339
+ function applyMustache(content, vars) {
340
+ return content.replace(/\{\{(\w+)\}\}/g, (m, key) => (key in vars ? String(vars[key]) : m));
341
+ }
342
+
343
+ // Substitutes the npm package name `luxen-ui` with the consumer's name in
344
+ // quoted import paths — covers both `'luxen-ui'` (bare) and `'luxen-ui/...'`
345
+ // (sub-paths like `'luxen-ui/css/badge'`). The strict patterns (quote + exact
346
+ // name) avoid false positives on unrelated identifiers like
347
+ // `Symbol.for('luxen-dialog-scroll-lock')` (no closing quote on `luxen-ui`,
348
+ // continues with other text).
349
+ function applyPackageName(content, ctx) {
350
+ const pkg = ctx.jsImportPath;
351
+ if (pkg === 'luxen-ui') return content;
352
+ return content
353
+ .replace(/'luxen-ui'/g, `'${pkg}'`)
354
+ .replace(/"luxen-ui"/g, `"${pkg}"`)
355
+ .replace(/'luxen-ui\//g, `'${pkg}/`)
356
+ .replace(/"luxen-ui\//g, `"${pkg}/`);
357
+ }
358
+
359
+ // Prefix substitution for markdown / generic text. Patterns are split by
360
+ // surface: tag-shaped patterns use elementPrefix (matching the Vite plugin's
361
+ // elementPrefix and registry.js), CSS-shaped patterns use cssPrefix (matching
362
+ // postcss-plugin-prefix). Quoted forms (e.g. `'l-'`) default to elementPrefix
363
+ // because they overwhelmingly refer to tag names in JS strings / JSON. When
364
+ // elementPrefix === 'l' and cssPrefix === 'l', this is a no-op.
365
+ function applyPrefix(content, ctx) {
366
+ const { elementPrefix: e, cssPrefix: c } = ctx;
367
+ if (e === 'l' && c === 'l') return content;
368
+ return content
369
+ .replace(/<l-/g, `<${e}-`)
370
+ .replace(/<\/l-/g, `</${e}-`)
371
+ .replace(/--l-/g, `--${c}-`)
372
+ .replace(/\.l-/g, `.${c}-`)
373
+ .replace(/"l-/g, `"${e}-`)
374
+ .replace(/'l-/g, `'${e}-`)
375
+ .replace(/`l-/g, `\`${e}-`)
376
+ .replace(/ l-/g, ` ${e}-`)
377
+ .replace(/\(l-/g, `(${e}-`)
378
+ .replace(/\[l-/g, `[${e}-`)
379
+ .replace(/,l-/g, `,${e}-`)
380
+ .replace(/=l-/g, `=${e}-`)
381
+ .replace(/\nl-/g, `\n${e}-`);
382
+ }
383
+
384
+ // Prefix substitution for CSS files. Three surfaces, two prefixes (mirrors
385
+ // postcss-plugin-prefix):
386
+ // - CSS variables `--l-*` → cssPrefix
387
+ // - Class selectors `.l-*` → cssPrefix
388
+ // - Type selectors `l-foo { ... }`, `l-foo:hover`, `, l-foo` → elementPrefix
389
+ // The type-selector pattern matches `l-` only at positions where a CSS selector
390
+ // can start (line start, whitespace, comma, combinators), to avoid touching the
391
+ // `l-` inside `--l-`, `.l-`, `--prefix-l-something`, etc.
392
+ function applyPrefixCss(content, ctx) {
393
+ const { elementPrefix: e, cssPrefix: c } = ctx;
394
+ if (e === 'l' && c === 'l') return content;
395
+ return content
396
+ .replace(/--l-/g, `--${c}-`)
397
+ .replace(/\.l-/g, `.${c}-`)
398
+ .replace(/(^|[\s,>+~(])l-/gm, `$1${e}-`);
399
+ }
400
+
401
+ // Prefix substitution for the standalone JS bundle: registry initialisers,
402
+ // tag-name string literals, shadow-DOM CSS inlined as JS strings, and (if
403
+ // included) custom-elements.json. The bundle is built unminified so these
404
+ // patterns are stable.
405
+ function applyPrefixJs(content, ctx) {
406
+ const { elementPrefix: e, cssPrefix: c } = ctx;
407
+ if (e === 'l' && c === 'l') return content;
408
+ return (
409
+ content
410
+ .replace(/'l-/g, `'${e}-`)
411
+ .replace(/"l-/g, `"${e}-`)
412
+ .replace(/--l-/g, `--${c}-`)
413
+ // Registry initialisers — match the standalone bundle's unminified form:
414
+ // var _elementPrefix = "l"; → var _elementPrefix = "pulse";
415
+ // var _cssPrefix = "l"; → var _cssPrefix = "p";
416
+ .replace(/_elementPrefix = "l"/g, `_elementPrefix = "${e}"`)
417
+ .replace(/_cssPrefix = "l"/g, `_cssPrefix = "${c}"`)
418
+ );
419
+ }
420
+
421
+ function buildElementsTable(elements, ctx) {
422
+ const lines = [
423
+ '| Element | Type | Selector | Reference |',
424
+ '|---------|------|----------|-----------|',
425
+ ];
426
+ for (const e of elements) {
427
+ const type = e.kind === 'native' ? 'CSS class' : 'Custom element';
428
+ // CSS classes use cssPrefix; custom elements use elementPrefix.
429
+ const prefix = e.kind === 'native' ? ctx.cssPrefix : ctx.elementPrefix;
430
+ const sel =
431
+ e.selector ?? (e.kind === 'native' ? `.${prefix}-${e.name}` : `<${prefix}-${e.name}>`);
432
+ // Selector overrides (e.g. `.l-close`) need manual prefix swap. Choose the
433
+ // right prefix based on the leading character (`<` = tag, `.` = class).
434
+ const finalSel = e.selector
435
+ ? e.selector.replace(/^([<.])l-/, (_, ch) =>
436
+ ch === '<' ? `<${ctx.elementPrefix}-` : `.${ctx.cssPrefix}-`,
437
+ )
438
+ : sel;
439
+ lines.push(`| ${e.displayName} | ${type} | \`${finalSel}\` | [${e.name}.md](${e.name}.md) |`);
440
+ }
441
+ return lines.join('\n');
442
+ }
443
+
444
+ function buildElementsList(elements) {
445
+ return elements.map((e) => e.displayName).join(', ') + '.';
446
+ }
447
+
448
+ // Builds the comma-separated `l-foo` tag list for mockups.md (from manifest
449
+ // entries flagged `inMockups`, excluding native CSS-only elements). The result
450
+ // is processed by applyPrefix at render time, so the tags reflect the consumer's
451
+ // rebrand if any.
452
+ function buildTagsList(allElements) {
453
+ return (
454
+ allElements
455
+ .filter((e) => e.inMockups && e.kind !== 'native')
456
+ .map((e) => `\`l-${e.name}\``)
457
+ .join(', ') + '.'
458
+ );
459
+ }
460
+
461
+ // =============================================================================
462
+ // Command dispatcher
463
+ // =============================================================================
464
+
465
+ function usageImport(code = 1) {
466
+ console.error('Usage: luxen-ui import <noun> [path]');
467
+ console.error('');
468
+ console.error('Available nouns:');
469
+ console.error(' preset Import the CSS preset (base + tokens).');
470
+ console.error(' Default: ./luxen-preset.css');
471
+ console.error(' tailwind Import the Tailwind theme preset (bridge).');
472
+ console.error(' Default: ./luxen-tailwind.css');
473
+ console.error(' design-tokens Import the semantic aliases for customization.');
474
+ console.error(' Default: ./luxen-design-tokens.css');
475
+ process.exit(code);
476
+ }
477
+
478
+ function usageGenerateSkill(code = 1) {
479
+ console.error('Usage: luxen-ui generate-skill [flags]');
480
+ console.error('');
481
+ console.error('Flags:');
482
+ console.error(' --config <path> Config file (default: ./luxen.config.mjs)');
483
+ console.error(' --name <name> Skill name (default: luxen-ui)');
484
+ console.error(' --element-prefix <p> Tag prefix without trailing dash (default: l)');
485
+ console.error(
486
+ ' --css-prefix <p> CSS class/var prefix without trailing dash (default: l)',
487
+ );
488
+ console.error(' --theme-css <path> Optional CSS file with token overrides');
489
+ console.error(' --out <path> Output dir (default: .claude/skills/<name>)');
490
+ console.error('');
491
+ console.error('Config file (luxen.config.mjs) takes the same keys, plus identity:');
492
+ console.error(' export default {');
493
+ console.error(" name: 'pulse',");
494
+ console.error(" displayName: 'Pulse',");
495
+ console.error(" description: '...',");
496
+ console.error(" elementPrefix: 'pulse',");
497
+ console.error(" cssPrefix: 'pulse',");
498
+ console.error(" themeCss: 'src/styles/tokens.css',");
499
+ console.error(" out: '.claude/skills/pulse',");
500
+ console.error(' }');
501
+ console.error('');
502
+ console.error('The Vite plugin (luxen-ui/vite-plugin) reads the same file —');
503
+ console.error('keep elementPrefix/cssPrefix in sync between dev and skill generation.');
504
+ process.exit(code);
505
+ }
506
+
507
+ function usage(code = 1) {
508
+ console.error('Usage: luxen-ui <command> [args]');
509
+ console.error('');
510
+ console.error('Commands:');
511
+ console.error(' import <noun> [path] Copy a CSS preset / token file into the project.');
512
+ console.error(' generate-skill Produce a brand-aware Agent Skill folder.');
513
+ console.error('');
514
+ console.error('Run `luxen-ui <command> --help` for command-specific flags.');
515
+ process.exit(code);
516
+ }
517
+
518
+ const [, , command, ...rest] = process.argv;
519
+
520
+ if (!command || command === '-h' || command === '--help') usage(0);
521
+
522
+ if (command === 'import') cmdImport(rest);
523
+ else if (command === 'generate-skill') await cmdGenerateSkill(rest);
524
+ else {
525
+ console.error(`✗ Unknown command: ${command}`);
526
+ usage(1);
527
+ }