@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
@@ -315,7 +315,7 @@ function isRegex(value) {
315
315
  function createDOMPurify() {
316
316
  let window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
317
317
  const DOMPurify = (root) => createDOMPurify(root);
318
- DOMPurify.version = "3.4.5";
318
+ DOMPurify.version = "3.4.12";
319
319
  DOMPurify.removed = [];
320
320
  if (!window2 || !window2.document || window2.document.nodeType !== NODE_TYPE.document || !window2.Element) {
321
321
  DOMPurify.isSupported = false;
@@ -324,14 +324,21 @@ function createDOMPurify() {
324
324
  let document2 = window2.document;
325
325
  const originalDocument = document2;
326
326
  const currentScript = originalDocument.currentScript;
327
- const DocumentFragment = window2.DocumentFragment, HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window2.HTMLFormElement, DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes;
327
+ window2.DocumentFragment;
328
+ const HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap;
329
+ _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap;
330
+ window2.HTMLFormElement;
331
+ const DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes;
328
332
  const ElementPrototype = Element.prototype;
329
333
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
330
334
  const remove = lookupGetter(ElementPrototype, "remove");
331
335
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
332
336
  const getChildNodes = lookupGetter(ElementPrototype, "childNodes");
333
337
  const getParentNode = lookupGetter(ElementPrototype, "parentNode");
338
+ const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot");
339
+ const getAttributes = lookupGetter(ElementPrototype, "attributes");
334
340
  const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null;
341
+ const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null;
335
342
  if (typeof HTMLTemplateElement === "function") {
336
343
  const template = document2.createElement("template");
337
344
  if (template.content && template.content.ownerDocument) {
@@ -340,6 +347,39 @@ function createDOMPurify() {
340
347
  }
341
348
  let trustedTypesPolicy;
342
349
  let emptyHTML = "";
350
+ let defaultTrustedTypesPolicy;
351
+ let defaultTrustedTypesPolicyResolved = false;
352
+ let IN_TRUSTED_TYPES_POLICY = 0;
353
+ const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy2() {
354
+ if (IN_TRUSTED_TYPES_POLICY > 0) {
355
+ throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted Types" section of the README.');
356
+ }
357
+ };
358
+ const _createTrustedHTML = function _createTrustedHTML2(html2) {
359
+ _assertNotInTrustedTypesPolicy();
360
+ IN_TRUSTED_TYPES_POLICY++;
361
+ try {
362
+ return trustedTypesPolicy.createHTML(html2);
363
+ } finally {
364
+ IN_TRUSTED_TYPES_POLICY--;
365
+ }
366
+ };
367
+ const _createTrustedScriptURL = function _createTrustedScriptURL2(scriptUrl) {
368
+ _assertNotInTrustedTypesPolicy();
369
+ IN_TRUSTED_TYPES_POLICY++;
370
+ try {
371
+ return trustedTypesPolicy.createScriptURL(scriptUrl);
372
+ } finally {
373
+ IN_TRUSTED_TYPES_POLICY--;
374
+ }
375
+ };
376
+ const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy2() {
377
+ if (!defaultTrustedTypesPolicyResolved) {
378
+ defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
379
+ defaultTrustedTypesPolicyResolved = true;
380
+ }
381
+ return defaultTrustedTypesPolicy;
382
+ };
343
383
  const _document = document2, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
344
384
  const importNode = originalDocument.importNode;
345
385
  let hooks = _createHooksMap();
@@ -394,6 +434,8 @@ function createDOMPurify() {
394
434
  let SAFE_FOR_XML = true;
395
435
  let WHOLE_DOCUMENT = false;
396
436
  let SET_CONFIG = false;
437
+ let SET_CONFIG_ALLOWED_TAGS = null;
438
+ let SET_CONFIG_ALLOWED_ATTR = null;
397
439
  let FORCE_BODY = false;
398
440
  let RETURN_DOM = false;
399
441
  let RETURN_DOM_FRAGMENT = false;
@@ -405,7 +447,43 @@ function createDOMPurify() {
405
447
  let IN_PLACE = false;
406
448
  let USE_PROFILES = {};
407
449
  let FORBID_CONTENTS = null;
408
- const DEFAULT_FORBID_CONTENTS = addToSet({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]);
450
+ const DEFAULT_FORBID_CONTENTS = addToSet({}, [
451
+ "annotation-xml",
452
+ "audio",
453
+ "colgroup",
454
+ "desc",
455
+ "foreignobject",
456
+ "head",
457
+ "iframe",
458
+ "math",
459
+ "mi",
460
+ "mn",
461
+ "mo",
462
+ "ms",
463
+ "mtext",
464
+ "noembed",
465
+ "noframes",
466
+ "noscript",
467
+ "plaintext",
468
+ "script",
469
+ // <selectedcontent> mirrors the selected <option>'s subtree, cloned by
470
+ // the UA (customizable <select>) — including any on* handlers — and the
471
+ // engine re-mirrors synchronously whenever a removal changes which
472
+ // option/selectedcontent is current, even inside DOMPurify's inert
473
+ // DOMParser document. Hoisting its children on removal re-inserts a fresh
474
+ // mirror target ahead of the walk, which the engine refills, looping
475
+ // forever (DoS) and amplifying output. Dropping its content on removal
476
+ // (rather than hoisting) breaks that cascade; the content is a duplicate
477
+ // of the option, which is sanitized on its own. See campaign-3 F1/F6.
478
+ "selectedcontent",
479
+ "style",
480
+ "svg",
481
+ "template",
482
+ "thead",
483
+ "title",
484
+ "video",
485
+ "xmp"
486
+ ]);
409
487
  let DATA_URI_TAGS = null;
410
488
  const DEFAULT_DATA_URI_TAGS = addToSet({}, ["audio", "video", "img", "source", "image", "track"]);
411
489
  let URI_SAFE_ATTRIBUTES = null;
@@ -417,8 +495,10 @@ function createDOMPurify() {
417
495
  let IS_EMPTY_INPUT = false;
418
496
  let ALLOWED_NAMESPACES = null;
419
497
  const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
420
- let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ["mi", "mo", "mn", "ms", "mtext"]);
421
- let HTML_INTEGRATION_POINTS = addToSet({}, ["annotation-xml"]);
498
+ const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze(["mi", "mo", "mn", "ms", "mtext"]);
499
+ let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
500
+ const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]);
501
+ let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
422
502
  const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ["title", "style", "font", "a", "script"]);
423
503
  let PARSER_MEDIA_TYPE = null;
424
504
  const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"];
@@ -441,14 +521,32 @@ function createDOMPurify() {
441
521
  PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
442
522
  SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
443
523
  transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase;
444
- ALLOWED_TAGS = objectHasOwnProperty(cfg, "ALLOWED_TAGS") && arrayIsArray(cfg.ALLOWED_TAGS) ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
445
- ALLOWED_ATTR = objectHasOwnProperty(cfg, "ALLOWED_ATTR") && arrayIsArray(cfg.ALLOWED_ATTR) ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
446
- ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, "ALLOWED_NAMESPACES") && arrayIsArray(cfg.ALLOWED_NAMESPACES) ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
447
- URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR) ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
448
- DATA_URI_TAGS = objectHasOwnProperty(cfg, "ADD_DATA_URI_TAGS") && arrayIsArray(cfg.ADD_DATA_URI_TAGS) ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
449
- FORBID_CONTENTS = objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS) ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
450
- FORBID_TAGS = objectHasOwnProperty(cfg, "FORBID_TAGS") && arrayIsArray(cfg.FORBID_TAGS) ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
451
- FORBID_ATTR = objectHasOwnProperty(cfg, "FORBID_ATTR") && arrayIsArray(cfg.FORBID_ATTR) ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
524
+ ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, {
525
+ transform: transformCaseFunc
526
+ });
527
+ ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, {
528
+ transform: transformCaseFunc
529
+ });
530
+ ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, {
531
+ transform: stringToString
532
+ });
533
+ URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, {
534
+ transform: transformCaseFunc,
535
+ base: DEFAULT_URI_SAFE_ATTRIBUTES
536
+ });
537
+ DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, {
538
+ transform: transformCaseFunc,
539
+ base: DEFAULT_DATA_URI_TAGS
540
+ });
541
+ FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, {
542
+ transform: transformCaseFunc
543
+ });
544
+ FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), {
545
+ transform: transformCaseFunc
546
+ });
547
+ FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), {
548
+ transform: transformCaseFunc
549
+ });
452
550
  USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
453
551
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
454
552
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
@@ -467,8 +565,8 @@ function createDOMPurify() {
467
565
  IN_PLACE = cfg.IN_PLACE || false;
468
566
  IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
469
567
  NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
470
- MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, ["mi", "mo", "mn", "ms", "mtext"]);
471
- HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, ["annotation-xml"]);
568
+ MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
569
+ HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
472
570
  const customElementHandling = objectHasOwnProperty(cfg, "CUSTOM_ELEMENT_HANDLING") && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === "object" ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
473
571
  CUSTOM_ELEMENT_HANDLING = create(null);
474
572
  if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) {
@@ -480,6 +578,7 @@ function createDOMPurify() {
480
578
  if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") {
481
579
  CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements;
482
580
  }
581
+ seal(CUSTOM_ELEMENT_HANDLING);
483
582
  if (SAFE_FOR_TEMPLATES) {
484
583
  ALLOW_DATA_ATTR = false;
485
584
  }
@@ -563,14 +662,23 @@ function createDOMPurify() {
563
662
  if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") {
564
663
  throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
565
664
  }
665
+ const previousTrustedTypesPolicy = trustedTypesPolicy;
566
666
  trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
567
- emptyHTML = trustedTypesPolicy.createHTML("");
667
+ try {
668
+ emptyHTML = _createTrustedHTML("");
669
+ } catch (error) {
670
+ trustedTypesPolicy = previousTrustedTypesPolicy;
671
+ throw error;
672
+ }
673
+ } else if (cfg.TRUSTED_TYPES_POLICY === null) {
674
+ trustedTypesPolicy = void 0;
675
+ emptyHTML = "";
568
676
  } else {
569
677
  if (trustedTypesPolicy === void 0) {
570
- trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
678
+ trustedTypesPolicy = _getDefaultTrustedTypesPolicy();
571
679
  }
572
- if (trustedTypesPolicy !== null && typeof emptyHTML === "string") {
573
- emptyHTML = trustedTypesPolicy.createHTML("");
680
+ if (trustedTypesPolicy && typeof emptyHTML === "string") {
681
+ emptyHTML = _createTrustedHTML("");
574
682
  }
575
683
  }
576
684
  if (freeze) {
@@ -580,6 +688,33 @@ function createDOMPurify() {
580
688
  };
581
689
  const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
582
690
  const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
691
+ const _checkSvgNamespace = function _checkSvgNamespace2(tagName, parent, parentTagName) {
692
+ if (parent.namespaceURI === HTML_NAMESPACE) {
693
+ return tagName === "svg";
694
+ }
695
+ if (parent.namespaceURI === MATHML_NAMESPACE) {
696
+ return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
697
+ }
698
+ return Boolean(ALL_SVG_TAGS[tagName]);
699
+ };
700
+ const _checkMathMlNamespace = function _checkMathMlNamespace2(tagName, parent, parentTagName) {
701
+ if (parent.namespaceURI === HTML_NAMESPACE) {
702
+ return tagName === "math";
703
+ }
704
+ if (parent.namespaceURI === SVG_NAMESPACE) {
705
+ return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName];
706
+ }
707
+ return Boolean(ALL_MATHML_TAGS[tagName]);
708
+ };
709
+ const _checkHtmlNamespace = function _checkHtmlNamespace2(tagName, parent, parentTagName) {
710
+ if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
711
+ return false;
712
+ }
713
+ if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
714
+ return false;
715
+ }
716
+ return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
717
+ };
583
718
  const _checkValidNamespace = function _checkValidNamespace2(element) {
584
719
  let parent = getParentNode(element);
585
720
  if (!parent || !parent.tagName) {
@@ -594,31 +729,13 @@ function createDOMPurify() {
594
729
  return false;
595
730
  }
596
731
  if (element.namespaceURI === SVG_NAMESPACE) {
597
- if (parent.namespaceURI === HTML_NAMESPACE) {
598
- return tagName === "svg";
599
- }
600
- if (parent.namespaceURI === MATHML_NAMESPACE) {
601
- return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
602
- }
603
- return Boolean(ALL_SVG_TAGS[tagName]);
732
+ return _checkSvgNamespace(tagName, parent, parentTagName);
604
733
  }
605
734
  if (element.namespaceURI === MATHML_NAMESPACE) {
606
- if (parent.namespaceURI === HTML_NAMESPACE) {
607
- return tagName === "math";
608
- }
609
- if (parent.namespaceURI === SVG_NAMESPACE) {
610
- return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName];
611
- }
612
- return Boolean(ALL_MATHML_TAGS[tagName]);
735
+ return _checkMathMlNamespace(tagName, parent, parentTagName);
613
736
  }
614
737
  if (element.namespaceURI === HTML_NAMESPACE) {
615
- if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
616
- return false;
617
- }
618
- if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
619
- return false;
620
- }
621
- return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
738
+ return _checkHtmlNamespace(tagName, parent, parentTagName);
622
739
  }
623
740
  if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) {
624
741
  return true;
@@ -633,6 +750,38 @@ function createDOMPurify() {
633
750
  getParentNode(node).removeChild(node);
634
751
  } catch (_) {
635
752
  remove(node);
753
+ if (!getParentNode(node)) {
754
+ throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place");
755
+ }
756
+ }
757
+ };
758
+ const _neutralizeRoot = function _neutralizeRoot2(root) {
759
+ _neutralizeSubtree(root);
760
+ const childNodes = getChildNodes(root);
761
+ if (childNodes) {
762
+ const snapshot = [];
763
+ arrayForEach(childNodes, (child) => {
764
+ arrayPush(snapshot, child);
765
+ });
766
+ arrayForEach(snapshot, (child) => {
767
+ try {
768
+ remove(child);
769
+ } catch (_) {
770
+ }
771
+ });
772
+ }
773
+ const attributes = getAttributes(root);
774
+ if (attributes) {
775
+ for (let i = attributes.length - 1; i >= 0; --i) {
776
+ const attribute = attributes[i];
777
+ const name = attribute && attribute.name;
778
+ if (typeof name === "string") {
779
+ try {
780
+ root.removeAttribute(name);
781
+ } catch (_) {
782
+ }
783
+ }
784
+ }
636
785
  }
637
786
  };
638
787
  const _removeAttribute = function _removeAttribute2(name, element) {
@@ -662,6 +811,75 @@ function createDOMPurify() {
662
811
  }
663
812
  }
664
813
  };
814
+ const _stripDisallowedAttributes = function _stripDisallowedAttributes2(element) {
815
+ const attributes = getAttributes(element);
816
+ if (!attributes) {
817
+ return;
818
+ }
819
+ for (let i = attributes.length - 1; i >= 0; --i) {
820
+ const attribute = attributes[i];
821
+ const name = attribute && attribute.name;
822
+ if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) {
823
+ continue;
824
+ }
825
+ try {
826
+ element.removeAttribute(name);
827
+ } catch (_) {
828
+ }
829
+ }
830
+ };
831
+ const _neutralizeSubtree = function _neutralizeSubtree2(root) {
832
+ const stack = [root];
833
+ while (stack.length > 0) {
834
+ const node = stack.pop();
835
+ const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
836
+ if (nodeType === NODE_TYPE.element) {
837
+ _stripDisallowedAttributes(node);
838
+ }
839
+ const childNodes = getChildNodes(node);
840
+ if (childNodes) {
841
+ for (let i = childNodes.length - 1; i >= 0; --i) {
842
+ stack.push(childNodes[i]);
843
+ }
844
+ }
845
+ }
846
+ };
847
+ const _neutralizePatchLinkage = function _neutralizePatchLinkage2(root) {
848
+ if (!SAFE_FOR_XML) {
849
+ return;
850
+ }
851
+ const stack = [root];
852
+ while (stack.length > 0) {
853
+ const node = stack.pop();
854
+ const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
855
+ if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
856
+ try {
857
+ remove(node);
858
+ } catch (_) {
859
+ }
860
+ continue;
861
+ }
862
+ if (nodeType === NODE_TYPE.element) {
863
+ const element = node;
864
+ const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName);
865
+ try {
866
+ if (element.hasAttribute && element.hasAttribute("patchsrc")) {
867
+ element.removeAttribute("patchsrc");
868
+ }
869
+ if (element.hasAttribute && element.hasAttribute("for") && lcTag !== "label" && lcTag !== "output") {
870
+ element.removeAttribute("for");
871
+ }
872
+ } catch (_) {
873
+ }
874
+ }
875
+ const childNodes = getChildNodes(node);
876
+ if (childNodes) {
877
+ for (let i = childNodes.length - 1; i >= 0; --i) {
878
+ stack.push(childNodes[i]);
879
+ }
880
+ }
881
+ }
882
+ };
665
883
  const _initDocument = function _initDocument2(dirty) {
666
884
  let doc = null;
667
885
  let leadingWhitespace = null;
@@ -674,7 +892,7 @@ function createDOMPurify() {
674
892
  if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) {
675
893
  dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + "</body></html>";
676
894
  }
677
- const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
895
+ const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
678
896
  if (NAMESPACE === HTML_NAMESPACE) {
679
897
  try {
680
898
  doc = new DOMParser2().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
@@ -706,7 +924,14 @@ function createDOMPurify() {
706
924
  null
707
925
  );
708
926
  };
709
- const _scrubTemplateExpressions = function _scrubTemplateExpressions2(node) {
927
+ const _stripTemplateExpressions = function _stripTemplateExpressions2(value) {
928
+ value = stringReplace(value, MUSTACHE_EXPR$1, " ");
929
+ value = stringReplace(value, ERB_EXPR$1, " ");
930
+ value = stringReplace(value, TMPLIT_EXPR$1, " ");
931
+ return value;
932
+ };
933
+ const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
934
+ var _node$querySelectorAl;
710
935
  node.normalize();
711
936
  const walker = createNodeIterator.call(
712
937
  node.ownerDocument || node,
@@ -717,16 +942,60 @@ function createDOMPurify() {
717
942
  );
718
943
  let currentNode = walker.nextNode();
719
944
  while (currentNode) {
720
- let data = currentNode.data;
721
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], (expr) => {
722
- data = stringReplace(data, expr, " ");
723
- });
724
- currentNode.data = data;
945
+ currentNode.data = _stripTemplateExpressions(currentNode.data);
725
946
  currentNode = walker.nextNode();
726
947
  }
948
+ const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template");
949
+ if (templates) {
950
+ arrayForEach(templates, (tmpl) => {
951
+ if (_isDocumentFragment(tmpl.content)) {
952
+ _scrubTemplateExpressions2(tmpl.content);
953
+ }
954
+ });
955
+ }
727
956
  };
728
957
  const _isClobbered = function _isClobbered2(element) {
729
- return element instanceof HTMLFormElement && (typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function");
958
+ const realTagName = getNodeName ? getNodeName(element) : null;
959
+ if (typeof realTagName !== "string") {
960
+ return false;
961
+ }
962
+ if (transformCaseFunc(realTagName) !== "form") {
963
+ return false;
964
+ }
965
+ return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || // Realm-safe NamedNodeMap detection: equality against the cached
966
+ // prototype getter. Clobbered .attributes (e.g. <input name="attributes">)
967
+ // makes the direct read diverge from the cached read; a clean form
968
+ // (same-realm OR foreign-realm) has both reads pointing at the same
969
+ // canonical NamedNodeMap.
970
+ element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || // NodeType clobbering probe. Cached Node.prototype.nodeType getter
971
+ // returns the integer 1 for any Element regardless of realm; direct
972
+ // read on a clobbered form (e.g. <input name="nodeType">) returns
973
+ // the named child element. Cheap addition — nodeType is read from
974
+ // an internal slot, no serialization cost — and removes a residual
975
+ // clobbering surface used by several mXSS / PI / comment branches
976
+ // in _sanitizeElements that compare currentNode.nodeType directly.
977
+ element.nodeType !== getNodeType(element) || // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
978
+ // "childNodes" shadows the prototype getter. Direct reads of
979
+ // form.childNodes from a clobbered form return the named child
980
+ // instead of the real NodeList, so any walk that reads it directly
981
+ // skips the form's real children. Compare the direct read to the
982
+ // cached Node.prototype getter — when the form's named-property
983
+ // getter intercepts the read, the two values differ and we flag
984
+ // the form. This catches every clobbering child type (input,
985
+ // select, etc.) regardless of whether the named child happens to
986
+ // carry a numeric .length, which a typeof-based probe would miss
987
+ // (e.g. HTMLSelectElement.length is a defined unsigned-long).
988
+ element.childNodes !== getChildNodes(element);
989
+ };
990
+ const _isDocumentFragment = function _isDocumentFragment2(value) {
991
+ if (!getNodeType || typeof value !== "object" || value === null) {
992
+ return false;
993
+ }
994
+ try {
995
+ return getNodeType(value) === NODE_TYPE.documentFragment;
996
+ } catch (_) {
997
+ return false;
998
+ }
730
999
  };
731
1000
  const _isNode = function _isNode2(value) {
732
1001
  if (!getNodeType || typeof value !== "object" || value === null) {
@@ -739,74 +1008,90 @@ function createDOMPurify() {
739
1008
  }
740
1009
  };
741
1010
  function _executeHooks(hooks2, currentNode, data) {
1011
+ if (hooks2.length === 0) {
1012
+ return;
1013
+ }
742
1014
  arrayForEach(hooks2, (hook) => {
743
1015
  hook.call(DOMPurify, currentNode, data, CONFIG);
744
1016
  });
745
1017
  }
746
- const _sanitizeElements = function _sanitizeElements2(currentNode) {
747
- let content = null;
1018
+ const _isUnsafeNode = function _isUnsafeNode2(currentNode, tagName) {
1019
+ if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) {
1020
+ return true;
1021
+ }
1022
+ if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) {
1023
+ return true;
1024
+ }
1025
+ if (currentNode.nodeType === NODE_TYPE.processingInstruction) {
1026
+ return true;
1027
+ }
1028
+ if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) {
1029
+ return true;
1030
+ }
1031
+ return false;
1032
+ };
1033
+ const _sanitizeDisallowedNode = function _sanitizeDisallowedNode2(currentNode, tagName) {
1034
+ if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
1035
+ if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
1036
+ return false;
1037
+ }
1038
+ if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
1039
+ return false;
1040
+ }
1041
+ }
1042
+ if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
1043
+ const parentNode = getParentNode(currentNode);
1044
+ const childNodes = getChildNodes(currentNode);
1045
+ if (childNodes && parentNode) {
1046
+ const childCount = childNodes.length;
1047
+ for (let i = childCount - 1; i >= 0; --i) {
1048
+ const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true);
1049
+ parentNode.insertBefore(hoisted, getNextSibling(currentNode));
1050
+ }
1051
+ }
1052
+ }
1053
+ _forceRemove(currentNode);
1054
+ return true;
1055
+ };
1056
+ const _sanitizeElements = function _sanitizeElements2(currentNode, root) {
748
1057
  _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
1058
+ if (currentNode !== root && getParentNode(currentNode) === null) {
1059
+ return true;
1060
+ }
749
1061
  if (_isClobbered(currentNode)) {
750
1062
  _forceRemove(currentNode);
751
1063
  return true;
752
1064
  }
753
- const tagName = transformCaseFunc(currentNode.nodeName);
1065
+ const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
754
1066
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
755
1067
  tagName,
756
1068
  allowedTags: ALLOWED_TAGS
757
1069
  });
758
- if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w!]/g, currentNode.innerHTML) && regExpTest(/<[/\w!]/g, currentNode.textContent)) {
759
- _forceRemove(currentNode);
760
- return true;
761
- }
762
- if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) {
763
- _forceRemove(currentNode);
764
- return true;
765
- }
766
- if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
767
- _forceRemove(currentNode);
1070
+ if (currentNode !== root && getParentNode(currentNode) === null) {
768
1071
  return true;
769
1072
  }
770
- if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
1073
+ if (_isUnsafeNode(currentNode, tagName)) {
771
1074
  _forceRemove(currentNode);
772
1075
  return true;
773
1076
  }
774
1077
  if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
775
- if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
776
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
777
- return false;
778
- }
779
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
780
- return false;
781
- }
782
- }
783
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
784
- const parentNode = getParentNode(currentNode) || currentNode.parentNode;
785
- const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
786
- if (childNodes && parentNode) {
787
- const childCount = childNodes.length;
788
- for (let i = childCount - 1; i >= 0; --i) {
789
- const childClone = cloneNode(childNodes[i], true);
790
- parentNode.insertBefore(childClone, getNextSibling(currentNode));
791
- }
792
- }
1078
+ const removed2 = _sanitizeDisallowedNode(currentNode, tagName);
1079
+ if (removed2 === false) {
1080
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
793
1081
  }
794
- _forceRemove(currentNode);
795
- return true;
1082
+ return removed2;
796
1083
  }
797
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
1084
+ const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType;
1085
+ if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
798
1086
  _forceRemove(currentNode);
799
1087
  return true;
800
1088
  }
801
- if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
1089
+ if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) {
802
1090
  _forceRemove(currentNode);
803
1091
  return true;
804
1092
  }
805
1093
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
806
- content = currentNode.textContent;
807
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], (expr) => {
808
- content = stringReplace(content, expr, " ");
809
- });
1094
+ const content = _stripTemplateExpressions(currentNode.textContent);
810
1095
  if (currentNode.textContent !== content) {
811
1096
  arrayPush(DOMPurify.removed, {
812
1097
  element: currentNode.cloneNode()
@@ -821,13 +1106,19 @@ function createDOMPurify() {
821
1106
  if (FORBID_ATTR[lcName]) {
822
1107
  return false;
823
1108
  }
1109
+ if (SAFE_FOR_XML && lcName === "patchsrc") {
1110
+ return false;
1111
+ }
1112
+ if (SAFE_FOR_XML && lcName === "for" && lcTag !== "label" && lcTag !== "output") {
1113
+ return false;
1114
+ }
824
1115
  if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document2 || value in formElement)) {
825
1116
  return false;
826
1117
  }
827
1118
  const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
828
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ;
1119
+ if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) ;
829
1120
  else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ;
830
- else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
1121
+ else if (!nameIsPermitted) {
831
1122
  if (
832
1123
  // First condition does a very basic check if a) it's basically a valid custom element tagname AND
833
1124
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
@@ -852,6 +1143,35 @@ function createDOMPurify() {
852
1143
  const _isBasicCustomElement = function _isBasicCustomElement2(tagName) {
853
1144
  return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
854
1145
  };
1146
+ const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute2(lcTag, lcName, namespaceURI, value) {
1147
+ if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) {
1148
+ switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1149
+ case "TrustedHTML": {
1150
+ return _createTrustedHTML(value);
1151
+ }
1152
+ case "TrustedScriptURL": {
1153
+ return _createTrustedScriptURL(value);
1154
+ }
1155
+ }
1156
+ }
1157
+ return value;
1158
+ };
1159
+ const _setAttributeValue = function _setAttributeValue2(currentNode, name, namespaceURI, value) {
1160
+ try {
1161
+ if (namespaceURI) {
1162
+ currentNode.setAttributeNS(namespaceURI, name, value);
1163
+ } else {
1164
+ currentNode.setAttribute(name, value);
1165
+ }
1166
+ if (_isClobbered(currentNode)) {
1167
+ _forceRemove(currentNode);
1168
+ } else {
1169
+ arrayPop(DOMPurify.removed);
1170
+ }
1171
+ } catch (_) {
1172
+ _removeAttribute(name, currentNode);
1173
+ }
1174
+ };
855
1175
  const _sanitizeAttributes = function _sanitizeAttributes2(currentNode) {
856
1176
  _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
857
1177
  const attributes = currentNode.attributes;
@@ -866,6 +1186,7 @@ function createDOMPurify() {
866
1186
  forceKeepAttr: void 0
867
1187
  };
868
1188
  let l = attributes.length;
1189
+ const lcTag = transformCaseFunc(currentNode.nodeName);
869
1190
  while (l--) {
870
1191
  const attr = attributes[l];
871
1192
  const name = attr.name, namespaceURI = attr.namespaceURI, attrValue = attr.value;
@@ -897,50 +1218,20 @@ function createDOMPurify() {
897
1218
  _removeAttribute(name, currentNode);
898
1219
  continue;
899
1220
  }
900
- if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
1221
+ if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
901
1222
  _removeAttribute(name, currentNode);
902
1223
  continue;
903
1224
  }
904
1225
  if (SAFE_FOR_TEMPLATES) {
905
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], (expr) => {
906
- value = stringReplace(value, expr, " ");
907
- });
1226
+ value = _stripTemplateExpressions(value);
908
1227
  }
909
- const lcTag = transformCaseFunc(currentNode.nodeName);
910
1228
  if (!_isValidAttribute(lcTag, lcName, value)) {
911
1229
  _removeAttribute(name, currentNode);
912
1230
  continue;
913
1231
  }
914
- if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function") {
915
- if (namespaceURI) ;
916
- else {
917
- switch (trustedTypes.getAttributeType(lcTag, lcName)) {
918
- case "TrustedHTML": {
919
- value = trustedTypesPolicy.createHTML(value);
920
- break;
921
- }
922
- case "TrustedScriptURL": {
923
- value = trustedTypesPolicy.createScriptURL(value);
924
- break;
925
- }
926
- }
927
- }
928
- }
1232
+ value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
929
1233
  if (value !== initValue) {
930
- try {
931
- if (namespaceURI) {
932
- currentNode.setAttributeNS(namespaceURI, name, value);
933
- } else {
934
- currentNode.setAttribute(name, value);
935
- }
936
- if (_isClobbered(currentNode)) {
937
- _forceRemove(currentNode);
938
- } else {
939
- arrayPop(DOMPurify.removed);
940
- }
941
- } catch (_) {
942
- _removeAttribute(name, currentNode);
943
- }
1234
+ _setAttributeValue(currentNode, name, namespaceURI, value);
944
1235
  }
945
1236
  }
946
1237
  _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
@@ -951,30 +1242,69 @@ function createDOMPurify() {
951
1242
  _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
952
1243
  while (shadowNode = shadowIterator.nextNode()) {
953
1244
  _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
954
- _sanitizeElements(shadowNode);
1245
+ _sanitizeElements(shadowNode, fragment);
955
1246
  _sanitizeAttributes(shadowNode);
956
- if (shadowNode.content instanceof DocumentFragment) {
1247
+ if (_isDocumentFragment(shadowNode.content)) {
957
1248
  _sanitizeShadowDOM2(shadowNode.content);
958
1249
  }
1250
+ const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType;
1251
+ if (shadowNodeType === NODE_TYPE.element) {
1252
+ const innerSr = getShadowRoot(shadowNode);
1253
+ if (_isDocumentFragment(innerSr)) {
1254
+ _sanitizeAttachedShadowRoots(innerSr);
1255
+ _sanitizeShadowDOM2(innerSr);
1256
+ }
1257
+ }
959
1258
  }
960
1259
  _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
961
1260
  };
962
- const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
963
- if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) {
964
- const sr = root.shadowRoot;
965
- _sanitizeAttachedShadowRoots2(sr);
966
- _sanitizeShadowDOM2(sr);
967
- }
968
- const childNodes = root.childNodes;
969
- if (!childNodes) {
970
- return;
971
- }
972
- const snapshot = [];
973
- arrayForEach(childNodes, (child) => {
974
- arrayPush(snapshot, child);
975
- });
976
- for (const child of snapshot) {
977
- _sanitizeAttachedShadowRoots2(child);
1261
+ const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots2(root) {
1262
+ const stack = [{
1263
+ node: root,
1264
+ shadow: null
1265
+ }];
1266
+ while (stack.length > 0) {
1267
+ const item = stack.pop();
1268
+ if (item.shadow) {
1269
+ _sanitizeShadowDOM2(item.shadow);
1270
+ continue;
1271
+ }
1272
+ const node = item.node;
1273
+ const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
1274
+ const isElement = nodeType === NODE_TYPE.element;
1275
+ const childNodes = getChildNodes(node);
1276
+ if (childNodes) {
1277
+ for (let i = childNodes.length - 1; i >= 0; --i) {
1278
+ stack.push({
1279
+ node: childNodes[i],
1280
+ shadow: null
1281
+ });
1282
+ }
1283
+ }
1284
+ if (isElement) {
1285
+ const rootName = getNodeName ? getNodeName(node) : null;
1286
+ if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") {
1287
+ const content = node.content;
1288
+ if (_isDocumentFragment(content)) {
1289
+ stack.push({
1290
+ node: content,
1291
+ shadow: null
1292
+ });
1293
+ }
1294
+ }
1295
+ }
1296
+ if (isElement) {
1297
+ const sr = getShadowRoot(node);
1298
+ if (_isDocumentFragment(sr)) {
1299
+ stack.push({
1300
+ node: null,
1301
+ shadow: sr
1302
+ }, {
1303
+ node: sr,
1304
+ shadow: null
1305
+ });
1306
+ }
1307
+ }
978
1308
  }
979
1309
  };
980
1310
  DOMPurify.sanitize = function(dirty) {
@@ -996,22 +1326,40 @@ function createDOMPurify() {
996
1326
  if (!DOMPurify.isSupported) {
997
1327
  return dirty;
998
1328
  }
999
- if (!SET_CONFIG) {
1329
+ if (SET_CONFIG) {
1330
+ ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS;
1331
+ ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR;
1332
+ } else {
1000
1333
  _parseConfig(cfg);
1001
1334
  }
1002
- DOMPurify.removed = [];
1003
- if (typeof dirty === "string") {
1004
- IN_PLACE = false;
1335
+ if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) {
1336
+ ALLOWED_TAGS = clone(ALLOWED_TAGS);
1005
1337
  }
1006
- if (IN_PLACE) {
1007
- const nn = dirty.nodeName;
1338
+ if (hooks.uponSanitizeAttribute.length > 0) {
1339
+ ALLOWED_ATTR = clone(ALLOWED_ATTR);
1340
+ }
1341
+ DOMPurify.removed = [];
1342
+ const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
1343
+ if (inPlace) {
1344
+ _neutralizePatchLinkage(dirty);
1345
+ const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
1008
1346
  if (typeof nn === "string") {
1009
1347
  const tagName = transformCaseFunc(nn);
1010
1348
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1349
+ _neutralizeRoot(dirty);
1011
1350
  throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place");
1012
1351
  }
1013
1352
  }
1014
- _sanitizeAttachedShadowRoots2(dirty);
1353
+ if (_isClobbered(dirty)) {
1354
+ _neutralizeRoot(dirty);
1355
+ throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place");
1356
+ }
1357
+ try {
1358
+ _sanitizeAttachedShadowRoots(dirty);
1359
+ } catch (error) {
1360
+ _neutralizeRoot(dirty);
1361
+ throw error;
1362
+ }
1015
1363
  } else if (_isNode(dirty)) {
1016
1364
  body = _initDocument("<!---->");
1017
1365
  importedNode = body.ownerDocument.importNode(dirty, true);
@@ -1022,11 +1370,11 @@ function createDOMPurify() {
1022
1370
  } else {
1023
1371
  body.appendChild(importedNode);
1024
1372
  }
1025
- _sanitizeAttachedShadowRoots2(importedNode);
1373
+ _sanitizeAttachedShadowRoots(importedNode);
1026
1374
  } else {
1027
1375
  if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes
1028
1376
  dirty.indexOf("<") === -1) {
1029
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
1377
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
1030
1378
  }
1031
1379
  body = _initDocument(dirty);
1032
1380
  if (!body) {
@@ -1036,23 +1384,41 @@ function createDOMPurify() {
1036
1384
  if (body && FORCE_BODY) {
1037
1385
  _forceRemove(body.firstChild);
1038
1386
  }
1039
- const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
1040
- while (currentNode = nodeIterator.nextNode()) {
1041
- _sanitizeElements(currentNode);
1042
- _sanitizeAttributes(currentNode);
1043
- if (currentNode.content instanceof DocumentFragment) {
1044
- _sanitizeShadowDOM2(currentNode.content);
1387
+ const walkRoot = inPlace ? dirty : body;
1388
+ const nodeIterator = _createNodeIterator(walkRoot);
1389
+ try {
1390
+ while (currentNode = nodeIterator.nextNode()) {
1391
+ _sanitizeElements(currentNode, walkRoot);
1392
+ _sanitizeAttributes(currentNode);
1393
+ if (_isDocumentFragment(currentNode.content)) {
1394
+ _sanitizeShadowDOM2(currentNode.content);
1395
+ }
1396
+ }
1397
+ } catch (error) {
1398
+ if (inPlace) {
1399
+ _neutralizeRoot(dirty);
1400
+ arrayForEach(DOMPurify.removed, (entry) => {
1401
+ if (entry.element) {
1402
+ _neutralizeSubtree(entry.element);
1403
+ }
1404
+ });
1045
1405
  }
1406
+ throw error;
1046
1407
  }
1047
- if (IN_PLACE) {
1408
+ if (inPlace) {
1409
+ arrayForEach(DOMPurify.removed, (entry) => {
1410
+ if (entry.element) {
1411
+ _neutralizeSubtree(entry.element);
1412
+ }
1413
+ });
1048
1414
  if (SAFE_FOR_TEMPLATES) {
1049
- _scrubTemplateExpressions(dirty);
1415
+ _scrubTemplateExpressions2(dirty);
1050
1416
  }
1051
1417
  return dirty;
1052
1418
  }
1053
1419
  if (RETURN_DOM) {
1054
1420
  if (SAFE_FOR_TEMPLATES) {
1055
- _scrubTemplateExpressions(body);
1421
+ _scrubTemplateExpressions2(body);
1056
1422
  }
1057
1423
  if (RETURN_DOM_FRAGMENT) {
1058
1424
  returnNode = createDocumentFragment.call(body.ownerDocument);
@@ -1072,20 +1438,24 @@ function createDOMPurify() {
1072
1438
  serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML;
1073
1439
  }
1074
1440
  if (SAFE_FOR_TEMPLATES) {
1075
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], (expr) => {
1076
- serializedHTML = stringReplace(serializedHTML, expr, " ");
1077
- });
1441
+ serializedHTML = _stripTemplateExpressions(serializedHTML);
1078
1442
  }
1079
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
1443
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
1080
1444
  };
1081
1445
  DOMPurify.setConfig = function() {
1082
1446
  let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
1083
1447
  _parseConfig(cfg);
1084
1448
  SET_CONFIG = true;
1449
+ SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS;
1450
+ SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR;
1085
1451
  };
1086
1452
  DOMPurify.clearConfig = function() {
1087
1453
  CONFIG = null;
1088
1454
  SET_CONFIG = false;
1455
+ SET_CONFIG_ALLOWED_TAGS = null;
1456
+ SET_CONFIG_ALLOWED_ATTR = null;
1457
+ trustedTypesPolicy = defaultTrustedTypesPolicy;
1458
+ emptyHTML = "";
1089
1459
  };
1090
1460
  DOMPurify.isValidAttribute = function(tag, attr, value) {
1091
1461
  if (!CONFIG) {
@@ -1099,9 +1469,15 @@ function createDOMPurify() {
1099
1469
  if (typeof hookFunction !== "function") {
1100
1470
  return;
1101
1471
  }
1472
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
1473
+ return;
1474
+ }
1102
1475
  arrayPush(hooks[entryPoint], hookFunction);
1103
1476
  };
1104
1477
  DOMPurify.removeHook = function(entryPoint, hookFunction) {
1478
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
1479
+ return void 0;
1480
+ }
1105
1481
  if (hookFunction !== void 0) {
1106
1482
  const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
1107
1483
  return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0];
@@ -1109,6 +1485,9 @@ function createDOMPurify() {
1109
1485
  return arrayPop(hooks[entryPoint]);
1110
1486
  };
1111
1487
  DOMPurify.removeHooks = function(entryPoint) {
1488
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
1489
+ return;
1490
+ }
1112
1491
  hooks[entryPoint] = [];
1113
1492
  };
1114
1493
  DOMPurify.removeAllHooks = function() {
@@ -1116,7 +1495,7 @@ function createDOMPurify() {
1116
1495
  };
1117
1496
  return DOMPurify;
1118
1497
  }
1119
- var entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor, freeze, seal, create, _ref, apply, construct, arrayForEach, arrayLastIndexOf, arrayPop, arrayPush, arraySplice, arrayIsArray, stringToLowerCase, stringToString, stringMatch, stringReplace, stringIndexOf, stringTrim, numberToString, booleanToString, bigintToString, symbolToString, objectHasOwnProperty, objectToString, regExpTest, typeErrorCreate, html$1, svg$1, svgFilters, svgDisallowed, mathMl$1, mathMlDisallowed, text, html, svg, mathMl, xml, MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_ALLOWED_URI, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE, DOCTYPE_NAME, CUSTOM_ELEMENT, NODE_TYPE, getGlobal, _createTrustedTypesPolicy, _createHooksMap, purify;
1498
+ var entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor, freeze, seal, create, _ref, apply, construct, arrayForEach, arrayLastIndexOf, arrayPop, arrayPush, arraySplice, arrayIsArray, stringToLowerCase, stringToString, stringMatch, stringReplace, stringIndexOf, stringTrim, numberToString, booleanToString, bigintToString, symbolToString, objectHasOwnProperty, objectToString, regExpTest, typeErrorCreate, html$1, svg$1, svgFilters, svgDisallowed, mathMl$1, mathMlDisallowed, text, html, svg, mathMl, xml, MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_ALLOWED_URI, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE, DOCTYPE_NAME, CUSTOM_ELEMENT, ELEMENT_MARKUP_PROBE, COMMENT_MARKUP_PROBE, FALLBACK_TAG_CLOSE, SELF_CLOSING_TAG, NODE_TYPE, getGlobal, _createTrustedTypesPolicy, _createHooksMap, _resolveSetOption, purify;
1120
1499
  var init_purify_es = __esm({
1121
1500
  "node_modules/dompurify/dist/purify.es.mjs"() {
1122
1501
  entries = Object.entries;
@@ -1184,7 +1563,7 @@ var init_purify_es = __esm({
1184
1563
  mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]);
1185
1564
  text = freeze(["#text"]);
1186
1565
  html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "command", "commandfor", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns"]);
1187
- svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
1566
+ svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dominant-baseline", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-orientation", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
1188
1567
  mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnalign", "columnlines", "columnspacing", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lquote", "lspace", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]);
1189
1568
  xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]);
1190
1569
  MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
@@ -1203,13 +1582,26 @@ var init_purify_es = __esm({
1203
1582
  );
1204
1583
  DOCTYPE_NAME = seal(/^html$/i);
1205
1584
  CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
1585
+ ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
1586
+ COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
1587
+ FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
1588
+ SELF_CLOSING_TAG = seal(/\/>/i);
1206
1589
  NODE_TYPE = {
1207
1590
  element: 1,
1591
+ attribute: 2,
1208
1592
  text: 3,
1593
+ cdataSection: 4,
1594
+ entityReference: 5,
1209
1595
  // Deprecated
1210
- progressingInstruction: 7,
1596
+ entityNode: 6,
1597
+ // Deprecated
1598
+ processingInstruction: 7,
1211
1599
  comment: 8,
1212
- document: 9
1600
+ document: 9,
1601
+ documentType: 10,
1602
+ documentFragment: 11,
1603
+ notation: 12
1604
+ // Deprecated
1213
1605
  };
1214
1606
  getGlobal = function getGlobal2() {
1215
1607
  return typeof window === "undefined" ? null : window;
@@ -1251,6 +1643,9 @@ var init_purify_es = __esm({
1251
1643
  uponSanitizeShadowNode: []
1252
1644
  };
1253
1645
  };
1646
+ _resolveSetOption = function _resolveSetOption2(cfg, key, fallback, options) {
1647
+ return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
1648
+ };
1254
1649
  purify = createDOMPurify();
1255
1650
  }
1256
1651
  });
@@ -1540,7 +1935,6 @@ var init_velin_modal = __esm({
1540
1935
  this._previouslyFocused = saveFocus();
1541
1936
  setBackgroundInert(this);
1542
1937
  document.addEventListener("keydown", this._onKeydown);
1543
- document.body.style.overflow = "hidden";
1544
1938
  requestAnimationFrame(() => {
1545
1939
  const focusable = getFocusableElements(this.shadowRoot);
1546
1940
  if (focusable.length > 0) focusable[0].focus();
@@ -1548,8 +1942,7 @@ var init_velin_modal = __esm({
1548
1942
  }
1549
1943
  _close() {
1550
1944
  document.removeEventListener("keydown", this._onKeydown);
1551
- document.body.style.overflow = "";
1552
- clearBackgroundInert();
1945
+ clearBackgroundInert(this);
1553
1946
  restoreFocus(this._previouslyFocused);
1554
1947
  }
1555
1948
  _onKeydown(event) {
@@ -1561,7 +1954,7 @@ var init_velin_modal = __esm({
1561
1954
  }
1562
1955
  disconnectedCallback() {
1563
1956
  document.removeEventListener("keydown", this._onKeydown);
1564
- document.body.style.overflow = "";
1957
+ clearBackgroundInert(this);
1565
1958
  }
1566
1959
  };
1567
1960
  customElements.define("velin-modal", VelinModal);
@@ -1750,26 +2143,36 @@ var velin_accordion_exports = {};
1750
2143
  __export(velin_accordion_exports, {
1751
2144
  default: () => velin_accordion_default
1752
2145
  });
1753
- var styles3, VelinAccordion, velin_accordion_default;
2146
+ function ensureLightStyles() {
2147
+ if (typeof document === "undefined") return;
2148
+ if (document.getElementById(LIGHT_STYLE_ID)) return;
2149
+ const style = document.createElement("style");
2150
+ style.id = LIGHT_STYLE_ID;
2151
+ style.textContent = lightStyles;
2152
+ document.head.appendChild(style);
2153
+ }
2154
+ var LIGHT_STYLE_ID, lightStyles, shadowStyles, VelinAccordion, velin_accordion_default;
1754
2155
  var init_velin_accordion = __esm({
1755
2156
  "components/velin-accordion.js"() {
1756
- styles3 = `
1757
- :host {
2157
+ LIGHT_STYLE_ID = "velin-accordion-light-css";
2158
+ lightStyles = `
2159
+ velin-accordion {
1758
2160
  display: block;
1759
2161
  border: 1px solid var(--velin-color-border, #ddd);
1760
2162
  border-radius: var(--velin-radius-md, 0.5rem);
1761
2163
  overflow: hidden;
1762
2164
  }
1763
- ::slotted(details) {
2165
+ velin-accordion details {
1764
2166
  border-bottom: 1px solid var(--velin-color-border, #ddd);
1765
2167
  }
1766
- ::slotted(details:last-child) {
2168
+ velin-accordion details:last-child {
1767
2169
  border-bottom: none;
1768
2170
  }
1769
- ::slotted(details > summary) {
2171
+ velin-accordion details > summary {
1770
2172
  display: flex;
1771
2173
  align-items: center;
1772
2174
  justify-content: space-between;
2175
+ gap: var(--velin-space-3, 0.75rem);
1773
2176
  padding: var(--velin-space-4, 1rem);
1774
2177
  min-block-size: 2.75rem;
1775
2178
  font-size: var(--velin-text-base, 1rem);
@@ -1778,37 +2181,57 @@ var init_velin_accordion = __esm({
1778
2181
  user-select: none;
1779
2182
  list-style: none;
1780
2183
  }
1781
- ::slotted(details > summary::-webkit-details-marker) {
2184
+ velin-accordion details > summary::-webkit-details-marker {
1782
2185
  display: none;
1783
2186
  }
1784
- ::slotted(details[open] > summary) {
2187
+ velin-accordion details > summary::after {
2188
+ content: "";
2189
+ flex-shrink: 0;
2190
+ inline-size: 0.5rem;
2191
+ block-size: 0.5rem;
2192
+ border-inline-end: 2px solid currentColor;
2193
+ border-block-end: 2px solid currentColor;
2194
+ transform: rotate(45deg);
2195
+ transition: transform 150ms ease;
2196
+ }
2197
+ velin-accordion details[open] > summary {
1785
2198
  background: var(--velin-color-primary-subtle, #eff6ff);
1786
2199
  color: var(--velin-color-primary, #2563eb);
1787
2200
  }
1788
- ::slotted(details > :not(summary)) {
2201
+ velin-accordion details[open] > summary::after {
2202
+ transform: rotate(225deg);
2203
+ }
2204
+ velin-accordion details > :not(summary) {
1789
2205
  padding: var(--velin-space-4, 1rem) var(--velin-space-5, 1.25rem);
1790
- background: var(--velin-color-bg-subtle, #f8fafc);
2206
+ background: var(--velin-color-surface-dim, var(--velin-color-bg-subtle, #f8fafc));
1791
2207
  color: var(--velin-color-text-muted, #64748b);
1792
2208
  font-size: var(--velin-text-sm, 0.875rem);
1793
2209
  line-height: 1.6;
1794
2210
  border-block-start: 1px solid var(--velin-color-border, #e2e8f0);
1795
2211
  }
2212
+ `;
2213
+ shadowStyles = `
2214
+ :host {
2215
+ display: block;
2216
+ }
1796
2217
  `;
1797
2218
  VelinAccordion = class extends HTMLElement {
1798
2219
  constructor() {
1799
2220
  super();
1800
2221
  this.attachShadow({ mode: "open" });
1801
2222
  this._onToggle = this._onToggle.bind(this);
2223
+ this._onKeydown = this._onKeydown.bind(this);
1802
2224
  }
1803
2225
  connectedCallback() {
2226
+ ensureLightStyles();
1804
2227
  this.shadowRoot.innerHTML = `
1805
- <style>${styles3}</style>
2228
+ <style>${shadowStyles}</style>
1806
2229
  <slot></slot>
1807
2230
  `;
1808
2231
  this._exclusive = this.hasAttribute("exclusive");
1809
2232
  this._wireDetails();
1810
2233
  this.addEventListener("toggle", this._onToggle, true);
1811
- this.addEventListener("keydown", this._onKeydown.bind(this));
2234
+ this.addEventListener("keydown", this._onKeydown);
1812
2235
  }
1813
2236
  _wireDetails() {
1814
2237
  let panelIndex = 0;
@@ -1819,13 +2242,21 @@ var init_velin_accordion = __esm({
1819
2242
  if (panel && !panel.id) panel.id = panelId;
1820
2243
  if (summary && panel) {
1821
2244
  summary.setAttribute("aria-controls", panelId);
2245
+ summary.setAttribute("aria-expanded", details.open ? "true" : "false");
2246
+ }
2247
+ if (summary && !summary.hasAttribute("tabindex")) {
2248
+ summary.setAttribute("tabindex", "0");
1822
2249
  }
1823
2250
  }
1824
2251
  }
1825
2252
  _onToggle(event) {
1826
- if (!this._exclusive) return;
1827
2253
  const openedDetail = event.target;
1828
- if (!openedDetail.open) return;
2254
+ if (!(openedDetail instanceof HTMLDetailsElement)) return;
2255
+ const summary = openedDetail.querySelector("summary");
2256
+ if (summary) {
2257
+ summary.setAttribute("aria-expanded", openedDetail.open ? "true" : "false");
2258
+ }
2259
+ if (!this._exclusive || !openedDetail.open) return;
1829
2260
  const details = [...this.querySelectorAll("details")];
1830
2261
  details.forEach((d) => {
1831
2262
  if (d !== openedDetail && d.open) {
@@ -1855,6 +2286,9 @@ var init_velin_accordion = __esm({
1855
2286
  event.preventDefault();
1856
2287
  nextIndex = summaries.length - 1;
1857
2288
  break;
2289
+ case "Enter":
2290
+ case " ":
2291
+ return;
1858
2292
  default:
1859
2293
  return;
1860
2294
  }
@@ -1862,6 +2296,7 @@ var init_velin_accordion = __esm({
1862
2296
  }
1863
2297
  disconnectedCallback() {
1864
2298
  this.removeEventListener("toggle", this._onToggle, true);
2299
+ this.removeEventListener("keydown", this._onKeydown);
1865
2300
  }
1866
2301
  };
1867
2302
  customElements.define("velin-accordion", VelinAccordion);
@@ -1874,11 +2309,11 @@ var velin_tabs_exports = {};
1874
2309
  __export(velin_tabs_exports, {
1875
2310
  default: () => velin_tabs_default
1876
2311
  });
1877
- var styles4, VelinTabs, velin_tabs_default;
2312
+ var styles3, VelinTabs, velin_tabs_default;
1878
2313
  var init_velin_tabs = __esm({
1879
2314
  "components/velin-tabs.js"() {
1880
2315
  init_focus_manager();
1881
- styles4 = `
2316
+ styles3 = `
1882
2317
  :host {
1883
2318
  display: block;
1884
2319
  }
@@ -1930,7 +2365,7 @@ var init_velin_tabs = __esm({
1930
2365
  }
1931
2366
  connectedCallback() {
1932
2367
  this.shadowRoot.innerHTML = `
1933
- <style>${styles4}</style>
2368
+ <style>${styles3}</style>
1934
2369
  <div class="tablist" role="tablist" part="tablist">
1935
2370
  <slot name="tab"></slot>
1936
2371
  </div>
@@ -2016,11 +2451,11 @@ var velin_toast_exports = {};
2016
2451
  __export(velin_toast_exports, {
2017
2452
  default: () => velin_toast_default
2018
2453
  });
2019
- var styles5, VelinToast, velin_toast_default;
2454
+ var styles4, VelinToast, velin_toast_default;
2020
2455
  var init_velin_toast = __esm({
2021
2456
  "components/velin-toast.js"() {
2022
2457
  init_sanitize();
2023
- styles5 = `
2458
+ styles4 = `
2024
2459
  :host {
2025
2460
  position: fixed;
2026
2461
  z-index: var(--velin-z-toast, 600);
@@ -2090,7 +2525,7 @@ var init_velin_toast = __esm({
2090
2525
  this._container = null;
2091
2526
  }
2092
2527
  connectedCallback() {
2093
- this.shadowRoot.innerHTML = `<style>${styles5}</style>`;
2528
+ this.shadowRoot.innerHTML = `<style>${styles4}</style>`;
2094
2529
  this._container = this.shadowRoot;
2095
2530
  this.setAttribute("role", "status");
2096
2531
  this.setAttribute("aria-live", "polite");
@@ -2138,7 +2573,18 @@ function resolveProviderUrl(provider, variant) {
2138
2573
  if (variant && variants?.[variant]) return variants[variant];
2139
2574
  return PROVIDER_CDNS[provider];
2140
2575
  }
2141
- var PROVIDER_CDNS, PROVIDER_VARIANTS, _svgCache, VelinIcon, velin_icon_default;
2576
+ function resolveDefaultSpriteUrl() {
2577
+ if (typeof document !== "undefined") {
2578
+ const meta = document.querySelector('meta[name="velin-icon-sprite"]');
2579
+ const fromMeta = meta?.getAttribute("content")?.trim();
2580
+ if (fromMeta) return fromMeta;
2581
+ const fromHtml = document.documentElement?.getAttribute("data-velin-icon-sprite")?.trim();
2582
+ if (fromHtml) return fromHtml;
2583
+ }
2584
+ const configured = typeof VelinIcon.defaultSprite === "string" ? VelinIcon.defaultSprite.trim() : "";
2585
+ return configured || DEFAULT_SPRITE;
2586
+ }
2587
+ var PROVIDER_CDNS, PROVIDER_VARIANTS, _svgCache, DEFAULT_SPRITE, VelinIcon, velin_icon_default;
2142
2588
  var init_velin_icon = __esm({
2143
2589
  "components/velin-icon.js"() {
2144
2590
  init_sanitize();
@@ -2162,7 +2608,10 @@ var init_velin_icon = __esm({
2162
2608
  }
2163
2609
  };
2164
2610
  _svgCache = /* @__PURE__ */ new Map();
2611
+ DEFAULT_SPRITE = "velin-icons.svg";
2165
2612
  VelinIcon = class extends HTMLElement {
2613
+ /** @type {string} Relative or absolute sprite URL used when `sprite` attribute is omitted. */
2614
+ static defaultSprite = DEFAULT_SPRITE;
2166
2615
  static get observedAttributes() {
2167
2616
  return ["name", "size", "label", "provider", "variant", "sprite"];
2168
2617
  }
@@ -2218,7 +2667,8 @@ var init_velin_icon = __esm({
2218
2667
  if (spriteAttr === "" || spriteAttr == null && isLocalSymbol) {
2219
2668
  href = `#${name}`;
2220
2669
  } else {
2221
- const spriteUrl = sanitizeURL(spriteAttr || "/dist/velin-icons.svg") || "/dist/velin-icons.svg";
2670
+ const fallback = resolveDefaultSpriteUrl();
2671
+ const spriteUrl = sanitizeURL(spriteAttr || fallback) || fallback || DEFAULT_SPRITE;
2222
2672
  href = `${spriteUrl}#${name}`;
2223
2673
  }
2224
2674
  use.setAttribute("href", href);
@@ -2327,12 +2777,12 @@ var velin_drawer_exports = {};
2327
2777
  __export(velin_drawer_exports, {
2328
2778
  default: () => velin_drawer_default
2329
2779
  });
2330
- var styles6, VelinDrawer, velin_drawer_default;
2780
+ var styles5, VelinDrawer, velin_drawer_default;
2331
2781
  var init_velin_drawer = __esm({
2332
2782
  "components/velin-drawer.js"() {
2333
2783
  init_focus_manager();
2334
2784
  init_sanitize();
2335
- styles6 = `
2785
+ styles5 = `
2336
2786
  :host { display: contents; }
2337
2787
  .overlay {
2338
2788
  position: fixed;
@@ -2393,7 +2843,7 @@ var init_velin_drawer = __esm({
2393
2843
  const safeTitle = escapeHTML(title);
2394
2844
  const titleId = "velin-drawer-title";
2395
2845
  this.shadowRoot.innerHTML = `
2396
- <style>${styles6}</style>
2846
+ <style>${styles5}</style>
2397
2847
  <div class="overlay" part="overlay"></div>
2398
2848
  <div class="drawer" role="dialog" aria-modal="true" aria-labelledby="${titleId}" part="drawer">
2399
2849
  <div class="header" part="header">
@@ -2420,7 +2870,6 @@ var init_velin_drawer = __esm({
2420
2870
  this._prev = saveFocus();
2421
2871
  setBackgroundInert(this);
2422
2872
  document.addEventListener("keydown", this._onKey);
2423
- document.body.style.overflow = "hidden";
2424
2873
  requestAnimationFrame(() => {
2425
2874
  const f = getFocusableElements(this.shadowRoot);
2426
2875
  if (f.length) f[0].focus();
@@ -2428,8 +2877,7 @@ var init_velin_drawer = __esm({
2428
2877
  }
2429
2878
  _close() {
2430
2879
  document.removeEventListener("keydown", this._onKey);
2431
- document.body.style.overflow = "";
2432
- clearBackgroundInert();
2880
+ clearBackgroundInert(this);
2433
2881
  restoreFocus(this._prev);
2434
2882
  }
2435
2883
  _onKey(e) {
@@ -2441,7 +2889,7 @@ var init_velin_drawer = __esm({
2441
2889
  }
2442
2890
  disconnectedCallback() {
2443
2891
  document.removeEventListener("keydown", this._onKey);
2444
- document.body.style.overflow = "";
2892
+ clearBackgroundInert(this);
2445
2893
  }
2446
2894
  };
2447
2895
  customElements.define("velin-drawer", VelinDrawer);
@@ -2469,7 +2917,7 @@ function ensureThemeStylesheet(slug, base) {
2469
2917
  document.head.appendChild(link);
2470
2918
  loadedThemeStylesheets.add(slug);
2471
2919
  }
2472
- var THEMES, BUILTIN_THEMES, loadedThemeStylesheets, styles7, VelinThemeToggle, velin_theme_toggle_default;
2920
+ var THEMES, BUILTIN_THEMES, loadedThemeStylesheets, styles6, VelinThemeToggle, velin_theme_toggle_default;
2473
2921
  var init_velin_theme_toggle = __esm({
2474
2922
  "components/velin-theme-toggle.js"() {
2475
2923
  THEMES = [
@@ -2491,7 +2939,7 @@ var init_velin_theme_toggle = __esm({
2491
2939
  ];
2492
2940
  BUILTIN_THEMES = /* @__PURE__ */ new Set(["", "dark"]);
2493
2941
  loadedThemeStylesheets = /* @__PURE__ */ new Set();
2494
- styles7 = `
2942
+ styles6 = `
2495
2943
  :host { display: inline-flex; position: relative; }
2496
2944
  .group {
2497
2945
  display: inline-flex; align-items: stretch;
@@ -2580,7 +3028,7 @@ var init_velin_theme_toggle = __esm({
2580
3028
  }
2581
3029
  connectedCallback() {
2582
3030
  this.shadowRoot.innerHTML = `
2583
- <style>${styles7}</style>
3031
+ <style>${styles6}</style>
2584
3032
  <div class="group" part="group">
2585
3033
  <button class="toggle" part="button" aria-label="Toggle dark mode" aria-pressed="false">
2586
3034
  <svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false">
@@ -2752,12 +3200,12 @@ var velin_popover_exports = {};
2752
3200
  __export(velin_popover_exports, {
2753
3201
  default: () => velin_popover_default
2754
3202
  });
2755
- var styles8, popoverId, VelinPopover, velin_popover_default;
3203
+ var styles7, popoverId, VelinPopover, velin_popover_default;
2756
3204
  var init_velin_popover = __esm({
2757
3205
  "components/velin-popover.js"() {
2758
3206
  init_sanitize();
2759
3207
  init_focus_manager();
2760
- styles8 = `
3208
+ styles7 = `
2761
3209
  :host { position: relative; display: inline-block; }
2762
3210
  .popover {
2763
3211
  position: absolute; z-index: var(--velin-z-dropdown, 200);
@@ -2805,7 +3253,7 @@ var init_velin_popover = __esm({
2805
3253
  this._isDialog = role === "dialog";
2806
3254
  const titleId = title ? `${this._popoverId}-title` : "";
2807
3255
  this.shadowRoot.innerHTML = `
2808
- <style>${styles8}</style>
3256
+ <style>${styles7}</style>
2809
3257
  <slot name="trigger"></slot>
2810
3258
  <div class="popover popover--${placement}" id="${this._popoverId}" role="${role}" part="popover"${titleId ? ` aria-labelledby="${titleId}"` : ""}>
2811
3259
  ${title ? `<div class="popover__title" id="${titleId}" part="title">${escapeHTML(title)}</div>` : ""}
@@ -2923,11 +3371,11 @@ var velin_copy_exports = {};
2923
3371
  __export(velin_copy_exports, {
2924
3372
  default: () => velin_copy_default
2925
3373
  });
2926
- var styles9, VelinCopy, velin_copy_default;
3374
+ var styles8, VelinCopy, velin_copy_default;
2927
3375
  var init_velin_copy = __esm({
2928
3376
  "components/velin-copy.js"() {
2929
3377
  init_sanitize();
2930
- styles9 = `
3378
+ styles8 = `
2931
3379
  :host { display: inline-flex; }
2932
3380
  button {
2933
3381
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
@@ -2956,7 +3404,7 @@ var init_velin_copy = __esm({
2956
3404
  connectedCallback() {
2957
3405
  const label = escapeHTML(this.getAttribute("label") || "");
2958
3406
  this.shadowRoot.innerHTML = `
2959
- <style>${styles9}</style>
3407
+ <style>${styles8}</style>
2960
3408
  <button part="button" aria-label="Copy">
2961
3409
  <svg class="copy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
2962
3410
  <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
@@ -3008,10 +3456,10 @@ var velin_scroll_top_exports = {};
3008
3456
  __export(velin_scroll_top_exports, {
3009
3457
  default: () => velin_scroll_top_default
3010
3458
  });
3011
- var styles10, VelinScrollTop, velin_scroll_top_default;
3459
+ var styles9, VelinScrollTop, velin_scroll_top_default;
3012
3460
  var init_velin_scroll_top = __esm({
3013
3461
  "components/velin-scroll-top.js"() {
3014
- styles10 = `
3462
+ styles9 = `
3015
3463
  :host { position: fixed; inset-block-end: var(--velin-scroll-top-bottom, var(--velin-space-4, 1rem)); inset-inline-end: var(--velin-scroll-top-end, var(--velin-space-4, 1rem)); z-index: var(--velin-z-fixed, 300); }
3016
3464
  button {
3017
3465
  display: inline-flex; align-items: center; justify-content: center;
@@ -3038,7 +3486,7 @@ var init_velin_scroll_top = __esm({
3038
3486
  const threshold = parseInt(this.getAttribute("threshold") || "300", 10);
3039
3487
  this._threshold = threshold;
3040
3488
  this.shadowRoot.innerHTML = `
3041
- <style>${styles10}</style>
3489
+ <style>${styles9}</style>
3042
3490
  <button part="button" aria-label="Scroll to top">
3043
3491
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
3044
3492
  <line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/>
@@ -3073,10 +3521,10 @@ var velin_carousel_exports = {};
3073
3521
  __export(velin_carousel_exports, {
3074
3522
  default: () => velin_carousel_default
3075
3523
  });
3076
- var styles11, VelinCarousel, velin_carousel_default;
3524
+ var styles10, VelinCarousel, velin_carousel_default;
3077
3525
  var init_velin_carousel = __esm({
3078
3526
  "components/velin-carousel.js"() {
3079
- styles11 = `
3527
+ styles10 = `
3080
3528
  :host { display: block; position: relative; overflow: hidden; }
3081
3529
  .track {
3082
3530
  display: flex; transition: transform 400ms ease;
@@ -3142,7 +3590,7 @@ var init_velin_carousel = __esm({
3142
3590
  }
3143
3591
  connectedCallback() {
3144
3592
  this.shadowRoot.innerHTML = `
3145
- <style>${styles11}</style>
3593
+ <style>${styles10}</style>
3146
3594
  <div class="track" role="group" aria-roledescription="carousel" part="track"><slot></slot></div>
3147
3595
  <div class="controls" part="controls">
3148
3596
  <button class="prev" aria-label="Previous slide" part="prev">
@@ -3297,10 +3745,10 @@ function isButtonLike(el) {
3297
3745
  const tag = el.tagName;
3298
3746
  return tag === "BUTTON" || tag === "A" && el.hasAttribute("href") || el.getAttribute("role") === "button";
3299
3747
  }
3300
- var styles12, collapseId, VelinCollapse, velin_collapse_default;
3748
+ var styles11, collapseId, VelinCollapse, velin_collapse_default;
3301
3749
  var init_velin_collapse = __esm({
3302
3750
  "components/velin-collapse.js"() {
3303
- styles12 = `
3751
+ styles11 = `
3304
3752
  :host { display: block; }
3305
3753
  .content {
3306
3754
  overflow: hidden;
@@ -3325,7 +3773,7 @@ var init_velin_collapse = __esm({
3325
3773
  }
3326
3774
  connectedCallback() {
3327
3775
  const panelId = this._contentId;
3328
- this.shadowRoot.innerHTML = "<style>" + styles12 + '</style><slot name="trigger"></slot><div class="content" id="' + panelId + '" part="content"><div class="inner"><slot></slot></div></div>';
3776
+ this.shadowRoot.innerHTML = "<style>" + styles11 + '</style><slot name="trigger"></slot><div class="content" id="' + panelId + '" part="content"><div class="inner"><slot></slot></div></div>';
3329
3777
  const triggerSlot = this.shadowRoot.querySelector('slot[name="trigger"]');
3330
3778
  triggerSlot.addEventListener("slotchange", () => this._wireTrigger());
3331
3779
  this._wireTrigger();
@@ -3439,11 +3887,11 @@ __export(velin_tooltip_exports, {
3439
3887
  VelinTooltipWC: () => VelinTooltipWC,
3440
3888
  default: () => velin_tooltip_default
3441
3889
  });
3442
- var styles13, tooltipId, VelinTooltip, VelinTooltipWC, velin_tooltip_default;
3890
+ var styles12, tooltipId, VelinTooltip, VelinTooltipWC, velin_tooltip_default;
3443
3891
  var init_velin_tooltip = __esm({
3444
3892
  "components/velin-tooltip.js"() {
3445
3893
  init_sanitize();
3446
- styles13 = `
3894
+ styles12 = `
3447
3895
  :host { position: relative; display: inline-block; }
3448
3896
  .tip {
3449
3897
  position: absolute; z-index: var(--velin-z-tooltip, 700);
@@ -3477,7 +3925,7 @@ var init_velin_tooltip = __esm({
3477
3925
  const placement = this.getAttribute("placement") || "top";
3478
3926
  const D = "div";
3479
3927
  this.shadowRoot.innerHTML = `
3480
- <style>${styles13}</style>
3928
+ <style>${styles12}</style>
3481
3929
  <slot></slot>
3482
3930
  <${D} class="tip" id="${this._tipId}" role="tooltip" data-placement="${escapeHTML(placement)}" part="tip">${escapeHTML(this.getAttribute("content") || "")}</${D}>
3483
3931
  `;
@@ -3609,13 +4057,13 @@ var velin_lightbox_exports = {};
3609
4057
  __export(velin_lightbox_exports, {
3610
4058
  default: () => velin_lightbox_default
3611
4059
  });
3612
- var styles14, VelinLightbox, velin_lightbox_default;
4060
+ var styles13, VelinLightbox, velin_lightbox_default;
3613
4061
  var init_velin_lightbox = __esm({
3614
4062
  "components/velin-lightbox.js"() {
3615
4063
  init_focus_manager();
3616
4064
  init_a11y_utils();
3617
4065
  init_sanitize();
3618
- styles14 = `
4066
+ styles13 = `
3619
4067
  :host { display: contents; }
3620
4068
  .overlay {
3621
4069
  position: fixed; inset: 0; z-index: var(--velin-z-modal, 500);
@@ -3668,7 +4116,7 @@ var init_velin_lightbox = __esm({
3668
4116
  }
3669
4117
  connectedCallback() {
3670
4118
  this.shadowRoot.innerHTML = `
3671
- <style>${styles14}</style>
4119
+ <style>${styles13}</style>
3672
4120
  <slot></slot>
3673
4121
  <div class="overlay" role="dialog" aria-modal="true" aria-label="Image lightbox" aria-roledescription="lightbox" part="overlay">
3674
4122
  <button class="nav nav--prev" aria-label="Previous">&#8249;</button>
@@ -3704,7 +4152,6 @@ var init_velin_lightbox = __esm({
3704
4152
  this.setAttribute("open", "");
3705
4153
  setBackgroundInert(this);
3706
4154
  this._render();
3707
- document.body.style.overflow = "hidden";
3708
4155
  const overlay = this.shadowRoot.querySelector(".overlay");
3709
4156
  overlay.removeEventListener("keydown", this._onTrapKey);
3710
4157
  overlay.addEventListener("keydown", this._onTrapKey);
@@ -3712,14 +4159,16 @@ var init_velin_lightbox = __esm({
3712
4159
  }
3713
4160
  close() {
3714
4161
  this.removeAttribute("open");
3715
- clearBackgroundInert();
3716
- document.body.style.overflow = "";
4162
+ clearBackgroundInert(this);
3717
4163
  if (this._previousFocus) {
3718
4164
  this._previousFocus.focus();
3719
4165
  this._previousFocus = null;
3720
4166
  }
3721
4167
  this.dispatchEvent(new CustomEvent("velin-close", { bubbles: true }));
3722
4168
  }
4169
+ disconnectedCallback() {
4170
+ clearBackgroundInert(this);
4171
+ }
3723
4172
  _prev() {
3724
4173
  this._index = (this._index - 1 + this._items.length) % this._items.length;
3725
4174
  this._render();
@@ -3757,11 +4206,11 @@ __export(velin_stepper_exports, {
3757
4206
  VelinStepperWC: () => VelinStepperWC,
3758
4207
  default: () => velin_stepper_default
3759
4208
  });
3760
- var styles15, VelinStepper, VelinStepperWC, velin_stepper_default;
4209
+ var styles14, VelinStepper, VelinStepperWC, velin_stepper_default;
3761
4210
  var init_velin_stepper = __esm({
3762
4211
  "components/velin-stepper.js"() {
3763
4212
  init_sanitize();
3764
- styles15 = `
4213
+ styles14 = `
3765
4214
  :host { display: block; }
3766
4215
  .steps {
3767
4216
  display: flex; gap: var(--velin-space-2, 0.5rem);
@@ -3840,7 +4289,7 @@ var init_velin_stepper = __esm({
3840
4289
  return `<div class="step ${state}" role="listitem" aria-label="${escapeHTML(itemLabel)}"${ariaCurrent}><span class="step__marker">${marker}</span><span class="step__label">${escapeHTML(label)}</span></div>`;
3841
4290
  }).join("");
3842
4291
  this.shadowRoot.innerHTML = `
3843
- <style>${styles15}</style>
4292
+ <style>${styles14}</style>
3844
4293
  <div class="steps" role="list" aria-label="${escapeHTML(listLabel)}" part="steps">${stepsHTML}</div>
3845
4294
  <div class="panels" part="panels"><slot></slot></div>
3846
4295
  `;
@@ -3907,11 +4356,11 @@ var velin_dialog_exports = {};
3907
4356
  __export(velin_dialog_exports, {
3908
4357
  default: () => velin_dialog_default
3909
4358
  });
3910
- var styles16, VelinDialog, velin_dialog_default;
4359
+ var styles15, VelinDialog, velin_dialog_default;
3911
4360
  var init_velin_dialog = __esm({
3912
4361
  "components/velin-dialog.js"() {
3913
4362
  init_sanitize();
3914
- styles16 = `
4363
+ styles15 = `
3915
4364
  :host { display: contents; }
3916
4365
  dialog {
3917
4366
  border: none; border-radius: var(--velin-radius-lg, 0.75rem);
@@ -3977,7 +4426,7 @@ var init_velin_dialog = __esm({
3977
4426
  this._previousFocus = null;
3978
4427
  }
3979
4428
  connectedCallback() {
3980
- this.shadowRoot.innerHTML = `<style>${styles16}</style><dialog part="dialog"></dialog>`;
4429
+ this.shadowRoot.innerHTML = `<style>${styles15}</style><dialog part="dialog"></dialog>`;
3981
4430
  const dialog = this.shadowRoot.querySelector("dialog");
3982
4431
  if (dialog) {
3983
4432
  dialog.setAttribute("aria-label", this.getAttribute("aria-label") || "Dialog");
@@ -4050,7 +4499,9 @@ var init_velin_dialog = __esm({
4050
4499
  }
4051
4500
  this._resolve(value);
4052
4501
  this._resolve = null;
4053
- this.dispatchEvent(new CustomEvent("velin-dialog-close", { bubbles: true, detail: { value } }));
4502
+ const detail = { value };
4503
+ this.dispatchEvent(new CustomEvent("velin-close", { bubbles: true, detail }));
4504
+ this.dispatchEvent(new CustomEvent("velin-dialog-close", { bubbles: true, detail }));
4054
4505
  }
4055
4506
  };
4056
4507
  customElements.define("velin-dialog", VelinDialog);
@@ -4063,11 +4514,11 @@ var velin_countdown_exports = {};
4063
4514
  __export(velin_countdown_exports, {
4064
4515
  default: () => velin_countdown_default
4065
4516
  });
4066
- var styles17, VelinCountdown, velin_countdown_default;
4517
+ var styles16, VelinCountdown, velin_countdown_default;
4067
4518
  var init_velin_countdown = __esm({
4068
4519
  "components/velin-countdown.js"() {
4069
4520
  init_sanitize();
4070
- styles17 = `
4521
+ styles16 = `
4071
4522
  :host { display: inline-flex; font-variant-numeric: tabular-nums; }
4072
4523
  .wrap { display: inline-flex; gap: var(--velin-space-3, 0.75rem); align-items: flex-start; }
4073
4524
  .segment {
@@ -4108,7 +4559,7 @@ var init_velin_countdown = __esm({
4108
4559
  this._timer = null;
4109
4560
  }
4110
4561
  connectedCallback() {
4111
- this.shadowRoot.innerHTML = `<style>${styles17}</style><div class="wrap"></div>`;
4562
+ this.shadowRoot.innerHTML = `<style>${styles16}</style><div class="wrap"></div>`;
4112
4563
  this._wrap = this.shadowRoot.querySelector(".wrap");
4113
4564
  this.setAttribute("role", "timer");
4114
4565
  this.setAttribute("aria-live", "polite");
@@ -4168,10 +4619,10 @@ var velin_progress_ring_exports = {};
4168
4619
  __export(velin_progress_ring_exports, {
4169
4620
  default: () => velin_progress_ring_default
4170
4621
  });
4171
- var styles18, VelinProgressRing, velin_progress_ring_default;
4622
+ var styles17, VelinProgressRing, velin_progress_ring_default;
4172
4623
  var init_velin_progress_ring = __esm({
4173
4624
  "components/velin-progress-ring.js"() {
4174
- styles18 = `
4625
+ styles17 = `
4175
4626
  :host { display: inline-flex; align-items: center; justify-content: center; }
4176
4627
  svg { transform: rotate(-90deg); }
4177
4628
  .track { fill: none; stroke: var(--velin-color-border, #e5e5e5); }
@@ -4212,7 +4663,7 @@ var init_velin_progress_ring = __esm({
4212
4663
  const colorStyle = color ? `stroke: var(--velin-color-${color}, ${color});` : "";
4213
4664
  const showLabel = this.getAttribute("label") !== "false";
4214
4665
  this.shadowRoot.innerHTML = `
4215
- <style>${styles18}</style>
4666
+ <style>${styles17}</style>
4216
4667
  <svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" part="svg" role="progressbar" aria-valuenow="${value}" aria-valuemin="0" aria-valuemax="100">
4217
4668
  <circle class="track" cx="${size / 2}" cy="${size / 2}" r="${radius}" stroke-width="${strokeWidth}" />
4218
4669
  <circle class="fill" cx="${size / 2}" cy="${size / 2}" r="${radius}" stroke-width="${strokeWidth}"
@@ -4358,12 +4809,12 @@ var velin_combobox_exports = {};
4358
4809
  __export(velin_combobox_exports, {
4359
4810
  default: () => velin_combobox_default
4360
4811
  });
4361
- var styles19, VelinCombobox, velin_combobox_default;
4812
+ var styles18, VelinCombobox, velin_combobox_default;
4362
4813
  var init_velin_combobox = __esm({
4363
4814
  "components/velin-combobox.js"() {
4364
4815
  init_focus_manager();
4365
4816
  init_sanitize();
4366
- styles19 = `
4817
+ styles18 = `
4367
4818
  :host { display: inline-block; position: relative; }
4368
4819
  .listbox {
4369
4820
  position: absolute; z-index: var(--velin-z-dropdown, 100);
@@ -4404,7 +4855,7 @@ var init_velin_combobox = __esm({
4404
4855
  this._listId = listId;
4405
4856
  const listLabel = escapeHTML(this.getAttribute("aria-label") || "Options");
4406
4857
  this.shadowRoot.innerHTML = `
4407
- <style>${styles19}</style>
4858
+ <style>${styles18}</style>
4408
4859
  <slot name="trigger"></slot>
4409
4860
  <div class="listbox" id="${listId}" role="listbox" aria-label="${listLabel}" part="listbox"><slot></slot></div>
4410
4861
  `;
@@ -4515,11 +4966,11 @@ var velin_bottom_nav_exports = {};
4515
4966
  __export(velin_bottom_nav_exports, {
4516
4967
  default: () => velin_bottom_nav_default
4517
4968
  });
4518
- var styles20, VelinBottomNav, velin_bottom_nav_default;
4969
+ var styles19, VelinBottomNav, velin_bottom_nav_default;
4519
4970
  var init_velin_bottom_nav = __esm({
4520
4971
  "components/velin-bottom-nav.js"() {
4521
4972
  init_sanitize();
4522
- styles20 = `
4973
+ styles19 = `
4523
4974
  :host { display: block; }
4524
4975
  nav {
4525
4976
  display: flex;
@@ -4559,7 +5010,7 @@ var init_velin_bottom_nav = __esm({
4559
5010
  connectedCallback() {
4560
5011
  const label = escapeHTML(this.getAttribute("aria-label") || "Bottom navigation");
4561
5012
  this.shadowRoot.innerHTML = `
4562
- <style>${styles20}</style>
5013
+ <style>${styles19}</style>
4563
5014
  <nav role="navigation" aria-label="${label}"><slot></slot></nav>
4564
5015
  `;
4565
5016
  const slot = this.shadowRoot.querySelector("slot");
@@ -4581,6 +5032,16 @@ var init_velin_bottom_nav = __esm({
4581
5032
  }
4582
5033
  if (el.tagName === "A" && !el.getAttribute("href")) {
4583
5034
  el.setAttribute("role", "button");
5035
+ if (!el.hasAttribute("tabindex")) el.setAttribute("tabindex", "0");
5036
+ if (!el._velinBottomNavKey) {
5037
+ el._velinBottomNavKey = (e) => {
5038
+ if (e.key === "Enter" || e.key === " ") {
5039
+ e.preventDefault();
5040
+ el.click();
5041
+ }
5042
+ };
5043
+ el.addEventListener("keydown", el._velinBottomNavKey);
5044
+ }
4584
5045
  }
4585
5046
  });
4586
5047
  }
@@ -4644,13 +5105,13 @@ var velin_sheet_exports = {};
4644
5105
  __export(velin_sheet_exports, {
4645
5106
  default: () => velin_sheet_default
4646
5107
  });
4647
- var styles21, VelinSheet, velin_sheet_default;
5108
+ var styles20, VelinSheet, velin_sheet_default;
4648
5109
  var init_velin_sheet = __esm({
4649
5110
  "components/velin-sheet.js"() {
4650
5111
  init_focus_manager();
4651
5112
  init_sanitize();
4652
5113
  init_shadow_a11y_styles();
4653
- styles21 = `
5114
+ styles20 = `
4654
5115
  ${SHADOW_A11Y_STYLES}
4655
5116
  :host { display: contents; }
4656
5117
  .overlay {
@@ -4696,7 +5157,7 @@ var init_velin_sheet = __esm({
4696
5157
  const title = escapeHTML(this.getAttribute("title") || this.getAttribute("label") || "");
4697
5158
  const titleId = "velin-sheet-title";
4698
5159
  this.shadowRoot.innerHTML = `
4699
- <style>${styles21}</style>
5160
+ <style>${styles20}</style>
4700
5161
  <div class="overlay" part="overlay"></div>
4701
5162
  <div class="sheet" role="dialog" aria-modal="true" aria-labelledby="${titleId}" part="sheet">
4702
5163
  <div class="header" part="header">
@@ -4724,7 +5185,6 @@ var init_velin_sheet = __esm({
4724
5185
  this._prev = saveFocus();
4725
5186
  setBackgroundInert(this);
4726
5187
  document.addEventListener("keydown", this._onKey);
4727
- document.body.style.overflow = "hidden";
4728
5188
  requestAnimationFrame(() => {
4729
5189
  const f = getFocusableElements(this.shadowRoot);
4730
5190
  if (f.length) f[0].focus();
@@ -4732,8 +5192,7 @@ var init_velin_sheet = __esm({
4732
5192
  }
4733
5193
  _close() {
4734
5194
  document.removeEventListener("keydown", this._onKey);
4735
- document.body.style.overflow = "";
4736
- clearBackgroundInert();
5195
+ clearBackgroundInert(this);
4737
5196
  restoreFocus(this._prev);
4738
5197
  }
4739
5198
  _onKey(e) {
@@ -4745,7 +5204,7 @@ var init_velin_sheet = __esm({
4745
5204
  }
4746
5205
  disconnectedCallback() {
4747
5206
  document.removeEventListener("keydown", this._onKey);
4748
- document.body.style.overflow = "";
5207
+ clearBackgroundInert(this);
4749
5208
  }
4750
5209
  };
4751
5210
  customElements.define("velin-sheet", VelinSheet);
@@ -4758,13 +5217,13 @@ var velin_segmented_control_exports = {};
4758
5217
  __export(velin_segmented_control_exports, {
4759
5218
  default: () => velin_segmented_control_default
4760
5219
  });
4761
- var styles22, VelinSegmentedControl, velin_segmented_control_default;
5220
+ var styles21, VelinSegmentedControl, velin_segmented_control_default;
4762
5221
  var init_velin_segmented_control = __esm({
4763
5222
  "components/velin-segmented-control.js"() {
4764
5223
  init_focus_manager();
4765
5224
  init_sanitize();
4766
5225
  init_shadow_a11y_styles();
4767
- styles22 = `
5226
+ styles21 = `
4768
5227
  ${SHADOW_A11Y_STYLES}
4769
5228
  :host { display: block; }
4770
5229
  .group {
@@ -4802,7 +5261,7 @@ var init_velin_segmented_control = __esm({
4802
5261
  connectedCallback() {
4803
5262
  const label = escapeHTML(this.getAttribute("aria-label") || "Segmented control");
4804
5263
  this.shadowRoot.innerHTML = `
4805
- <style>${styles22}</style>
5264
+ <style>${styles21}</style>
4806
5265
  <div class="group" role="group" aria-label="${label}"><slot></slot></div>
4807
5266
  `;
4808
5267
  this.addEventListener("click", this._onClick);
@@ -4867,13 +5326,13 @@ var velin_rating_exports = {};
4867
5326
  __export(velin_rating_exports, {
4868
5327
  default: () => velin_rating_default
4869
5328
  });
4870
- var styles23, MAX, VelinRating, velin_rating_default;
5329
+ var styles22, MAX, VelinRating, velin_rating_default;
4871
5330
  var init_velin_rating = __esm({
4872
5331
  "components/velin-rating.js"() {
4873
5332
  init_focus_manager();
4874
5333
  init_sanitize();
4875
5334
  init_shadow_a11y_styles();
4876
- styles23 = `
5335
+ styles22 = `
4877
5336
  ${SHADOW_A11Y_STYLES}
4878
5337
  :host { display: inline-block; }
4879
5338
  .stars { display: inline-flex; gap: var(--velin-space-1, 0.25rem); }
@@ -4896,7 +5355,7 @@ var init_velin_rating = __esm({
4896
5355
  this._onKey = this._onKey.bind(this);
4897
5356
  }
4898
5357
  connectedCallback() {
4899
- this.shadowRoot.innerHTML = `<style>${styles23}</style><div class="stars" role="radiogroup"></div>`;
5358
+ this.shadowRoot.innerHTML = `<style>${styles22}</style><div class="stars" role="radiogroup"></div>`;
4900
5359
  this._render();
4901
5360
  this.shadowRoot.querySelector(".stars").addEventListener("click", this._onClick);
4902
5361
  this.shadowRoot.querySelector(".stars").addEventListener("keydown", this._onKey);
@@ -4958,13 +5417,13 @@ var velin_menubar_exports = {};
4958
5417
  __export(velin_menubar_exports, {
4959
5418
  default: () => velin_menubar_default
4960
5419
  });
4961
- var styles24, VelinMenubar, velin_menubar_default;
5420
+ var styles23, VelinMenubar, velin_menubar_default;
4962
5421
  var init_velin_menubar = __esm({
4963
5422
  "components/velin-menubar.js"() {
4964
5423
  init_focus_manager();
4965
5424
  init_sanitize();
4966
5425
  init_shadow_a11y_styles();
4967
- styles24 = `
5426
+ styles23 = `
4968
5427
  ${SHADOW_A11Y_STYLES}
4969
5428
  :host { display: block; }
4970
5429
  .menubar {
@@ -4999,7 +5458,7 @@ var init_velin_menubar = __esm({
4999
5458
  connectedCallback() {
5000
5459
  const label = escapeHTML(this.getAttribute("aria-label") || "Menu bar");
5001
5460
  this.shadowRoot.innerHTML = `
5002
- <style>${styles24}</style>
5461
+ <style>${styles23}</style>
5003
5462
  <div class="menubar" role="menubar" aria-label="${label}"><slot></slot></div>
5004
5463
  `;
5005
5464
  this.addEventListener("keydown", this._onKey);
@@ -5044,13 +5503,13 @@ var velin_command_exports = {};
5044
5503
  __export(velin_command_exports, {
5045
5504
  default: () => velin_command_default
5046
5505
  });
5047
- var styles25, VelinCommand, velin_command_default;
5506
+ var styles24, VelinCommand, velin_command_default;
5048
5507
  var init_velin_command = __esm({
5049
5508
  "components/velin-command.js"() {
5050
5509
  init_focus_manager();
5051
5510
  init_sanitize();
5052
5511
  init_shadow_a11y_styles();
5053
- styles25 = `
5512
+ styles24 = `
5054
5513
  ${SHADOW_A11Y_STYLES}
5055
5514
  :host { display: contents; }
5056
5515
  .overlay {
@@ -5059,9 +5518,14 @@ var init_velin_command = __esm({
5059
5518
  padding: 10vh var(--velin-space-4, 1rem) var(--velin-space-4, 1rem);
5060
5519
  background: var(--velin-color-overlay, rgba(0,0,0,0.4));
5061
5520
  opacity: 0; visibility: hidden;
5521
+ pointer-events: none;
5062
5522
  transition: opacity 150ms ease, visibility 150ms ease;
5063
5523
  }
5064
- :host([open]) .overlay { opacity: 1; visibility: visible; }
5524
+ :host([open]) .overlay {
5525
+ opacity: 1;
5526
+ visibility: visible;
5527
+ pointer-events: auto;
5528
+ }
5065
5529
  .panel {
5066
5530
  inline-size: min(32rem, 100%);
5067
5531
  background: var(--velin-color-surface-bright, #fff);
@@ -5104,7 +5568,7 @@ var init_velin_command = __esm({
5104
5568
  connectedCallback() {
5105
5569
  const placeholder = escapeHTML(this.getAttribute("placeholder") || "Search commands\u2026");
5106
5570
  this.shadowRoot.innerHTML = `
5107
- <style>${styles25}</style>
5571
+ <style>${styles24}</style>
5108
5572
  <div class="overlay" part="overlay">
5109
5573
  <div class="panel" role="dialog" aria-modal="true" aria-label="Command palette" part="panel">
5110
5574
  <input class="search" type="search" autocomplete="off" placeholder="${placeholder}" aria-label="Search" part="search" />
@@ -5113,6 +5577,7 @@ var init_velin_command = __esm({
5113
5577
  </div>
5114
5578
  `;
5115
5579
  this.shadowRoot.querySelector(".search").addEventListener("input", this._onInput);
5580
+ this.shadowRoot.querySelector(".overlay")?.addEventListener("click", this._onOverlayClick);
5116
5581
  this.shadowRoot.querySelector("slot")?.addEventListener("slotchange", () => this._filter(""));
5117
5582
  this._filter("");
5118
5583
  }
@@ -5126,6 +5591,13 @@ var init_velin_command = __esm({
5126
5591
  this.removeAttribute("open");
5127
5592
  this.dispatchEvent(new CustomEvent("velin-close", { bubbles: true }));
5128
5593
  }
5594
+ toggle() {
5595
+ if (this.hasAttribute("open")) this.close();
5596
+ else this.open();
5597
+ }
5598
+ _onOverlayClick = (event) => {
5599
+ if (event.target === event.currentTarget) this.close();
5600
+ };
5129
5601
  _open() {
5130
5602
  this._prev = saveFocus();
5131
5603
  setBackgroundInert(this);
@@ -5137,7 +5609,7 @@ var init_velin_command = __esm({
5137
5609
  }
5138
5610
  _close() {
5139
5611
  document.removeEventListener("keydown", this._onKey);
5140
- clearBackgroundInert();
5612
+ clearBackgroundInert(this);
5141
5613
  restoreFocus(this._prev);
5142
5614
  const input = this.shadowRoot.querySelector(".search");
5143
5615
  if (input) input.value = "";
@@ -5176,6 +5648,8 @@ var init_velin_command = __esm({
5176
5648
  }
5177
5649
  disconnectedCallback() {
5178
5650
  document.removeEventListener("keydown", this._onKey);
5651
+ this.shadowRoot?.querySelector(".overlay")?.removeEventListener("click", this._onOverlayClick);
5652
+ if (this.hasAttribute("open")) clearBackgroundInert(this);
5179
5653
  }
5180
5654
  };
5181
5655
  customElements.define("velin-command", VelinCommand);
@@ -5188,17 +5662,17 @@ var velin_announcer_exports = {};
5188
5662
  __export(velin_announcer_exports, {
5189
5663
  default: () => velin_announcer_default
5190
5664
  });
5191
- var styles26, VelinAnnouncer, velin_announcer_default;
5665
+ var styles25, VelinAnnouncer, velin_announcer_default;
5192
5666
  var init_velin_announcer = __esm({
5193
5667
  "components/velin-announcer.js"() {
5194
- styles26 = `
5668
+ styles25 = `
5195
5669
  :host { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
5196
5670
  `;
5197
5671
  VelinAnnouncer = class extends HTMLElement {
5198
5672
  connectedCallback() {
5199
5673
  if (!this.shadowRoot) this.attachShadow({ mode: "open" });
5200
5674
  const live = this.getAttribute("polite") === "false" ? "assertive" : "polite";
5201
- this.shadowRoot.innerHTML = "<style>" + styles26 + '</style><div role="status" aria-live="' + live + '" aria-atomic="true" part="region"></div>';
5675
+ this.shadowRoot.innerHTML = "<style>" + styles25 + '</style><div role="status" aria-live="' + live + '" aria-atomic="true" part="region"></div>';
5202
5676
  this._region = this.shadowRoot.querySelector('[role="status"]');
5203
5677
  }
5204
5678
  announce(message, { assertive = false } = {}) {
@@ -5242,11 +5716,11 @@ function decodeObfuscated(raw, method) {
5242
5716
  return raw;
5243
5717
  }
5244
5718
  }
5245
- var styles27, VelinEmail, velin_email_default;
5719
+ var styles26, VelinEmail, velin_email_default;
5246
5720
  var init_velin_email = __esm({
5247
5721
  "components/velin-email.js"() {
5248
5722
  init_sanitize();
5249
- styles27 = `
5723
+ styles26 = `
5250
5724
  :host { display: inline; }
5251
5725
  button {
5252
5726
  font: inherit;
@@ -5293,13 +5767,13 @@ var init_velin_email = __esm({
5293
5767
  const safeEmail = escapeHTML(email);
5294
5768
  if (this._revealed) {
5295
5769
  this.shadowRoot.innerHTML = `
5296
- <style>${styles27}</style>
5770
+ <style>${styles26}</style>
5297
5771
  <span class="revealed" part="email"><a href="mailto:${escapeHTMLAttribute(email)}">${safeEmail}</a></span>
5298
5772
  `;
5299
5773
  return;
5300
5774
  }
5301
5775
  this.shadowRoot.innerHTML = `
5302
- <style>${styles27}</style>
5776
+ <style>${styles26}</style>
5303
5777
  <button type="button" part="reveal" aria-label="${escapeHTMLAttribute(label)}">${escapeHTML(label)}</button>
5304
5778
  `;
5305
5779
  this.shadowRoot.querySelector("button").addEventListener("click", () => {
@@ -5316,6 +5790,227 @@ var init_velin_email = __esm({
5316
5790
  }
5317
5791
  });
5318
5792
 
5793
+ // components/velin-calendar.js
5794
+ var velin_calendar_exports = {};
5795
+ __export(velin_calendar_exports, {
5796
+ default: () => velin_calendar_default
5797
+ });
5798
+ function iso(d) {
5799
+ const y = d.getFullYear();
5800
+ const m = String(d.getMonth() + 1).padStart(2, "0");
5801
+ const day = String(d.getDate()).padStart(2, "0");
5802
+ return `${y}-${m}-${day}`;
5803
+ }
5804
+ function parseISO(v) {
5805
+ if (!v) return null;
5806
+ const m = String(v).match(/^(\d{4})-(\d{2})-(\d{2})$/);
5807
+ if (!m) return null;
5808
+ const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
5809
+ return Number.isNaN(d.getTime()) ? null : d;
5810
+ }
5811
+ var styles27, VelinCalendar, velin_calendar_default;
5812
+ var init_velin_calendar = __esm({
5813
+ "components/velin-calendar.js"() {
5814
+ init_sanitize();
5815
+ styles27 = `
5816
+ :host { display: block; max-inline-size: 100%; }
5817
+ .cal {
5818
+ box-sizing: border-box;
5819
+ border: 1px solid var(--velin-color-border, #ddd);
5820
+ border-radius: var(--velin-radius-md, 0.5rem);
5821
+ background: var(--velin-color-surface, #fff);
5822
+ color: var(--velin-color-text, #111);
5823
+ padding: var(--velin-space-3, 0.75rem);
5824
+ max-inline-size: min(20rem, 100%);
5825
+ inline-size: 100%;
5826
+ }
5827
+ .head {
5828
+ display: flex; align-items: center; justify-content: space-between;
5829
+ gap: var(--velin-space-2, 0.5rem); margin-block-end: var(--velin-space-3, 0.75rem);
5830
+ }
5831
+ .title { font-weight: var(--velin-weight-semibold, 600); margin: 0; font-size: var(--velin-text-base, 1rem); }
5832
+ .nav {
5833
+ display: inline-flex; align-items: center; justify-content: center;
5834
+ flex-shrink: 0;
5835
+ min-inline-size: 2.5rem; min-block-size: 2.5rem;
5836
+ border: 1px solid var(--velin-color-border, #ddd);
5837
+ border-radius: var(--velin-radius-sm, 0.25rem);
5838
+ background: var(--velin-color-surface-bright, #fff);
5839
+ color: inherit; cursor: pointer;
5840
+ }
5841
+ .nav:focus-visible { outline: 2px solid var(--velin-color-focus, #2563eb); outline-offset: 2px; }
5842
+ .grid {
5843
+ display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.25rem;
5844
+ }
5845
+ .dow {
5846
+ text-align: center; font-size: var(--velin-text-xs, 0.75rem);
5847
+ color: var(--velin-color-text-muted, #64748b); padding-block: 0.25rem;
5848
+ }
5849
+ .day {
5850
+ inline-size: 100%;
5851
+ min-inline-size: 0;
5852
+ min-block-size: 2.25rem;
5853
+ aspect-ratio: 1;
5854
+ border: none; border-radius: var(--velin-radius-sm, 0.25rem);
5855
+ background: transparent; color: inherit; cursor: pointer;
5856
+ font: inherit;
5857
+ padding: 0;
5858
+ }
5859
+ .day[aria-disabled="true"] { opacity: 0.35; cursor: not-allowed; }
5860
+ .day[aria-selected="true"] {
5861
+ background: var(--velin-color-primary, #2563eb);
5862
+ color: var(--velin-color-on-primary, #fff);
5863
+ }
5864
+ .day:not([aria-disabled="true"]):hover {
5865
+ background: var(--velin-color-primary-subtle, #eff6ff);
5866
+ }
5867
+ .day:focus-visible { outline: 2px solid var(--velin-color-focus, #2563eb); outline-offset: 1px; }
5868
+ .out { color: var(--velin-color-text-muted, #94a3b8); }
5869
+ `;
5870
+ VelinCalendar = class extends HTMLElement {
5871
+ static get observedAttributes() {
5872
+ return ["value", "min", "max", "label"];
5873
+ }
5874
+ constructor() {
5875
+ super();
5876
+ this.attachShadow({ mode: "open" });
5877
+ this._view = /* @__PURE__ */ new Date();
5878
+ this._view.setDate(1);
5879
+ this._onKey = this._onKey.bind(this);
5880
+ }
5881
+ connectedCallback() {
5882
+ const selected = parseISO(this.getAttribute("value")) || /* @__PURE__ */ new Date();
5883
+ this._view = new Date(selected.getFullYear(), selected.getMonth(), 1);
5884
+ this._render();
5885
+ }
5886
+ attributeChangedCallback(name, prev, next) {
5887
+ if (prev === next || !this.shadowRoot?.querySelector(".cal")) return;
5888
+ if (name === "value" && next) {
5889
+ const d = parseISO(next);
5890
+ if (d) this._view = new Date(d.getFullYear(), d.getMonth(), 1);
5891
+ }
5892
+ this._render();
5893
+ }
5894
+ get value() {
5895
+ return this.getAttribute("value") || "";
5896
+ }
5897
+ set value(v) {
5898
+ if (v) this.setAttribute("value", v);
5899
+ else this.removeAttribute("value");
5900
+ }
5901
+ _inRange(d) {
5902
+ const min = parseISO(this.getAttribute("min"));
5903
+ const max = parseISO(this.getAttribute("max"));
5904
+ if (min && d < min) return false;
5905
+ if (max && d > max) return false;
5906
+ return true;
5907
+ }
5908
+ _select(d) {
5909
+ if (!this._inRange(d)) return;
5910
+ const v = iso(d);
5911
+ this.setAttribute("value", v);
5912
+ this.dispatchEvent(new CustomEvent("velin-change", { bubbles: true, detail: { value: v, date: d } }));
5913
+ this._render();
5914
+ }
5915
+ _shiftMonth(delta) {
5916
+ this._view = new Date(this._view.getFullYear(), this._view.getMonth() + delta, 1);
5917
+ this._render();
5918
+ }
5919
+ _onKey(e) {
5920
+ const selected = parseISO(this.getAttribute("value")) || /* @__PURE__ */ new Date();
5921
+ let next = new Date(selected);
5922
+ switch (e.key) {
5923
+ case "ArrowLeft":
5924
+ next.setDate(next.getDate() - 1);
5925
+ break;
5926
+ case "ArrowRight":
5927
+ next.setDate(next.getDate() + 1);
5928
+ break;
5929
+ case "ArrowUp":
5930
+ next.setDate(next.getDate() - 7);
5931
+ break;
5932
+ case "ArrowDown":
5933
+ next.setDate(next.getDate() + 7);
5934
+ break;
5935
+ case "Home":
5936
+ next = new Date(next.getFullYear(), next.getMonth(), 1);
5937
+ break;
5938
+ case "End":
5939
+ next = new Date(next.getFullYear(), next.getMonth() + 1, 0);
5940
+ break;
5941
+ case "PageUp":
5942
+ next = new Date(next.getFullYear(), next.getMonth() - 1, next.getDate());
5943
+ break;
5944
+ case "PageDown":
5945
+ next = new Date(next.getFullYear(), next.getMonth() + 1, next.getDate());
5946
+ break;
5947
+ case "Enter":
5948
+ case " ":
5949
+ e.preventDefault();
5950
+ this._select(selected);
5951
+ return;
5952
+ default:
5953
+ return;
5954
+ }
5955
+ e.preventDefault();
5956
+ if (!this._inRange(next)) return;
5957
+ this._view = new Date(next.getFullYear(), next.getMonth(), 1);
5958
+ this.setAttribute("value", iso(next));
5959
+ this.dispatchEvent(new CustomEvent("velin-change", { bubbles: true, detail: { value: iso(next), date: next } }));
5960
+ this._render();
5961
+ this.shadowRoot.querySelector(`[data-iso="${iso(next)}"]`)?.focus();
5962
+ }
5963
+ _render() {
5964
+ const label = escapeHTML(this.getAttribute("label") || "Choose date");
5965
+ const selected = parseISO(this.getAttribute("value"));
5966
+ const y = this._view.getFullYear();
5967
+ const m = this._view.getMonth();
5968
+ const title = this._view.toLocaleString(void 0, { month: "long", year: "numeric" });
5969
+ const start = new Date(y, m, 1);
5970
+ const startDow = (start.getDay() + 6) % 7;
5971
+ const daysInMonth = new Date(y, m + 1, 0).getDate();
5972
+ const dows = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
5973
+ let cells = dows.map((d) => `<div class="dow" aria-hidden="true">${d}</div>`).join("");
5974
+ for (let i = 0; i < startDow; i += 1) {
5975
+ const d = new Date(y, m, -startDow + i + 1);
5976
+ cells += `<button type="button" class="day out" tabindex="-1" data-iso="${iso(d)}" aria-label="${iso(d)}">${d.getDate()}</button>`;
5977
+ }
5978
+ for (let day = 1; day <= daysInMonth; day += 1) {
5979
+ const d = new Date(y, m, day);
5980
+ const id = iso(d);
5981
+ const sel = selected && iso(selected) === id;
5982
+ const disabled = !this._inRange(d);
5983
+ cells += `<button type="button" class="day" data-iso="${id}" aria-label="${id}" aria-selected="${sel ? "true" : "false"}" aria-disabled="${disabled ? "true" : "false"}" tabindex="${sel ? "0" : "-1"}">${day}</button>`;
5984
+ }
5985
+ this.shadowRoot.innerHTML = `
5986
+ <style>${styles27}</style>
5987
+ <div class="cal" role="group" aria-label="${label}">
5988
+ <div class="head">
5989
+ <button type="button" class="nav" data-nav="-1" aria-label="Previous month">\u2039</button>
5990
+ <p class="title" id="cal-title">${escapeHTML(title)}</p>
5991
+ <button type="button" class="nav" data-nav="1" aria-label="Next month">\u203A</button>
5992
+ </div>
5993
+ <div class="grid" role="grid" aria-labelledby="cal-title">${cells}</div>
5994
+ </div>
5995
+ `;
5996
+ this.shadowRoot.querySelectorAll("[data-nav]").forEach((btn) => {
5997
+ btn.addEventListener("click", () => this._shiftMonth(Number(btn.getAttribute("data-nav"))));
5998
+ });
5999
+ this.shadowRoot.querySelectorAll(".day").forEach((btn) => {
6000
+ btn.addEventListener("click", () => {
6001
+ if (btn.getAttribute("aria-disabled") === "true") return;
6002
+ const d = parseISO(btn.getAttribute("data-iso"));
6003
+ if (d) this._select(d);
6004
+ });
6005
+ btn.addEventListener("keydown", this._onKey);
6006
+ });
6007
+ }
6008
+ };
6009
+ customElements.define("velin-calendar", VelinCalendar);
6010
+ velin_calendar_default = VelinCalendar;
6011
+ }
6012
+ });
6013
+
5319
6014
  // core/highlight/languages/_utils.js
5320
6015
  function tokenize(code, rules) {
5321
6016
  const tokens = [];
@@ -5705,6 +6400,146 @@ var init_blade = __esm({
5705
6400
  }
5706
6401
  });
5707
6402
 
6403
+ // core/highlight/languages/python.js
6404
+ var python_exports = {};
6405
+ __export(python_exports, {
6406
+ default: () => lexPython
6407
+ });
6408
+ function lexPython(code) {
6409
+ return tokenize(code, RULES9);
6410
+ }
6411
+ var RULES9;
6412
+ var init_python = __esm({
6413
+ "core/highlight/languages/python.js"() {
6414
+ init_utils();
6415
+ RULES9 = [
6416
+ { type: "comment", re: /#[^\n]*/y },
6417
+ // Triple-quoted strings first so the single-quote rules cannot split them.
6418
+ { type: "string", re: /[rbfu]{0,2}"""[\s\S]*?"""/y },
6419
+ { type: "string", re: /[rbfu]{0,2}'''[\s\S]*?'''/y },
6420
+ { type: "string", re: /[rbfu]{0,2}"(?:\\.|[^"\\\n])*"/y },
6421
+ { type: "string", re: /[rbfu]{0,2}'(?:\\.|[^'\\\n])*'/y },
6422
+ { type: "number", re: /\b0[xX][\da-fA-F_]+\b|\b\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?\d+)?j?\b/y },
6423
+ {
6424
+ type: "keyword",
6425
+ re: /\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|raise|return|try|while|with|yield)\b/y
6426
+ },
6427
+ {
6428
+ type: "builtin",
6429
+ re: /\b(?:None|True|False|self|cls|abs|all|any|bool|bytes|dict|dir|enumerate|filter|float|format|frozenset|getattr|hasattr|int|isinstance|issubclass|iter|len|list|map|max|min|next|object|open|print|range|repr|reversed|round|set|setattr|sorted|str|sum|super|tuple|type|zip)\b/y
6430
+ },
6431
+ // Multi-character operators first so `->` is not split into `-` and `>`.
6432
+ { type: "operator", re: /->|:=|\*\*=?|\/\/=?|<<=?|>>=?|[-+*/%&|^~<>!=]=?/y },
6433
+ { type: "punctuation", re: /[[\]{}(),:;.@]/y },
6434
+ { type: "identifier", re: /\b[A-Za-z_]\w*\b/y }
6435
+ ];
6436
+ }
6437
+ });
6438
+
6439
+ // core/highlight/languages/yaml.js
6440
+ var yaml_exports = {};
6441
+ __export(yaml_exports, {
6442
+ default: () => lexYaml
6443
+ });
6444
+ function lexYaml(code) {
6445
+ return tokenize(code, RULES10);
6446
+ }
6447
+ var RULES10;
6448
+ var init_yaml = __esm({
6449
+ "core/highlight/languages/yaml.js"() {
6450
+ init_utils();
6451
+ RULES10 = [
6452
+ { type: "comment", re: /#[^\n]*/y },
6453
+ // Document markers and block scalar indicators.
6454
+ { type: "punctuation", re: /^(?:---|\.\.\.)$/my },
6455
+ { type: "string", re: /"(?:\\.|[^"\\])*"/y },
6456
+ { type: "string", re: /'(?:''|[^'])*'/y },
6457
+ // Keys are the primary structure in YAML, so they get the attr-name colour.
6458
+ { type: "attr-name", re: /^[ \t]*-?[ \t]*[\w.$-]+(?=[ \t]*:(?:[ \t]|$))/my },
6459
+ { type: "punctuation", re: /^[ \t]*-(?=[ \t]|$)/my },
6460
+ { type: "keyword", re: /\b(?:true|false|null|yes|no|on|off|~)\b/yi },
6461
+ { type: "number", re: /\b-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/y },
6462
+ // Anchors, aliases, tags and block scalar headers.
6463
+ { type: "operator", re: /[&*]\w+|![\w/!-]*|[|>][+-]?\d*(?=\s*$)/my },
6464
+ { type: "punctuation", re: /[:,[\]{}]/y }
6465
+ ];
6466
+ }
6467
+ });
6468
+
6469
+ // core/highlight/languages/go.js
6470
+ var go_exports = {};
6471
+ __export(go_exports, {
6472
+ default: () => lexGo
6473
+ });
6474
+ function lexGo(code) {
6475
+ return tokenize(code, RULES11);
6476
+ }
6477
+ var RULES11;
6478
+ var init_go = __esm({
6479
+ "core/highlight/languages/go.js"() {
6480
+ init_utils();
6481
+ RULES11 = [
6482
+ { type: "comment", re: /\/\/[^\n]*/y },
6483
+ { type: "comment", re: /\/\*[\s\S]*?\*\//y },
6484
+ // Raw strings may span lines.
6485
+ { type: "string", re: /`[^`]*`/y },
6486
+ { type: "string", re: /"(?:\\.|[^"\\\n])*"/y },
6487
+ { type: "string", re: /'(?:\\.|[^'\\\n])*'/y },
6488
+ { type: "number", re: /\b0[xX][\da-fA-F_]+\b|\b\d[\d_]*(?:\.[\d_]*)?(?:[eE][+-]?\d+)?i?\b/y },
6489
+ {
6490
+ type: "keyword",
6491
+ re: /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/y
6492
+ },
6493
+ {
6494
+ type: "builtin",
6495
+ re: /\b(?:append|bool|byte|cap|clear|close|complex|complex64|complex128|copy|delete|error|float32|float64|imag|int|int8|int16|int32|int64|len|make|max|min|new|nil|panic|print|println|real|recover|rune|string|true|false|iota|uint|uint8|uint16|uint32|uint64|uintptr|any)\b/y
6496
+ },
6497
+ { type: "operator", re: /:=|\.\.\.|&&|\|\||<-|\+\+|--|<<=?|>>=?|&\^=?|[-+*/%&|^<>!=]=?|~/y },
6498
+ { type: "punctuation", re: /[[\]{}(),;:.]/y },
6499
+ { type: "identifier", re: /\b[A-Za-z_]\w*\b/y }
6500
+ ];
6501
+ }
6502
+ });
6503
+
6504
+ // core/highlight/languages/rust.js
6505
+ var rust_exports = {};
6506
+ __export(rust_exports, {
6507
+ default: () => lexRust
6508
+ });
6509
+ function lexRust(code) {
6510
+ return tokenize(code, RULES12);
6511
+ }
6512
+ var RULES12;
6513
+ var init_rust = __esm({
6514
+ "core/highlight/languages/rust.js"() {
6515
+ init_utils();
6516
+ RULES12 = [
6517
+ { type: "comment", re: /\/\/\/?[^\n]*/y },
6518
+ { type: "comment", re: /\/\*[\s\S]*?\*\//y },
6519
+ // Raw strings close on the same number of hashes they opened with.
6520
+ { type: "string", re: /b?r(#*)"[\s\S]*?"\1/y },
6521
+ { type: "string", re: /b?"(?:\\.|[^"\\])*"/y },
6522
+ { type: "string", re: /b?'(?:\\.|[^'\\])'/y },
6523
+ // Attributes such as #[derive(Debug)] read as annotations.
6524
+ { type: "builtin", re: /#!?\[[^\]]*\]/y },
6525
+ { type: "number", re: /\b0[xXbo][\da-fA-F_]+\b|\b\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?\d+)?(?:[iuf](?:8|16|32|64|128|size))?\b/y },
6526
+ {
6527
+ type: "keyword",
6528
+ re: /\b(?:as|async|await|break|const|continue|crate|dyn|else|enum|extern|fn|for|if|impl|in|let|loop|match|mod|move|mut|pub|ref|return|self|Self|static|struct|super|trait|type|unsafe|use|where|while)\b/y
6529
+ },
6530
+ {
6531
+ type: "builtin",
6532
+ re: /\b(?:bool|char|f32|f64|i8|i16|i32|i64|i128|isize|str|u8|u16|u32|u64|u128|usize|String|Vec|Option|Result|Some|None|Ok|Err|Box|Rc|Arc|true|false)\b/y
6533
+ },
6534
+ // Lifetimes such as 'a must not be read as an unterminated char literal.
6535
+ { type: "operator", re: /'[a-z_]\w*\b/y },
6536
+ { type: "operator", re: /=>|->|::|\.\.=?|&&|\|\||<<=?|>>=?|[-+*/%&|^<>!=]=?|[?@]/y },
6537
+ { type: "punctuation", re: /[[\]{}(),;:.#]/y },
6538
+ { type: "identifier", re: /\b[A-Za-z_]\w*!?\b/y }
6539
+ ];
6540
+ }
6541
+ });
6542
+
5708
6543
  // core/highlight/registry.js
5709
6544
  function normalizeLanguage(name) {
5710
6545
  const n = (name || "").trim().toLowerCase();
@@ -5724,11 +6559,14 @@ function normalizeLanguage(name) {
5724
6559
  md: "markdown",
5725
6560
  plaintext: "text",
5726
6561
  "plain-text": "text",
5727
- yml: "text",
5728
- yaml: "text",
6562
+ yml: "yaml",
5729
6563
  toml: "text",
5730
6564
  ini: "text",
5731
- php8: "php"
6565
+ php8: "php",
6566
+ py: "python",
6567
+ python3: "python",
6568
+ golang: "go",
6569
+ rs: "rust"
5732
6570
  };
5733
6571
  return map[n] || n;
5734
6572
  }
@@ -5784,7 +6622,15 @@ var init_registry = __esm({
5784
6622
  markup: () => Promise.resolve().then(() => (init_html(), html_exports)),
5785
6623
  console: () => Promise.resolve().then(() => (init_plain(), plain_exports)),
5786
6624
  php: () => Promise.resolve().then(() => (init_php(), php_exports)),
5787
- blade: () => Promise.resolve().then(() => (init_blade(), blade_exports))
6625
+ blade: () => Promise.resolve().then(() => (init_blade(), blade_exports)),
6626
+ python: () => Promise.resolve().then(() => (init_python(), python_exports)),
6627
+ py: () => Promise.resolve().then(() => (init_python(), python_exports)),
6628
+ yaml: () => Promise.resolve().then(() => (init_yaml(), yaml_exports)),
6629
+ yml: () => Promise.resolve().then(() => (init_yaml(), yaml_exports)),
6630
+ go: () => Promise.resolve().then(() => (init_go(), go_exports)),
6631
+ golang: () => Promise.resolve().then(() => (init_go(), go_exports)),
6632
+ rust: () => Promise.resolve().then(() => (init_rust(), rust_exports)),
6633
+ rs: () => Promise.resolve().then(() => (init_rust(), rust_exports))
5788
6634
  };
5789
6635
  registerLanguage("js", lexJs);
5790
6636
  }
@@ -6307,12 +7153,823 @@ var init_velin_counter = __esm({
6307
7153
  }
6308
7154
  });
6309
7155
 
7156
+ // components/velin-data-table.js
7157
+ var velin_data_table_exports = {};
7158
+ __export(velin_data_table_exports, {
7159
+ default: () => velin_data_table_default
7160
+ });
7161
+ function sortValue(cell, type) {
7162
+ const raw = cell?.dataset?.sortValue ?? cell?.textContent ?? "";
7163
+ const text2 = raw.trim();
7164
+ if (type === "number") {
7165
+ const num = Number.parseFloat(text2.replace(/[^\d.,-]/g, "").replace(",", "."));
7166
+ return Number.isNaN(num) ? Number.NEGATIVE_INFINITY : num;
7167
+ }
7168
+ if (type === "date") {
7169
+ const time = Date.parse(text2);
7170
+ return Number.isNaN(time) ? Number.NEGATIVE_INFINITY : time;
7171
+ }
7172
+ return text2.toLowerCase();
7173
+ }
7174
+ var SORT_TYPES, warnedMissingName, VelinDataTable, velin_data_table_default;
7175
+ var init_velin_data_table = __esm({
7176
+ "components/velin-data-table.js"() {
7177
+ init_a11y_utils();
7178
+ SORT_TYPES = /* @__PURE__ */ new Set(["text", "number", "date"]);
7179
+ warnedMissingName = false;
7180
+ VelinDataTable = class extends HTMLElement {
7181
+ static get observedAttributes() {
7182
+ return ["page-size", "filter-input", "empty-text", "label", "editable"];
7183
+ }
7184
+ constructor() {
7185
+ super();
7186
+ this._table = null;
7187
+ this._page = 1;
7188
+ this._query = "";
7189
+ this._sortIndex = -1;
7190
+ this._sortDirection = "ascending";
7191
+ this._filterEl = null;
7192
+ this._pagination = null;
7193
+ this._emptyRow = null;
7194
+ this._filterTimer = null;
7195
+ this._onFilterInput = this._onFilterInput.bind(this);
7196
+ }
7197
+ connectedCallback() {
7198
+ this.classList.add("velin-data-table");
7199
+ requestAnimationFrame(() => this._init());
7200
+ }
7201
+ disconnectedCallback() {
7202
+ if (this._filterEl) this._filterEl.removeEventListener("input", this._onFilterInput);
7203
+ if (this._filterTimer) clearTimeout(this._filterTimer);
7204
+ }
7205
+ attributeChangedCallback(name, previous, next) {
7206
+ if (previous === next || !this._table) return;
7207
+ if (name === "page-size") {
7208
+ this._page = 1;
7209
+ this._render();
7210
+ } else if (name === "filter-input") {
7211
+ this._bindFilterInput();
7212
+ } else if (name === "label") {
7213
+ this._ensureAccessibleName();
7214
+ }
7215
+ }
7216
+ // ── Public API ─────────────────────────────────────────────────────────────
7217
+ /** @returns {HTMLTableRowElement[]} */
7218
+ get rows() {
7219
+ const body = this._table?.tBodies?.[0];
7220
+ return body ? [...body.rows].filter((row) => row !== this._emptyRow) : [];
7221
+ }
7222
+ /** Rows matching the current filter, across all pages. */
7223
+ get matchingRows() {
7224
+ return this.rows.filter((row) => !row.dataset.velinFiltered);
7225
+ }
7226
+ /** Rows visible on the current page. */
7227
+ get visibleRows() {
7228
+ return this.matchingRows.filter((row) => !row.hidden);
7229
+ }
7230
+ get page() {
7231
+ return this._page;
7232
+ }
7233
+ get pageSize() {
7234
+ const size = Number.parseInt(this.getAttribute("page-size") || "", 10);
7235
+ return Number.isFinite(size) && size > 0 ? size : 0;
7236
+ }
7237
+ get pageCount() {
7238
+ const size = this.pageSize;
7239
+ if (!size) return 1;
7240
+ return Math.max(1, Math.ceil(this.matchingRows.length / size));
7241
+ }
7242
+ /**
7243
+ * @param {number} index Column index
7244
+ * @param {'ascending' | 'descending'} [direction]
7245
+ */
7246
+ sort(index, direction) {
7247
+ const headers = this._headers();
7248
+ const header = headers[index];
7249
+ if (!header) return;
7250
+ const type = this._sortType(header);
7251
+ if (type === "none") return;
7252
+ this._sortDirection = direction || (this._sortIndex === index && this._sortDirection === "ascending" ? "descending" : "ascending");
7253
+ this._sortIndex = index;
7254
+ const factor = this._sortDirection === "ascending" ? 1 : -1;
7255
+ const body = this._table.tBodies[0];
7256
+ const sorted = this.rows.slice().sort((a, b) => {
7257
+ const av = sortValue(a.cells[index], type);
7258
+ const bv = sortValue(b.cells[index], type);
7259
+ if (av < bv) return -1 * factor;
7260
+ if (av > bv) return 1 * factor;
7261
+ return 0;
7262
+ });
7263
+ for (const row of sorted) body.appendChild(row);
7264
+ this._syncSortState();
7265
+ this._page = 1;
7266
+ this._render();
7267
+ const label = header.dataset.sortLabel || header.textContent.trim();
7268
+ announce(`${label} sorted ${this._sortDirection}`);
7269
+ this.dispatchEvent(new CustomEvent("velin-data-table-sort", {
7270
+ bubbles: true,
7271
+ detail: { index, direction: this._sortDirection, column: label }
7272
+ }));
7273
+ }
7274
+ /** @param {string} query */
7275
+ filter(query) {
7276
+ this._query = String(query || "").trim().toLowerCase();
7277
+ for (const row of this.rows) {
7278
+ const match = !this._query || this._rowText(row).includes(this._query);
7279
+ if (match) delete row.dataset.velinFiltered;
7280
+ else row.dataset.velinFiltered = "true";
7281
+ }
7282
+ this._page = 1;
7283
+ this._render();
7284
+ const count = this.matchingRows.length;
7285
+ announce(count === 1 ? "1 row matches" : `${count} rows match`);
7286
+ this.dispatchEvent(new CustomEvent("velin-data-table-filter", {
7287
+ bubbles: true,
7288
+ detail: { query: this._query, count }
7289
+ }));
7290
+ }
7291
+ /** @param {number} page */
7292
+ goToPage(page) {
7293
+ const target = Math.min(Math.max(1, Math.trunc(page) || 1), this.pageCount);
7294
+ if (target === this._page) return;
7295
+ this._page = target;
7296
+ this._render();
7297
+ announce(`Page ${this._page} of ${this.pageCount}`);
7298
+ this.dispatchEvent(new CustomEvent("velin-data-table-page", {
7299
+ bubbles: true,
7300
+ detail: { page: this._page, pageCount: this.pageCount }
7301
+ }));
7302
+ }
7303
+ // ── Setup ──────────────────────────────────────────────────────────────────
7304
+ _init() {
7305
+ this._table = this.querySelector("table");
7306
+ if (!this._table || !this._table.tBodies.length) return;
7307
+ this._ensureAccessibleName();
7308
+ this._setupSorting();
7309
+ this._setupEditable();
7310
+ this._bindFilterInput();
7311
+ this._render();
7312
+ }
7313
+ _headers() {
7314
+ const headRow = this._table.tHead?.rows?.[0];
7315
+ return headRow ? [...headRow.cells] : [];
7316
+ }
7317
+ /** @param {HTMLTableCellElement} header */
7318
+ _sortType(header) {
7319
+ const declared = (header.dataset.sort || "").toLowerCase();
7320
+ if (declared === "none") return "none";
7321
+ if (SORT_TYPES.has(declared)) return declared;
7322
+ return this.hasAttribute("sortable") ? "text" : "none";
7323
+ }
7324
+ /**
7325
+ * A table without a name is unusable with a screen reader, so surface it
7326
+ * instead of failing silently (WCAG 1.3.1 / 2.4.6).
7327
+ */
7328
+ _ensureAccessibleName() {
7329
+ const table = this._table;
7330
+ if (!table) return;
7331
+ const label = this.getAttribute("label");
7332
+ const hasName = table.caption?.textContent.trim() || table.getAttribute("aria-label")?.trim() || table.getAttribute("aria-labelledby")?.trim();
7333
+ if (!hasName && label) {
7334
+ table.setAttribute("aria-label", label);
7335
+ return;
7336
+ }
7337
+ if (!hasName && !warnedMissingName) {
7338
+ warnedMissingName = true;
7339
+ console.warn("[velinstyle] <velin-data-table> needs a <caption>, aria-label, or a label attribute.");
7340
+ }
7341
+ }
7342
+ /** Sortable headers get a real button so keyboard and AT support come for free. */
7343
+ _setupSorting() {
7344
+ this._headers().forEach((header, index) => {
7345
+ if (this._sortType(header) === "none") return;
7346
+ if (header.querySelector(".velin-data-table__sort")) return;
7347
+ const label = header.textContent.trim();
7348
+ header.dataset.sortLabel = label;
7349
+ header.setAttribute("aria-sort", "none");
7350
+ header.classList.add("velin-data-table__th");
7351
+ const button = document.createElement("button");
7352
+ button.type = "button";
7353
+ button.className = "velin-data-table__sort";
7354
+ button.textContent = label;
7355
+ const icon = document.createElement("span");
7356
+ icon.className = "velin-data-table__sort-icon";
7357
+ icon.setAttribute("aria-hidden", "true");
7358
+ button.appendChild(icon);
7359
+ button.addEventListener("click", () => this.sort(index));
7360
+ header.textContent = "";
7361
+ header.appendChild(button);
7362
+ });
7363
+ }
7364
+ /**
7365
+ * Inline edit: double-click or Enter on focused cell with data-editable / host editable.
7366
+ * Enter saves, Escape cancels. Dispatches velin-data-table-edit.
7367
+ */
7368
+ _setupEditable() {
7369
+ if (!this.hasAttribute("editable") && !this.querySelector("[data-editable]")) return;
7370
+ const body = this._table.tBodies[0];
7371
+ if (!body || body.dataset.velinEditBound) return;
7372
+ body.dataset.velinEditBound = "true";
7373
+ body.addEventListener("dblclick", (e) => {
7374
+ const cell = e.target.closest("td");
7375
+ if (!cell || !body.contains(cell)) return;
7376
+ if (!this.hasAttribute("editable") && !cell.hasAttribute("data-editable")) return;
7377
+ this._beginEdit(cell);
7378
+ });
7379
+ body.addEventListener("keydown", (e) => {
7380
+ const cell = e.target.closest("td");
7381
+ if (!cell || e.target !== cell) return;
7382
+ if (e.key === "Enter" || e.key === "F2") {
7383
+ if (!this.hasAttribute("editable") && !cell.hasAttribute("data-editable")) return;
7384
+ e.preventDefault();
7385
+ this._beginEdit(cell);
7386
+ }
7387
+ });
7388
+ for (const cell of body.querySelectorAll("td[data-editable], td")) {
7389
+ if (!this.hasAttribute("editable") && !cell.hasAttribute("data-editable")) continue;
7390
+ if (!cell.hasAttribute("tabindex")) cell.setAttribute("tabindex", "0");
7391
+ }
7392
+ }
7393
+ /** @param {HTMLTableCellElement} cell */
7394
+ _beginEdit(cell) {
7395
+ if (cell.querySelector("input")) return;
7396
+ const previous = cell.textContent.trim();
7397
+ const input = document.createElement("input");
7398
+ input.className = "velin-input velin-data-table__edit";
7399
+ input.value = previous;
7400
+ input.setAttribute("aria-label", "Edit cell");
7401
+ cell.textContent = "";
7402
+ cell.appendChild(input);
7403
+ input.focus();
7404
+ input.select();
7405
+ const commit = (save) => {
7406
+ const next = save ? input.value.trim() : previous;
7407
+ cell.textContent = next;
7408
+ if (save && next !== previous) {
7409
+ this.dispatchEvent(new CustomEvent("velin-data-table-edit", {
7410
+ bubbles: true,
7411
+ detail: {
7412
+ cell,
7413
+ row: cell.parentElement,
7414
+ previous,
7415
+ value: next,
7416
+ columnIndex: cell.cellIndex
7417
+ }
7418
+ }));
7419
+ announce("Cell updated");
7420
+ }
7421
+ };
7422
+ input.addEventListener("keydown", (e) => {
7423
+ if (e.key === "Enter") {
7424
+ e.preventDefault();
7425
+ commit(true);
7426
+ } else if (e.key === "Escape") {
7427
+ e.preventDefault();
7428
+ commit(false);
7429
+ }
7430
+ });
7431
+ input.addEventListener("blur", () => commit(true));
7432
+ }
7433
+ _syncSortState() {
7434
+ this._headers().forEach((header, index) => {
7435
+ if (this._sortType(header) === "none") return;
7436
+ const active = index === this._sortIndex;
7437
+ header.setAttribute("aria-sort", active ? this._sortDirection : "none");
7438
+ header.querySelector(".velin-data-table__sort")?.classList.toggle("velin-data-table__sort--active", active);
7439
+ });
7440
+ }
7441
+ _bindFilterInput() {
7442
+ if (this._filterEl) this._filterEl.removeEventListener("input", this._onFilterInput);
7443
+ const selector = this.getAttribute("filter-input");
7444
+ this._filterEl = selector ? document.querySelector(selector) : null;
7445
+ if (this._filterEl) this._filterEl.addEventListener("input", this._onFilterInput);
7446
+ }
7447
+ _onFilterInput(event) {
7448
+ if (this._filterTimer) clearTimeout(this._filterTimer);
7449
+ const value = event.target.value;
7450
+ this._filterTimer = setTimeout(() => this.filter(value), 150);
7451
+ }
7452
+ /** @param {HTMLTableRowElement} row */
7453
+ _rowText(row) {
7454
+ const scoped = [...row.cells].filter((cell) => cell.hasAttribute("data-filter"));
7455
+ const cells = scoped.length ? scoped : [...row.cells];
7456
+ return cells.map((cell) => cell.textContent || "").join(" ").toLowerCase();
7457
+ }
7458
+ // ── Rendering ──────────────────────────────────────────────────────────────
7459
+ _render() {
7460
+ const size = this.pageSize;
7461
+ this._page = Math.min(this._page, this.pageCount);
7462
+ const matching = this.matchingRows;
7463
+ const start = size ? (this._page - 1) * size : 0;
7464
+ const end = size ? start + size : matching.length;
7465
+ for (const row of this.rows) {
7466
+ const index = matching.indexOf(row);
7467
+ row.hidden = index === -1 || index < start || index >= end;
7468
+ }
7469
+ this._renderEmptyState(matching.length === 0);
7470
+ this._renderPagination();
7471
+ }
7472
+ /** @param {boolean} isEmpty */
7473
+ _renderEmptyState(isEmpty) {
7474
+ if (!isEmpty) {
7475
+ this._emptyRow?.remove();
7476
+ this._emptyRow = null;
7477
+ return;
7478
+ }
7479
+ if (this._emptyRow?.isConnected) return;
7480
+ const columns = this._headers().length || 1;
7481
+ const row = document.createElement("tr");
7482
+ row.className = "velin-data-table__empty";
7483
+ const cell = document.createElement("td");
7484
+ cell.colSpan = columns;
7485
+ cell.textContent = this.getAttribute("empty-text") || "No matching rows";
7486
+ row.appendChild(cell);
7487
+ this._table.tBodies[0].appendChild(row);
7488
+ this._emptyRow = row;
7489
+ }
7490
+ _renderPagination() {
7491
+ if (!this.pageSize || this.pageCount <= 1) {
7492
+ this._pagination?.remove();
7493
+ this._pagination = null;
7494
+ return;
7495
+ }
7496
+ if (!this._pagination?.isConnected) {
7497
+ const nav = document.createElement("nav");
7498
+ nav.className = "velin-data-table__pagination";
7499
+ nav.setAttribute("aria-label", this.getAttribute("pagination-label") || "Table pagination");
7500
+ const previous2 = document.createElement("button");
7501
+ previous2.type = "button";
7502
+ previous2.className = "velin-btn velin-btn--outline velin-btn--sm";
7503
+ previous2.dataset.velinPage = "previous";
7504
+ previous2.textContent = this.getAttribute("previous-text") || "Previous";
7505
+ previous2.addEventListener("click", () => this.goToPage(this._page - 1));
7506
+ const status2 = document.createElement("p");
7507
+ status2.className = "velin-data-table__page-status";
7508
+ status2.dataset.velinPage = "status";
7509
+ const next2 = document.createElement("button");
7510
+ next2.type = "button";
7511
+ next2.className = "velin-btn velin-btn--outline velin-btn--sm";
7512
+ next2.dataset.velinPage = "next";
7513
+ next2.textContent = this.getAttribute("next-text") || "Next";
7514
+ next2.addEventListener("click", () => this.goToPage(this._page + 1));
7515
+ nav.append(previous2, status2, next2);
7516
+ this.appendChild(nav);
7517
+ this._pagination = nav;
7518
+ }
7519
+ const status = this._pagination.querySelector('[data-velin-page="status"]');
7520
+ if (status) status.textContent = `Page ${this._page} of ${this.pageCount}`;
7521
+ const previous = this._pagination.querySelector('[data-velin-page="previous"]');
7522
+ const next = this._pagination.querySelector('[data-velin-page="next"]');
7523
+ if (previous) previous.disabled = this._page <= 1;
7524
+ if (next) next.disabled = this._page >= this.pageCount;
7525
+ }
7526
+ };
7527
+ customElements.define("velin-data-table", VelinDataTable);
7528
+ velin_data_table_default = VelinDataTable;
7529
+ }
7530
+ });
7531
+
7532
+ // components/velin-file-dropzone.js
7533
+ var velin_file_dropzone_exports = {};
7534
+ __export(velin_file_dropzone_exports, {
7535
+ default: () => velin_file_dropzone_default
7536
+ });
7537
+ var styles28, VelinFileDropzone, velin_file_dropzone_default;
7538
+ var init_velin_file_dropzone = __esm({
7539
+ "components/velin-file-dropzone.js"() {
7540
+ init_sanitize();
7541
+ styles28 = `
7542
+ :host { display: block; }
7543
+ .zone {
7544
+ border: 2px dashed var(--velin-color-border, #cbd5e1);
7545
+ border-radius: var(--velin-radius-md, 0.5rem);
7546
+ padding: var(--velin-space-6, 1.5rem);
7547
+ background: var(--velin-color-surface-dim, var(--velin-color-bg-subtle, #f8fafc));
7548
+ color: var(--velin-color-text, #111);
7549
+ text-align: center;
7550
+ transition: border-color 150ms ease, background 150ms ease;
7551
+ }
7552
+ :host([dragging]) .zone {
7553
+ border-color: var(--velin-color-primary, #2563eb);
7554
+ background: var(--velin-color-primary-subtle, #eff6ff);
7555
+ }
7556
+ .hint { margin: 0 0 var(--velin-space-3, 0.75rem); color: var(--velin-color-text-muted, #64748b); }
7557
+ .browse {
7558
+ display: inline-flex; align-items: center; justify-content: center;
7559
+ min-block-size: 2.75rem; padding-inline: var(--velin-space-4, 1rem);
7560
+ border-radius: var(--velin-radius-md, 0.5rem);
7561
+ border: none; cursor: pointer;
7562
+ background: var(--velin-color-primary, #2563eb);
7563
+ color: var(--velin-color-on-primary, #fff);
7564
+ font: inherit;
7565
+ }
7566
+ .browse:focus-visible { outline: 2px solid var(--velin-color-focus, #2563eb); outline-offset: 2px; }
7567
+ input[type="file"] {
7568
+ position: absolute; inline-size: 1px; block-size: 1px; padding: 0; margin: -1px;
7569
+ overflow: hidden; clip: rect(0,0,0,0); border: 0;
7570
+ }
7571
+ .list { list-style: none; padding: 0; margin: var(--velin-space-4, 1rem) 0 0; text-align: start; }
7572
+ .list li {
7573
+ display: flex; justify-content: space-between; gap: var(--velin-space-3, 0.75rem);
7574
+ padding: var(--velin-space-2, 0.5rem) 0;
7575
+ border-block-end: 1px solid var(--velin-color-border, #e2e8f0);
7576
+ font-size: var(--velin-text-sm, 0.875rem);
7577
+ }
7578
+ .progress {
7579
+ margin-block-start: var(--velin-space-3, 0.75rem);
7580
+ block-size: 0.5rem; border-radius: 999px;
7581
+ background: var(--velin-color-border, #e2e8f0); overflow: hidden;
7582
+ }
7583
+ .bar {
7584
+ block-size: 100%; inline-size: 0%;
7585
+ background: var(--velin-color-primary, #2563eb);
7586
+ transition: inline-size 150ms ease;
7587
+ }
7588
+ .status { margin: var(--velin-space-2, 0.5rem) 0 0; font-size: var(--velin-text-sm, 0.875rem); }
7589
+ .status[data-tone="error"] { color: var(--velin-color-danger, #b91c1c); }
7590
+ `;
7591
+ VelinFileDropzone = class extends HTMLElement {
7592
+ static get observedAttributes() {
7593
+ return ["accept", "multiple", "label", "progress"];
7594
+ }
7595
+ constructor() {
7596
+ super();
7597
+ this.attachShadow({ mode: "open" });
7598
+ this._files = [];
7599
+ }
7600
+ connectedCallback() {
7601
+ this._render();
7602
+ }
7603
+ attributeChangedCallback() {
7604
+ if (this.shadowRoot?.querySelector(".zone")) this._render();
7605
+ }
7606
+ get files() {
7607
+ return this._files.slice();
7608
+ }
7609
+ _emitFiles(fileList) {
7610
+ const accept = this.getAttribute("accept");
7611
+ const files = [...fileList];
7612
+ if (accept) {
7613
+ const parts = accept.split(",").map((s) => s.trim().toLowerCase());
7614
+ const bad = files.find((f) => {
7615
+ const name = f.name.toLowerCase();
7616
+ const type = (f.type || "").toLowerCase();
7617
+ return !parts.some((p) => p.startsWith(".") ? name.endsWith(p) : type === p || type.startsWith(p.replace("/*", "/")));
7618
+ });
7619
+ if (bad) {
7620
+ this._setStatus(`File type not allowed: ${bad.name}`, "error");
7621
+ this.dispatchEvent(new CustomEvent("velin-error", { bubbles: true, detail: { message: "accept", file: bad } }));
7622
+ return;
7623
+ }
7624
+ }
7625
+ this._files = files;
7626
+ this._setStatus(files.length ? `${files.length} file(s) ready` : "", "ok");
7627
+ this.dispatchEvent(new CustomEvent("velin-files", { bubbles: true, detail: { files } }));
7628
+ this._renderList();
7629
+ }
7630
+ _setStatus(text2, tone = "ok") {
7631
+ const el = this.shadowRoot?.querySelector(".status");
7632
+ if (!el) return;
7633
+ el.textContent = text2;
7634
+ el.dataset.tone = tone;
7635
+ }
7636
+ _renderList() {
7637
+ const ul = this.shadowRoot?.querySelector(".list");
7638
+ if (!ul) return;
7639
+ ul.innerHTML = this._files.map((f) => `<li><span>${escapeHTML(f.name)}</span><span>${Math.round(f.size / 1024)} KB</span></li>`).join("");
7640
+ }
7641
+ _render() {
7642
+ const label = escapeHTML(this.getAttribute("label") || "Upload files");
7643
+ const accept = this.getAttribute("accept") || "";
7644
+ const multiple = this.hasAttribute("multiple");
7645
+ const progress = Math.max(0, Math.min(100, Number(this.getAttribute("progress") || 0)));
7646
+ this.shadowRoot.innerHTML = `
7647
+ <style>${styles28}</style>
7648
+ <div class="zone" role="group" aria-label="${label}">
7649
+ <p class="hint">Drag and drop files here, or browse. Client-side only \u2014 wire <code>velin-files</code> to your upload API.</p>
7650
+ <button type="button" class="browse">Browse files</button>
7651
+ <input type="file" ${accept ? `accept="${escapeHTML(accept)}"` : ""} ${multiple ? "multiple" : ""} />
7652
+ <div class="progress" hidden="${progress <= 0 ? "true" : "false"}" aria-hidden="${progress <= 0 ? "true" : "false"}">
7653
+ <div class="bar" style="inline-size:${progress}%"></div>
7654
+ </div>
7655
+ <p class="status" role="status" aria-live="polite"></p>
7656
+ <ul class="list"></ul>
7657
+ </div>
7658
+ `;
7659
+ const input = this.shadowRoot.querySelector("input");
7660
+ const browse = this.shadowRoot.querySelector(".browse");
7661
+ const zone = this.shadowRoot.querySelector(".zone");
7662
+ browse.addEventListener("click", () => input.click());
7663
+ input.addEventListener("change", () => {
7664
+ if (input.files?.length) this._emitFiles(input.files);
7665
+ });
7666
+ ["dragenter", "dragover"].forEach((ev) => {
7667
+ zone.addEventListener(ev, (e) => {
7668
+ e.preventDefault();
7669
+ this.setAttribute("dragging", "");
7670
+ });
7671
+ });
7672
+ ["dragleave", "drop"].forEach((ev) => {
7673
+ zone.addEventListener(ev, (e) => {
7674
+ e.preventDefault();
7675
+ this.removeAttribute("dragging");
7676
+ });
7677
+ });
7678
+ zone.addEventListener("drop", (e) => {
7679
+ const list = e.dataTransfer?.files;
7680
+ if (list?.length) this._emitFiles(list);
7681
+ });
7682
+ this._renderList();
7683
+ }
7684
+ };
7685
+ customElements.define("velin-file-dropzone", VelinFileDropzone);
7686
+ velin_file_dropzone_default = VelinFileDropzone;
7687
+ }
7688
+ });
7689
+
7690
+ // components/velin-form-summary.js
7691
+ var velin_form_summary_exports = {};
7692
+ __export(velin_form_summary_exports, {
7693
+ default: () => velin_form_summary_default
7694
+ });
7695
+ function escapeSelector(value) {
7696
+ const text2 = String(value ?? "");
7697
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") return CSS.escape(text2);
7698
+ return text2.replace(/[^\w-]/g, (char) => `\\${char}`);
7699
+ }
7700
+ function fieldLabel(field) {
7701
+ const explicit = field.getAttribute("data-error-label");
7702
+ if (explicit) return explicit;
7703
+ const ariaLabel = field.getAttribute("aria-label");
7704
+ if (ariaLabel?.trim()) return ariaLabel.trim();
7705
+ const labelledBy = field.getAttribute("aria-labelledby");
7706
+ if (labelledBy) {
7707
+ const text2 = labelledBy.split(/\s+/).map((id) => field.ownerDocument.getElementById(id)?.textContent?.trim() || "").filter(Boolean).join(" ");
7708
+ if (text2) return text2;
7709
+ }
7710
+ if (field.id) {
7711
+ const label = field.ownerDocument.querySelector(`label[for="${escapeSelector(field.id)}"]`);
7712
+ if (label?.textContent.trim()) return label.textContent.trim();
7713
+ }
7714
+ const wrapping = field.closest("label");
7715
+ if (wrapping?.textContent.trim()) return wrapping.textContent.trim();
7716
+ return field.name || "This field";
7717
+ }
7718
+ function fieldMessage(field) {
7719
+ return field.getAttribute("data-error-message")?.trim() || field.validationMessage || "Invalid value";
7720
+ }
7721
+ function addDescribedBy(field, id) {
7722
+ const ids = (field.getAttribute("aria-describedby") || "").split(/\s+/).filter(Boolean);
7723
+ if (!ids.includes(id)) {
7724
+ ids.push(id);
7725
+ field.setAttribute("aria-describedby", ids.join(" "));
7726
+ }
7727
+ }
7728
+ function removeDescribedBy(field, id) {
7729
+ const ids = (field.getAttribute("aria-describedby") || "").split(/\s+/).filter(Boolean);
7730
+ const next = ids.filter((value) => value !== id);
7731
+ if (next.length) field.setAttribute("aria-describedby", next.join(" "));
7732
+ else field.removeAttribute("aria-describedby");
7733
+ }
7734
+ var FIELD_SELECTOR, IGNORED_TYPES, fieldIdCounter, VelinFormSummary, velin_form_summary_default;
7735
+ var init_velin_form_summary = __esm({
7736
+ "components/velin-form-summary.js"() {
7737
+ init_a11y_utils();
7738
+ FIELD_SELECTOR = "input, select, textarea";
7739
+ IGNORED_TYPES = /* @__PURE__ */ new Set(["submit", "reset", "button", "image", "hidden"]);
7740
+ fieldIdCounter = 0;
7741
+ VelinFormSummary = class extends HTMLElement {
7742
+ static get observedAttributes() {
7743
+ return ["for", "heading"];
7744
+ }
7745
+ constructor() {
7746
+ super();
7747
+ this._form = null;
7748
+ this._panel = null;
7749
+ this._errors = [];
7750
+ this._onSubmit = this._onSubmit.bind(this);
7751
+ this._onFieldChange = this._onFieldChange.bind(this);
7752
+ this._onReset = this._onReset.bind(this);
7753
+ }
7754
+ connectedCallback() {
7755
+ this.classList.add("velin-form-summary");
7756
+ requestAnimationFrame(() => this._bindForm());
7757
+ }
7758
+ disconnectedCallback() {
7759
+ this._unbindForm();
7760
+ }
7761
+ attributeChangedCallback(name, previous, next) {
7762
+ if (previous === next) return;
7763
+ if (name === "for" && this.isConnected) {
7764
+ this._unbindForm();
7765
+ this._bindForm();
7766
+ } else if (name === "heading" && this._panel) {
7767
+ const heading = this._panel.querySelector(".velin-form-summary__heading");
7768
+ if (heading) heading.textContent = this.headingText;
7769
+ }
7770
+ }
7771
+ // ── Public API ─────────────────────────────────────────────────────────────
7772
+ get form() {
7773
+ return this._form;
7774
+ }
7775
+ /** @returns {{ field: HTMLElement, label: string, message: string }[]} */
7776
+ get errors() {
7777
+ return this._errors.slice();
7778
+ }
7779
+ get headingText() {
7780
+ return this.getAttribute("heading") || "There is a problem";
7781
+ }
7782
+ /** Validate the form and render the summary. @returns {boolean} valid */
7783
+ validate() {
7784
+ if (!this._form) return true;
7785
+ const errors = [];
7786
+ for (const field of this._fields()) {
7787
+ if (field.checkValidity()) {
7788
+ this._clearFieldError(field);
7789
+ continue;
7790
+ }
7791
+ const error = { field, label: fieldLabel(field), message: fieldMessage(field) };
7792
+ this._markFieldError(field, error.message);
7793
+ errors.push(error);
7794
+ }
7795
+ this._errors = errors;
7796
+ this._render();
7797
+ return errors.length === 0;
7798
+ }
7799
+ /** Remove the summary and all field error state. */
7800
+ clear() {
7801
+ for (const field of this._fields()) this._clearFieldError(field);
7802
+ this._errors = [];
7803
+ this._render();
7804
+ }
7805
+ /** Move focus to the first field with an error. */
7806
+ focusFirstError() {
7807
+ const first = this._errors[0];
7808
+ if (first) this._focusField(first.field);
7809
+ }
7810
+ // ── Form wiring ────────────────────────────────────────────────────────────
7811
+ _bindForm() {
7812
+ const id = this.getAttribute("for");
7813
+ this._form = id ? this.ownerDocument.getElementById(id) : this.closest("form");
7814
+ if (!this._form) return;
7815
+ if (!this.hasAttribute("native-validation")) this._form.noValidate = true;
7816
+ this._form.addEventListener("submit", this._onSubmit);
7817
+ this._form.addEventListener("reset", this._onReset);
7818
+ this._form.addEventListener("input", this._onFieldChange);
7819
+ this._form.addEventListener("change", this._onFieldChange);
7820
+ }
7821
+ _unbindForm() {
7822
+ if (!this._form) return;
7823
+ this._form.removeEventListener("submit", this._onSubmit);
7824
+ this._form.removeEventListener("reset", this._onReset);
7825
+ this._form.removeEventListener("input", this._onFieldChange);
7826
+ this._form.removeEventListener("change", this._onFieldChange);
7827
+ this._form = null;
7828
+ }
7829
+ /** @returns {HTMLElement[]} */
7830
+ _fields() {
7831
+ if (!this._form) return [];
7832
+ const seenRadioNames = /* @__PURE__ */ new Set();
7833
+ return [...this._form.querySelectorAll(FIELD_SELECTOR)].filter((field) => {
7834
+ if (IGNORED_TYPES.has(field.type)) return false;
7835
+ if (field.disabled || field.hasAttribute("data-error-ignore")) return false;
7836
+ if (typeof field.checkValidity !== "function") return false;
7837
+ if (field.type === "radio" && field.name) {
7838
+ if (seenRadioNames.has(field.name)) return false;
7839
+ seenRadioNames.add(field.name);
7840
+ }
7841
+ return true;
7842
+ });
7843
+ }
7844
+ _onSubmit(event) {
7845
+ if (this.validate()) return;
7846
+ event.preventDefault();
7847
+ this._announceErrors();
7848
+ this._focusPanel();
7849
+ this.dispatchEvent(new CustomEvent("velin-form-invalid", {
7850
+ bubbles: true,
7851
+ detail: { errors: this.errors.map(({ label, message }) => ({ label, message })) }
7852
+ }));
7853
+ }
7854
+ _onReset() {
7855
+ requestAnimationFrame(() => this.clear());
7856
+ }
7857
+ /** Re-validate a single field once it already had an error, never before. */
7858
+ _onFieldChange(event) {
7859
+ const field = event.target;
7860
+ if (!field || !this._errors.some((error) => error.field === field)) return;
7861
+ if (!field.checkValidity()) return;
7862
+ this._clearFieldError(field);
7863
+ this._errors = this._errors.filter((error) => error.field !== field);
7864
+ this._render();
7865
+ if (this._errors.length === 0) {
7866
+ this.dispatchEvent(new CustomEvent("velin-form-valid", { bubbles: true }));
7867
+ }
7868
+ }
7869
+ // ── Field state ────────────────────────────────────────────────────────────
7870
+ /** @param {HTMLElement} field */
7871
+ _errorId(field) {
7872
+ if (!field.id) field.id = `velin-field-${++fieldIdCounter}`;
7873
+ return `${field.id}-error`;
7874
+ }
7875
+ /**
7876
+ * @param {HTMLElement} field
7877
+ * @param {string} message
7878
+ */
7879
+ _markFieldError(field, message) {
7880
+ const errorId = this._errorId(field);
7881
+ field.setAttribute("aria-invalid", "true");
7882
+ let holder = this.ownerDocument.getElementById(errorId);
7883
+ if (!holder) {
7884
+ holder = this._form.querySelector(`[data-velin-error-for="${escapeSelector(field.name || field.id)}"]`);
7885
+ }
7886
+ if (!holder) {
7887
+ holder = this.ownerDocument.createElement("p");
7888
+ holder.dataset.velinErrorGenerated = "true";
7889
+ field.insertAdjacentElement("afterend", holder);
7890
+ }
7891
+ holder.id = errorId;
7892
+ holder.classList.add("velin-field-error");
7893
+ holder.textContent = message;
7894
+ addDescribedBy(field, errorId);
7895
+ }
7896
+ /** @param {HTMLElement} field */
7897
+ _clearFieldError(field) {
7898
+ if (!field.id) return;
7899
+ const errorId = `${field.id}-error`;
7900
+ field.removeAttribute("aria-invalid");
7901
+ removeDescribedBy(field, errorId);
7902
+ const holder = this.ownerDocument.getElementById(errorId);
7903
+ if (!holder) return;
7904
+ if (holder.dataset.velinErrorGenerated) holder.remove();
7905
+ else holder.textContent = "";
7906
+ }
7907
+ /** @param {HTMLElement} field */
7908
+ _focusField(field) {
7909
+ const target = field.type === "radio" && field.name ? this._form.querySelector(`input[type="radio"][name="${escapeSelector(field.name)}"]`) || field : field;
7910
+ target.focus();
7911
+ this.dispatchEvent(new CustomEvent("velin-form-error-focus", {
7912
+ bubbles: true,
7913
+ detail: { name: target.name || target.id }
7914
+ }));
7915
+ }
7916
+ // ── Summary panel ──────────────────────────────────────────────────────────
7917
+ _render() {
7918
+ if (!this._errors.length) {
7919
+ this._panel?.remove();
7920
+ this._panel = null;
7921
+ this.hidden = true;
7922
+ return;
7923
+ }
7924
+ this.hidden = false;
7925
+ if (!this._panel?.isConnected) {
7926
+ const panel = this.ownerDocument.createElement("div");
7927
+ panel.className = "velin-form-summary__panel velin-alert velin-alert--danger";
7928
+ panel.setAttribute("role", "alert");
7929
+ panel.tabIndex = -1;
7930
+ const heading = this.ownerDocument.createElement("p");
7931
+ heading.className = "velin-form-summary__heading";
7932
+ heading.textContent = this.headingText;
7933
+ const list2 = this.ownerDocument.createElement("ul");
7934
+ list2.className = "velin-form-summary__list";
7935
+ panel.append(heading, list2);
7936
+ this.appendChild(panel);
7937
+ this._panel = panel;
7938
+ }
7939
+ const list = this._panel.querySelector(".velin-form-summary__list");
7940
+ list.textContent = "";
7941
+ for (const error of this._errors) {
7942
+ const item = this.ownerDocument.createElement("li");
7943
+ const link = this.ownerDocument.createElement("a");
7944
+ link.href = `#${this._errorId(error.field).replace(/-error$/, "")}`;
7945
+ link.textContent = `${error.label}: ${error.message}`;
7946
+ link.addEventListener("click", (event) => {
7947
+ event.preventDefault();
7948
+ this._focusField(error.field);
7949
+ });
7950
+ item.appendChild(link);
7951
+ list.appendChild(item);
7952
+ }
7953
+ }
7954
+ _focusPanel() {
7955
+ this._panel?.focus();
7956
+ }
7957
+ _announceErrors() {
7958
+ const count = this._errors.length;
7959
+ announce(count === 1 ? "1 field needs attention" : `${count} fields need attention`, "assertive");
7960
+ }
7961
+ };
7962
+ customElements.define("velin-form-summary", VelinFormSummary);
7963
+ velin_form_summary_default = VelinFormSummary;
7964
+ }
7965
+ });
7966
+
6310
7967
  // components/velin-live-dot.js
6311
7968
  var velin_live_dot_exports = {};
6312
7969
  __export(velin_live_dot_exports, {
6313
7970
  default: () => velin_live_dot_default
6314
7971
  });
6315
- var STATUS_COLORS, styles28, KEYFRAMES_FALLBACK, VelinLiveDot, velin_live_dot_default;
7972
+ var STATUS_COLORS, styles29, KEYFRAMES_FALLBACK, VelinLiveDot, velin_live_dot_default;
6316
7973
  var init_velin_live_dot = __esm({
6317
7974
  "components/velin-live-dot.js"() {
6318
7975
  init_a11y_utils();
@@ -6323,7 +7980,7 @@ var init_velin_live_dot = __esm({
6323
7980
  error: "var(--velin-color-danger, oklch(60% 0.2 25))",
6324
7981
  muted: "var(--velin-color-border, oklch(85% 0.01 240))"
6325
7982
  };
6326
- styles28 = `
7983
+ styles29 = `
6327
7984
  :host {
6328
7985
  display: inline-flex;
6329
7986
  align-items: center;
@@ -6373,7 +8030,7 @@ var init_velin_live_dot = __esm({
6373
8030
  this.setAttribute("aria-label", label);
6374
8031
  this.style.setProperty("--velin-live-color", color);
6375
8032
  this.shadowRoot.innerHTML = `
6376
- <style>${styles28}${KEYFRAMES_FALLBACK}</style>
8033
+ <style>${styles29}${KEYFRAMES_FALLBACK}</style>
6377
8034
  <span class="dot" aria-hidden="true"></span><slot></slot>
6378
8035
  `;
6379
8036
  }
@@ -6991,7 +8648,7 @@ var init_velin_search = __esm({
6991
8648
  return;
6992
8649
  }
6993
8650
  if (!this._indexLoaded) await this._loadIndex();
6994
- const { groups } = this._search.query(q, {
8651
+ const { groups } = await this._search.query(q, {
6995
8652
  minChars: this.minChars,
6996
8653
  fuzzy: this.fuzzy,
6997
8654
  categories: this.categories || void 0,
@@ -7122,11 +8779,11 @@ async function encryptValue(plain, mode) {
7122
8779
  cipher: Array.from(new Uint8Array(cipher))
7123
8780
  });
7124
8781
  }
7125
- var styles29, VelinSecureField, velin_secure_field_default;
8782
+ var styles30, VelinSecureField, velin_secure_field_default;
7126
8783
  var init_velin_secure_field = __esm({
7127
8784
  "components/velin-secure-field.js"() {
7128
8785
  init_sanitize();
7129
- styles29 = `
8786
+ styles30 = `
7130
8787
  :host { display: block; }
7131
8788
  label { display: block; font-size: var(--velin-text-sm); margin-block-end: var(--velin-space-1); }
7132
8789
  input {
@@ -7176,7 +8833,7 @@ var init_velin_secure_field = __esm({
7176
8833
  const input = this.shadowRoot?.querySelector("input");
7177
8834
  if (input && this._onChange) input.removeEventListener("change", this._onChange);
7178
8835
  this.shadowRoot.innerHTML = `
7179
- <style>${styles29}</style>
8836
+ <style>${styles30}</style>
7180
8837
  <label for="${id}">${escapeHTML(label)}</label>
7181
8838
  <input id="${id}" type="${type}" autocomplete="${autocomplete}" part="input" />
7182
8839
  <p class="velin-field-help">Demo-only client encoding \u2014 use HTTPS and server-side crypto for real secrets.</p>
@@ -7396,6 +9053,7 @@ var init_component_loaders = __esm({
7396
9053
  "velin-accordion": () => Promise.resolve().then(() => (init_velin_accordion(), velin_accordion_exports)),
7397
9054
  "velin-announcer": () => Promise.resolve().then(() => (init_velin_announcer(), velin_announcer_exports)),
7398
9055
  "velin-bottom-nav": () => Promise.resolve().then(() => (init_velin_bottom_nav(), velin_bottom_nav_exports)),
9056
+ "velin-calendar": () => Promise.resolve().then(() => (init_velin_calendar(), velin_calendar_exports)),
7399
9057
  "velin-carousel": () => Promise.resolve().then(() => (init_velin_carousel(), velin_carousel_exports)),
7400
9058
  "velin-code-block": () => Promise.resolve().then(() => (init_velin_code_block(), velin_code_block_exports)),
7401
9059
  "velin-collapse": () => Promise.resolve().then(() => (init_velin_collapse(), velin_collapse_exports)),
@@ -7404,10 +9062,13 @@ var init_component_loaders = __esm({
7404
9062
  "velin-copy": () => Promise.resolve().then(() => (init_velin_copy(), velin_copy_exports)),
7405
9063
  "velin-countdown": () => Promise.resolve().then(() => (init_velin_countdown(), velin_countdown_exports)),
7406
9064
  "velin-counter": () => Promise.resolve().then(() => (init_velin_counter(), velin_counter_exports)),
9065
+ "velin-data-table": () => Promise.resolve().then(() => (init_velin_data_table(), velin_data_table_exports)),
7407
9066
  "velin-dialog": () => Promise.resolve().then(() => (init_velin_dialog(), velin_dialog_exports)),
7408
9067
  "velin-drawer": () => Promise.resolve().then(() => (init_velin_drawer(), velin_drawer_exports)),
7409
9068
  "velin-dropdown": () => Promise.resolve().then(() => (init_velin_dropdown(), velin_dropdown_exports)),
7410
9069
  "velin-email": () => Promise.resolve().then(() => (init_velin_email(), velin_email_exports)),
9070
+ "velin-file-dropzone": () => Promise.resolve().then(() => (init_velin_file_dropzone(), velin_file_dropzone_exports)),
9071
+ "velin-form-summary": () => Promise.resolve().then(() => (init_velin_form_summary(), velin_form_summary_exports)),
7411
9072
  "velin-icon": () => Promise.resolve().then(() => (init_velin_icon(), velin_icon_exports)),
7412
9073
  "velin-lightbox": () => Promise.resolve().then(() => (init_velin_lightbox(), velin_lightbox_exports)),
7413
9074
  "velin-live-dot": () => Promise.resolve().then(() => (init_velin_live_dot(), velin_live_dot_exports)),
@@ -8023,6 +9684,10 @@ init_velin_sparkline();
8023
9684
  init_velin_counter();
8024
9685
  init_velin_live_dot();
8025
9686
  init_velin_code_block();
9687
+ init_velin_data_table();
9688
+ init_velin_form_summary();
9689
+ init_velin_calendar();
9690
+ init_velin_file_dropzone();
8026
9691
  init_velin_search();
8027
9692
  init_velin_search();
8028
9693
 
@@ -8246,6 +9911,7 @@ export {
8246
9911
  velin_accordion_default as VelinAccordion,
8247
9912
  velin_announcer_default as VelinAnnouncer,
8248
9913
  velin_bottom_nav_default as VelinBottomNav,
9914
+ velin_calendar_default as VelinCalendar,
8249
9915
  velin_carousel_default as VelinCarousel,
8250
9916
  velin_code_block_default as VelinCodeBlock,
8251
9917
  velin_collapse_default as VelinCollapse,
@@ -8254,10 +9920,13 @@ export {
8254
9920
  velin_copy_default as VelinCopy,
8255
9921
  velin_countdown_default as VelinCountdown,
8256
9922
  velin_counter_default as VelinCounter,
9923
+ velin_data_table_default as VelinDataTable,
8257
9924
  velin_dialog_default as VelinDialog,
8258
9925
  velin_drawer_default as VelinDrawer,
8259
9926
  velin_dropdown_default as VelinDropdown,
8260
9927
  velin_email_default as VelinEmail,
9928
+ velin_file_dropzone_default as VelinFileDropzone,
9929
+ velin_form_summary_default as VelinFormSummary,
8261
9930
  VelinHapticObserver,
8262
9931
  velin_icon_default as VelinIcon,
8263
9932
  velin_lightbox_default as VelinLightbox,
@@ -8327,5 +9996,5 @@ export {
8327
9996
  /*! Bundled license information:
8328
9997
 
8329
9998
  dompurify/dist/purify.es.mjs:
8330
- (*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE *)
9999
+ (*! @license DOMPurify 3.4.12 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.12/LICENSE *)
8331
10000
  */