@birdapi/velinstyle 1.1.0 → 1.2.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 (308) hide show
  1. package/README.de.md +87 -162
  2. package/README.md +188 -119
  3. package/cli/blueprint.js +98 -5
  4. package/cli/blueprints/app-chrome.html +18 -0
  5. package/cli/blueprints/benefits-grid.html +9 -0
  6. package/cli/blueprints/bottom-nav-mobile.html +2 -1
  7. package/cli/blueprints/cookie-consent.html +1 -1
  8. package/cli/blueprints/cta-band.html +6 -0
  9. package/cli/blueprints/faq-section.html +18 -0
  10. package/cli/blueprints/filter-bar.html +4 -4
  11. package/cli/blueprints/form-contact.html +6 -5
  12. package/cli/blueprints/hero-section.html +3 -3
  13. package/cli/blueprints/notification-center.html +1 -1
  14. package/cli/blueprints/onboarding.html +2 -1
  15. package/cli/blueprints/ops-console.html +29 -0
  16. package/cli/blueprints/pricing-band.html +37 -0
  17. package/cli/blueprints/process-steps.html +10 -0
  18. package/cli/blueprints/services-grid.html +9 -0
  19. package/cli/blueprints/settings-panel.html +8 -6
  20. package/cli/blueprints/split-hero.html +25 -0
  21. package/cli/blueprints/testimonials.html +8 -0
  22. package/cli/blueprints/trust-bar.html +10 -0
  23. package/cli/cli-manifest.json +81 -17
  24. package/cli/contrast-utils.js +97 -0
  25. package/cli/create.js +370 -0
  26. package/cli/docgen/extract-attributes.js +126 -10
  27. package/cli/docgen/extract-cli.js +3 -2
  28. package/cli/docgen/extract-components.js +61 -2
  29. package/cli/docgen/extract-utilities.js +10 -10
  30. package/cli/doctor.js +119 -0
  31. package/cli/index.js +531 -44
  32. package/cli/meta.js +84 -1
  33. package/cli/perf-audit.js +15 -2
  34. package/cli/prompt-engine.js +243 -0
  35. package/cli/review.js +268 -0
  36. package/cli/scaffold.js +119 -4
  37. package/cli/scanner-rules-data.js +7 -0
  38. package/cli/scanner.js +357 -4
  39. package/cli/serve.js +81 -0
  40. package/cli/skills.js +223 -0
  41. package/cli/wc-api.js +89 -0
  42. package/cli/workflow.js +42 -0
  43. package/components/index.js +2 -0
  44. package/components/runtime/component-loaders.js +2 -0
  45. package/components/velin-accordion.js +62 -13
  46. package/components/velin-bottom-nav.js +10 -0
  47. package/components/velin-calendar.js +212 -0
  48. package/components/velin-command.js +18 -2
  49. package/components/velin-data-table.js +78 -1
  50. package/components/velin-dialog.js +4 -1
  51. package/components/velin-drawer.js +2 -4
  52. package/components/velin-file-dropzone.js +162 -0
  53. package/components/velin-icon.js +22 -1
  54. package/components/velin-lightbox.js +5 -3
  55. package/components/velin-modal.js +2 -4
  56. package/components/velin-search.js +1 -1
  57. package/components/velin-sheet.js +2 -4
  58. package/core/a11y/component-contracts.json +20 -3
  59. package/core/meta/build.js +125 -5
  60. package/core/meta/design-constraints/contact.json +9 -0
  61. package/core/meta/design-constraints/faq.json +9 -0
  62. package/core/meta/design-constraints/hero.json +13 -0
  63. package/core/meta/knowledge/components.json +622 -0
  64. package/core/meta/knowledge/tokens.json +282 -0
  65. package/core/meta/pages/registry.json +294 -0
  66. package/core/meta/schema.js +3 -1
  67. package/core/meta/sections/registry.json +185 -0
  68. package/dist/chunks/{attributes-STYCS3O5.js → attributes-A423NX5J.js} +3 -3
  69. package/dist/chunks/{attributes-353XDOAX.js → attributes-F6UPIEVP.js} +1 -1
  70. package/dist/chunks/{attributes-ADOKLKA7.js → attributes-GLYXGGAL.js} +3 -3
  71. package/dist/chunks/{attributes-TPANLMLF.js → attributes-UFTYOSAU.js} +3 -3
  72. package/dist/chunks/attributes-XGLXLR2T.js +391 -0
  73. package/dist/chunks/attributes-YF4NI2QS.js +391 -0
  74. package/dist/chunks/browser-AUABBYUK.js +1544 -0
  75. package/dist/chunks/{chunk-RSMRR27R.js → chunk-2LSKX57P.js} +12 -10
  76. package/dist/chunks/{chunk-IEHKRARD.js → chunk-2TGCVDUL.js} +11 -9
  77. package/dist/chunks/{chunk-SRL6EWHP.js → chunk-5JWGUAPC.js} +17 -13
  78. package/dist/chunks/chunk-7YSO2OQ2.js +113 -0
  79. package/dist/chunks/{chunk-QVHYL3R4.js → chunk-BHR3ZG6U.js} +6 -6
  80. package/dist/chunks/{chunk-J472ERN2.js → chunk-JMSIHEYX.js} +15 -4
  81. package/dist/chunks/{chunk-MKZP2TBH.js → chunk-L7ZGUU4D.js} +2 -2
  82. package/dist/chunks/chunk-TUGIPKW5.js +113 -0
  83. package/dist/chunks/{highlight-GJHHV4KM.js → highlight-M2ELQNYK.js} +1 -1
  84. package/dist/chunks/runtime-entry.js +1 -1
  85. package/dist/chunks/{velin-accordion-FBIPAEXG.js → velin-accordion-WSY6BMLA.js} +64 -10
  86. package/dist/chunks/{velin-bottom-nav-7GEMPIM6.js → velin-bottom-nav-5RVRNGIP.js} +25 -0
  87. package/dist/chunks/{velin-bottom-nav-N3DFQR66.js → velin-bottom-nav-N5F4UO2I.js} +26 -1
  88. package/dist/chunks/velin-calendar-OFE6THUD.js +210 -0
  89. package/dist/chunks/velin-calendar-PGVNJTXK.js +217 -0
  90. package/dist/chunks/velin-calendar-XC7JRDSH.js +217 -0
  91. package/dist/chunks/{velin-code-block-CIAURDRJ.js → velin-code-block-ZGWG7JI5.js} +1 -1
  92. package/dist/chunks/{velin-combobox-NXS4QB4R.js → velin-combobox-56V2ZWT5.js} +1 -1
  93. package/dist/chunks/{velin-command-ONKO2A3J.js → velin-command-2HO2EKR6.js} +29 -2
  94. package/dist/chunks/{velin-command-TMLSRGIU.js → velin-command-ZJSLPK7B.js} +30 -3
  95. package/dist/chunks/{velin-copy-NYDBOKXT.js → velin-copy-XDQSV2XU.js} +1 -1
  96. package/dist/chunks/{velin-countdown-4ZVDGK4R.js → velin-countdown-V4Z5MA63.js} +1 -1
  97. package/dist/chunks/velin-data-table-UVR42UUM.js +372 -0
  98. package/dist/chunks/{velin-dialog-GTTZI564.js → velin-dialog-3YK2RPRV.js} +9 -2
  99. package/dist/chunks/{velin-dialog-ELFOZIXZ.js → velin-dialog-S24KAP4S.js} +3 -1
  100. package/dist/chunks/{velin-drawer-BE6TYN3H.js → velin-drawer-5PNU624J.js} +2 -4
  101. package/dist/chunks/{velin-drawer-DLL2GLT6.js → velin-drawer-CCM6S25D.js} +3 -5
  102. package/dist/chunks/{velin-email-RBX6ZR4S.js → velin-email-TNFONXPW.js} +1 -1
  103. package/dist/chunks/velin-file-dropzone-QRGF2JNA.js +154 -0
  104. package/dist/chunks/velin-file-dropzone-XIZMJ3NB.js +154 -0
  105. package/dist/chunks/{velin-icon-7M76DOPB.js → velin-icon-A6NCXGUK.js} +59 -17
  106. package/dist/chunks/{velin-icon-ZTSKUOVN.js → velin-icon-EC4B5XCM.js} +18 -5
  107. package/dist/chunks/{velin-lightbox-6E7CAATP.js → velin-lightbox-FFK4TUUP.js} +7 -6
  108. package/dist/chunks/{velin-lightbox-NXA3U2FM.js → velin-lightbox-P725FLTY.js} +5 -4
  109. package/dist/chunks/{velin-menubar-J66JXRWW.js → velin-menubar-6I2LM5HL.js} +1 -1
  110. package/dist/chunks/{velin-modal-5HYNNNUI.js → velin-modal-ICTMGRSU.js} +7 -8
  111. package/dist/chunks/{velin-modal-AEOTZ67O.js → velin-modal-JBNODH7D.js} +2 -4
  112. package/dist/chunks/{velin-popover-T72HK3DF.js → velin-popover-WZG2GHBL.js} +25 -4
  113. package/dist/chunks/{velin-rating-N4DI2XNL.js → velin-rating-QBBYRRBU.js} +1 -1
  114. package/dist/chunks/{velin-search-7B4KJ6TX.js → velin-search-B3L6J2RP.js} +2 -2
  115. package/dist/chunks/{velin-search-2XRQFBCS.js → velin-search-L3UG6NDQ.js} +5 -4
  116. package/dist/chunks/{velin-secure-field-6PV7RZDJ.js → velin-secure-field-DGYMP7OK.js} +1 -1
  117. package/dist/chunks/{velin-segmented-control-GYD5BIXQ.js → velin-segmented-control-P74GJPAR.js} +1 -1
  118. package/dist/chunks/{velin-sheet-R2Y67X6H.js → velin-sheet-M5GZZD7G.js} +2 -4
  119. package/dist/chunks/{velin-sheet-OUK6572T.js → velin-sheet-X7RXIWKV.js} +3 -5
  120. package/dist/chunks/{velin-stepper-X54WGHDG.js → velin-stepper-4YQJUHPC.js} +12 -5
  121. package/dist/chunks/{velin-toast-OMMOA2DK.js → velin-toast-UG5LWTG2.js} +5 -1
  122. package/dist/chunks/{velin-tooltip-BDHGRTQB.js → velin-tooltip-ZDH5SDLU.js} +1 -1
  123. package/dist/llms.txt +29 -7
  124. package/dist/search-index.json +156 -10
  125. package/dist/velin-agent.json +3973 -28
  126. package/dist/velinstyle-components.iife.js +1211 -284
  127. package/dist/velinstyle-components.js +1213 -284
  128. package/dist/velinstyle-components.min.js +266 -118
  129. package/dist/velinstyle.css +252 -67
  130. package/dist/velinstyle.d.ts +2 -0
  131. package/dist/velinstyle.min.css +1 -1
  132. package/package.json +20 -6
  133. package/packages/skill-engine/README.md +24 -0
  134. package/packages/skill-engine/package.json +7 -0
  135. package/packages/skill-engine/src/catalog.js +29 -0
  136. package/packages/skill-engine/src/index.js +5 -0
  137. package/packages/skill-engine/src/install.js +69 -0
  138. package/packages/skill-engine/src/registry.js +27 -0
  139. package/packages/skill-engine/src/resolve.js +68 -0
  140. package/packages/skill-engine/src/validate.js +40 -0
  141. package/packages/velinstyle-skills/README.md +6 -0
  142. package/packages/velinstyle-skills/adapter.json +8 -0
  143. package/packages/velinstyle-skills/bundles/landing-starter.bundle.yaml +12 -0
  144. package/packages/velinstyle-skills/bundles/review-suite.bundle.yaml +11 -0
  145. package/packages/velinstyle-skills/catalog.json +1004 -0
  146. package/packages/velinstyle-skills/graphs/component-ship.graph.yaml +14 -0
  147. package/packages/velinstyle-skills/graphs/landingpage.graph.yaml +21 -0
  148. package/packages/velinstyle-skills/graphs/release-gate.graph.yaml +15 -0
  149. package/packages/velinstyle-skills/index.js +22 -0
  150. package/packages/velinstyle-skills/package.json +7 -0
  151. package/packages/velinstyle-skills/packs/accessibility.pack.yaml +9 -0
  152. package/packages/velinstyle-skills/packs/design.pack.yaml +10 -0
  153. package/packages/velinstyle-skills/packs/documentation.pack.yaml +8 -0
  154. package/packages/velinstyle-skills/packs/enterprise.pack.yaml +10 -0
  155. package/packages/velinstyle-skills/packs/frontend.pack.yaml +10 -0
  156. package/packages/velinstyle-skills/packs/review.pack.yaml +9 -0
  157. package/packages/velinstyle-skills/projects/admin-panel.project.yaml +12 -0
  158. package/packages/velinstyle-skills/projects/blog.project.yaml +11 -0
  159. package/packages/velinstyle-skills/projects/documentation-portal.project.yaml +13 -0
  160. package/packages/velinstyle-skills/projects/ecommerce-shop.project.yaml +12 -0
  161. package/packages/velinstyle-skills/projects/landing-page.project.yaml +12 -0
  162. package/packages/velinstyle-skills/projects/laravel-dashboard.project.yaml +12 -0
  163. package/packages/velinstyle-skills/projects/marketing-website.project.yaml +14 -0
  164. package/packages/velinstyle-skills/projects/portfolio.project.yaml +12 -0
  165. package/packages/velinstyle-skills/registry.json +142 -0
  166. package/packages/velinstyle-skills/scripts/generate-assets.mjs +163 -0
  167. package/packages/velinstyle-skills/skills/velin-a11y-focus-keyboard/SKILL.md +57 -0
  168. package/packages/velinstyle-skills/skills/velin-a11y-page-checklist/SKILL.md +57 -0
  169. package/packages/velinstyle-skills/skills/velin-a11y-scan-fix/SKILL.md +57 -0
  170. package/packages/velinstyle-skills/skills/velin-ai-agent-briefing/SKILL.md +57 -0
  171. package/packages/velinstyle-skills/skills/velin-ai-plan-scaffold-review/SKILL.md +57 -0
  172. package/packages/velinstyle-skills/skills/velin-ai-skill-authoring/SKILL.md +57 -0
  173. package/packages/velinstyle-skills/skills/velin-components-accessibility-map/SKILL.md +57 -0
  174. package/packages/velinstyle-skills/skills/velin-components-api-contract/SKILL.md +57 -0
  175. package/packages/velinstyle-skills/skills/velin-components-recipe/SKILL.md +57 -0
  176. package/packages/velinstyle-skills/skills/velin-components-select-compose/SKILL.md +57 -0
  177. package/packages/velinstyle-skills/skills/velin-design-hero-compose/SKILL.md +57 -0
  178. package/packages/velinstyle-skills/skills/velin-design-section-rhythm/SKILL.md +57 -0
  179. package/packages/velinstyle-skills/skills/velin-design-surface-roles/SKILL.md +57 -0
  180. package/packages/velinstyle-skills/skills/velin-dev-component-wire/SKILL.md +57 -0
  181. package/packages/velinstyle-skills/skills/velin-dev-page-scaffold/SKILL.md +57 -0
  182. package/packages/velinstyle-skills/skills/velin-dev-plan-first/SKILL.md +57 -0
  183. package/packages/velinstyle-skills/skills/velin-docs-component-guide/SKILL.md +57 -0
  184. package/packages/velinstyle-skills/skills/velin-docs-generate-api/SKILL.md +57 -0
  185. package/packages/velinstyle-skills/skills/velin-dx-doctor-setup/SKILL.md +57 -0
  186. package/packages/velinstyle-skills/skills/velin-dx-project-init/SKILL.md +57 -0
  187. package/packages/velinstyle-skills/skills/velin-migration-legacy-wc/SKILL.md +57 -0
  188. package/packages/velinstyle-skills/skills/velin-migration-prefix-classes/SKILL.md +57 -0
  189. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +57 -0
  190. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +57 -0
  191. package/packages/velinstyle-skills/skills/velin-perf-audit-fix/SKILL.md +57 -0
  192. package/packages/velinstyle-skills/skills/velin-perf-runtime-tree-shake/SKILL.md +57 -0
  193. package/packages/velinstyle-skills/skills/velin-release-changelog-sync/SKILL.md +57 -0
  194. package/packages/velinstyle-skills/skills/velin-release-meta-rebuild/SKILL.md +57 -0
  195. package/packages/velinstyle-skills/skills/velin-review-conversion-hero/SKILL.md +57 -0
  196. package/packages/velinstyle-skills/skills/velin-review-page-gate/SKILL.md +57 -0
  197. package/packages/velinstyle-skills/skills/velin-review-seo-meta/SKILL.md +57 -0
  198. package/packages/velinstyle-skills/skills/velin-security-sanitize-html/SKILL.md +57 -0
  199. package/packages/velinstyle-skills/skills/velin-security-scan-pii/SKILL.md +57 -0
  200. package/packages/velinstyle-skills/skills/velin-testing-a11y-suite/SKILL.md +57 -0
  201. package/packages/velinstyle-skills/skills/velin-testing-visual-smoke/SKILL.md +57 -0
  202. package/packages/velinstyle-skills/skills/velin-themes-apply-token/SKILL.md +57 -0
  203. package/packages/velinstyle-skills/skills/velin-themes-contrast-check/SKILL.md +57 -0
  204. package/packages/velinstyle-skills/skills/velin-utilities-layout-apply/SKILL.md +57 -0
  205. package/packages/velinstyle-skills/skills/velin-utilities-prefix-fix/SKILL.md +57 -0
  206. package/packages/velinstyle-skills/skills/velin-utilities-token-map/SKILL.md +57 -0
  207. package/packages/velinstyle-skills/templates/admin-panel.template.yaml +12 -0
  208. package/packages/velinstyle-skills/templates/blog.template.yaml +12 -0
  209. package/packages/velinstyle-skills/templates/documentation-portal.template.yaml +12 -0
  210. package/packages/velinstyle-skills/templates/ecommerce-shop.template.yaml +13 -0
  211. package/packages/velinstyle-skills/templates/landing-page.template.yaml +12 -0
  212. package/packages/velinstyle-skills/templates/laravel-dashboard.template.yaml +11 -0
  213. package/packages/velinstyle-skills/templates/marketing-website.template.yaml +13 -0
  214. package/packages/velinstyle-skills/templates/portfolio.template.yaml +12 -0
  215. package/schemas/component-knowledge.schema.json +33 -0
  216. package/schemas/design-constraint.schema.json +15 -0
  217. package/schemas/design-intelligence.schema.json +19 -0
  218. package/schemas/design-rule.schema.json +19 -0
  219. package/schemas/page-template.schema.json +24 -0
  220. package/schemas/review-report.schema.json +36 -0
  221. package/schemas/section.schema.json +22 -0
  222. package/schemas/skill-bundle.schema.json +15 -0
  223. package/schemas/skill-graph.schema.json +25 -0
  224. package/schemas/skill-pack.schema.json +14 -0
  225. package/schemas/skill-project.schema.json +16 -0
  226. package/schemas/skill-record.schema.json +27 -0
  227. package/schemas/skill-registry.schema.json +17 -0
  228. package/schemas/skill-template.schema.json +17 -0
  229. package/schemas/token-graph.schema.json +27 -0
  230. package/schemas/utility.schema.json +166 -0
  231. package/src/components/alert.css +22 -1
  232. package/src/components/calendar-dropzone.css +5 -0
  233. package/src/layout/app-shell.css +33 -0
  234. package/src/tokens/shadow.css +13 -0
  235. package/src/utilities/border.css +2 -0
  236. package/src/utilities/display.css +1 -24
  237. package/src/utilities/responsive.css +16 -1
  238. package/src/utilities/spacing.css +32 -0
  239. package/src/velinstyle.css +2 -0
  240. package/dist/chunks/attributes-3BZLI7XF.js +0 -364
  241. package/dist/chunks/attributes-4N5JP4CG.js +0 -364
  242. package/dist/chunks/attributes-5Q2WXGRC.js +0 -374
  243. package/dist/chunks/attributes-AIR7SVLK.js +0 -364
  244. package/dist/chunks/attributes-BGRN5XZO.js +0 -364
  245. package/dist/chunks/attributes-BVSQAYLR.js +0 -364
  246. package/dist/chunks/attributes-CDYFUY7Y.js +0 -364
  247. package/dist/chunks/attributes-JMYJZBPE.js +0 -364
  248. package/dist/chunks/attributes-R5JY3X4O.js +0 -374
  249. package/dist/chunks/attributes-TNSPQTHX.js +0 -374
  250. package/dist/chunks/chunk-2354NEBP.js +0 -109
  251. package/dist/chunks/chunk-2VNA7G7S.js +0 -109
  252. package/dist/chunks/chunk-AQLRJSGG.js +0 -109
  253. package/dist/chunks/chunk-EWPSDMQT.js +0 -109
  254. package/dist/chunks/chunk-LA7264K4.js +0 -85
  255. package/dist/chunks/chunk-QTJJ3DPO.js +0 -109
  256. package/dist/chunks/chunk-RZQVWFHW.js +0 -109
  257. package/dist/chunks/chunk-U4XHMZ7D.js +0 -109
  258. package/dist/chunks/chunk-V5YIUA6G.js +0 -109
  259. package/dist/chunks/chunk-XIET2VSZ.js +0 -109
  260. package/dist/chunks/chunk-XYLJ2GCB.js +0 -205
  261. package/dist/chunks/chunk-ZPSPKUYD.js +0 -109
  262. package/dist/chunks/highlight-XTHRKBA3.js +0 -37
  263. package/dist/chunks/velin-bottom-nav-2N2TYWOF.js +0 -86
  264. package/dist/chunks/velin-carousel-Y5VCOABZ.js +0 -213
  265. package/dist/chunks/velin-code-block-ASUBTAQV.js +0 -119
  266. package/dist/chunks/velin-code-block-TSUKPY4C.js +0 -123
  267. package/dist/chunks/velin-code-block-Y6CM726Q.js +0 -119
  268. package/dist/chunks/velin-combobox-2KDTCQ7N.js +0 -155
  269. package/dist/chunks/velin-command-M7RNHUPR.js +0 -136
  270. package/dist/chunks/velin-copy-T5KDTDXP.js +0 -81
  271. package/dist/chunks/velin-countdown-5XSTN3BH.js +0 -101
  272. package/dist/chunks/velin-counter-ISCTEAHI.js +0 -118
  273. package/dist/chunks/velin-dialog-D2GUHSCD.js +0 -144
  274. package/dist/chunks/velin-dialog-IJLFDXAJ.js +0 -144
  275. package/dist/chunks/velin-dialog-TNS3WXMB.js +0 -144
  276. package/dist/chunks/velin-drawer-MJS6WCF7.js +0 -130
  277. package/dist/chunks/velin-email-N5B5ZYTE.js +0 -90
  278. package/dist/chunks/velin-icon-KZO3IEHG.js +0 -164
  279. package/dist/chunks/velin-lightbox-I75U6JF4.js +0 -140
  280. package/dist/chunks/velin-lightbox-QOTB4PRL.js +0 -140
  281. package/dist/chunks/velin-lightbox-UCD6N7HF.js +0 -140
  282. package/dist/chunks/velin-live-dot-XHUZCIDZ.js +0 -67
  283. package/dist/chunks/velin-menubar-SFEXJE56.js +0 -86
  284. package/dist/chunks/velin-modal-2HOBXE6F.js +0 -176
  285. package/dist/chunks/velin-modal-GLI2XZZB.js +0 -176
  286. package/dist/chunks/velin-popover-EXINRIGJ.js +0 -145
  287. package/dist/chunks/velin-popover-OXX7MRZ6.js +0 -145
  288. package/dist/chunks/velin-popover-YKCCROJG.js +0 -145
  289. package/dist/chunks/velin-rating-XRQJV4LO.js +0 -91
  290. package/dist/chunks/velin-scroll-top-F2FCZNYD.js +0 -58
  291. package/dist/chunks/velin-search-4YHJWYSS.js +0 -556
  292. package/dist/chunks/velin-search-LWHY23Q5.js +0 -474
  293. package/dist/chunks/velin-secure-field-H7FSBUJW.js +0 -95
  294. package/dist/chunks/velin-segmented-control-PQX6LKOJ.js +0 -109
  295. package/dist/chunks/velin-sheet-3OGI4HD7.js +0 -119
  296. package/dist/chunks/velin-sparkline-GVEANJVW.js +0 -184
  297. package/dist/chunks/velin-sparkline-KDA3GQAN.js +0 -162
  298. package/dist/chunks/velin-stepper-2ZIHLKGM.js +0 -141
  299. package/dist/chunks/velin-stepper-FYEUEWE6.js +0 -141
  300. package/dist/chunks/velin-stepper-wc-QU3KRVQR.js +0 -133
  301. package/dist/chunks/velin-theme-toggle-BNNS7WLV.js +0 -285
  302. package/dist/chunks/velin-theme-toggle-NO7V4TWI.js +0 -285
  303. package/dist/chunks/velin-theme-toggle-QELCJM2Q.js +0 -291
  304. package/dist/chunks/velin-toast-RCZ4CSUC.js +0 -109
  305. package/dist/chunks/velin-toast-WEUBTJG6.js +0 -109
  306. package/dist/chunks/velin-tooltip-664IOHZA.js +0 -112
  307. package/dist/chunks/velin-tooltip-wc-LXDVT6DE.js +0 -103
  308. package/dist/chunks/worker-client-R6DBYPFT.js +0 -46
package/cli/serve.js ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Static file server for local previews.
3
+ */
4
+ import { createServer } from 'http';
5
+ import { readFileSync, existsSync, statSync } from 'fs';
6
+ import { join, resolve, extname, normalize } from 'path';
7
+
8
+ const MIME = {
9
+ '.html': 'text/html; charset=utf-8',
10
+ '.css': 'text/css; charset=utf-8',
11
+ '.js': 'text/javascript; charset=utf-8',
12
+ '.mjs': 'text/javascript; charset=utf-8',
13
+ '.json': 'application/json; charset=utf-8',
14
+ '.svg': 'image/svg+xml',
15
+ '.png': 'image/png',
16
+ '.jpg': 'image/jpeg',
17
+ '.jpeg': 'image/jpeg',
18
+ '.webp': 'image/webp',
19
+ '.woff2': 'font/woff2',
20
+ '.ico': 'image/x-icon',
21
+ '.map': 'application/json',
22
+ };
23
+
24
+ function safeJoin(root, reqPath) {
25
+ const decoded = decodeURIComponent((reqPath || '/').split('?')[0]);
26
+ const cleaned = normalize(decoded).replace(/^(\.\.[/\\])+/, '');
27
+ const full = resolve(root, '.' + (cleaned.startsWith('/') || cleaned.startsWith('\\') ? cleaned : `/${cleaned}`));
28
+ if (!full.startsWith(resolve(root))) return null;
29
+ return full;
30
+ }
31
+
32
+ /**
33
+ * @param {{ dir?: string, port?: number, host?: string }} opts
34
+ */
35
+ export function serveStatic(opts = {}) {
36
+ const dir = resolve(opts.dir || '.');
37
+ const port = Number(opts.port) || 4173;
38
+ const host = opts.host || '127.0.0.1';
39
+
40
+ if (!existsSync(dir) || !statSync(dir).isDirectory()) {
41
+ return { ok: false, error: `Not a directory: ${dir}` };
42
+ }
43
+
44
+ const server = createServer((req, res) => {
45
+ let filePath = safeJoin(dir, req.url || '/');
46
+ if (!filePath) {
47
+ res.writeHead(403);
48
+ res.end('Forbidden');
49
+ return;
50
+ }
51
+ if (existsSync(filePath) && statSync(filePath).isDirectory()) {
52
+ filePath = join(filePath, 'index.html');
53
+ }
54
+ if (!existsSync(filePath) || !statSync(filePath).isFile()) {
55
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
56
+ res.end('Not found');
57
+ return;
58
+ }
59
+ const type = MIME[extname(filePath).toLowerCase()] || 'application/octet-stream';
60
+ try {
61
+ const body = readFileSync(filePath);
62
+ res.writeHead(200, { 'Content-Type': type });
63
+ res.end(body);
64
+ } catch {
65
+ res.writeHead(500);
66
+ res.end('Read error');
67
+ }
68
+ });
69
+
70
+ return new Promise((resolvePromise) => {
71
+ server.listen(port, host, () => {
72
+ resolvePromise({
73
+ ok: true,
74
+ server,
75
+ url: `http://${host}:${port}/`,
76
+ dir,
77
+ close: () => new Promise((r) => server.close(() => r())),
78
+ });
79
+ });
80
+ });
81
+ }
package/cli/skills.js ADDED
@@ -0,0 +1,223 @@
1
+ import { resolve, join, dirname } from 'path';
2
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
3
+ import { fileURLToPath } from 'url';
4
+ import {
5
+ loadRegistry,
6
+ listSkills,
7
+ findSkillById,
8
+ validateRegistry,
9
+ resolveSkillGraph,
10
+ installSelection,
11
+ } from '../packages/skill-engine/src/index.js';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const PKG_ROOT = join(__dirname, '..');
15
+ const REGISTRY_PATH = join(PKG_ROOT, 'packages', 'velinstyle-skills', 'registry.json');
16
+ const SKILLS_ROOT = join(PKG_ROOT, 'packages', 'velinstyle-skills');
17
+
18
+ function argValue(argv, flag) {
19
+ const idx = argv.indexOf(flag);
20
+ return idx !== -1 ? argv[idx + 1] : null;
21
+ }
22
+
23
+ function hasFlag(argv, flag) {
24
+ return argv.includes(flag);
25
+ }
26
+
27
+ export function loadSkillRegistry() {
28
+ return loadRegistry(REGISTRY_PATH);
29
+ }
30
+
31
+ export function skillsList(argv = []) {
32
+ const registry = loadSkillRegistry();
33
+ const items = listSkills(registry, {
34
+ capability: argValue(argv, '--capability') || undefined,
35
+ status: argValue(argv, '--status') || undefined,
36
+ priority: argValue(argv, '--priority') || undefined,
37
+ origin: argValue(argv, '--origin') || undefined,
38
+ category: argValue(argv, '--category') || undefined,
39
+ });
40
+ if (hasFlag(argv, '--json')) {
41
+ console.log(JSON.stringify(items, null, 2));
42
+ return;
43
+ }
44
+ for (const item of items) {
45
+ console.log(`${item.id} [${item.category}] ${item.priority}/${item.status} capabilities=${(item.capabilities || []).join(',')}`);
46
+ }
47
+ console.log(`\n${items.length} skill(s)`);
48
+ }
49
+
50
+ export function skillsShow(skillId, argv = []) {
51
+ const registry = loadSkillRegistry();
52
+ const skill = findSkillById(registry, skillId);
53
+ if (!skill) {
54
+ console.error(`Unknown skill: ${skillId}`);
55
+ process.exit(1);
56
+ }
57
+ if (hasFlag(argv, '--human')) {
58
+ console.log(formatSkillHuman(skill));
59
+ return;
60
+ }
61
+ console.log(JSON.stringify(skill, null, 2));
62
+ }
63
+
64
+ function formatSkillHuman(skill) {
65
+ const lines = [
66
+ `# ${skill.id}`,
67
+ '',
68
+ skill.title ? `**${skill.title}**` : '',
69
+ skill.summary || skill.description || '',
70
+ '',
71
+ `- Category: ${skill.category || '—'}`,
72
+ `- Status: ${skill.status || '—'}`,
73
+ `- Priority: ${skill.priority || '—'}`,
74
+ `- Capabilities: ${(skill.capabilities || []).join(', ') || '—'}`,
75
+ ];
76
+ if (skill.requiresCli?.length) lines.push(`- CLI: ${skill.requiresCli.join(', ')}`);
77
+ if (skill.inputs?.length) {
78
+ lines.push('', '## Inputs');
79
+ for (const input of skill.inputs) {
80
+ if (typeof input === 'string') {
81
+ lines.push(`- \`${input}\``);
82
+ continue;
83
+ }
84
+ const label = input.name || input.id || input.key || input.type || JSON.stringify(input);
85
+ lines.push(`- \`${label}\`${input.required ? ' (required)' : ''}: ${input.description || input.type || ''}`.trim());
86
+ }
87
+ }
88
+ if (skill.outputs?.length) {
89
+ lines.push('', '## Outputs');
90
+ for (const output of skill.outputs) {
91
+ if (typeof output === 'string') {
92
+ lines.push(`- \`${output}\``);
93
+ continue;
94
+ }
95
+ const label = output.name || output.id || output.key || output.type || JSON.stringify(output);
96
+ lines.push(`- \`${label}\`: ${output.description || output.type || ''}`.trim());
97
+ }
98
+ }
99
+ if (skill.dependsOn?.length) {
100
+ lines.push('', `## Depends on`, skill.dependsOn.map((d) => `- ${d}`).join('\n'));
101
+ }
102
+ lines.push('', '_Tip: blueprints must only emit classes present in CSS (`velinstyle blueprint --strict`)._');
103
+ return lines.filter(Boolean).join('\n');
104
+ }
105
+
106
+ export function skillsInstall(argv = []) {
107
+ const selection = argv[0];
108
+ if (!selection) {
109
+ console.error('Usage: velinstyle skills install <skill-id|pack|bundle:id|project:id>');
110
+ process.exit(1);
111
+ }
112
+ const target = resolve(argValue(argv, '--target') || '.cursor/skills');
113
+ mkdirSync(target, { recursive: true });
114
+ const registry = loadSkillRegistry();
115
+ const result = installSelection(registry, {
116
+ selection,
117
+ skillsRoot: SKILLS_ROOT,
118
+ targetRoot: target,
119
+ includeDependencies: !hasFlag(argv, '--no-deps'),
120
+ });
121
+ for (const installed of result.installed) console.log(`Installed ${installed}`);
122
+ if (result.issues.length) {
123
+ for (const issue of result.issues) console.warn(`Warning: ${issue}`);
124
+ }
125
+ const markerPath = join(target, 'registry-source.json');
126
+ writeFileSync(markerPath, JSON.stringify({ source: REGISTRY_PATH, installed: result.installed }, null, 2), 'utf-8');
127
+ }
128
+
129
+ export function skillsRun(skillId, argv = []) {
130
+ const registry = loadSkillRegistry();
131
+ const resolved = resolveSkillGraph(registry, skillId);
132
+ if (resolved.issues.length) {
133
+ for (const issue of resolved.issues) console.error(issue);
134
+ process.exit(1);
135
+ }
136
+ const steps = [];
137
+ for (const id of resolved.orderedSkillIds) {
138
+ const skill = findSkillById(registry, id);
139
+ if (!skill) continue;
140
+ steps.push({ id: skill.id, requiresCli: skill.requiresCli || [], onlyIf: skill.onlyIf || [] });
141
+ }
142
+ if (hasFlag(argv, '--json')) {
143
+ console.log(JSON.stringify({ steps }, null, 2));
144
+ return;
145
+ }
146
+ for (const step of steps) {
147
+ console.log(`- ${step.id}`);
148
+ if (step.requiresCli.length) console.log(` cli: ${step.requiresCli.join(', ')}`);
149
+ if (step.onlyIf.length) console.log(` onlyIf: ${step.onlyIf.join(', ')}`);
150
+ }
151
+ }
152
+
153
+ export function skillsValidate() {
154
+ const registry = loadSkillRegistry();
155
+ const result = validateRegistry(registry);
156
+ if (result.errors.length) {
157
+ for (const error of result.errors) console.error(`Error: ${error}`);
158
+ }
159
+ if (result.warnings.length) {
160
+ for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
161
+ }
162
+ console.log(result.ok ? 'skills registry valid' : 'skills registry invalid');
163
+ process.exit(result.ok ? 0 : 1);
164
+ }
165
+
166
+ export async function skillsDoctor(argv = []) {
167
+ const { doctorSkillPaths } = await import('../scripts/check-skills-paths.mjs');
168
+ const result = doctorSkillPaths(PKG_ROOT);
169
+ if (hasFlag(argv, '--json')) {
170
+ console.log(JSON.stringify(result, null, 2));
171
+ process.exit(result.ok ? 0 : 1);
172
+ }
173
+ if (!result.ok) {
174
+ console.error(`skills doctor FAILED (${result.errors.length} missing path(s)):`);
175
+ for (const e of result.errors) console.error(` - ${e}`);
176
+ process.exit(1);
177
+ }
178
+ console.log(`skills doctor OK (${result.checked} paths).`);
179
+ }
180
+
181
+ export function skillsIndex(kind) {
182
+ const registry = loadSkillRegistry();
183
+ const map = {
184
+ packs: registry.packs || [],
185
+ bundles: registry.bundles || [],
186
+ templates: registry.templates || [],
187
+ projects: registry.projects || [],
188
+ graphs: registry.workflowGraphs || [],
189
+ };
190
+ const out = map[kind] || [];
191
+ console.log(JSON.stringify(out, null, 2));
192
+ }
193
+
194
+ export function skillsCommand(argv = []) {
195
+ const sub = argv[0];
196
+ if (!sub || sub === '--help' || sub === '-h') {
197
+ console.log(`Usage: velinstyle skills <subcommand>
198
+
199
+ Subcommands:
200
+ list [--category <id>] [--status <id>] [--json]
201
+ show <skill-id> [--human]
202
+ install <skill-id|pack:id|bundle:id|template:id>
203
+ run <skill-id> [--json] (dry-run / inspect — not apply)
204
+ validate
205
+ doctor [--json] Fail if demo/docs/starter paths missing
206
+ packs | bundles | templates | projects | graphs
207
+ `);
208
+ process.exit(0);
209
+ }
210
+ if (sub === 'list') return skillsList(argv.slice(1));
211
+ if (sub === 'show') return skillsShow(argv[1], argv.slice(2));
212
+ if (sub === 'install') return skillsInstall(argv.slice(1));
213
+ if (sub === 'run') return skillsRun(argv[1], argv.slice(2));
214
+ if (sub === 'validate') return skillsValidate();
215
+ if (sub === 'doctor') return skillsDoctor(argv.slice(1));
216
+ if (sub === 'packs' || sub === 'bundles' || sub === 'templates' || sub === 'projects' || sub === 'graphs') return skillsIndex(sub);
217
+ console.error(`Unknown skills subcommand: ${sub}`);
218
+ process.exit(1);
219
+ }
220
+
221
+ export function getRegistryPathForMeta() {
222
+ return REGISTRY_PATH;
223
+ }
package/cli/wc-api.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Human-readable WC API from source + generated docs tip.
3
+ */
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+
7
+ /**
8
+ * @param {string} pkgRoot
9
+ * @param {string} tag
10
+ */
11
+ export function describeWcApi(pkgRoot, tag) {
12
+ const name = String(tag || '').replace(/^</, '').replace(/>$/, '').trim();
13
+ if (!name.startsWith('velin-')) {
14
+ return { ok: false, error: `Expected a velin-* tag (got "${tag || ''}"). Example: velinstyle wc api velin-toast` };
15
+ }
16
+ const file = join(pkgRoot, 'components', `${name}.js`);
17
+ if (!existsSync(file)) {
18
+ return { ok: false, error: `No source at components/${name}.js` };
19
+ }
20
+ const src = readFileSync(file, 'utf-8');
21
+ const attrs = [...src.matchAll(/static\s+get\s+observedAttributes\(\)\s*\{\s*return\s*\[([^\]]*)\]/gs)]
22
+ .map((m) => m[1].split(',').map((s) => s.replace(/['"`\s]/g, '')).filter(Boolean))
23
+ .flat();
24
+ const methods = [...src.matchAll(/^\s{2}([a-zA-Z_][\w]*)\s*\([^)]*\)\s*\{/gm)]
25
+ .map((m) => m[1])
26
+ .filter((n) => !['constructor', 'connectedCallback', 'disconnectedCallback', 'attributeChangedCallback', 'adoptedCallback'].includes(n));
27
+ const showSig = src.match(/show\s*\(\s*\{([^}]*)\}\s*=\s*\{\s*\}\s*\)/);
28
+ const events = [...src.matchAll(/new\s+CustomEvent\(\s*['"]([^'"]+)['"]/g)].map((m) => m[1]);
29
+ const unique = (arr) => [...new Set(arr)];
30
+
31
+ const docPath = join(pkgRoot, 'docs/generated/components', `${name}.md`);
32
+ const hasDoc = existsSync(docPath);
33
+
34
+ let example = '';
35
+ if (name === 'velin-toast' && showSig) {
36
+ example = `<velin-toast></velin-toast>
37
+ <script type="module">
38
+ const t = document.querySelector('velin-toast');
39
+ t.show({ message: 'Saved', type: 'success', duration: 4000 });
40
+ </script>`;
41
+ } else if (name === 'velin-calendar') {
42
+ example = `<velin-calendar label="Pick a day" value="2026-07-30"></velin-calendar>`;
43
+ } else if (name === 'velin-file-dropzone') {
44
+ example = `<velin-file-dropzone label="Files" accept=".pdf,.png" multiple></velin-file-dropzone>`;
45
+ } else if (name === 'velin-data-table') {
46
+ example = `<velin-data-table label="Rows" page-size="5" filter-input="#q" editable>
47
+ <table>…</table>
48
+ </velin-data-table>`;
49
+ }
50
+
51
+ return {
52
+ ok: true,
53
+ tag: name,
54
+ source: `components/${name}.js`,
55
+ observedAttributes: unique(attrs),
56
+ methods: unique(methods),
57
+ events: unique(events),
58
+ showSignature: showSig ? `show({ ${showSig[1].trim()} } = {})` : null,
59
+ generatedDoc: hasDoc ? `docs/generated/components/${name}.md` : null,
60
+ example: example || null,
61
+ };
62
+ }
63
+
64
+ export function formatWcApi(report) {
65
+ if (!report.ok) return report.error;
66
+ const lines = [
67
+ `# <${report.tag}>`,
68
+ '',
69
+ `Source: \`${report.source}\``,
70
+ report.generatedDoc ? `Generated docs: \`${report.generatedDoc}\`` : 'Generated docs: (missing — run `velinstyle docs generate`)',
71
+ '',
72
+ '## observedAttributes',
73
+ report.observedAttributes.length ? report.observedAttributes.map((a) => `- \`${a}\``).join('\n') : '_none_',
74
+ '',
75
+ '## Methods (from source)',
76
+ report.methods.length ? report.methods.map((m) => `- \`${m}()\``).join('\n') : '_none detected_',
77
+ ];
78
+ if (report.showSignature) {
79
+ lines.push('', '## Toast show()', `\`${report.showSignature}\``);
80
+ }
81
+ if (report.events.length) {
82
+ lines.push('', '## Custom events', report.events.map((e) => `- \`${e}\``).join('\n'));
83
+ }
84
+ if (report.example) {
85
+ lines.push('', '## Example', '```html', report.example, '```');
86
+ }
87
+ lines.push('', '_Tip: offline create projects include `vendor/velinstyle/docs/` mini copies of core WC markdown._');
88
+ return lines.join('\n');
89
+ }
@@ -0,0 +1,42 @@
1
+ import { loadRegistry, resolveWorkflowGraph } from '../packages/skill-engine/src/index.js';
2
+ import { getRegistryPathForMeta } from './skills.js';
3
+
4
+ function hasFlag(argv, flag) {
5
+ return argv.includes(flag);
6
+ }
7
+
8
+ export function workflowCommand(argv = []) {
9
+ const workflowId = argv[0];
10
+ if (!workflowId || workflowId === '--help' || workflowId === '-h') {
11
+ console.log(`Usage: velinstyle workflow <graph-id|project:id> [--json]
12
+
13
+ Examples:
14
+ velinstyle workflow landingpage
15
+ velinstyle workflow project:marketing-site --json
16
+ `);
17
+ process.exit(0);
18
+ }
19
+ const registry = loadRegistry(getRegistryPathForMeta());
20
+ let resolved;
21
+ if (workflowId.startsWith('project:')) {
22
+ const projectId = workflowId.replace('project:', '');
23
+ const project = (registry.projects || []).find((item) => item.id === projectId);
24
+ if (!project) {
25
+ console.error(`Unknown project: ${projectId}`);
26
+ process.exit(1);
27
+ }
28
+ resolved = resolveWorkflowGraph(registry, project.workflowGraph);
29
+ } else {
30
+ resolved = resolveWorkflowGraph(registry, workflowId);
31
+ }
32
+ if (resolved.issues.length) {
33
+ for (const issue of resolved.issues) console.error(issue);
34
+ process.exit(1);
35
+ }
36
+ if (hasFlag(argv, '--json')) {
37
+ console.log(JSON.stringify(resolved, null, 2));
38
+ return;
39
+ }
40
+ console.log(`Workflow steps (${resolved.orderedSteps.length}):`);
41
+ for (const step of resolved.orderedSteps) console.log(`- ${step}`);
42
+ }
@@ -35,6 +35,8 @@ export { default as VelinLiveDot } from './velin-live-dot.js';
35
35
  export { default as VelinCodeBlock } from './velin-code-block.js';
36
36
  export { default as VelinDataTable } from './velin-data-table.js';
37
37
  export { default as VelinFormSummary } from './velin-form-summary.js';
38
+ export { default as VelinCalendar } from './velin-calendar.js';
39
+ export { default as VelinFileDropzone } from './velin-file-dropzone.js';
38
40
  export { default as VelinSearch } from './velin-search.js';
39
41
  export { bindDeclarativeSearch } from './velin-search.js';
40
42
  export { initReveal, initMotion, velinMotion } from './velin-reveal.js';
@@ -5,6 +5,7 @@ export const COMPONENT_LOADERS = {
5
5
  'velin-accordion': () => import('../velin-accordion.js'),
6
6
  'velin-announcer': () => import('../velin-announcer.js'),
7
7
  'velin-bottom-nav': () => import('../velin-bottom-nav.js'),
8
+ 'velin-calendar': () => import('../velin-calendar.js'),
8
9
  'velin-carousel': () => import('../velin-carousel.js'),
9
10
  'velin-code-block': () => import('../velin-code-block.js'),
10
11
  'velin-collapse': () => import('../velin-collapse.js'),
@@ -18,6 +19,7 @@ export const COMPONENT_LOADERS = {
18
19
  'velin-drawer': () => import('../velin-drawer.js'),
19
20
  'velin-dropdown': () => import('../velin-dropdown.js'),
20
21
  'velin-email': () => import('../velin-email.js'),
22
+ 'velin-file-dropzone': () => import('../velin-file-dropzone.js'),
21
23
  'velin-form-summary': () => import('../velin-form-summary.js'),
22
24
  'velin-icon': () => import('../velin-icon.js'),
23
25
  'velin-lightbox': () => import('../velin-lightbox.js'),
@@ -1,20 +1,24 @@
1
- const styles = `
2
- :host {
1
+ const LIGHT_STYLE_ID = 'velin-accordion-light-css';
2
+
3
+ /** Light-DOM styles: ::slotted() cannot target descendants of slotted <details>. */
4
+ const lightStyles = `
5
+ velin-accordion {
3
6
  display: block;
4
7
  border: 1px solid var(--velin-color-border, #ddd);
5
8
  border-radius: var(--velin-radius-md, 0.5rem);
6
9
  overflow: hidden;
7
10
  }
8
- ::slotted(details) {
11
+ velin-accordion details {
9
12
  border-bottom: 1px solid var(--velin-color-border, #ddd);
10
13
  }
11
- ::slotted(details:last-child) {
14
+ velin-accordion details:last-child {
12
15
  border-bottom: none;
13
16
  }
14
- ::slotted(details > summary) {
17
+ velin-accordion details > summary {
15
18
  display: flex;
16
19
  align-items: center;
17
20
  justify-content: space-between;
21
+ gap: var(--velin-space-3, 0.75rem);
18
22
  padding: var(--velin-space-4, 1rem);
19
23
  min-block-size: 2.75rem;
20
24
  font-size: var(--velin-text-base, 1rem);
@@ -23,16 +27,29 @@ const styles = `
23
27
  user-select: none;
24
28
  list-style: none;
25
29
  }
26
- ::slotted(details > summary::-webkit-details-marker) {
30
+ velin-accordion details > summary::-webkit-details-marker {
27
31
  display: none;
28
32
  }
29
- ::slotted(details[open] > summary) {
33
+ velin-accordion details > summary::after {
34
+ content: "";
35
+ flex-shrink: 0;
36
+ inline-size: 0.5rem;
37
+ block-size: 0.5rem;
38
+ border-inline-end: 2px solid currentColor;
39
+ border-block-end: 2px solid currentColor;
40
+ transform: rotate(45deg);
41
+ transition: transform 150ms ease;
42
+ }
43
+ velin-accordion details[open] > summary {
30
44
  background: var(--velin-color-primary-subtle, #eff6ff);
31
45
  color: var(--velin-color-primary, #2563eb);
32
46
  }
33
- ::slotted(details > :not(summary)) {
47
+ velin-accordion details[open] > summary::after {
48
+ transform: rotate(225deg);
49
+ }
50
+ velin-accordion details > :not(summary) {
34
51
  padding: var(--velin-space-4, 1rem) var(--velin-space-5, 1.25rem);
35
- background: var(--velin-color-bg-subtle, #f8fafc);
52
+ background: var(--velin-color-surface-dim, var(--velin-color-bg-subtle, #f8fafc));
36
53
  color: var(--velin-color-text-muted, #64748b);
37
54
  font-size: var(--velin-text-sm, 0.875rem);
38
55
  line-height: 1.6;
@@ -40,16 +57,33 @@ const styles = `
40
57
  }
41
58
  `;
42
59
 
60
+ const shadowStyles = `
61
+ :host {
62
+ display: block;
63
+ }
64
+ `;
65
+
66
+ function ensureLightStyles() {
67
+ if (typeof document === 'undefined') return;
68
+ if (document.getElementById(LIGHT_STYLE_ID)) return;
69
+ const style = document.createElement('style');
70
+ style.id = LIGHT_STYLE_ID;
71
+ style.textContent = lightStyles;
72
+ document.head.appendChild(style);
73
+ }
74
+
43
75
  class VelinAccordion extends HTMLElement {
44
76
  constructor() {
45
77
  super();
46
78
  this.attachShadow({ mode: 'open' });
47
79
  this._onToggle = this._onToggle.bind(this);
80
+ this._onKeydown = this._onKeydown.bind(this);
48
81
  }
49
82
 
50
83
  connectedCallback() {
84
+ ensureLightStyles();
51
85
  this.shadowRoot.innerHTML = `
52
- <style>${styles}</style>
86
+ <style>${shadowStyles}</style>
53
87
  <slot></slot>
54
88
  `;
55
89
 
@@ -57,7 +91,7 @@ class VelinAccordion extends HTMLElement {
57
91
  this._wireDetails();
58
92
 
59
93
  this.addEventListener('toggle', this._onToggle, true);
60
- this.addEventListener('keydown', this._onKeydown.bind(this));
94
+ this.addEventListener('keydown', this._onKeydown);
61
95
  }
62
96
 
63
97
  _wireDetails() {
@@ -69,14 +103,24 @@ class VelinAccordion extends HTMLElement {
69
103
  if (panel && !panel.id) panel.id = panelId;
70
104
  if (summary && panel) {
71
105
  summary.setAttribute('aria-controls', panelId);
106
+ summary.setAttribute('aria-expanded', details.open ? 'true' : 'false');
107
+ }
108
+ if (summary && !summary.hasAttribute('tabindex')) {
109
+ summary.setAttribute('tabindex', '0');
72
110
  }
73
111
  }
74
112
  }
75
113
 
76
114
  _onToggle(event) {
77
- if (!this._exclusive) return;
78
115
  const openedDetail = event.target;
79
- if (!openedDetail.open) return;
116
+ if (!(openedDetail instanceof HTMLDetailsElement)) return;
117
+
118
+ const summary = openedDetail.querySelector('summary');
119
+ if (summary) {
120
+ summary.setAttribute('aria-expanded', openedDetail.open ? 'true' : 'false');
121
+ }
122
+
123
+ if (!this._exclusive || !openedDetail.open) return;
80
124
 
81
125
  const details = [...this.querySelectorAll('details')];
82
126
  details.forEach((d) => {
@@ -109,6 +153,10 @@ class VelinAccordion extends HTMLElement {
109
153
  event.preventDefault();
110
154
  nextIndex = summaries.length - 1;
111
155
  break;
156
+ case 'Enter':
157
+ case ' ':
158
+ // Native summary already toggles on Enter/Space; don't double-handle.
159
+ return;
112
160
  default:
113
161
  return;
114
162
  }
@@ -117,6 +165,7 @@ class VelinAccordion extends HTMLElement {
117
165
 
118
166
  disconnectedCallback() {
119
167
  this.removeEventListener('toggle', this._onToggle, true);
168
+ this.removeEventListener('keydown', this._onKeydown);
120
169
  }
121
170
  }
122
171
 
@@ -69,6 +69,16 @@ class VelinBottomNav extends HTMLElement {
69
69
  }
70
70
  if (el.tagName === 'A' && !el.getAttribute('href')) {
71
71
  el.setAttribute('role', 'button');
72
+ if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '0');
73
+ if (!el._velinBottomNavKey) {
74
+ el._velinBottomNavKey = (e) => {
75
+ if (e.key === 'Enter' || e.key === ' ') {
76
+ e.preventDefault();
77
+ el.click();
78
+ }
79
+ };
80
+ el.addEventListener('keydown', el._velinBottomNavKey);
81
+ }
72
82
  }
73
83
  });
74
84
  }