@birdapi/velinstyle 1.0.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 (321) hide show
  1. package/README.de.md +87 -158
  2. package/README.md +188 -115
  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-a11y.js +4 -2
  27. package/cli/docgen/extract-attributes.js +126 -10
  28. package/cli/docgen/extract-cli.js +3 -2
  29. package/cli/docgen/extract-components.js +61 -2
  30. package/cli/docgen/extract-utilities.js +10 -10
  31. package/cli/doctor.js +119 -0
  32. package/cli/index.js +535 -46
  33. package/cli/meta.js +84 -1
  34. package/cli/perf-audit.js +15 -2
  35. package/cli/prompt-engine.js +243 -0
  36. package/cli/review.js +268 -0
  37. package/cli/scaffold.js +119 -4
  38. package/cli/scanner-rules-data.js +7 -0
  39. package/cli/scanner.js +357 -4
  40. package/cli/serve.js +81 -0
  41. package/cli/skills.js +223 -0
  42. package/cli/wc-api.js +89 -0
  43. package/cli/workflow.js +42 -0
  44. package/components/index.js +4 -0
  45. package/components/runtime/component-loaders.js +4 -0
  46. package/components/velin-accordion.js +62 -13
  47. package/components/velin-bottom-nav.js +10 -0
  48. package/components/velin-calendar.js +212 -0
  49. package/components/velin-command.js +18 -2
  50. package/components/velin-data-table.js +438 -0
  51. package/components/velin-dialog.js +4 -1
  52. package/components/velin-drawer.js +2 -4
  53. package/components/velin-file-dropzone.js +162 -0
  54. package/components/velin-form-summary.js +348 -0
  55. package/components/velin-icon.js +22 -1
  56. package/components/velin-lightbox.js +5 -3
  57. package/components/velin-modal.js +2 -4
  58. package/components/velin-search.js +1 -1
  59. package/components/velin-sheet.js +2 -4
  60. package/core/a11y/component-contracts.json +35 -1
  61. package/core/highlight/languages/go.js +28 -0
  62. package/core/highlight/languages/python.js +29 -0
  63. package/core/highlight/languages/rust.js +32 -0
  64. package/core/highlight/languages/yaml.js +23 -0
  65. package/core/highlight/registry.js +13 -2
  66. package/core/meta/build.js +126 -6
  67. package/core/meta/design-constraints/contact.json +9 -0
  68. package/core/meta/design-constraints/faq.json +9 -0
  69. package/core/meta/design-constraints/hero.json +13 -0
  70. package/core/meta/knowledge/components.json +622 -0
  71. package/core/meta/knowledge/tokens.json +282 -0
  72. package/core/meta/pages/registry.json +294 -0
  73. package/core/meta/schema.js +3 -1
  74. package/core/meta/sections/registry.json +185 -0
  75. package/dist/chunks/{attributes-TPANLMLF.js → attributes-A423NX5J.js} +3 -3
  76. package/dist/chunks/{attributes-ADOKLKA7.js → attributes-F6UPIEVP.js} +2 -2
  77. package/dist/chunks/{attributes-STYCS3O5.js → attributes-GLYXGGAL.js} +3 -3
  78. package/dist/chunks/{attributes-5Q2WXGRC.js → attributes-UFTYOSAU.js} +20 -3
  79. package/dist/chunks/attributes-XGLXLR2T.js +391 -0
  80. package/dist/chunks/attributes-YF4NI2QS.js +391 -0
  81. package/dist/chunks/browser-AUABBYUK.js +1544 -0
  82. package/dist/chunks/{chunk-SRL6EWHP.js → chunk-2LSKX57P.js} +13 -11
  83. package/dist/chunks/{chunk-RSMRR27R.js → chunk-2TGCVDUL.js} +11 -9
  84. package/dist/chunks/{chunk-XIET2VSZ.js → chunk-5JWGUAPC.js} +17 -13
  85. package/dist/chunks/chunk-7YSO2OQ2.js +113 -0
  86. package/dist/chunks/{chunk-IEHKRARD.js → chunk-BHR3ZG6U.js} +10 -8
  87. package/dist/chunks/{chunk-J472ERN2.js → chunk-ERF5YVP4.js} +15 -4
  88. package/dist/chunks/{chunk-XYLJ2GCB.js → chunk-JMSIHEYX.js} +55 -7
  89. package/dist/chunks/{chunk-MKZP2TBH.js → chunk-L7ZGUU4D.js} +2 -2
  90. package/dist/chunks/chunk-TUGIPKW5.js +113 -0
  91. package/dist/chunks/go-HZ6XTFCK.js +31 -0
  92. package/dist/chunks/{highlight-GJHHV4KM.js → highlight-IBDX4XWS.js} +1 -1
  93. package/dist/chunks/{highlight-XTHRKBA3.js → highlight-M2ELQNYK.js} +1 -1
  94. package/dist/chunks/python-BMPKDKNO.js +32 -0
  95. package/dist/chunks/runtime-entry.js +1 -1
  96. package/dist/chunks/rust-2BWKI2MN.js +35 -0
  97. package/dist/chunks/{velin-accordion-FBIPAEXG.js → velin-accordion-WSY6BMLA.js} +64 -10
  98. package/dist/chunks/{velin-bottom-nav-7GEMPIM6.js → velin-bottom-nav-5RVRNGIP.js} +25 -0
  99. package/dist/chunks/{velin-bottom-nav-2N2TYWOF.js → velin-bottom-nav-N5F4UO2I.js} +26 -1
  100. package/dist/chunks/velin-calendar-OFE6THUD.js +210 -0
  101. package/dist/chunks/velin-calendar-PGVNJTXK.js +217 -0
  102. package/dist/chunks/velin-calendar-XC7JRDSH.js +217 -0
  103. package/dist/chunks/{velin-code-block-CIAURDRJ.js → velin-code-block-ITCLIC6T.js} +1 -1
  104. package/dist/chunks/{velin-code-block-TSUKPY4C.js → velin-code-block-ZGWG7JI5.js} +12 -3
  105. package/dist/chunks/{velin-combobox-NXS4QB4R.js → velin-combobox-56V2ZWT5.js} +1 -1
  106. package/dist/chunks/{velin-command-ONKO2A3J.js → velin-command-2HO2EKR6.js} +29 -2
  107. package/dist/chunks/{velin-command-TMLSRGIU.js → velin-command-ZJSLPK7B.js} +30 -3
  108. package/dist/chunks/{velin-copy-NYDBOKXT.js → velin-copy-XDQSV2XU.js} +1 -1
  109. package/dist/chunks/{velin-countdown-4ZVDGK4R.js → velin-countdown-V4Z5MA63.js} +1 -1
  110. package/dist/chunks/velin-data-table-KK7IDGTP.js +302 -0
  111. package/dist/chunks/velin-data-table-UVR42UUM.js +372 -0
  112. package/dist/chunks/{velin-dialog-GTTZI564.js → velin-dialog-3YK2RPRV.js} +9 -2
  113. package/dist/chunks/{velin-dialog-ELFOZIXZ.js → velin-dialog-S24KAP4S.js} +3 -1
  114. package/dist/chunks/{velin-drawer-BE6TYN3H.js → velin-drawer-5PNU624J.js} +2 -4
  115. package/dist/chunks/{velin-drawer-DLL2GLT6.js → velin-drawer-CCM6S25D.js} +3 -5
  116. package/dist/chunks/{velin-email-RBX6ZR4S.js → velin-email-TNFONXPW.js} +1 -1
  117. package/dist/chunks/velin-file-dropzone-QRGF2JNA.js +154 -0
  118. package/dist/chunks/velin-file-dropzone-XIZMJ3NB.js +154 -0
  119. package/dist/chunks/velin-form-summary-XRQ7COQH.js +273 -0
  120. package/dist/chunks/{velin-icon-7M76DOPB.js → velin-icon-A6NCXGUK.js} +59 -17
  121. package/dist/chunks/{velin-icon-ZTSKUOVN.js → velin-icon-EC4B5XCM.js} +18 -5
  122. package/dist/chunks/{velin-lightbox-6E7CAATP.js → velin-lightbox-FFK4TUUP.js} +7 -6
  123. package/dist/chunks/{velin-lightbox-I75U6JF4.js → velin-lightbox-P725FLTY.js} +15 -5
  124. package/dist/chunks/{velin-menubar-J66JXRWW.js → velin-menubar-6I2LM5HL.js} +1 -1
  125. package/dist/chunks/{velin-modal-5HYNNNUI.js → velin-modal-ICTMGRSU.js} +7 -8
  126. package/dist/chunks/{velin-modal-AEOTZ67O.js → velin-modal-JBNODH7D.js} +2 -4
  127. package/dist/chunks/{velin-popover-T72HK3DF.js → velin-popover-WZG2GHBL.js} +25 -4
  128. package/dist/chunks/{velin-rating-N4DI2XNL.js → velin-rating-QBBYRRBU.js} +1 -1
  129. package/dist/chunks/{velin-search-7B4KJ6TX.js → velin-search-B3L6J2RP.js} +2 -2
  130. package/dist/chunks/{velin-search-2XRQFBCS.js → velin-search-L3UG6NDQ.js} +5 -4
  131. package/dist/chunks/{velin-secure-field-6PV7RZDJ.js → velin-secure-field-DGYMP7OK.js} +1 -1
  132. package/dist/chunks/{velin-segmented-control-GYD5BIXQ.js → velin-segmented-control-P74GJPAR.js} +1 -1
  133. package/dist/chunks/{velin-sheet-R2Y67X6H.js → velin-sheet-M5GZZD7G.js} +2 -4
  134. package/dist/chunks/{velin-sheet-OUK6572T.js → velin-sheet-X7RXIWKV.js} +3 -5
  135. package/dist/chunks/{velin-stepper-X54WGHDG.js → velin-stepper-4YQJUHPC.js} +12 -5
  136. package/dist/chunks/{velin-toast-OMMOA2DK.js → velin-toast-UG5LWTG2.js} +5 -1
  137. package/dist/chunks/{velin-tooltip-BDHGRTQB.js → velin-tooltip-ZDH5SDLU.js} +1 -1
  138. package/dist/chunks/yaml-O67LEQYT.js +26 -0
  139. package/dist/llms.txt +29 -7
  140. package/dist/search-index.json +182 -10
  141. package/dist/velin-agent.json +3997 -26
  142. package/dist/velinstyle-components.iife.js +1952 -287
  143. package/dist/velinstyle-components.js +1956 -287
  144. package/dist/velinstyle-components.min.js +267 -119
  145. package/dist/velinstyle.css +381 -67
  146. package/dist/velinstyle.d.ts +4 -0
  147. package/dist/velinstyle.min.css +1 -1
  148. package/package.json +26 -6
  149. package/packages/skill-engine/README.md +24 -0
  150. package/packages/skill-engine/package.json +7 -0
  151. package/packages/skill-engine/src/catalog.js +29 -0
  152. package/packages/skill-engine/src/index.js +5 -0
  153. package/packages/skill-engine/src/install.js +69 -0
  154. package/packages/skill-engine/src/registry.js +27 -0
  155. package/packages/skill-engine/src/resolve.js +68 -0
  156. package/packages/skill-engine/src/validate.js +40 -0
  157. package/packages/velinstyle-skills/README.md +6 -0
  158. package/packages/velinstyle-skills/adapter.json +8 -0
  159. package/packages/velinstyle-skills/bundles/landing-starter.bundle.yaml +12 -0
  160. package/packages/velinstyle-skills/bundles/review-suite.bundle.yaml +11 -0
  161. package/packages/velinstyle-skills/catalog.json +1004 -0
  162. package/packages/velinstyle-skills/graphs/component-ship.graph.yaml +14 -0
  163. package/packages/velinstyle-skills/graphs/landingpage.graph.yaml +21 -0
  164. package/packages/velinstyle-skills/graphs/release-gate.graph.yaml +15 -0
  165. package/packages/velinstyle-skills/index.js +22 -0
  166. package/packages/velinstyle-skills/package.json +7 -0
  167. package/packages/velinstyle-skills/packs/accessibility.pack.yaml +9 -0
  168. package/packages/velinstyle-skills/packs/design.pack.yaml +10 -0
  169. package/packages/velinstyle-skills/packs/documentation.pack.yaml +8 -0
  170. package/packages/velinstyle-skills/packs/enterprise.pack.yaml +10 -0
  171. package/packages/velinstyle-skills/packs/frontend.pack.yaml +10 -0
  172. package/packages/velinstyle-skills/packs/review.pack.yaml +9 -0
  173. package/packages/velinstyle-skills/projects/admin-panel.project.yaml +12 -0
  174. package/packages/velinstyle-skills/projects/blog.project.yaml +11 -0
  175. package/packages/velinstyle-skills/projects/documentation-portal.project.yaml +13 -0
  176. package/packages/velinstyle-skills/projects/ecommerce-shop.project.yaml +12 -0
  177. package/packages/velinstyle-skills/projects/landing-page.project.yaml +12 -0
  178. package/packages/velinstyle-skills/projects/laravel-dashboard.project.yaml +12 -0
  179. package/packages/velinstyle-skills/projects/marketing-website.project.yaml +14 -0
  180. package/packages/velinstyle-skills/projects/portfolio.project.yaml +12 -0
  181. package/packages/velinstyle-skills/registry.json +142 -0
  182. package/packages/velinstyle-skills/scripts/generate-assets.mjs +163 -0
  183. package/packages/velinstyle-skills/skills/velin-a11y-focus-keyboard/SKILL.md +57 -0
  184. package/packages/velinstyle-skills/skills/velin-a11y-page-checklist/SKILL.md +57 -0
  185. package/packages/velinstyle-skills/skills/velin-a11y-scan-fix/SKILL.md +57 -0
  186. package/packages/velinstyle-skills/skills/velin-ai-agent-briefing/SKILL.md +57 -0
  187. package/packages/velinstyle-skills/skills/velin-ai-plan-scaffold-review/SKILL.md +57 -0
  188. package/packages/velinstyle-skills/skills/velin-ai-skill-authoring/SKILL.md +57 -0
  189. package/packages/velinstyle-skills/skills/velin-components-accessibility-map/SKILL.md +57 -0
  190. package/packages/velinstyle-skills/skills/velin-components-api-contract/SKILL.md +57 -0
  191. package/packages/velinstyle-skills/skills/velin-components-recipe/SKILL.md +57 -0
  192. package/packages/velinstyle-skills/skills/velin-components-select-compose/SKILL.md +57 -0
  193. package/packages/velinstyle-skills/skills/velin-design-hero-compose/SKILL.md +57 -0
  194. package/packages/velinstyle-skills/skills/velin-design-section-rhythm/SKILL.md +57 -0
  195. package/packages/velinstyle-skills/skills/velin-design-surface-roles/SKILL.md +57 -0
  196. package/packages/velinstyle-skills/skills/velin-dev-component-wire/SKILL.md +57 -0
  197. package/packages/velinstyle-skills/skills/velin-dev-page-scaffold/SKILL.md +57 -0
  198. package/packages/velinstyle-skills/skills/velin-dev-plan-first/SKILL.md +57 -0
  199. package/packages/velinstyle-skills/skills/velin-docs-component-guide/SKILL.md +57 -0
  200. package/packages/velinstyle-skills/skills/velin-docs-generate-api/SKILL.md +57 -0
  201. package/packages/velinstyle-skills/skills/velin-dx-doctor-setup/SKILL.md +57 -0
  202. package/packages/velinstyle-skills/skills/velin-dx-project-init/SKILL.md +57 -0
  203. package/packages/velinstyle-skills/skills/velin-migration-legacy-wc/SKILL.md +57 -0
  204. package/packages/velinstyle-skills/skills/velin-migration-prefix-classes/SKILL.md +57 -0
  205. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +57 -0
  206. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +57 -0
  207. package/packages/velinstyle-skills/skills/velin-perf-audit-fix/SKILL.md +57 -0
  208. package/packages/velinstyle-skills/skills/velin-perf-runtime-tree-shake/SKILL.md +57 -0
  209. package/packages/velinstyle-skills/skills/velin-release-changelog-sync/SKILL.md +57 -0
  210. package/packages/velinstyle-skills/skills/velin-release-meta-rebuild/SKILL.md +57 -0
  211. package/packages/velinstyle-skills/skills/velin-review-conversion-hero/SKILL.md +57 -0
  212. package/packages/velinstyle-skills/skills/velin-review-page-gate/SKILL.md +57 -0
  213. package/packages/velinstyle-skills/skills/velin-review-seo-meta/SKILL.md +57 -0
  214. package/packages/velinstyle-skills/skills/velin-security-sanitize-html/SKILL.md +57 -0
  215. package/packages/velinstyle-skills/skills/velin-security-scan-pii/SKILL.md +57 -0
  216. package/packages/velinstyle-skills/skills/velin-testing-a11y-suite/SKILL.md +57 -0
  217. package/packages/velinstyle-skills/skills/velin-testing-visual-smoke/SKILL.md +57 -0
  218. package/packages/velinstyle-skills/skills/velin-themes-apply-token/SKILL.md +57 -0
  219. package/packages/velinstyle-skills/skills/velin-themes-contrast-check/SKILL.md +57 -0
  220. package/packages/velinstyle-skills/skills/velin-utilities-layout-apply/SKILL.md +57 -0
  221. package/packages/velinstyle-skills/skills/velin-utilities-prefix-fix/SKILL.md +57 -0
  222. package/packages/velinstyle-skills/skills/velin-utilities-token-map/SKILL.md +57 -0
  223. package/packages/velinstyle-skills/templates/admin-panel.template.yaml +12 -0
  224. package/packages/velinstyle-skills/templates/blog.template.yaml +12 -0
  225. package/packages/velinstyle-skills/templates/documentation-portal.template.yaml +12 -0
  226. package/packages/velinstyle-skills/templates/ecommerce-shop.template.yaml +13 -0
  227. package/packages/velinstyle-skills/templates/landing-page.template.yaml +12 -0
  228. package/packages/velinstyle-skills/templates/laravel-dashboard.template.yaml +11 -0
  229. package/packages/velinstyle-skills/templates/marketing-website.template.yaml +13 -0
  230. package/packages/velinstyle-skills/templates/portfolio.template.yaml +12 -0
  231. package/schemas/component-knowledge.schema.json +33 -0
  232. package/schemas/design-constraint.schema.json +15 -0
  233. package/schemas/design-intelligence.schema.json +19 -0
  234. package/schemas/design-rule.schema.json +19 -0
  235. package/schemas/page-template.schema.json +24 -0
  236. package/schemas/review-report.schema.json +36 -0
  237. package/schemas/section.schema.json +22 -0
  238. package/schemas/skill-bundle.schema.json +15 -0
  239. package/schemas/skill-graph.schema.json +25 -0
  240. package/schemas/skill-pack.schema.json +14 -0
  241. package/schemas/skill-project.schema.json +16 -0
  242. package/schemas/skill-record.schema.json +27 -0
  243. package/schemas/skill-registry.schema.json +17 -0
  244. package/schemas/skill-template.schema.json +17 -0
  245. package/schemas/token-graph.schema.json +27 -0
  246. package/schemas/utility.schema.json +166 -0
  247. package/src/base/wc-placeholder.css +7 -0
  248. package/src/components/alert.css +22 -1
  249. package/src/components/calendar-dropzone.css +5 -0
  250. package/src/components/data-table.css +93 -0
  251. package/src/components/form-validation.css +40 -0
  252. package/src/layout/app-shell.css +33 -0
  253. package/src/tokens/shadow.css +13 -0
  254. package/src/utilities/border.css +2 -0
  255. package/src/utilities/display.css +1 -24
  256. package/src/utilities/responsive.css +16 -1
  257. package/src/utilities/spacing.css +32 -0
  258. package/src/velinstyle.css +3 -0
  259. package/dist/chunks/attributes-3BZLI7XF.js +0 -364
  260. package/dist/chunks/attributes-4N5JP4CG.js +0 -364
  261. package/dist/chunks/attributes-AIR7SVLK.js +0 -364
  262. package/dist/chunks/attributes-BGRN5XZO.js +0 -364
  263. package/dist/chunks/attributes-BVSQAYLR.js +0 -364
  264. package/dist/chunks/attributes-CDYFUY7Y.js +0 -364
  265. package/dist/chunks/attributes-JMYJZBPE.js +0 -364
  266. package/dist/chunks/attributes-R5JY3X4O.js +0 -374
  267. package/dist/chunks/attributes-TNSPQTHX.js +0 -374
  268. package/dist/chunks/chunk-2354NEBP.js +0 -109
  269. package/dist/chunks/chunk-2VNA7G7S.js +0 -109
  270. package/dist/chunks/chunk-AQLRJSGG.js +0 -109
  271. package/dist/chunks/chunk-EWPSDMQT.js +0 -109
  272. package/dist/chunks/chunk-LA7264K4.js +0 -85
  273. package/dist/chunks/chunk-QTJJ3DPO.js +0 -109
  274. package/dist/chunks/chunk-RZQVWFHW.js +0 -109
  275. package/dist/chunks/chunk-U4XHMZ7D.js +0 -109
  276. package/dist/chunks/chunk-V5YIUA6G.js +0 -109
  277. package/dist/chunks/chunk-ZPSPKUYD.js +0 -109
  278. package/dist/chunks/velin-bottom-nav-N3DFQR66.js +0 -86
  279. package/dist/chunks/velin-carousel-Y5VCOABZ.js +0 -213
  280. package/dist/chunks/velin-code-block-ASUBTAQV.js +0 -119
  281. package/dist/chunks/velin-code-block-Y6CM726Q.js +0 -119
  282. package/dist/chunks/velin-combobox-2KDTCQ7N.js +0 -155
  283. package/dist/chunks/velin-command-M7RNHUPR.js +0 -136
  284. package/dist/chunks/velin-copy-T5KDTDXP.js +0 -81
  285. package/dist/chunks/velin-countdown-5XSTN3BH.js +0 -101
  286. package/dist/chunks/velin-counter-ISCTEAHI.js +0 -118
  287. package/dist/chunks/velin-dialog-D2GUHSCD.js +0 -144
  288. package/dist/chunks/velin-dialog-IJLFDXAJ.js +0 -144
  289. package/dist/chunks/velin-dialog-TNS3WXMB.js +0 -144
  290. package/dist/chunks/velin-drawer-MJS6WCF7.js +0 -130
  291. package/dist/chunks/velin-email-N5B5ZYTE.js +0 -90
  292. package/dist/chunks/velin-icon-KZO3IEHG.js +0 -164
  293. package/dist/chunks/velin-lightbox-QOTB4PRL.js +0 -140
  294. package/dist/chunks/velin-lightbox-UCD6N7HF.js +0 -140
  295. package/dist/chunks/velin-live-dot-XHUZCIDZ.js +0 -67
  296. package/dist/chunks/velin-menubar-SFEXJE56.js +0 -86
  297. package/dist/chunks/velin-modal-2HOBXE6F.js +0 -176
  298. package/dist/chunks/velin-modal-GLI2XZZB.js +0 -176
  299. package/dist/chunks/velin-popover-EXINRIGJ.js +0 -145
  300. package/dist/chunks/velin-popover-OXX7MRZ6.js +0 -145
  301. package/dist/chunks/velin-popover-YKCCROJG.js +0 -145
  302. package/dist/chunks/velin-rating-XRQJV4LO.js +0 -91
  303. package/dist/chunks/velin-scroll-top-F2FCZNYD.js +0 -58
  304. package/dist/chunks/velin-search-4YHJWYSS.js +0 -556
  305. package/dist/chunks/velin-search-LWHY23Q5.js +0 -474
  306. package/dist/chunks/velin-secure-field-H7FSBUJW.js +0 -95
  307. package/dist/chunks/velin-segmented-control-PQX6LKOJ.js +0 -109
  308. package/dist/chunks/velin-sheet-3OGI4HD7.js +0 -119
  309. package/dist/chunks/velin-sparkline-GVEANJVW.js +0 -184
  310. package/dist/chunks/velin-sparkline-KDA3GQAN.js +0 -162
  311. package/dist/chunks/velin-stepper-2ZIHLKGM.js +0 -141
  312. package/dist/chunks/velin-stepper-FYEUEWE6.js +0 -141
  313. package/dist/chunks/velin-stepper-wc-QU3KRVQR.js +0 -133
  314. package/dist/chunks/velin-theme-toggle-BNNS7WLV.js +0 -285
  315. package/dist/chunks/velin-theme-toggle-NO7V4TWI.js +0 -285
  316. package/dist/chunks/velin-theme-toggle-QELCJM2Q.js +0 -291
  317. package/dist/chunks/velin-toast-RCZ4CSUC.js +0 -109
  318. package/dist/chunks/velin-toast-WEUBTJG6.js +0 -109
  319. package/dist/chunks/velin-tooltip-664IOHZA.js +0 -112
  320. package/dist/chunks/velin-tooltip-wc-LXDVT6DE.js +0 -103
  321. package/dist/chunks/worker-client-R6DBYPFT.js +0 -46
@@ -0,0 +1,273 @@
1
+ import {
2
+ announce
3
+ } from "./chunk-Z4JYQ2XX.js";
4
+
5
+ // components/velin-form-summary.js
6
+ var FIELD_SELECTOR = "input, select, textarea";
7
+ var IGNORED_TYPES = /* @__PURE__ */ new Set(["submit", "reset", "button", "image", "hidden"]);
8
+ var fieldIdCounter = 0;
9
+ function escapeSelector(value) {
10
+ const text = String(value ?? "");
11
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") return CSS.escape(text);
12
+ return text.replace(/[^\w-]/g, (char) => `\\${char}`);
13
+ }
14
+ function fieldLabel(field) {
15
+ const explicit = field.getAttribute("data-error-label");
16
+ if (explicit) return explicit;
17
+ const ariaLabel = field.getAttribute("aria-label");
18
+ if (ariaLabel?.trim()) return ariaLabel.trim();
19
+ const labelledBy = field.getAttribute("aria-labelledby");
20
+ if (labelledBy) {
21
+ const text = labelledBy.split(/\s+/).map((id) => field.ownerDocument.getElementById(id)?.textContent?.trim() || "").filter(Boolean).join(" ");
22
+ if (text) return text;
23
+ }
24
+ if (field.id) {
25
+ const label = field.ownerDocument.querySelector(`label[for="${escapeSelector(field.id)}"]`);
26
+ if (label?.textContent.trim()) return label.textContent.trim();
27
+ }
28
+ const wrapping = field.closest("label");
29
+ if (wrapping?.textContent.trim()) return wrapping.textContent.trim();
30
+ return field.name || "This field";
31
+ }
32
+ function fieldMessage(field) {
33
+ return field.getAttribute("data-error-message")?.trim() || field.validationMessage || "Invalid value";
34
+ }
35
+ function addDescribedBy(field, id) {
36
+ const ids = (field.getAttribute("aria-describedby") || "").split(/\s+/).filter(Boolean);
37
+ if (!ids.includes(id)) {
38
+ ids.push(id);
39
+ field.setAttribute("aria-describedby", ids.join(" "));
40
+ }
41
+ }
42
+ function removeDescribedBy(field, id) {
43
+ const ids = (field.getAttribute("aria-describedby") || "").split(/\s+/).filter(Boolean);
44
+ const next = ids.filter((value) => value !== id);
45
+ if (next.length) field.setAttribute("aria-describedby", next.join(" "));
46
+ else field.removeAttribute("aria-describedby");
47
+ }
48
+ var VelinFormSummary = class extends HTMLElement {
49
+ static get observedAttributes() {
50
+ return ["for", "heading"];
51
+ }
52
+ constructor() {
53
+ super();
54
+ this._form = null;
55
+ this._panel = null;
56
+ this._errors = [];
57
+ this._onSubmit = this._onSubmit.bind(this);
58
+ this._onFieldChange = this._onFieldChange.bind(this);
59
+ this._onReset = this._onReset.bind(this);
60
+ }
61
+ connectedCallback() {
62
+ this.classList.add("velin-form-summary");
63
+ requestAnimationFrame(() => this._bindForm());
64
+ }
65
+ disconnectedCallback() {
66
+ this._unbindForm();
67
+ }
68
+ attributeChangedCallback(name, previous, next) {
69
+ if (previous === next) return;
70
+ if (name === "for" && this.isConnected) {
71
+ this._unbindForm();
72
+ this._bindForm();
73
+ } else if (name === "heading" && this._panel) {
74
+ const heading = this._panel.querySelector(".velin-form-summary__heading");
75
+ if (heading) heading.textContent = this.headingText;
76
+ }
77
+ }
78
+ // ── Public API ─────────────────────────────────────────────────────────────
79
+ get form() {
80
+ return this._form;
81
+ }
82
+ /** @returns {{ field: HTMLElement, label: string, message: string }[]} */
83
+ get errors() {
84
+ return this._errors.slice();
85
+ }
86
+ get headingText() {
87
+ return this.getAttribute("heading") || "There is a problem";
88
+ }
89
+ /** Validate the form and render the summary. @returns {boolean} valid */
90
+ validate() {
91
+ if (!this._form) return true;
92
+ const errors = [];
93
+ for (const field of this._fields()) {
94
+ if (field.checkValidity()) {
95
+ this._clearFieldError(field);
96
+ continue;
97
+ }
98
+ const error = { field, label: fieldLabel(field), message: fieldMessage(field) };
99
+ this._markFieldError(field, error.message);
100
+ errors.push(error);
101
+ }
102
+ this._errors = errors;
103
+ this._render();
104
+ return errors.length === 0;
105
+ }
106
+ /** Remove the summary and all field error state. */
107
+ clear() {
108
+ for (const field of this._fields()) this._clearFieldError(field);
109
+ this._errors = [];
110
+ this._render();
111
+ }
112
+ /** Move focus to the first field with an error. */
113
+ focusFirstError() {
114
+ const first = this._errors[0];
115
+ if (first) this._focusField(first.field);
116
+ }
117
+ // ── Form wiring ────────────────────────────────────────────────────────────
118
+ _bindForm() {
119
+ const id = this.getAttribute("for");
120
+ this._form = id ? this.ownerDocument.getElementById(id) : this.closest("form");
121
+ if (!this._form) return;
122
+ if (!this.hasAttribute("native-validation")) this._form.noValidate = true;
123
+ this._form.addEventListener("submit", this._onSubmit);
124
+ this._form.addEventListener("reset", this._onReset);
125
+ this._form.addEventListener("input", this._onFieldChange);
126
+ this._form.addEventListener("change", this._onFieldChange);
127
+ }
128
+ _unbindForm() {
129
+ if (!this._form) return;
130
+ this._form.removeEventListener("submit", this._onSubmit);
131
+ this._form.removeEventListener("reset", this._onReset);
132
+ this._form.removeEventListener("input", this._onFieldChange);
133
+ this._form.removeEventListener("change", this._onFieldChange);
134
+ this._form = null;
135
+ }
136
+ /** @returns {HTMLElement[]} */
137
+ _fields() {
138
+ if (!this._form) return [];
139
+ const seenRadioNames = /* @__PURE__ */ new Set();
140
+ return [...this._form.querySelectorAll(FIELD_SELECTOR)].filter((field) => {
141
+ if (IGNORED_TYPES.has(field.type)) return false;
142
+ if (field.disabled || field.hasAttribute("data-error-ignore")) return false;
143
+ if (typeof field.checkValidity !== "function") return false;
144
+ if (field.type === "radio" && field.name) {
145
+ if (seenRadioNames.has(field.name)) return false;
146
+ seenRadioNames.add(field.name);
147
+ }
148
+ return true;
149
+ });
150
+ }
151
+ _onSubmit(event) {
152
+ if (this.validate()) return;
153
+ event.preventDefault();
154
+ this._announceErrors();
155
+ this._focusPanel();
156
+ this.dispatchEvent(new CustomEvent("velin-form-invalid", {
157
+ bubbles: true,
158
+ detail: { errors: this.errors.map(({ label, message }) => ({ label, message })) }
159
+ }));
160
+ }
161
+ _onReset() {
162
+ requestAnimationFrame(() => this.clear());
163
+ }
164
+ /** Re-validate a single field once it already had an error, never before. */
165
+ _onFieldChange(event) {
166
+ const field = event.target;
167
+ if (!field || !this._errors.some((error) => error.field === field)) return;
168
+ if (!field.checkValidity()) return;
169
+ this._clearFieldError(field);
170
+ this._errors = this._errors.filter((error) => error.field !== field);
171
+ this._render();
172
+ if (this._errors.length === 0) {
173
+ this.dispatchEvent(new CustomEvent("velin-form-valid", { bubbles: true }));
174
+ }
175
+ }
176
+ // ── Field state ────────────────────────────────────────────────────────────
177
+ /** @param {HTMLElement} field */
178
+ _errorId(field) {
179
+ if (!field.id) field.id = `velin-field-${++fieldIdCounter}`;
180
+ return `${field.id}-error`;
181
+ }
182
+ /**
183
+ * @param {HTMLElement} field
184
+ * @param {string} message
185
+ */
186
+ _markFieldError(field, message) {
187
+ const errorId = this._errorId(field);
188
+ field.setAttribute("aria-invalid", "true");
189
+ let holder = this.ownerDocument.getElementById(errorId);
190
+ if (!holder) {
191
+ holder = this._form.querySelector(`[data-velin-error-for="${escapeSelector(field.name || field.id)}"]`);
192
+ }
193
+ if (!holder) {
194
+ holder = this.ownerDocument.createElement("p");
195
+ holder.dataset.velinErrorGenerated = "true";
196
+ field.insertAdjacentElement("afterend", holder);
197
+ }
198
+ holder.id = errorId;
199
+ holder.classList.add("velin-field-error");
200
+ holder.textContent = message;
201
+ addDescribedBy(field, errorId);
202
+ }
203
+ /** @param {HTMLElement} field */
204
+ _clearFieldError(field) {
205
+ if (!field.id) return;
206
+ const errorId = `${field.id}-error`;
207
+ field.removeAttribute("aria-invalid");
208
+ removeDescribedBy(field, errorId);
209
+ const holder = this.ownerDocument.getElementById(errorId);
210
+ if (!holder) return;
211
+ if (holder.dataset.velinErrorGenerated) holder.remove();
212
+ else holder.textContent = "";
213
+ }
214
+ /** @param {HTMLElement} field */
215
+ _focusField(field) {
216
+ const target = field.type === "radio" && field.name ? this._form.querySelector(`input[type="radio"][name="${escapeSelector(field.name)}"]`) || field : field;
217
+ target.focus();
218
+ this.dispatchEvent(new CustomEvent("velin-form-error-focus", {
219
+ bubbles: true,
220
+ detail: { name: target.name || target.id }
221
+ }));
222
+ }
223
+ // ── Summary panel ──────────────────────────────────────────────────────────
224
+ _render() {
225
+ if (!this._errors.length) {
226
+ this._panel?.remove();
227
+ this._panel = null;
228
+ this.hidden = true;
229
+ return;
230
+ }
231
+ this.hidden = false;
232
+ if (!this._panel?.isConnected) {
233
+ const panel = this.ownerDocument.createElement("div");
234
+ panel.className = "velin-form-summary__panel velin-alert velin-alert--danger";
235
+ panel.setAttribute("role", "alert");
236
+ panel.tabIndex = -1;
237
+ const heading = this.ownerDocument.createElement("p");
238
+ heading.className = "velin-form-summary__heading";
239
+ heading.textContent = this.headingText;
240
+ const list2 = this.ownerDocument.createElement("ul");
241
+ list2.className = "velin-form-summary__list";
242
+ panel.append(heading, list2);
243
+ this.appendChild(panel);
244
+ this._panel = panel;
245
+ }
246
+ const list = this._panel.querySelector(".velin-form-summary__list");
247
+ list.textContent = "";
248
+ for (const error of this._errors) {
249
+ const item = this.ownerDocument.createElement("li");
250
+ const link = this.ownerDocument.createElement("a");
251
+ link.href = `#${this._errorId(error.field).replace(/-error$/, "")}`;
252
+ link.textContent = `${error.label}: ${error.message}`;
253
+ link.addEventListener("click", (event) => {
254
+ event.preventDefault();
255
+ this._focusField(error.field);
256
+ });
257
+ item.appendChild(link);
258
+ list.appendChild(item);
259
+ }
260
+ }
261
+ _focusPanel() {
262
+ this._panel?.focus();
263
+ }
264
+ _announceErrors() {
265
+ const count = this._errors.length;
266
+ announce(count === 1 ? "1 field needs attention" : `${count} fields need attention`, "assertive");
267
+ }
268
+ };
269
+ customElements.define("velin-form-summary", VelinFormSummary);
270
+ var velin_form_summary_default = VelinFormSummary;
271
+ export {
272
+ velin_form_summary_default as default
273
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  sanitizeSVG,
3
3
  sanitizeURL
4
- } from "./chunk-MKZP2TBH.js";
4
+ } from "./chunk-L7ZGUU4D.js";
5
5
 
6
6
  // components/velin-icon.js
7
7
  var PROVIDER_CDNS = {
@@ -29,7 +29,21 @@ function resolveProviderUrl(provider, variant) {
29
29
  return PROVIDER_CDNS[provider];
30
30
  }
31
31
  var _svgCache = /* @__PURE__ */ new Map();
32
+ var DEFAULT_SPRITE = "velin-icons.svg";
33
+ function resolveDefaultSpriteUrl() {
34
+ if (typeof document !== "undefined") {
35
+ const meta = document.querySelector('meta[name="velin-icon-sprite"]');
36
+ const fromMeta = meta?.getAttribute("content")?.trim();
37
+ if (fromMeta) return fromMeta;
38
+ const fromHtml = document.documentElement?.getAttribute("data-velin-icon-sprite")?.trim();
39
+ if (fromHtml) return fromHtml;
40
+ }
41
+ const configured = typeof VelinIcon.defaultSprite === "string" ? VelinIcon.defaultSprite.trim() : "";
42
+ return configured || DEFAULT_SPRITE;
43
+ }
32
44
  var VelinIcon = class extends HTMLElement {
45
+ /** @type {string} Relative or absolute sprite URL used when `sprite` attribute is omitted. */
46
+ static defaultSprite = DEFAULT_SPRITE;
33
47
  static get observedAttributes() {
34
48
  return ["name", "size", "label", "provider", "variant", "sprite"];
35
49
  }
@@ -46,7 +60,7 @@ var VelinIcon = class extends HTMLElement {
46
60
  _render() {
47
61
  const name = this.getAttribute("name");
48
62
  const size = this.getAttribute("size") || "24";
49
- const label = this.getAttribute("label");
63
+ const a11y = this._resolveA11y();
50
64
  const provider = this.getAttribute("provider");
51
65
  const variant = this.getAttribute("variant");
52
66
  if (!name) {
@@ -54,12 +68,18 @@ var VelinIcon = class extends HTMLElement {
54
68
  return;
55
69
  }
56
70
  if (provider && (PROVIDER_CDNS[provider] || PROVIDER_VARIANTS[provider])) {
57
- this._renderFromCDN(name, size, label, provider, variant);
71
+ this._renderFromCDN(name, size, a11y, provider, variant);
58
72
  return;
59
73
  }
60
- this._renderFromSprite(name, size, label);
74
+ this._renderFromSprite(name, size, a11y);
75
+ }
76
+ _resolveA11y() {
77
+ const label = (this.getAttribute("label") || this.getAttribute("aria-label") || "").trim();
78
+ if (label) return { label, hidden: false };
79
+ const hidden = this.getAttribute("aria-hidden") !== "false";
80
+ return { label: "", hidden };
61
81
  }
62
- _renderFromSprite(name, size, label) {
82
+ _renderFromSprite(name, size, a11y) {
63
83
  const svgNS = "http://www.w3.org/2000/svg";
64
84
  const svg = document.createElementNS(svgNS, "svg");
65
85
  svg.setAttribute("width", size);
@@ -71,7 +91,6 @@ var VelinIcon = class extends HTMLElement {
71
91
  svg.setAttribute("stroke-linecap", "round");
72
92
  svg.setAttribute("stroke-linejoin", "round");
73
93
  this._applyStyle(svg);
74
- this._applyA11y(svg, label);
75
94
  const use = document.createElementNS(svgNS, "use");
76
95
  const spriteAttr = this.getAttribute("sprite");
77
96
  const localSymbol = document.getElementById(name);
@@ -80,29 +99,31 @@ var VelinIcon = class extends HTMLElement {
80
99
  if (spriteAttr === "" || spriteAttr == null && isLocalSymbol) {
81
100
  href = `#${name}`;
82
101
  } else {
83
- const spriteUrl = sanitizeURL(spriteAttr || "/dist/velin-icons.svg") || "/dist/velin-icons.svg";
102
+ const fallback = resolveDefaultSpriteUrl();
103
+ const spriteUrl = sanitizeURL(spriteAttr || fallback) || fallback || DEFAULT_SPRITE;
84
104
  href = `${spriteUrl}#${name}`;
85
105
  }
86
106
  use.setAttribute("href", href);
87
107
  svg.appendChild(use);
108
+ this._applyA11y(svg, a11y);
88
109
  this.innerHTML = "";
89
110
  this.appendChild(svg);
90
111
  this._rendered = true;
91
112
  }
92
- async _renderFromCDN(name, size, label, provider, variant) {
113
+ async _renderFromCDN(name, size, a11y, provider, variant) {
93
114
  const cacheKey = `${provider}:${variant || "default"}:${name}`;
94
115
  if (_svgCache.has(cacheKey)) {
95
- this._injectSVG(_svgCache.get(cacheKey), size, label);
116
+ this._injectSVG(_svgCache.get(cacheKey), size, a11y);
96
117
  return;
97
118
  }
98
119
  const template = resolveProviderUrl(provider, variant);
99
120
  if (!template) {
100
- this._renderFromSprite(name, size, label);
121
+ this._renderFromSprite(name, size, a11y);
101
122
  return;
102
123
  }
103
124
  const url = sanitizeURL(template.replace("{name}", name));
104
125
  if (!url) {
105
- this._renderFromSprite(name, size, label);
126
+ this._renderFromSprite(name, size, a11y);
106
127
  return;
107
128
  }
108
129
  try {
@@ -112,12 +133,20 @@ var VelinIcon = class extends HTMLElement {
112
133
  if (!text.includes("<svg")) throw new Error("Not SVG");
113
134
  const clean = await sanitizeSVG(text);
114
135
  _svgCache.set(cacheKey, clean);
115
- this._injectSVG(clean, size, label);
136
+ this._injectSVG(clean, size, a11y);
116
137
  } catch {
117
- this._renderFromSprite(name, size, label);
138
+ this._renderFromSprite(name, size, a11y);
118
139
  }
119
140
  }
120
- _injectSVG(svgText, size, label) {
141
+ _stripForeignA11y(svg) {
142
+ svg.removeAttribute("role");
143
+ svg.removeAttribute("aria-label");
144
+ svg.removeAttribute("aria-labelledby");
145
+ svg.removeAttribute("aria-hidden");
146
+ svg.querySelector("title")?.remove();
147
+ svg.querySelector("desc")?.remove();
148
+ }
149
+ _injectSVG(svgText, size, a11y) {
121
150
  const parser = new DOMParser();
122
151
  const doc = parser.parseFromString(svgText, "image/svg+xml");
123
152
  const svg = doc.querySelector("svg");
@@ -125,11 +154,12 @@ var VelinIcon = class extends HTMLElement {
125
154
  this.innerHTML = "";
126
155
  return;
127
156
  }
157
+ this._stripForeignA11y(svg);
128
158
  svg.setAttribute("width", size);
129
159
  svg.setAttribute("height", size);
130
160
  if (!svg.getAttribute("viewBox")) svg.setAttribute("viewBox", "0 0 24 24");
131
161
  this._applyStyle(svg);
132
- this._applyA11y(svg, label);
162
+ this._applyA11y(svg, a11y);
133
163
  this.innerHTML = "";
134
164
  this.appendChild(document.importNode(svg, true));
135
165
  this._rendered = true;
@@ -139,12 +169,24 @@ var VelinIcon = class extends HTMLElement {
139
169
  svg.style.verticalAlign = "middle";
140
170
  svg.style.flexShrink = "0";
141
171
  }
142
- _applyA11y(svg, label) {
172
+ _applyA11y(svg, a11y) {
173
+ const { label, hidden } = a11y;
174
+ const use = svg.querySelector("use");
143
175
  if (label) {
144
176
  svg.setAttribute("role", "img");
145
177
  svg.setAttribute("aria-label", label);
146
- } else {
178
+ svg.removeAttribute("aria-hidden");
179
+ svg.removeAttribute("focusable");
180
+ if (use) use.removeAttribute("aria-hidden");
181
+ } else if (hidden) {
182
+ svg.setAttribute("role", "presentation");
147
183
  svg.setAttribute("aria-hidden", "true");
184
+ svg.setAttribute("focusable", "false");
185
+ svg.removeAttribute("aria-label");
186
+ if (use) {
187
+ use.setAttribute("aria-hidden", "true");
188
+ use.setAttribute("focusable", "false");
189
+ }
148
190
  }
149
191
  }
150
192
  static get providers() {
@@ -29,9 +29,23 @@ function resolveProviderUrl(provider, variant) {
29
29
  return PROVIDER_CDNS[provider];
30
30
  }
31
31
  var _svgCache = /* @__PURE__ */ new Map();
32
+ var DEFAULT_SPRITE = "velin-icons.svg";
33
+ function resolveDefaultSpriteUrl() {
34
+ if (typeof document !== "undefined") {
35
+ const meta = document.querySelector('meta[name="velin-icon-sprite"]');
36
+ const fromMeta = meta?.getAttribute("content")?.trim();
37
+ if (fromMeta) return fromMeta;
38
+ const fromHtml = document.documentElement?.getAttribute("data-velin-icon-sprite")?.trim();
39
+ if (fromHtml) return fromHtml;
40
+ }
41
+ const configured = typeof VelinIcon.defaultSprite === "string" ? VelinIcon.defaultSprite.trim() : "";
42
+ return configured || DEFAULT_SPRITE;
43
+ }
32
44
  var VelinIcon = class extends HTMLElement {
45
+ /** @type {string} Relative or absolute sprite URL used when `sprite` attribute is omitted. */
46
+ static defaultSprite = DEFAULT_SPRITE;
33
47
  static get observedAttributes() {
34
- return ["name", "size", "label", "provider", "variant", "sprite", "aria-hidden", "aria-label"];
48
+ return ["name", "size", "label", "provider", "variant", "sprite"];
35
49
  }
36
50
  constructor() {
37
51
  super();
@@ -77,7 +91,6 @@ var VelinIcon = class extends HTMLElement {
77
91
  svg.setAttribute("stroke-linecap", "round");
78
92
  svg.setAttribute("stroke-linejoin", "round");
79
93
  this._applyStyle(svg);
80
- this._applyA11y(svg, a11y);
81
94
  const use = document.createElementNS(svgNS, "use");
82
95
  const spriteAttr = this.getAttribute("sprite");
83
96
  const localSymbol = document.getElementById(name);
@@ -86,11 +99,13 @@ var VelinIcon = class extends HTMLElement {
86
99
  if (spriteAttr === "" || spriteAttr == null && isLocalSymbol) {
87
100
  href = `#${name}`;
88
101
  } else {
89
- const spriteUrl = sanitizeURL(spriteAttr || "/dist/velin-icons.svg") || "/dist/velin-icons.svg";
102
+ const fallback = resolveDefaultSpriteUrl();
103
+ const spriteUrl = sanitizeURL(spriteAttr || fallback) || fallback || DEFAULT_SPRITE;
90
104
  href = `${spriteUrl}#${name}`;
91
105
  }
92
106
  use.setAttribute("href", href);
93
107
  svg.appendChild(use);
108
+ this._applyA11y(svg, a11y);
94
109
  this.innerHTML = "";
95
110
  this.appendChild(svg);
96
111
  this._rendered = true;
@@ -162,14 +177,12 @@ var VelinIcon = class extends HTMLElement {
162
177
  svg.setAttribute("aria-label", label);
163
178
  svg.removeAttribute("aria-hidden");
164
179
  svg.removeAttribute("focusable");
165
- this.removeAttribute("aria-hidden");
166
180
  if (use) use.removeAttribute("aria-hidden");
167
181
  } else if (hidden) {
168
182
  svg.setAttribute("role", "presentation");
169
183
  svg.setAttribute("aria-hidden", "true");
170
184
  svg.setAttribute("focusable", "false");
171
185
  svg.removeAttribute("aria-label");
172
- this.setAttribute("aria-hidden", "true");
173
186
  if (use) {
174
187
  use.setAttribute("aria-hidden", "true");
175
188
  use.setAttribute("focusable", "false");
@@ -1,11 +1,11 @@
1
- import {
2
- announce
3
- } from "./chunk-Z4JYQ2XX.js";
4
1
  import {
5
2
  clearBackgroundInert,
6
3
  setBackgroundInert,
7
4
  trapFocus
8
5
  } from "./chunk-42VVPW6N.js";
6
+ import {
7
+ announce
8
+ } from "./chunk-Z4JYQ2XX.js";
9
9
  import {
10
10
  escapeHTML,
11
11
  sanitizeURL
@@ -101,7 +101,6 @@ var VelinLightbox = class extends HTMLElement {
101
101
  this.setAttribute("open", "");
102
102
  setBackgroundInert(this);
103
103
  this._render();
104
- document.body.style.overflow = "hidden";
105
104
  const overlay = this.shadowRoot.querySelector(".overlay");
106
105
  overlay.removeEventListener("keydown", this._onTrapKey);
107
106
  overlay.addEventListener("keydown", this._onTrapKey);
@@ -109,14 +108,16 @@ var VelinLightbox = class extends HTMLElement {
109
108
  }
110
109
  close() {
111
110
  this.removeAttribute("open");
112
- clearBackgroundInert();
113
- document.body.style.overflow = "";
111
+ clearBackgroundInert(this);
114
112
  if (this._previousFocus) {
115
113
  this._previousFocus.focus();
116
114
  this._previousFocus = null;
117
115
  }
118
116
  this.dispatchEvent(new CustomEvent("velin-close", { bubbles: true }));
119
117
  }
118
+ disconnectedCallback() {
119
+ clearBackgroundInert(this);
120
+ }
120
121
  _prev() {
121
122
  this._index = (this._index - 1 + this._items.length) % this._items.length;
122
123
  this._render();
@@ -1,10 +1,15 @@
1
1
  import {
2
+ clearBackgroundInert,
3
+ setBackgroundInert,
2
4
  trapFocus
3
5
  } from "./chunk-42VVPW6N.js";
6
+ import {
7
+ announce
8
+ } from "./chunk-Z4JYQ2XX.js";
4
9
  import {
5
10
  escapeHTML,
6
11
  sanitizeURL
7
- } from "./chunk-LA7264K4.js";
12
+ } from "./chunk-L7ZGUU4D.js";
8
13
 
9
14
  // components/velin-lightbox.js
10
15
  var styles = `
@@ -67,7 +72,7 @@ var VelinLightbox = class extends HTMLElement {
67
72
  <div class="content" part="content"></div>
68
73
  <button class="nav nav--next" aria-label="Next">&#8250;</button>
69
74
  <button class="close" aria-label="Close">&times;</button>
70
- <div class="counter" part="counter"></div>
75
+ <div class="counter" part="counter" aria-live="polite" aria-atomic="true"></div>
71
76
  </div>
72
77
  `;
73
78
  const slot = this.shadowRoot.querySelector("slot");
@@ -94,8 +99,8 @@ var VelinLightbox = class extends HTMLElement {
94
99
  this._previousFocus = document.activeElement;
95
100
  this._index = index;
96
101
  this.setAttribute("open", "");
102
+ setBackgroundInert(this);
97
103
  this._render();
98
- document.body.style.overflow = "hidden";
99
104
  const overlay = this.shadowRoot.querySelector(".overlay");
100
105
  overlay.removeEventListener("keydown", this._onTrapKey);
101
106
  overlay.addEventListener("keydown", this._onTrapKey);
@@ -103,13 +108,16 @@ var VelinLightbox = class extends HTMLElement {
103
108
  }
104
109
  close() {
105
110
  this.removeAttribute("open");
106
- document.body.style.overflow = "";
111
+ clearBackgroundInert(this);
107
112
  if (this._previousFocus) {
108
113
  this._previousFocus.focus();
109
114
  this._previousFocus = null;
110
115
  }
111
116
  this.dispatchEvent(new CustomEvent("velin-close", { bubbles: true }));
112
117
  }
118
+ disconnectedCallback() {
119
+ clearBackgroundInert(this);
120
+ }
113
121
  _prev() {
114
122
  this._index = (this._index - 1 + this._items.length) % this._items.length;
115
123
  this._render();
@@ -130,7 +138,9 @@ var VelinLightbox = class extends HTMLElement {
130
138
  container.innerHTML = `<img src="${escapeHTML(src)}" alt="${alt}">`;
131
139
  }
132
140
  const counter = this.shadowRoot.querySelector(".counter");
133
- counter.textContent = `${this._index + 1} / ${this._items.length}`;
141
+ const label = `${this._index + 1} / ${this._items.length}`;
142
+ counter.textContent = label;
143
+ announce(`Slide ${label}`, "polite");
134
144
  }
135
145
  };
136
146
  customElements.define("velin-lightbox", VelinLightbox);
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-42VVPW6N.js";
7
7
  import {
8
8
  escapeHTML
9
- } from "./chunk-LA7264K4.js";
9
+ } from "./chunk-L7ZGUU4D.js";
10
10
 
11
11
  // components/velin-menubar.js
12
12
  var styles = `
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-42VVPW6N.js";
9
9
  import {
10
10
  escapeHTML
11
- } from "./chunk-MKZP2TBH.js";
11
+ } from "./chunk-L7ZGUU4D.js";
12
12
 
13
13
  // components/velin-modal.js
14
14
  var styles = `
@@ -105,14 +105,15 @@ var VelinModal = class extends HTMLElement {
105
105
  this._onKeydown = this._onKeydown.bind(this);
106
106
  }
107
107
  connectedCallback() {
108
- const title = this.getAttribute("title") || "";
108
+ const title = (this.getAttribute("title") || "").trim();
109
109
  const safeTitle = escapeHTML(title);
110
+ const dialogLabel = title ? 'aria-labelledby="velin-modal-title"' : `aria-label="${escapeHTML(this.getAttribute("aria-label") || "Dialog")}"`;
110
111
  this.shadowRoot.innerHTML = `
111
112
  <style>${styles}</style>
112
113
  <div class="overlay" part="overlay">
113
- <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="velin-modal-title" part="dialog">
114
+ <div class="dialog" role="dialog" aria-modal="true" ${dialogLabel} part="dialog">
114
115
  <div class="header" part="header">
115
- <h2 class="title" id="velin-modal-title">${safeTitle}</h2>
116
+ <h2 class="title" id="velin-modal-title"${title ? "" : ' class="velin-sr-only"'}>${safeTitle || "Dialog"}</h2>
116
117
  <button class="close-btn" aria-label="Close" part="close">&#215;</button>
117
118
  </div>
118
119
  <div class="body" part="body"><slot></slot></div>
@@ -145,7 +146,6 @@ var VelinModal = class extends HTMLElement {
145
146
  this._previouslyFocused = saveFocus();
146
147
  setBackgroundInert(this);
147
148
  document.addEventListener("keydown", this._onKeydown);
148
- document.body.style.overflow = "hidden";
149
149
  requestAnimationFrame(() => {
150
150
  const focusable = getFocusableElements(this.shadowRoot);
151
151
  if (focusable.length > 0) focusable[0].focus();
@@ -153,8 +153,7 @@ var VelinModal = class extends HTMLElement {
153
153
  }
154
154
  _close() {
155
155
  document.removeEventListener("keydown", this._onKeydown);
156
- document.body.style.overflow = "";
157
- clearBackgroundInert();
156
+ clearBackgroundInert(this);
158
157
  restoreFocus(this._previouslyFocused);
159
158
  }
160
159
  _onKeydown(event) {
@@ -166,7 +165,7 @@ var VelinModal = class extends HTMLElement {
166
165
  }
167
166
  disconnectedCallback() {
168
167
  document.removeEventListener("keydown", this._onKeydown);
169
- document.body.style.overflow = "";
168
+ clearBackgroundInert(this);
170
169
  }
171
170
  };
172
171
  customElements.define("velin-modal", VelinModal);