@birdapi/velinstyle 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/README.de.md +87 -162
  2. package/README.md +188 -119
  3. package/cli/blueprint.js +98 -5
  4. package/cli/blueprints/app-chrome.html +18 -0
  5. package/cli/blueprints/benefits-grid.html +9 -0
  6. package/cli/blueprints/bottom-nav-mobile.html +2 -1
  7. package/cli/blueprints/cookie-consent.html +1 -1
  8. package/cli/blueprints/cta-band.html +6 -0
  9. package/cli/blueprints/faq-section.html +18 -0
  10. package/cli/blueprints/filter-bar.html +4 -4
  11. package/cli/blueprints/form-contact.html +6 -5
  12. package/cli/blueprints/hero-section.html +3 -3
  13. package/cli/blueprints/notification-center.html +1 -1
  14. package/cli/blueprints/onboarding.html +2 -1
  15. package/cli/blueprints/ops-console.html +29 -0
  16. package/cli/blueprints/pricing-band.html +37 -0
  17. package/cli/blueprints/process-steps.html +10 -0
  18. package/cli/blueprints/services-grid.html +9 -0
  19. package/cli/blueprints/settings-panel.html +8 -6
  20. package/cli/blueprints/split-hero.html +25 -0
  21. package/cli/blueprints/testimonials.html +8 -0
  22. package/cli/blueprints/trust-bar.html +10 -0
  23. package/cli/cli-manifest.json +81 -17
  24. package/cli/contrast-utils.js +97 -0
  25. package/cli/create.js +370 -0
  26. package/cli/docgen/extract-attributes.js +126 -10
  27. package/cli/docgen/extract-cli.js +3 -2
  28. package/cli/docgen/extract-components.js +61 -2
  29. package/cli/docgen/extract-utilities.js +10 -10
  30. package/cli/doctor.js +119 -0
  31. package/cli/index.js +531 -44
  32. package/cli/meta.js +84 -1
  33. package/cli/perf-audit.js +15 -2
  34. package/cli/prompt-engine.js +243 -0
  35. package/cli/review.js +268 -0
  36. package/cli/scaffold.js +119 -4
  37. package/cli/scanner-rules-data.js +7 -0
  38. package/cli/scanner.js +357 -4
  39. package/cli/serve.js +81 -0
  40. package/cli/skills.js +223 -0
  41. package/cli/wc-api.js +89 -0
  42. package/cli/workflow.js +42 -0
  43. package/components/index.js +2 -0
  44. package/components/runtime/component-loaders.js +2 -0
  45. package/components/velin-accordion.js +62 -13
  46. package/components/velin-bottom-nav.js +10 -0
  47. package/components/velin-calendar.js +212 -0
  48. package/components/velin-command.js +18 -2
  49. package/components/velin-data-table.js +78 -1
  50. package/components/velin-dialog.js +4 -1
  51. package/components/velin-drawer.js +2 -4
  52. package/components/velin-file-dropzone.js +162 -0
  53. package/components/velin-icon.js +22 -1
  54. package/components/velin-lightbox.js +5 -3
  55. package/components/velin-modal.js +2 -4
  56. package/components/velin-search.js +1 -1
  57. package/components/velin-sheet.js +2 -4
  58. package/core/a11y/component-contracts.json +20 -3
  59. package/core/meta/build.js +125 -5
  60. package/core/meta/design-constraints/contact.json +9 -0
  61. package/core/meta/design-constraints/faq.json +9 -0
  62. package/core/meta/design-constraints/hero.json +13 -0
  63. package/core/meta/knowledge/components.json +622 -0
  64. package/core/meta/knowledge/tokens.json +282 -0
  65. package/core/meta/pages/registry.json +294 -0
  66. package/core/meta/schema.js +3 -1
  67. package/core/meta/sections/registry.json +185 -0
  68. package/dist/chunks/{attributes-STYCS3O5.js → attributes-A423NX5J.js} +3 -3
  69. package/dist/chunks/{attributes-353XDOAX.js → attributes-F6UPIEVP.js} +1 -1
  70. package/dist/chunks/{attributes-ADOKLKA7.js → attributes-GLYXGGAL.js} +3 -3
  71. package/dist/chunks/{attributes-TPANLMLF.js → attributes-UFTYOSAU.js} +3 -3
  72. package/dist/chunks/attributes-XGLXLR2T.js +391 -0
  73. package/dist/chunks/attributes-YF4NI2QS.js +391 -0
  74. package/dist/chunks/browser-AUABBYUK.js +1544 -0
  75. package/dist/chunks/{chunk-RSMRR27R.js → chunk-2LSKX57P.js} +12 -10
  76. package/dist/chunks/{chunk-IEHKRARD.js → chunk-2TGCVDUL.js} +11 -9
  77. package/dist/chunks/{chunk-SRL6EWHP.js → chunk-5JWGUAPC.js} +17 -13
  78. package/dist/chunks/chunk-7YSO2OQ2.js +113 -0
  79. package/dist/chunks/{chunk-QVHYL3R4.js → chunk-BHR3ZG6U.js} +6 -6
  80. package/dist/chunks/{chunk-J472ERN2.js → chunk-JMSIHEYX.js} +15 -4
  81. package/dist/chunks/{chunk-MKZP2TBH.js → chunk-L7ZGUU4D.js} +2 -2
  82. package/dist/chunks/chunk-TUGIPKW5.js +113 -0
  83. package/dist/chunks/{highlight-GJHHV4KM.js → highlight-M2ELQNYK.js} +1 -1
  84. package/dist/chunks/runtime-entry.js +1 -1
  85. package/dist/chunks/{velin-accordion-FBIPAEXG.js → velin-accordion-WSY6BMLA.js} +64 -10
  86. package/dist/chunks/{velin-bottom-nav-7GEMPIM6.js → velin-bottom-nav-5RVRNGIP.js} +25 -0
  87. package/dist/chunks/{velin-bottom-nav-N3DFQR66.js → velin-bottom-nav-N5F4UO2I.js} +26 -1
  88. package/dist/chunks/velin-calendar-OFE6THUD.js +210 -0
  89. package/dist/chunks/velin-calendar-PGVNJTXK.js +217 -0
  90. package/dist/chunks/velin-calendar-XC7JRDSH.js +217 -0
  91. package/dist/chunks/{velin-code-block-CIAURDRJ.js → velin-code-block-ZGWG7JI5.js} +1 -1
  92. package/dist/chunks/{velin-combobox-NXS4QB4R.js → velin-combobox-56V2ZWT5.js} +1 -1
  93. package/dist/chunks/{velin-command-ONKO2A3J.js → velin-command-2HO2EKR6.js} +29 -2
  94. package/dist/chunks/{velin-command-TMLSRGIU.js → velin-command-ZJSLPK7B.js} +30 -3
  95. package/dist/chunks/{velin-copy-NYDBOKXT.js → velin-copy-XDQSV2XU.js} +1 -1
  96. package/dist/chunks/{velin-countdown-4ZVDGK4R.js → velin-countdown-V4Z5MA63.js} +1 -1
  97. package/dist/chunks/velin-data-table-UVR42UUM.js +372 -0
  98. package/dist/chunks/{velin-dialog-GTTZI564.js → velin-dialog-3YK2RPRV.js} +9 -2
  99. package/dist/chunks/{velin-dialog-ELFOZIXZ.js → velin-dialog-S24KAP4S.js} +3 -1
  100. package/dist/chunks/{velin-drawer-BE6TYN3H.js → velin-drawer-5PNU624J.js} +2 -4
  101. package/dist/chunks/{velin-drawer-DLL2GLT6.js → velin-drawer-CCM6S25D.js} +3 -5
  102. package/dist/chunks/{velin-email-RBX6ZR4S.js → velin-email-TNFONXPW.js} +1 -1
  103. package/dist/chunks/velin-file-dropzone-QRGF2JNA.js +154 -0
  104. package/dist/chunks/velin-file-dropzone-XIZMJ3NB.js +154 -0
  105. package/dist/chunks/{velin-icon-7M76DOPB.js → velin-icon-A6NCXGUK.js} +59 -17
  106. package/dist/chunks/{velin-icon-ZTSKUOVN.js → velin-icon-EC4B5XCM.js} +18 -5
  107. package/dist/chunks/{velin-lightbox-6E7CAATP.js → velin-lightbox-FFK4TUUP.js} +7 -6
  108. package/dist/chunks/{velin-lightbox-NXA3U2FM.js → velin-lightbox-P725FLTY.js} +5 -4
  109. package/dist/chunks/{velin-menubar-J66JXRWW.js → velin-menubar-6I2LM5HL.js} +1 -1
  110. package/dist/chunks/{velin-modal-5HYNNNUI.js → velin-modal-ICTMGRSU.js} +7 -8
  111. package/dist/chunks/{velin-modal-AEOTZ67O.js → velin-modal-JBNODH7D.js} +2 -4
  112. package/dist/chunks/{velin-popover-T72HK3DF.js → velin-popover-WZG2GHBL.js} +25 -4
  113. package/dist/chunks/{velin-rating-N4DI2XNL.js → velin-rating-QBBYRRBU.js} +1 -1
  114. package/dist/chunks/{velin-search-7B4KJ6TX.js → velin-search-B3L6J2RP.js} +2 -2
  115. package/dist/chunks/{velin-search-2XRQFBCS.js → velin-search-L3UG6NDQ.js} +5 -4
  116. package/dist/chunks/{velin-secure-field-6PV7RZDJ.js → velin-secure-field-DGYMP7OK.js} +1 -1
  117. package/dist/chunks/{velin-segmented-control-GYD5BIXQ.js → velin-segmented-control-P74GJPAR.js} +1 -1
  118. package/dist/chunks/{velin-sheet-R2Y67X6H.js → velin-sheet-M5GZZD7G.js} +2 -4
  119. package/dist/chunks/{velin-sheet-OUK6572T.js → velin-sheet-X7RXIWKV.js} +3 -5
  120. package/dist/chunks/{velin-stepper-X54WGHDG.js → velin-stepper-4YQJUHPC.js} +12 -5
  121. package/dist/chunks/{velin-toast-OMMOA2DK.js → velin-toast-UG5LWTG2.js} +5 -1
  122. package/dist/chunks/{velin-tooltip-BDHGRTQB.js → velin-tooltip-ZDH5SDLU.js} +1 -1
  123. package/dist/llms.txt +29 -7
  124. package/dist/search-index.json +156 -10
  125. package/dist/velin-agent.json +3973 -28
  126. package/dist/velinstyle-components.iife.js +1211 -284
  127. package/dist/velinstyle-components.js +1213 -284
  128. package/dist/velinstyle-components.min.js +266 -118
  129. package/dist/velinstyle.css +252 -67
  130. package/dist/velinstyle.d.ts +2 -0
  131. package/dist/velinstyle.min.css +1 -1
  132. package/package.json +20 -6
  133. package/packages/skill-engine/README.md +24 -0
  134. package/packages/skill-engine/package.json +7 -0
  135. package/packages/skill-engine/src/catalog.js +29 -0
  136. package/packages/skill-engine/src/index.js +5 -0
  137. package/packages/skill-engine/src/install.js +69 -0
  138. package/packages/skill-engine/src/registry.js +27 -0
  139. package/packages/skill-engine/src/resolve.js +68 -0
  140. package/packages/skill-engine/src/validate.js +40 -0
  141. package/packages/velinstyle-skills/README.md +6 -0
  142. package/packages/velinstyle-skills/adapter.json +8 -0
  143. package/packages/velinstyle-skills/bundles/landing-starter.bundle.yaml +12 -0
  144. package/packages/velinstyle-skills/bundles/review-suite.bundle.yaml +11 -0
  145. package/packages/velinstyle-skills/catalog.json +1004 -0
  146. package/packages/velinstyle-skills/graphs/component-ship.graph.yaml +14 -0
  147. package/packages/velinstyle-skills/graphs/landingpage.graph.yaml +21 -0
  148. package/packages/velinstyle-skills/graphs/release-gate.graph.yaml +15 -0
  149. package/packages/velinstyle-skills/index.js +22 -0
  150. package/packages/velinstyle-skills/package.json +7 -0
  151. package/packages/velinstyle-skills/packs/accessibility.pack.yaml +9 -0
  152. package/packages/velinstyle-skills/packs/design.pack.yaml +10 -0
  153. package/packages/velinstyle-skills/packs/documentation.pack.yaml +8 -0
  154. package/packages/velinstyle-skills/packs/enterprise.pack.yaml +10 -0
  155. package/packages/velinstyle-skills/packs/frontend.pack.yaml +10 -0
  156. package/packages/velinstyle-skills/packs/review.pack.yaml +9 -0
  157. package/packages/velinstyle-skills/projects/admin-panel.project.yaml +12 -0
  158. package/packages/velinstyle-skills/projects/blog.project.yaml +11 -0
  159. package/packages/velinstyle-skills/projects/documentation-portal.project.yaml +13 -0
  160. package/packages/velinstyle-skills/projects/ecommerce-shop.project.yaml +12 -0
  161. package/packages/velinstyle-skills/projects/landing-page.project.yaml +12 -0
  162. package/packages/velinstyle-skills/projects/laravel-dashboard.project.yaml +12 -0
  163. package/packages/velinstyle-skills/projects/marketing-website.project.yaml +14 -0
  164. package/packages/velinstyle-skills/projects/portfolio.project.yaml +12 -0
  165. package/packages/velinstyle-skills/registry.json +142 -0
  166. package/packages/velinstyle-skills/scripts/generate-assets.mjs +163 -0
  167. package/packages/velinstyle-skills/skills/velin-a11y-focus-keyboard/SKILL.md +57 -0
  168. package/packages/velinstyle-skills/skills/velin-a11y-page-checklist/SKILL.md +57 -0
  169. package/packages/velinstyle-skills/skills/velin-a11y-scan-fix/SKILL.md +57 -0
  170. package/packages/velinstyle-skills/skills/velin-ai-agent-briefing/SKILL.md +57 -0
  171. package/packages/velinstyle-skills/skills/velin-ai-plan-scaffold-review/SKILL.md +57 -0
  172. package/packages/velinstyle-skills/skills/velin-ai-skill-authoring/SKILL.md +57 -0
  173. package/packages/velinstyle-skills/skills/velin-components-accessibility-map/SKILL.md +57 -0
  174. package/packages/velinstyle-skills/skills/velin-components-api-contract/SKILL.md +57 -0
  175. package/packages/velinstyle-skills/skills/velin-components-recipe/SKILL.md +57 -0
  176. package/packages/velinstyle-skills/skills/velin-components-select-compose/SKILL.md +57 -0
  177. package/packages/velinstyle-skills/skills/velin-design-hero-compose/SKILL.md +57 -0
  178. package/packages/velinstyle-skills/skills/velin-design-section-rhythm/SKILL.md +57 -0
  179. package/packages/velinstyle-skills/skills/velin-design-surface-roles/SKILL.md +57 -0
  180. package/packages/velinstyle-skills/skills/velin-dev-component-wire/SKILL.md +57 -0
  181. package/packages/velinstyle-skills/skills/velin-dev-page-scaffold/SKILL.md +57 -0
  182. package/packages/velinstyle-skills/skills/velin-dev-plan-first/SKILL.md +57 -0
  183. package/packages/velinstyle-skills/skills/velin-docs-component-guide/SKILL.md +57 -0
  184. package/packages/velinstyle-skills/skills/velin-docs-generate-api/SKILL.md +57 -0
  185. package/packages/velinstyle-skills/skills/velin-dx-doctor-setup/SKILL.md +57 -0
  186. package/packages/velinstyle-skills/skills/velin-dx-project-init/SKILL.md +57 -0
  187. package/packages/velinstyle-skills/skills/velin-migration-legacy-wc/SKILL.md +57 -0
  188. package/packages/velinstyle-skills/skills/velin-migration-prefix-classes/SKILL.md +57 -0
  189. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +57 -0
  190. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +57 -0
  191. package/packages/velinstyle-skills/skills/velin-perf-audit-fix/SKILL.md +57 -0
  192. package/packages/velinstyle-skills/skills/velin-perf-runtime-tree-shake/SKILL.md +57 -0
  193. package/packages/velinstyle-skills/skills/velin-release-changelog-sync/SKILL.md +57 -0
  194. package/packages/velinstyle-skills/skills/velin-release-meta-rebuild/SKILL.md +57 -0
  195. package/packages/velinstyle-skills/skills/velin-review-conversion-hero/SKILL.md +57 -0
  196. package/packages/velinstyle-skills/skills/velin-review-page-gate/SKILL.md +57 -0
  197. package/packages/velinstyle-skills/skills/velin-review-seo-meta/SKILL.md +57 -0
  198. package/packages/velinstyle-skills/skills/velin-security-sanitize-html/SKILL.md +57 -0
  199. package/packages/velinstyle-skills/skills/velin-security-scan-pii/SKILL.md +57 -0
  200. package/packages/velinstyle-skills/skills/velin-testing-a11y-suite/SKILL.md +57 -0
  201. package/packages/velinstyle-skills/skills/velin-testing-visual-smoke/SKILL.md +57 -0
  202. package/packages/velinstyle-skills/skills/velin-themes-apply-token/SKILL.md +57 -0
  203. package/packages/velinstyle-skills/skills/velin-themes-contrast-check/SKILL.md +57 -0
  204. package/packages/velinstyle-skills/skills/velin-utilities-layout-apply/SKILL.md +57 -0
  205. package/packages/velinstyle-skills/skills/velin-utilities-prefix-fix/SKILL.md +57 -0
  206. package/packages/velinstyle-skills/skills/velin-utilities-token-map/SKILL.md +57 -0
  207. package/packages/velinstyle-skills/templates/admin-panel.template.yaml +12 -0
  208. package/packages/velinstyle-skills/templates/blog.template.yaml +12 -0
  209. package/packages/velinstyle-skills/templates/documentation-portal.template.yaml +12 -0
  210. package/packages/velinstyle-skills/templates/ecommerce-shop.template.yaml +13 -0
  211. package/packages/velinstyle-skills/templates/landing-page.template.yaml +12 -0
  212. package/packages/velinstyle-skills/templates/laravel-dashboard.template.yaml +11 -0
  213. package/packages/velinstyle-skills/templates/marketing-website.template.yaml +13 -0
  214. package/packages/velinstyle-skills/templates/portfolio.template.yaml +12 -0
  215. package/schemas/component-knowledge.schema.json +33 -0
  216. package/schemas/design-constraint.schema.json +15 -0
  217. package/schemas/design-intelligence.schema.json +19 -0
  218. package/schemas/design-rule.schema.json +19 -0
  219. package/schemas/page-template.schema.json +24 -0
  220. package/schemas/review-report.schema.json +36 -0
  221. package/schemas/section.schema.json +22 -0
  222. package/schemas/skill-bundle.schema.json +15 -0
  223. package/schemas/skill-graph.schema.json +25 -0
  224. package/schemas/skill-pack.schema.json +14 -0
  225. package/schemas/skill-project.schema.json +16 -0
  226. package/schemas/skill-record.schema.json +27 -0
  227. package/schemas/skill-registry.schema.json +17 -0
  228. package/schemas/skill-template.schema.json +17 -0
  229. package/schemas/token-graph.schema.json +27 -0
  230. package/schemas/utility.schema.json +166 -0
  231. package/src/components/alert.css +22 -1
  232. package/src/components/calendar-dropzone.css +5 -0
  233. package/src/layout/app-shell.css +33 -0
  234. package/src/tokens/shadow.css +13 -0
  235. package/src/utilities/border.css +2 -0
  236. package/src/utilities/display.css +1 -24
  237. package/src/utilities/responsive.css +16 -1
  238. package/src/utilities/spacing.css +32 -0
  239. package/src/velinstyle.css +2 -0
  240. package/dist/chunks/attributes-3BZLI7XF.js +0 -364
  241. package/dist/chunks/attributes-4N5JP4CG.js +0 -364
  242. package/dist/chunks/attributes-5Q2WXGRC.js +0 -374
  243. package/dist/chunks/attributes-AIR7SVLK.js +0 -364
  244. package/dist/chunks/attributes-BGRN5XZO.js +0 -364
  245. package/dist/chunks/attributes-BVSQAYLR.js +0 -364
  246. package/dist/chunks/attributes-CDYFUY7Y.js +0 -364
  247. package/dist/chunks/attributes-JMYJZBPE.js +0 -364
  248. package/dist/chunks/attributes-R5JY3X4O.js +0 -374
  249. package/dist/chunks/attributes-TNSPQTHX.js +0 -374
  250. package/dist/chunks/chunk-2354NEBP.js +0 -109
  251. package/dist/chunks/chunk-2VNA7G7S.js +0 -109
  252. package/dist/chunks/chunk-AQLRJSGG.js +0 -109
  253. package/dist/chunks/chunk-EWPSDMQT.js +0 -109
  254. package/dist/chunks/chunk-LA7264K4.js +0 -85
  255. package/dist/chunks/chunk-QTJJ3DPO.js +0 -109
  256. package/dist/chunks/chunk-RZQVWFHW.js +0 -109
  257. package/dist/chunks/chunk-U4XHMZ7D.js +0 -109
  258. package/dist/chunks/chunk-V5YIUA6G.js +0 -109
  259. package/dist/chunks/chunk-XIET2VSZ.js +0 -109
  260. package/dist/chunks/chunk-XYLJ2GCB.js +0 -205
  261. package/dist/chunks/chunk-ZPSPKUYD.js +0 -109
  262. package/dist/chunks/highlight-XTHRKBA3.js +0 -37
  263. package/dist/chunks/velin-bottom-nav-2N2TYWOF.js +0 -86
  264. package/dist/chunks/velin-carousel-Y5VCOABZ.js +0 -213
  265. package/dist/chunks/velin-code-block-ASUBTAQV.js +0 -119
  266. package/dist/chunks/velin-code-block-TSUKPY4C.js +0 -123
  267. package/dist/chunks/velin-code-block-Y6CM726Q.js +0 -119
  268. package/dist/chunks/velin-combobox-2KDTCQ7N.js +0 -155
  269. package/dist/chunks/velin-command-M7RNHUPR.js +0 -136
  270. package/dist/chunks/velin-copy-T5KDTDXP.js +0 -81
  271. package/dist/chunks/velin-countdown-5XSTN3BH.js +0 -101
  272. package/dist/chunks/velin-counter-ISCTEAHI.js +0 -118
  273. package/dist/chunks/velin-dialog-D2GUHSCD.js +0 -144
  274. package/dist/chunks/velin-dialog-IJLFDXAJ.js +0 -144
  275. package/dist/chunks/velin-dialog-TNS3WXMB.js +0 -144
  276. package/dist/chunks/velin-drawer-MJS6WCF7.js +0 -130
  277. package/dist/chunks/velin-email-N5B5ZYTE.js +0 -90
  278. package/dist/chunks/velin-icon-KZO3IEHG.js +0 -164
  279. package/dist/chunks/velin-lightbox-I75U6JF4.js +0 -140
  280. package/dist/chunks/velin-lightbox-QOTB4PRL.js +0 -140
  281. package/dist/chunks/velin-lightbox-UCD6N7HF.js +0 -140
  282. package/dist/chunks/velin-live-dot-XHUZCIDZ.js +0 -67
  283. package/dist/chunks/velin-menubar-SFEXJE56.js +0 -86
  284. package/dist/chunks/velin-modal-2HOBXE6F.js +0 -176
  285. package/dist/chunks/velin-modal-GLI2XZZB.js +0 -176
  286. package/dist/chunks/velin-popover-EXINRIGJ.js +0 -145
  287. package/dist/chunks/velin-popover-OXX7MRZ6.js +0 -145
  288. package/dist/chunks/velin-popover-YKCCROJG.js +0 -145
  289. package/dist/chunks/velin-rating-XRQJV4LO.js +0 -91
  290. package/dist/chunks/velin-scroll-top-F2FCZNYD.js +0 -58
  291. package/dist/chunks/velin-search-4YHJWYSS.js +0 -556
  292. package/dist/chunks/velin-search-LWHY23Q5.js +0 -474
  293. package/dist/chunks/velin-secure-field-H7FSBUJW.js +0 -95
  294. package/dist/chunks/velin-segmented-control-PQX6LKOJ.js +0 -109
  295. package/dist/chunks/velin-sheet-3OGI4HD7.js +0 -119
  296. package/dist/chunks/velin-sparkline-GVEANJVW.js +0 -184
  297. package/dist/chunks/velin-sparkline-KDA3GQAN.js +0 -162
  298. package/dist/chunks/velin-stepper-2ZIHLKGM.js +0 -141
  299. package/dist/chunks/velin-stepper-FYEUEWE6.js +0 -141
  300. package/dist/chunks/velin-stepper-wc-QU3KRVQR.js +0 -133
  301. package/dist/chunks/velin-theme-toggle-BNNS7WLV.js +0 -285
  302. package/dist/chunks/velin-theme-toggle-NO7V4TWI.js +0 -285
  303. package/dist/chunks/velin-theme-toggle-QELCJM2Q.js +0 -291
  304. package/dist/chunks/velin-toast-RCZ4CSUC.js +0 -109
  305. package/dist/chunks/velin-toast-WEUBTJG6.js +0 -109
  306. package/dist/chunks/velin-tooltip-664IOHZA.js +0 -112
  307. package/dist/chunks/velin-tooltip-wc-LXDVT6DE.js +0 -103
  308. package/dist/chunks/worker-client-R6DBYPFT.js +0 -46
@@ -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);
1070
+ if (currentNode !== root && getParentNode(currentNode) === null) {
760
1071
  return true;
761
1072
  }
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);
768
- return true;
769
- }
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);
1337
+ }
1338
+ if (hooks.uponSanitizeAttribute.length > 0) {
1339
+ ALLOWED_ATTR = clone(ALLOWED_ATTR);
1005
1340
  }
1006
- if (IN_PLACE) {
1007
- const nn = dirty.nodeName;
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 = [];
@@ -6484,7 +7179,7 @@ var init_velin_data_table = __esm({
6484
7179
  warnedMissingName = false;
6485
7180
  VelinDataTable = class extends HTMLElement {
6486
7181
  static get observedAttributes() {
6487
- return ["page-size", "filter-input", "empty-text", "label"];
7182
+ return ["page-size", "filter-input", "empty-text", "label", "editable"];
6488
7183
  }
6489
7184
  constructor() {
6490
7185
  super();
@@ -6611,6 +7306,7 @@ var init_velin_data_table = __esm({
6611
7306
  if (!this._table || !this._table.tBodies.length) return;
6612
7307
  this._ensureAccessibleName();
6613
7308
  this._setupSorting();
7309
+ this._setupEditable();
6614
7310
  this._bindFilterInput();
6615
7311
  this._render();
6616
7312
  }
@@ -6665,6 +7361,75 @@ var init_velin_data_table = __esm({
6665
7361
  header.appendChild(button);
6666
7362
  });
6667
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
+ }
6668
7433
  _syncSortState() {
6669
7434
  this._headers().forEach((header, index) => {
6670
7435
  if (this._sortType(header) === "none") return;
@@ -6764,6 +7529,164 @@ var init_velin_data_table = __esm({
6764
7529
  }
6765
7530
  });
6766
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
+
6767
7690
  // components/velin-form-summary.js
6768
7691
  var velin_form_summary_exports = {};
6769
7692
  __export(velin_form_summary_exports, {
@@ -7046,7 +7969,7 @@ var velin_live_dot_exports = {};
7046
7969
  __export(velin_live_dot_exports, {
7047
7970
  default: () => velin_live_dot_default
7048
7971
  });
7049
- var STATUS_COLORS, styles28, KEYFRAMES_FALLBACK, VelinLiveDot, velin_live_dot_default;
7972
+ var STATUS_COLORS, styles29, KEYFRAMES_FALLBACK, VelinLiveDot, velin_live_dot_default;
7050
7973
  var init_velin_live_dot = __esm({
7051
7974
  "components/velin-live-dot.js"() {
7052
7975
  init_a11y_utils();
@@ -7057,7 +7980,7 @@ var init_velin_live_dot = __esm({
7057
7980
  error: "var(--velin-color-danger, oklch(60% 0.2 25))",
7058
7981
  muted: "var(--velin-color-border, oklch(85% 0.01 240))"
7059
7982
  };
7060
- styles28 = `
7983
+ styles29 = `
7061
7984
  :host {
7062
7985
  display: inline-flex;
7063
7986
  align-items: center;
@@ -7107,7 +8030,7 @@ var init_velin_live_dot = __esm({
7107
8030
  this.setAttribute("aria-label", label);
7108
8031
  this.style.setProperty("--velin-live-color", color);
7109
8032
  this.shadowRoot.innerHTML = `
7110
- <style>${styles28}${KEYFRAMES_FALLBACK}</style>
8033
+ <style>${styles29}${KEYFRAMES_FALLBACK}</style>
7111
8034
  <span class="dot" aria-hidden="true"></span><slot></slot>
7112
8035
  `;
7113
8036
  }
@@ -7725,7 +8648,7 @@ var init_velin_search = __esm({
7725
8648
  return;
7726
8649
  }
7727
8650
  if (!this._indexLoaded) await this._loadIndex();
7728
- const { groups } = this._search.query(q, {
8651
+ const { groups } = await this._search.query(q, {
7729
8652
  minChars: this.minChars,
7730
8653
  fuzzy: this.fuzzy,
7731
8654
  categories: this.categories || void 0,
@@ -7856,11 +8779,11 @@ async function encryptValue(plain, mode) {
7856
8779
  cipher: Array.from(new Uint8Array(cipher))
7857
8780
  });
7858
8781
  }
7859
- var styles29, VelinSecureField, velin_secure_field_default;
8782
+ var styles30, VelinSecureField, velin_secure_field_default;
7860
8783
  var init_velin_secure_field = __esm({
7861
8784
  "components/velin-secure-field.js"() {
7862
8785
  init_sanitize();
7863
- styles29 = `
8786
+ styles30 = `
7864
8787
  :host { display: block; }
7865
8788
  label { display: block; font-size: var(--velin-text-sm); margin-block-end: var(--velin-space-1); }
7866
8789
  input {
@@ -7910,7 +8833,7 @@ var init_velin_secure_field = __esm({
7910
8833
  const input = this.shadowRoot?.querySelector("input");
7911
8834
  if (input && this._onChange) input.removeEventListener("change", this._onChange);
7912
8835
  this.shadowRoot.innerHTML = `
7913
- <style>${styles29}</style>
8836
+ <style>${styles30}</style>
7914
8837
  <label for="${id}">${escapeHTML(label)}</label>
7915
8838
  <input id="${id}" type="${type}" autocomplete="${autocomplete}" part="input" />
7916
8839
  <p class="velin-field-help">Demo-only client encoding \u2014 use HTTPS and server-side crypto for real secrets.</p>
@@ -8130,6 +9053,7 @@ var init_component_loaders = __esm({
8130
9053
  "velin-accordion": () => Promise.resolve().then(() => (init_velin_accordion(), velin_accordion_exports)),
8131
9054
  "velin-announcer": () => Promise.resolve().then(() => (init_velin_announcer(), velin_announcer_exports)),
8132
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)),
8133
9057
  "velin-carousel": () => Promise.resolve().then(() => (init_velin_carousel(), velin_carousel_exports)),
8134
9058
  "velin-code-block": () => Promise.resolve().then(() => (init_velin_code_block(), velin_code_block_exports)),
8135
9059
  "velin-collapse": () => Promise.resolve().then(() => (init_velin_collapse(), velin_collapse_exports)),
@@ -8143,6 +9067,7 @@ var init_component_loaders = __esm({
8143
9067
  "velin-drawer": () => Promise.resolve().then(() => (init_velin_drawer(), velin_drawer_exports)),
8144
9068
  "velin-dropdown": () => Promise.resolve().then(() => (init_velin_dropdown(), velin_dropdown_exports)),
8145
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)),
8146
9071
  "velin-form-summary": () => Promise.resolve().then(() => (init_velin_form_summary(), velin_form_summary_exports)),
8147
9072
  "velin-icon": () => Promise.resolve().then(() => (init_velin_icon(), velin_icon_exports)),
8148
9073
  "velin-lightbox": () => Promise.resolve().then(() => (init_velin_lightbox(), velin_lightbox_exports)),
@@ -8761,6 +9686,8 @@ init_velin_live_dot();
8761
9686
  init_velin_code_block();
8762
9687
  init_velin_data_table();
8763
9688
  init_velin_form_summary();
9689
+ init_velin_calendar();
9690
+ init_velin_file_dropzone();
8764
9691
  init_velin_search();
8765
9692
  init_velin_search();
8766
9693
 
@@ -8984,6 +9911,7 @@ export {
8984
9911
  velin_accordion_default as VelinAccordion,
8985
9912
  velin_announcer_default as VelinAnnouncer,
8986
9913
  velin_bottom_nav_default as VelinBottomNav,
9914
+ velin_calendar_default as VelinCalendar,
8987
9915
  velin_carousel_default as VelinCarousel,
8988
9916
  velin_code_block_default as VelinCodeBlock,
8989
9917
  velin_collapse_default as VelinCollapse,
@@ -8997,6 +9925,7 @@ export {
8997
9925
  velin_drawer_default as VelinDrawer,
8998
9926
  velin_dropdown_default as VelinDropdown,
8999
9927
  velin_email_default as VelinEmail,
9928
+ velin_file_dropzone_default as VelinFileDropzone,
9000
9929
  velin_form_summary_default as VelinFormSummary,
9001
9930
  VelinHapticObserver,
9002
9931
  velin_icon_default as VelinIcon,
@@ -9067,5 +9996,5 @@ export {
9067
9996
  /*! Bundled license information:
9068
9997
 
9069
9998
  dompurify/dist/purify.es.mjs:
9070
- (*! @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 *)
9071
10000
  */