microui-wc 0.1.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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +33 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
- package/.github/workflows/ci.yml +42 -0
- package/.github/workflows/deploy-pages.yml +112 -0
- package/AGENTS.md +2366 -0
- package/CHANGELOG.md +47 -0
- package/CODE_OF_CONDUCT.md +59 -0
- package/CONTRIBUTING.md +156 -0
- package/LICENSE +190 -0
- package/README.md +254 -0
- package/SECURITY.md +58 -0
- package/app/.generated/routes/alerts.js +8 -0
- package/app/.generated/routes/avatars.js +8 -0
- package/app/.generated/routes/badges.js +8 -0
- package/app/.generated/routes/buttons.js +10 -0
- package/app/.generated/routes/cards.js +10 -0
- package/app/.generated/routes/checkboxes.js +9 -0
- package/app/.generated/routes/chips.js +8 -0
- package/app/.generated/routes/dropdowns.js +9 -0
- package/app/.generated/routes/home.js +7 -0
- package/app/.generated/routes/icons.js +9 -0
- package/app/.generated/routes/inputs.js +10 -0
- package/app/.generated/routes/installation.js +7 -0
- package/app/.generated/routes/layout.js +9 -0
- package/app/.generated/routes/modals.js +9 -0
- package/app/.generated/routes/navbar.js +7 -0
- package/app/.generated/routes/progress.js +9 -0
- package/app/.generated/routes/radios.js +9 -0
- package/app/.generated/routes/switches.js +9 -0
- package/app/.generated/routes/tabs.js +8 -0
- package/app/.generated/routes/toasts.js +9 -0
- package/app/index.html +67 -0
- package/app/pages/alerts.html +23 -0
- package/app/pages/avatars.html +22 -0
- package/app/pages/badges.html +22 -0
- package/app/pages/buttons.html +71 -0
- package/app/pages/cards.html +54 -0
- package/app/pages/checkboxes.html +39 -0
- package/app/pages/chips.html +23 -0
- package/app/pages/dropdowns.html +41 -0
- package/app/pages/home.html +59 -0
- package/app/pages/icons.html +29 -0
- package/app/pages/inputs.html +66 -0
- package/app/pages/installation.html +34 -0
- package/app/pages/layout.html +30 -0
- package/app/pages/modals.html +21 -0
- package/app/pages/navbar.html +22 -0
- package/app/pages/progress.html +35 -0
- package/app/pages/radios.html +40 -0
- package/app/pages/switches.html +39 -0
- package/app/pages/tabs.html +30 -0
- package/app/pages/toasts.html +22 -0
- package/app-dist/index.html +67 -0
- package/app-dist/pages/alerts.html +23 -0
- package/app-dist/pages/avatars.html +22 -0
- package/app-dist/pages/badges.html +22 -0
- package/app-dist/pages/buttons.html +71 -0
- package/app-dist/pages/cards.html +54 -0
- package/app-dist/pages/checkboxes.html +39 -0
- package/app-dist/pages/chips.html +23 -0
- package/app-dist/pages/dropdowns.html +41 -0
- package/app-dist/pages/home.html +59 -0
- package/app-dist/pages/icons.html +29 -0
- package/app-dist/pages/inputs.html +66 -0
- package/app-dist/pages/installation.html +34 -0
- package/app-dist/pages/layout.html +30 -0
- package/app-dist/pages/modals.html +21 -0
- package/app-dist/pages/navbar.html +22 -0
- package/app-dist/pages/progress.html +35 -0
- package/app-dist/pages/radios.html +40 -0
- package/app-dist/pages/switches.html +39 -0
- package/app-dist/pages/tabs.html +30 -0
- package/app-dist/pages/toasts.html +22 -0
- package/app-dist/pages.json +217 -0
- package/app-dist/routes/alerts.js +5 -0
- package/app-dist/routes/avatars.js +1 -0
- package/app-dist/routes/badges.js +1 -0
- package/app-dist/routes/buttons.js +1 -0
- package/app-dist/routes/cards.js +1 -0
- package/app-dist/routes/checkboxes.js +9 -0
- package/app-dist/routes/chips.js +4 -0
- package/app-dist/routes/chunk-019e5e2f.js +5 -0
- package/app-dist/routes/chunk-0m4j19yd.js +2 -0
- package/app-dist/routes/chunk-0tmmp5q0.js +1 -0
- package/app-dist/routes/chunk-10xn709r.js +1 -0
- package/app-dist/routes/chunk-15m2qcda.js +2 -0
- package/app-dist/routes/chunk-1bh8g23n.js +1 -0
- package/app-dist/routes/chunk-1vg0v937.js +1 -0
- package/app-dist/routes/chunk-1zvcgy3j.js +1 -0
- package/app-dist/routes/chunk-2afb0861.js +1 -0
- package/app-dist/routes/chunk-2c6ttpzt.js +5 -0
- package/app-dist/routes/chunk-3dy30fhs.js +1 -0
- package/app-dist/routes/chunk-426dnces.js +13 -0
- package/app-dist/routes/chunk-44kgxery.js +1 -0
- package/app-dist/routes/chunk-47fdnejd.js +33 -0
- package/app-dist/routes/chunk-49a6t2vq.js +1 -0
- package/app-dist/routes/chunk-4fe1rm5b.js +1 -0
- package/app-dist/routes/chunk-4ggmvkta.js +33 -0
- package/app-dist/routes/chunk-4vkz81q7.js +33 -0
- package/app-dist/routes/chunk-4w4tmj8f.js +31 -0
- package/app-dist/routes/chunk-532s62kr.js +31 -0
- package/app-dist/routes/chunk-5hm3bssy.js +33 -0
- package/app-dist/routes/chunk-5vrh24hc.js +1 -0
- package/app-dist/routes/chunk-61pcg25a.js +1 -0
- package/app-dist/routes/chunk-6nfhygvf.js +1 -0
- package/app-dist/routes/chunk-700e7je6.js +33 -0
- package/app-dist/routes/chunk-7fsn17kg.js +1 -0
- package/app-dist/routes/chunk-7k789b32.js +1 -0
- package/app-dist/routes/chunk-7r46q0ys.js +36 -0
- package/app-dist/routes/chunk-86fmc1fr.js +5 -0
- package/app-dist/routes/chunk-8qth37vw.js +1 -0
- package/app-dist/routes/chunk-924wv8n0.js +1 -0
- package/app-dist/routes/chunk-9mbhgxk9.js +1 -0
- package/app-dist/routes/chunk-a216hyd9.js +1 -0
- package/app-dist/routes/chunk-akzxykh9.js +33 -0
- package/app-dist/routes/chunk-b3dcvy8c.js +1 -0
- package/app-dist/routes/chunk-b74zahz5.js +31 -0
- package/app-dist/routes/chunk-bftj53p2.js +5 -0
- package/app-dist/routes/chunk-c01hnz3e.js +1 -0
- package/app-dist/routes/chunk-d8pvv5km.js +1 -0
- package/app-dist/routes/chunk-dev0aezr.js +2 -0
- package/app-dist/routes/chunk-dh6vnv0e.js +1 -0
- package/app-dist/routes/chunk-dn2cbpva.js +36 -0
- package/app-dist/routes/chunk-dvn0my90.js +1 -0
- package/app-dist/routes/chunk-dvq8mnve.js +36 -0
- package/app-dist/routes/chunk-e8c2gc4d.js +5 -0
- package/app-dist/routes/chunk-ejf9ak2x.js +1 -0
- package/app-dist/routes/chunk-f083m55s.js +1 -0
- package/app-dist/routes/chunk-fnrj28s1.js +31 -0
- package/app-dist/routes/chunk-fvg3yjdp.js +31 -0
- package/app-dist/routes/chunk-g7k381n1.js +1 -0
- package/app-dist/routes/chunk-h01kq2ae.js +13 -0
- package/app-dist/routes/chunk-h4dk761v.js +5 -0
- package/app-dist/routes/chunk-hmx91z2x.js +5 -0
- package/app-dist/routes/chunk-hxbg4m42.js +36 -0
- package/app-dist/routes/chunk-jbjnfp2b.js +2 -0
- package/app-dist/routes/chunk-jxtz5vv6.js +36 -0
- package/app-dist/routes/chunk-jxzcs0ey.js +36 -0
- package/app-dist/routes/chunk-kt7wwhcx.js +1 -0
- package/app-dist/routes/chunk-kzptszyc.js +33 -0
- package/app-dist/routes/chunk-mhgca4w4.js +2 -0
- package/app-dist/routes/chunk-mhswxa20.js +1 -0
- package/app-dist/routes/chunk-n8zfeex6.js +1 -0
- package/app-dist/routes/chunk-pee47b2r.js +1 -0
- package/app-dist/routes/chunk-pesmw829.js +1 -0
- package/app-dist/routes/chunk-pgc4c6f3.js +36 -0
- package/app-dist/routes/chunk-q8egegm1.js +1 -0
- package/app-dist/routes/chunk-q9mn2qyq.js +36 -0
- package/app-dist/routes/chunk-qh0rtaf3.js +5 -0
- package/app-dist/routes/chunk-qqhmk6ye.js +2 -0
- package/app-dist/routes/chunk-qrxygmf7.js +33 -0
- package/app-dist/routes/chunk-r46yzksx.js +36 -0
- package/app-dist/routes/chunk-rgpbw2w0.js +5 -0
- package/app-dist/routes/chunk-rnpzv3d8.js +2 -0
- package/app-dist/routes/chunk-s5v8cv05.js +2 -0
- package/app-dist/routes/chunk-sbwn5bpc.js +1 -0
- package/app-dist/routes/chunk-sqbg8jbt.js +33 -0
- package/app-dist/routes/chunk-sv8dqnf7.js +1 -0
- package/app-dist/routes/chunk-t67sw3za.js +1 -0
- package/app-dist/routes/chunk-tjdpqwdf.js +31 -0
- package/app-dist/routes/chunk-tq2mfghg.js +1 -0
- package/app-dist/routes/chunk-ttn10vt6.js +1 -0
- package/app-dist/routes/chunk-v2hzpjxr.js +1 -0
- package/app-dist/routes/chunk-wfjjkw9y.js +1 -0
- package/app-dist/routes/chunk-wt8cxzmf.js +31 -0
- package/app-dist/routes/chunk-x45d372k.js +5 -0
- package/app-dist/routes/chunk-y3wsazkt.js +1 -0
- package/app-dist/routes/chunk-y7pmgc7t.js +33 -0
- package/app-dist/routes/chunk-zefdt2q3.js +31 -0
- package/app-dist/routes/dropdowns.js +6 -0
- package/app-dist/routes/home.js +1 -0
- package/app-dist/routes/icons.js +1 -0
- package/app-dist/routes/inputs.js +12 -0
- package/app-dist/routes/installation.js +1 -0
- package/app-dist/routes/layout.js +1 -0
- package/app-dist/routes/modals.js +7 -0
- package/app-dist/routes/navbar.js +1 -0
- package/app-dist/routes/progress.js +1 -0
- package/app-dist/routes/radios.js +6 -0
- package/app-dist/routes/switches.js +6 -0
- package/app-dist/routes/tabs.js +1 -0
- package/app-dist/routes/toasts.js +16 -0
- package/assets/fonts/material-symbols-mini.woff2 +0 -0
- package/assets/fonts/material-symbols.woff2 +0 -0
- package/assets/fonts/roboto-400.woff2 +0 -0
- package/assets/fonts/roboto-500.woff2 +0 -0
- package/assets/fonts/roboto-700.woff2 +0 -0
- package/assets/logo-banner-400.jpg +0 -0
- package/assets/logo-banner-400.webp +0 -0
- package/assets/logo-banner-800.webp +0 -0
- package/assets/logo-banner.jpg +0 -0
- package/assets/logo-icon-64.jpg +0 -0
- package/assets/logo-icon-64.webp +0 -0
- package/assets/logo-icon.jpg +0 -0
- package/assets/logo-square.jpg +0 -0
- package/bun.lock +312 -0
- package/bunfig.toml +4 -0
- package/custom-elements.json +1916 -0
- package/demo/api/sample-data.json +38 -0
- package/demo/content/alerts.html +115 -0
- package/demo/content/avatars.html +70 -0
- package/demo/content/badges.html +65 -0
- package/demo/content/buttons.html +188 -0
- package/demo/content/callouts.html +91 -0
- package/demo/content/cards.html +121 -0
- package/demo/content/checkboxes.html +178 -0
- package/demo/content/chips.html +67 -0
- package/demo/content/codeblocks.html +101 -0
- package/demo/content/confirms.html +115 -0
- package/demo/content/datatables.html +149 -0
- package/demo/content/dividers.html +119 -0
- package/demo/content/dropdowns.html +89 -0
- package/demo/content/enterprise.html +252 -0
- package/demo/content/home.html +149 -0
- package/demo/content/icons.html +89 -0
- package/demo/content/inputs.html +135 -0
- package/demo/content/installation.html +16 -0
- package/demo/content/layout.html +136 -0
- package/demo/content/modals.html +141 -0
- package/demo/content/navbar.html +70 -0
- package/demo/content/progress.html +119 -0
- package/demo/content/radios.html +88 -0
- package/demo/content/skeletons.html +109 -0
- package/demo/content/spinners.html +96 -0
- package/demo/content/switches.html +84 -0
- package/demo/content/tables.html +124 -0
- package/demo/content/tabs.html +85 -0
- package/demo/content/toasts.html +116 -0
- package/demo/content/tooltips.html +107 -0
- package/demo/content/virtual-lists.html +233 -0
- package/demo/favicon.ico +0 -0
- package/demo/favicon.png +0 -0
- package/demo/full.html +52 -0
- package/demo/iife.html +46 -0
- package/demo/manifest.json +34 -0
- package/demo/pages/datatable-demo.html +237 -0
- package/demo/pages/prompt-ui-demo.html +218 -0
- package/demo/pages/responsive-demo.html +122 -0
- package/demo/pages/schema-form-demo.html +270 -0
- package/demo/robots.txt +6 -0
- package/demo/shell.html +712 -0
- package/demo/sw.js +387 -0
- package/dist/AGENTS.md +2366 -0
- package/dist/README.md +254 -0
- package/dist/chunks/advanced.js +174 -0
- package/dist/chunks/chunk-1nhr1wrq.js +14 -0
- package/dist/chunks/chunk-hssyjbr0.js +2 -0
- package/dist/chunks/chunk-k8etzx0z.js +2 -0
- package/dist/chunks/chunk-rr1et8fg.js +2 -0
- package/dist/chunks/chunk-sjcx4fd5.js +6 -0
- package/dist/chunks/chunk-v1c777xh.js +5 -0
- package/dist/chunks/chunk-w5k5vwjd.js +13 -0
- package/dist/chunks/core.js +10 -0
- package/dist/chunks/display.js +17 -0
- package/dist/chunks/feedback.js +15 -0
- package/dist/chunks/forms.js +48 -0
- package/dist/chunks/layout.js +9 -0
- package/dist/components/chunk-4tezav8r.js +2 -0
- package/dist/components/chunk-fqyb2pms.js +2 -0
- package/dist/components/chunk-h7cdbhxw.js +13 -0
- package/dist/components/chunk-mzd8jwrs.js +2 -0
- package/dist/components/chunk-qwmxyn8e.js +2 -0
- package/dist/components/chunk-redtk47a.js +14 -0
- package/dist/components/mu-alert.js +5 -0
- package/dist/components/mu-api-table.js +33 -0
- package/dist/components/mu-avatar.js +1 -0
- package/dist/components/mu-badge.js +1 -0
- package/dist/components/mu-bottom-nav.js +1 -0
- package/dist/components/mu-button.js +1 -0
- package/dist/components/mu-callout.js +1 -0
- package/dist/components/mu-card.js +1 -0
- package/dist/components/mu-checkbox.js +9 -0
- package/dist/components/mu-chip.js +4 -0
- package/dist/components/mu-code.js +48 -0
- package/dist/components/mu-confirm.js +10 -0
- package/dist/components/mu-container.js +1 -0
- package/dist/components/mu-datatable.js +96 -0
- package/dist/components/mu-divider.js +1 -0
- package/dist/components/mu-doc-page.js +26 -0
- package/dist/components/mu-drawer-item.js +9 -0
- package/dist/components/mu-drawer.js +1 -0
- package/dist/components/mu-dropdown.js +6 -0
- package/dist/components/mu-error-boundary.js +10 -0
- package/dist/components/mu-example.js +38 -0
- package/dist/components/mu-fetch.js +1 -0
- package/dist/components/mu-form.js +1 -0
- package/dist/components/mu-grid.js +1 -0
- package/dist/components/mu-icon.js +5 -0
- package/dist/components/mu-input.js +12 -0
- package/dist/components/mu-layout.js +1 -0
- package/dist/components/mu-lazy.js +1 -0
- package/dist/components/mu-modal.js +7 -0
- package/dist/components/mu-navbar.js +1 -0
- package/dist/components/mu-page.js +1 -0
- package/dist/components/mu-progress.js +1 -0
- package/dist/components/mu-prompt-ui.js +20 -0
- package/dist/components/mu-radio.js +6 -0
- package/dist/components/mu-repeat.js +1 -0
- package/dist/components/mu-router.js +6 -0
- package/dist/components/mu-schema-form.js +76 -0
- package/dist/components/mu-sidebar.js +1 -0
- package/dist/components/mu-skeleton.js +13 -0
- package/dist/components/mu-spinner.js +1 -0
- package/dist/components/mu-stack.js +1 -0
- package/dist/components/mu-switch.js +6 -0
- package/dist/components/mu-table.js +1 -0
- package/dist/components/mu-tabs.js +1 -0
- package/dist/components/mu-textarea.js +11 -0
- package/dist/components/mu-theme-toggle.js +5 -0
- package/dist/components/mu-toast.js +4 -0
- package/dist/components/mu-tooltip.js +10 -0
- package/dist/components/mu-virtual-list.js +33 -0
- package/dist/components.css +1 -0
- package/dist/microui.css +1 -0
- package/dist/microui.d.ts +234 -0
- package/dist/microui.esm.js +549 -0
- package/dist/microui.esm.js.map +79 -0
- package/dist/microui.min.js +549 -0
- package/dist/microui.min.js.map +79 -0
- package/dist/routes/alerts.js +1 -0
- package/dist/routes/avatars.js +1 -0
- package/dist/routes/badges.js +1 -0
- package/dist/routes/buttons.js +1 -0
- package/dist/routes/callouts.js +1 -0
- package/dist/routes/cards.js +1 -0
- package/dist/routes/checkboxes.js +9 -0
- package/dist/routes/chips.js +4 -0
- package/dist/routes/chunk-19wgcncm.js +2 -0
- package/dist/routes/chunk-1khyr3v1.js +33 -0
- package/dist/routes/chunk-4rhxe97g.js +1 -0
- package/dist/routes/chunk-5qah04bh.js +2 -0
- package/dist/routes/chunk-7gfxy70n.js +5 -0
- package/dist/routes/chunk-e86zbeta.js +1 -0
- package/dist/routes/chunk-fagt36h6.js +2 -0
- package/dist/routes/chunk-fed7zr7m.js +1 -0
- package/dist/routes/chunk-hwj7pfwp.js +1 -0
- package/dist/routes/chunk-mhvcs2f8.js +5 -0
- package/dist/routes/chunk-nv3bddmj.js +13 -0
- package/dist/routes/chunk-q3f2aeqe.js +7 -0
- package/dist/routes/chunk-qxxa8trk.js +1 -0
- package/dist/routes/chunk-rw15y9zh.js +1 -0
- package/dist/routes/chunk-sfb7x11v.js +5 -0
- package/dist/routes/chunk-swyhghrm.js +48 -0
- package/dist/routes/chunk-sxddjs2d.js +2 -0
- package/dist/routes/chunk-vby0zg5w.js +17 -0
- package/dist/routes/chunk-w6zqjqqs.js +9 -0
- package/dist/routes/chunk-z960rexd.js +38 -0
- package/dist/routes/codeblocks.js +1 -0
- package/dist/routes/confirms.js +10 -0
- package/dist/routes/datatables.js +96 -0
- package/dist/routes/dividers.js +1 -0
- package/dist/routes/dropdowns.js +6 -0
- package/dist/routes/enterprise.js +15 -0
- package/dist/routes/home.js +1 -0
- package/dist/routes/icons.js +1 -0
- package/dist/routes/inputs.js +22 -0
- package/dist/routes/installation.js +1 -0
- package/dist/routes/layout.js +1 -0
- package/dist/routes/modals.js +1 -0
- package/dist/routes/navbar.js +1 -0
- package/dist/routes/page-components.json +316 -0
- package/dist/routes/progress.js +1 -0
- package/dist/routes/radios.js +6 -0
- package/dist/routes/route-deps.json +156 -0
- package/dist/routes/shell-critical.js +1 -0
- package/dist/routes/shell-deferred.js +1 -0
- package/dist/routes/shell.js +20 -0
- package/dist/routes/skeletons.js +13 -0
- package/dist/routes/spinners.js +1 -0
- package/dist/routes/src/chunks/core.js +36 -0
- package/dist/routes/switches.js +6 -0
- package/dist/routes/tables.js +1 -0
- package/dist/routes/tabs.js +1 -0
- package/dist/routes/toasts.js +1 -0
- package/dist/routes/tooltips.js +10 -0
- package/dist/routes/virtual-lists.js +33 -0
- package/dist/styles/common.css +1 -0
- package/dist/styles/components/animations.css +1 -0
- package/dist/styles/components/avatar.css +1 -0
- package/dist/styles/components/badge.css +1 -0
- package/dist/styles/components/bottom-nav.css +1 -0
- package/dist/styles/components/button.css +1 -0
- package/dist/styles/components/card.css +1 -0
- package/dist/styles/components/checkbox.css +1 -0
- package/dist/styles/components/chip.css +1 -0
- package/dist/styles/components/datatable.css +1 -0
- package/dist/styles/components/divider.css +1 -0
- package/dist/styles/components/drawer-item.css +1 -0
- package/dist/styles/components/drawer.css +1 -0
- package/dist/styles/components/grid.css +1 -0
- package/dist/styles/components/icon.css +1 -0
- package/dist/styles/components/input.css +1 -0
- package/dist/styles/components/layout.css +1 -0
- package/dist/styles/components/navbar.css +1 -0
- package/dist/styles/components/overlays.css +1 -0
- package/dist/styles/components/progress.css +1 -0
- package/dist/styles/components/prompt-ui.css +1 -0
- package/dist/styles/components/radio.css +1 -0
- package/dist/styles/components/schema-form.css +1 -0
- package/dist/styles/components/switch.css +1 -0
- package/dist/styles/components/tabs.css +1 -0
- package/dist/styles/components/tooltip.css +1 -0
- package/dist/styles/components/virtual-list.css +1 -0
- package/dist/tokens.css +1 -0
- package/docs/api-reference.md +175 -0
- package/docs/component-schema.md +231 -0
- package/docs/components.md +269 -0
- package/docs/design-system.md +183 -0
- package/docs/getting-started.md +198 -0
- package/docs/message-protocol.md +262 -0
- package/docs/utility-classes.md +205 -0
- package/lighthouse-audit.mjs +113 -0
- package/package.json +45 -0
- package/scripts/analyze-components.js +105 -0
- package/scripts/build-app.js +193 -0
- package/scripts/build-framework.js +444 -0
- package/scripts/build-utils.js +101 -0
- package/scripts/test-isolated.js +151 -0
- package/server.js +256 -0
- package/src/chunks/advanced.js +27 -0
- package/src/chunks/core.js +61 -0
- package/src/chunks/display.js +25 -0
- package/src/chunks/feedback.js +15 -0
- package/src/chunks/forms.js +25 -0
- package/src/chunks/layout.js +27 -0
- package/src/components/mu-alert.js +96 -0
- package/src/components/mu-api-table.js +167 -0
- package/src/components/mu-avatar.js +94 -0
- package/src/components/mu-badge.js +32 -0
- package/src/components/mu-bottom-nav.js +115 -0
- package/src/components/mu-button.js +61 -0
- package/src/components/mu-callout.js +71 -0
- package/src/components/mu-card.js +36 -0
- package/src/components/mu-checkbox.js +186 -0
- package/src/components/mu-chip.js +125 -0
- package/src/components/mu-code.js +534 -0
- package/src/components/mu-confirm.js +268 -0
- package/src/components/mu-container.js +53 -0
- package/src/components/mu-datatable.js +517 -0
- package/src/components/mu-divider.js +40 -0
- package/src/components/mu-doc-page.js +100 -0
- package/src/components/mu-drawer-item.js +158 -0
- package/src/components/mu-drawer.js +305 -0
- package/src/components/mu-dropdown.js +239 -0
- package/src/components/mu-error-boundary.js +191 -0
- package/src/components/mu-example.js +335 -0
- package/src/components/mu-fetch.js +256 -0
- package/src/components/mu-form.js +133 -0
- package/src/components/mu-grid.js +63 -0
- package/src/components/mu-icon.js +211 -0
- package/src/components/mu-input.js +142 -0
- package/src/components/mu-layout.js +129 -0
- package/src/components/mu-lazy.js +94 -0
- package/src/components/mu-modal.js +160 -0
- package/src/components/mu-navbar.js +71 -0
- package/src/components/mu-page.js +77 -0
- package/src/components/mu-progress.js +54 -0
- package/src/components/mu-prompt-ui.js +382 -0
- package/src/components/mu-radio.js +200 -0
- package/src/components/mu-repeat.js +135 -0
- package/src/components/mu-router.js +169 -0
- package/src/components/mu-schema-form.js +441 -0
- package/src/components/mu-sidebar.js +81 -0
- package/src/components/mu-skeleton.js +69 -0
- package/src/components/mu-spinner.js +30 -0
- package/src/components/mu-stack.js +59 -0
- package/src/components/mu-switch.js +150 -0
- package/src/components/mu-table.js +80 -0
- package/src/components/mu-tabs.js +112 -0
- package/src/components/mu-textarea.js +96 -0
- package/src/components/mu-theme-toggle.js +52 -0
- package/src/components/mu-toast.js +151 -0
- package/src/components/mu-tooltip.js +182 -0
- package/src/components/mu-virtual-list.js +184 -0
- package/src/core/MuElement.js +562 -0
- package/src/core/agent-api.js +771 -0
- package/src/core/breakpoints.js +195 -0
- package/src/core/bus.js +378 -0
- package/src/core/component-schema.js +287 -0
- package/src/core/feature-registry.js +241 -0
- package/src/core/form-state.js +252 -0
- package/src/core/http.js +104 -0
- package/src/core/keyboard.js +105 -0
- package/src/core/layers.js +71 -0
- package/src/core/render.js +201 -0
- package/src/core/ripple.js +158 -0
- package/src/core/router.js +100 -0
- package/src/core/scheduler.js +109 -0
- package/src/core/signals.js +164 -0
- package/src/core/store.js +268 -0
- package/src/core/theme.js +68 -0
- package/src/core/transitions.js +72 -0
- package/src/core/utils.js +30 -0
- package/src/index.d.ts +234 -0
- package/src/index.js +308 -0
- package/src/styles/animations.css +252 -0
- package/src/styles/common.css +82 -0
- package/src/styles/components/animations.css +129 -0
- package/src/styles/components/avatar.css +83 -0
- package/src/styles/components/badge.css +80 -0
- package/src/styles/components/bottom-nav.css +37 -0
- package/src/styles/components/button.css +348 -0
- package/src/styles/components/card.css +138 -0
- package/src/styles/components/checkbox.css +201 -0
- package/src/styles/components/chip.css +93 -0
- package/src/styles/components/datatable.css +180 -0
- package/src/styles/components/divider.css +49 -0
- package/src/styles/components/drawer-item.css +123 -0
- package/src/styles/components/drawer.css +273 -0
- package/src/styles/components/grid.css +189 -0
- package/src/styles/components/icon.css +40 -0
- package/src/styles/components/input.css +203 -0
- package/src/styles/components/layout.css +121 -0
- package/src/styles/components/navbar.css +91 -0
- package/src/styles/components/overlays.css +329 -0
- package/src/styles/components/progress.css +79 -0
- package/src/styles/components/prompt-ui.css +286 -0
- package/src/styles/components/radio.css +17 -0
- package/src/styles/components/schema-form.css +85 -0
- package/src/styles/components/switch.css +69 -0
- package/src/styles/components/tabs.css +145 -0
- package/src/styles/components/tooltip.css +93 -0
- package/src/styles/components/virtual-list.css +36 -0
- package/src/styles/components.css +3677 -0
- package/src/styles/routes/home.css +97 -0
- package/src/styles/tokens.css +675 -0
- package/tests/agents/agent-integration.test.js +76 -0
- package/tests/benchmark.html +296 -0
- package/tests/build/scan-components.test.js +173 -0
- package/tests/components/all-components.test.js +245 -0
- package/tests/components/all-missing-components.test.js +574 -0
- package/tests/components/mu-alert.test.js +113 -0
- package/tests/components/mu-avatar.test.js +148 -0
- package/tests/components/mu-badge.test.js +92 -0
- package/tests/components/mu-button.test.js +112 -0
- package/tests/components/mu-card.test.js +89 -0
- package/tests/components/mu-checkbox.test.js +158 -0
- package/tests/components/mu-chip.test.js +118 -0
- package/tests/components/mu-container.test.js +120 -0
- package/tests/components/mu-divider.test.js +98 -0
- package/tests/components/mu-drawer-item.test.js +199 -0
- package/tests/components/mu-drawer.test.js +96 -0
- package/tests/components/mu-dropdown.test.js +125 -0
- package/tests/components/mu-form.test.js +138 -0
- package/tests/components/mu-grid.test.js +135 -0
- package/tests/components/mu-icon.test.js +110 -0
- package/tests/components/mu-input.test.js +131 -0
- package/tests/components/mu-lazy.test.js +103 -0
- package/tests/components/mu-modal.test.js +275 -0
- package/tests/components/mu-navbar.test.js +101 -0
- package/tests/components/mu-progress.test.js +115 -0
- package/tests/components/mu-radio.test.js +114 -0
- package/tests/components/mu-repeat.test.js +106 -0
- package/tests/components/mu-sidebar.test.js +126 -0
- package/tests/components/mu-skeleton.test.js +162 -0
- package/tests/components/mu-stack.test.js +143 -0
- package/tests/components/mu-switch.test.js +292 -0
- package/tests/components/mu-table.test.js +124 -0
- package/tests/components/mu-tabs.test.js +104 -0
- package/tests/components/mu-textarea.test.js +115 -0
- package/tests/components/mu-toast.test.js +321 -0
- package/tests/components/mu-tooltip.test.js +133 -0
- package/tests/components/mu-virtual-list.test.js +109 -0
- package/tests/core/MuElement.test.js +120 -0
- package/tests/core/agent-api.test.js +125 -0
- package/tests/core/all-core-modules.test.js +442 -0
- package/tests/core/bus.test.js +364 -0
- package/tests/core/component-schema.test.js +160 -0
- package/tests/core/feature-registry.test.js +198 -0
- package/tests/core/form-state.test.js +167 -0
- package/tests/core/http.test.js +119 -0
- package/tests/core/keyboard.test.js +319 -0
- package/tests/core/layers.test.js +129 -0
- package/tests/core/namespaced-stores.test.js +114 -0
- package/tests/core/render.test.js +121 -0
- package/tests/core/ripple.test.js +131 -0
- package/tests/core/router.test.js +89 -0
- package/tests/core/scheduler.test.js +121 -0
- package/tests/core/signals.test.js +128 -0
- package/tests/core/store.test.js +171 -0
- package/tests/core/transitions.test.js +82 -0
- package/tests/e2e/accessibility-harness.html +58 -0
- package/tests/e2e/accessibility.test.js +401 -0
- package/tests/e2e/agent-features.test.js +372 -0
- package/tests/e2e/card-spacing.test.js +287 -0
- package/tests/e2e/components.test.js +439 -0
- package/tests/e2e/demo-routes.test.js +478 -0
- package/tests/e2e/layout-css-fallback.test.js +334 -0
- package/tests/e2e/mu-alert.e2e.test.js +111 -0
- package/tests/e2e/mu-checkbox.test.js +489 -0
- package/tests/e2e/mu-chip.test.js +347 -0
- package/tests/e2e/mu-form.test.js +499 -0
- package/tests/e2e/mu-icon.test.js +114 -0
- package/tests/e2e/mu-radio.test.js +113 -0
- package/tests/e2e/mu-skeleton.test.js +140 -0
- package/tests/e2e/mu-switch.test.js +415 -0
- package/tests/e2e/mu-tabs.test.js +494 -0
- package/tests/e2e/mu-textarea.test.js +242 -0
- package/tests/e2e/mu-virtual-list.test.js +427 -0
- package/tests/e2e/perf-memory.test.js +161 -0
- package/tests/e2e/puppeteer-helper.js +137 -0
- package/tests/e2e/puppeteer.test.js +226 -0
- package/tests/e2e/pwa.test.js +261 -0
- package/tests/e2e/test-harness.html +319 -0
- package/tests/manual/test-components.html +120 -0
- package/tests/memory-test.html +309 -0
- package/tests/setup-dom.js +93 -0
- package/tests/visual-test.html +301 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MuElement - Base Web Component Class (Optimized)
|
|
3
|
+
*
|
|
4
|
+
* 2025/2026 Best Practices Applied:
|
|
5
|
+
* - Proper disconnectedCallback for memory safety
|
|
6
|
+
* - Event listener tracking and cleanup
|
|
7
|
+
* - AbortController for efficient listener removal
|
|
8
|
+
* - CSS containment hints
|
|
9
|
+
* - No memory leaks guaranteed
|
|
10
|
+
*
|
|
11
|
+
* Performance optimizations:
|
|
12
|
+
* - No Shadow DOM overhead
|
|
13
|
+
* - Efficient attribute observation
|
|
14
|
+
* - DOM updates via mutation, not recreation
|
|
15
|
+
* - content-visibility auto for off-screen elements
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export class MuElement extends HTMLElement {
|
|
19
|
+
/** @type {string[]} Attributes to observe for changes */
|
|
20
|
+
static observedAttributes = [];
|
|
21
|
+
|
|
22
|
+
/** @type {string} Base CSS class for the component */
|
|
23
|
+
static baseClass = '';
|
|
24
|
+
|
|
25
|
+
/** @type {string|null} CSS file name for lazy loading (e.g., 'button' loads components/button.css) */
|
|
26
|
+
static cssFile = null;
|
|
27
|
+
|
|
28
|
+
/** @type {Set} Track loaded CSS files globally to prevent duplicates */
|
|
29
|
+
static _loadedCSS = new Set();
|
|
30
|
+
|
|
31
|
+
/** @type {boolean} Apply CSS containment for perf */
|
|
32
|
+
static useContainment = true;
|
|
33
|
+
|
|
34
|
+
/** @type {boolean} Track if initial render has occurred */
|
|
35
|
+
_rendered = false;
|
|
36
|
+
|
|
37
|
+
/** @type {AbortController} For cleaning up event listeners */
|
|
38
|
+
_abortController = null;
|
|
39
|
+
|
|
40
|
+
/** @type {Set} Track timers for cleanup */
|
|
41
|
+
_timers = new Set();
|
|
42
|
+
|
|
43
|
+
/** @type {Set} Track intervals for cleanup */
|
|
44
|
+
_intervals = new Set();
|
|
45
|
+
|
|
46
|
+
constructor() {
|
|
47
|
+
super();
|
|
48
|
+
this._initAgentLogger();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_initAgentLogger() {
|
|
52
|
+
if (!window.__MICROUI_ERRORS__) {
|
|
53
|
+
window.__MICROUI_ERRORS__ = [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Agent Help Utilities
|
|
57
|
+
if (!window.microUIAgent) {
|
|
58
|
+
window.microUIAgent = {
|
|
59
|
+
// Clear errors for a fresh test
|
|
60
|
+
reset: () => {
|
|
61
|
+
window.__MICROUI_ERRORS__ = [];
|
|
62
|
+
console.log('[microUIAgent] Errors cleared');
|
|
63
|
+
},
|
|
64
|
+
// Get all errors
|
|
65
|
+
getErrors: () => window.__MICROUI_ERRORS__,
|
|
66
|
+
// Check if component has error
|
|
67
|
+
hasError: (tagName, code) => {
|
|
68
|
+
return window.__MICROUI_ERRORS__.some(e =>
|
|
69
|
+
e.component === tagName.toLowerCase() && e.code === code
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Log error for Agent Debugging (Puppeteer/Playwright access)
|
|
78
|
+
* @param {string} code - Error code (e.g. 'A11Y_MISSING_LABEL')
|
|
79
|
+
* @param {string} message - Human readable message
|
|
80
|
+
*/
|
|
81
|
+
logError(code, message) {
|
|
82
|
+
const error = {
|
|
83
|
+
component: this.tagName.toLowerCase(),
|
|
84
|
+
code,
|
|
85
|
+
message,
|
|
86
|
+
element: this, // Reference leak only if used in dev tools, should be safe for tests
|
|
87
|
+
timestamp: Date.now()
|
|
88
|
+
};
|
|
89
|
+
window.__MICROUI_ERRORS__.push(error);
|
|
90
|
+
console.warn(`[microUI] ${code}: ${message}`, this);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Called when element is added to DOM.
|
|
95
|
+
* Sets up base class, containment, and triggers initial render.
|
|
96
|
+
*/
|
|
97
|
+
connectedCallback() {
|
|
98
|
+
// Reuse existing AbortController to prevent duplicate event listeners
|
|
99
|
+
// when element is moved in DOM (connectedCallback called multiple times)
|
|
100
|
+
if (!this._abortController) {
|
|
101
|
+
this._abortController = new AbortController();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Add base class
|
|
105
|
+
if (this.constructor.baseClass) {
|
|
106
|
+
this.classList.add(this.constructor.baseClass);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Apply CSS containment for rendering performance
|
|
110
|
+
if (this.constructor.useContainment && !this.style.contain) {
|
|
111
|
+
this.style.contain = 'layout style';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// SOTA 2026: Automatic event delegation on component root
|
|
115
|
+
// Single listener handles all [data-action] clicks - no timing issues
|
|
116
|
+
// Attached BEFORE render so it catches events on dynamically created elements
|
|
117
|
+
this.#setupEventDelegation();
|
|
118
|
+
|
|
119
|
+
// Initial render
|
|
120
|
+
if (!this._rendered) {
|
|
121
|
+
this.render();
|
|
122
|
+
this._rendered = true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Lazy load component CSS
|
|
126
|
+
this._loadComponentCSS();
|
|
127
|
+
|
|
128
|
+
// 2026 Agent Optimization: Auto-infer semantic action attributes
|
|
129
|
+
this._inferSemanticAttributes();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* SOTA 2026: Centralized event delegation pattern.
|
|
134
|
+
* Single click listener on component root that delegates to [data-action] elements.
|
|
135
|
+
* Components implement handleAction(action, target, event) to handle actions.
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
#setupEventDelegation() {
|
|
139
|
+
this.listen(this, 'click', (e) => {
|
|
140
|
+
const actionEl = e.target.closest('[data-action]');
|
|
141
|
+
if (!actionEl || !this.contains(actionEl)) return;
|
|
142
|
+
|
|
143
|
+
const action = actionEl.dataset.action;
|
|
144
|
+
if (this.handleAction) {
|
|
145
|
+
this.handleAction(action, actionEl, e);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Lazy load component-specific CSS file.
|
|
152
|
+
* Only loads once per CSS file across all instances.
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
_loadComponentCSS() {
|
|
156
|
+
const cssFile = this.constructor.cssFile;
|
|
157
|
+
if (!cssFile) return;
|
|
158
|
+
|
|
159
|
+
// Check if already loaded (global static Set)
|
|
160
|
+
if (MuElement._loadedCSS.has(cssFile)) return;
|
|
161
|
+
MuElement._loadedCSS.add(cssFile);
|
|
162
|
+
|
|
163
|
+
// Create and append link element
|
|
164
|
+
const link = document.createElement('link');
|
|
165
|
+
link.id = `mu-css-${cssFile}`;
|
|
166
|
+
link.rel = 'stylesheet';
|
|
167
|
+
|
|
168
|
+
// Determine base path - check multiple sources
|
|
169
|
+
let basePath = '/styles/';
|
|
170
|
+
|
|
171
|
+
// 1. Check for existing styles/ link (direct styles loading)
|
|
172
|
+
const stylesLink = document.querySelector('link[href*="/styles/"]');
|
|
173
|
+
if (stylesLink) {
|
|
174
|
+
const match = stylesLink.href.match(/(.*\/(?:src\/|dist\/)?styles\/)/);
|
|
175
|
+
if (match) basePath = match[1];
|
|
176
|
+
}
|
|
177
|
+
// 2. Check for dist/microui.css (shell.html pattern) -> use dist/styles/
|
|
178
|
+
else {
|
|
179
|
+
const distLink = document.querySelector('link[href*="/dist/"]');
|
|
180
|
+
if (distLink) {
|
|
181
|
+
const match = distLink.href.match(/(.*\/dist\/)/);
|
|
182
|
+
if (match) basePath = match[1] + 'styles/';
|
|
183
|
+
}
|
|
184
|
+
// 3. Check for src/ pattern in scripts (dev mode)
|
|
185
|
+
else {
|
|
186
|
+
const srcScript = document.querySelector('script[src*="/src/"]');
|
|
187
|
+
if (srcScript) {
|
|
188
|
+
const match = srcScript.src.match(/(.*\/src\/)/);
|
|
189
|
+
if (match) basePath = match[1] + 'styles/';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
link.href = `${basePath}components/${cssFile}.css`;
|
|
195
|
+
document.head.appendChild(link);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Infer and set data-mu-action and data-mu-role attributes for AI agents.
|
|
200
|
+
* Based on 2026 Agentic Web research - semantic attributes reduce task failure.
|
|
201
|
+
* @private
|
|
202
|
+
*/
|
|
203
|
+
_inferSemanticAttributes() {
|
|
204
|
+
const tag = this.tagName.toLowerCase();
|
|
205
|
+
|
|
206
|
+
// Skip if already has explicit action
|
|
207
|
+
if (this.hasAttribute('data-mu-action')) return;
|
|
208
|
+
|
|
209
|
+
// Infer action based on component type
|
|
210
|
+
let action = '';
|
|
211
|
+
let role = '';
|
|
212
|
+
|
|
213
|
+
switch (tag) {
|
|
214
|
+
case 'mu-button':
|
|
215
|
+
action = this._inferButtonAction();
|
|
216
|
+
role = this._inferButtonRole();
|
|
217
|
+
break;
|
|
218
|
+
case 'mu-input':
|
|
219
|
+
case 'mu-textarea':
|
|
220
|
+
action = 'input';
|
|
221
|
+
role = 'text-field';
|
|
222
|
+
break;
|
|
223
|
+
case 'mu-checkbox':
|
|
224
|
+
case 'mu-switch':
|
|
225
|
+
action = 'toggle';
|
|
226
|
+
role = 'control';
|
|
227
|
+
break;
|
|
228
|
+
case 'mu-dropdown':
|
|
229
|
+
action = 'select';
|
|
230
|
+
role = 'selector';
|
|
231
|
+
break;
|
|
232
|
+
case 'mu-modal':
|
|
233
|
+
action = 'dialog';
|
|
234
|
+
role = 'overlay';
|
|
235
|
+
break;
|
|
236
|
+
case 'mu-tabs':
|
|
237
|
+
action = 'navigate';
|
|
238
|
+
role = 'navigation';
|
|
239
|
+
break;
|
|
240
|
+
case 'mu-card':
|
|
241
|
+
role = 'container';
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (action) this.setAttribute('data-mu-action', action);
|
|
246
|
+
if (role) this.setAttribute('data-mu-role', role);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Infer button action from text content
|
|
251
|
+
* @private
|
|
252
|
+
*/
|
|
253
|
+
_inferButtonAction() {
|
|
254
|
+
const text = this.textContent?.toLowerCase().trim() || '';
|
|
255
|
+
|
|
256
|
+
// Submit/Save patterns
|
|
257
|
+
if (/^(save|submit|confirm|send|create|add|apply|ok|yes)$/.test(text)) {
|
|
258
|
+
return 'submit';
|
|
259
|
+
}
|
|
260
|
+
// Cancel/Close patterns
|
|
261
|
+
if (/^(cancel|close|dismiss|no|nevermind)$/.test(text)) {
|
|
262
|
+
return 'cancel';
|
|
263
|
+
}
|
|
264
|
+
// Delete/Remove patterns
|
|
265
|
+
if (/^(delete|remove|clear|trash)$/.test(text)) {
|
|
266
|
+
return 'delete';
|
|
267
|
+
}
|
|
268
|
+
// Navigation patterns
|
|
269
|
+
if (/^(back|next|previous|forward|continue)$/.test(text)) {
|
|
270
|
+
return 'navigate';
|
|
271
|
+
}
|
|
272
|
+
// Default
|
|
273
|
+
return 'click';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Infer button role from context
|
|
278
|
+
* @private
|
|
279
|
+
*/
|
|
280
|
+
_inferButtonRole() {
|
|
281
|
+
const variant = this.getAttribute('variant');
|
|
282
|
+
|
|
283
|
+
// Primary action buttons
|
|
284
|
+
if (variant === 'filled' || variant === 'elevated') {
|
|
285
|
+
return 'primary-action';
|
|
286
|
+
}
|
|
287
|
+
// Secondary actions
|
|
288
|
+
if (variant === 'tonal' || variant === 'outlined') {
|
|
289
|
+
return 'secondary-action';
|
|
290
|
+
}
|
|
291
|
+
// Tertiary/dismiss
|
|
292
|
+
if (variant === 'text') {
|
|
293
|
+
return 'tertiary-action';
|
|
294
|
+
}
|
|
295
|
+
// Danger
|
|
296
|
+
if (variant === 'danger') {
|
|
297
|
+
return 'destructive-action';
|
|
298
|
+
}
|
|
299
|
+
return 'action';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Called when element is removed from DOM.
|
|
304
|
+
* CRITICAL: Clean up all event listeners and timers to prevent memory leaks.
|
|
305
|
+
*/
|
|
306
|
+
disconnectedCallback() {
|
|
307
|
+
// Abort all event listeners registered with signal
|
|
308
|
+
if (this._abortController) {
|
|
309
|
+
this._abortController.abort();
|
|
310
|
+
this._abortController = null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Clear all timers
|
|
314
|
+
for (const timer of this._timers) {
|
|
315
|
+
clearTimeout(timer);
|
|
316
|
+
}
|
|
317
|
+
this._timers.clear();
|
|
318
|
+
|
|
319
|
+
// Clear all intervals
|
|
320
|
+
for (const interval of this._intervals) {
|
|
321
|
+
clearInterval(interval);
|
|
322
|
+
}
|
|
323
|
+
this._intervals.clear();
|
|
324
|
+
|
|
325
|
+
// Call subclass cleanup
|
|
326
|
+
this.cleanup();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Override in subclass for custom cleanup logic.
|
|
331
|
+
* Called when component is removed from DOM.
|
|
332
|
+
*/
|
|
333
|
+
cleanup() {
|
|
334
|
+
// Override in subclass
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Called when observed attribute changes.
|
|
339
|
+
* Triggers efficient update, not full re-render.
|
|
340
|
+
*/
|
|
341
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
342
|
+
if (oldValue !== newValue && this._rendered) {
|
|
343
|
+
this.update(name, newValue, oldValue);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Initial render - override in subclass.
|
|
349
|
+
*/
|
|
350
|
+
render() {
|
|
351
|
+
// Override in subclass
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Efficient update - override in subclass.
|
|
356
|
+
* Modifies existing DOM, never recreates.
|
|
357
|
+
*/
|
|
358
|
+
update(attr, newValue, oldValue) {
|
|
359
|
+
// Override in subclass
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* SOTA 2026: Deferred event setup - override in subclass.
|
|
364
|
+
* Called via queueMicrotask AFTER render() completes.
|
|
365
|
+
* Guarantees DOM is stable before attaching listeners.
|
|
366
|
+
* Use this.listen() for automatic cleanup on disconnect.
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* setupEvents() {
|
|
370
|
+
* this.listen(this.button, 'click', () => this.handleClick());
|
|
371
|
+
* }
|
|
372
|
+
*/
|
|
373
|
+
setupEvents() {
|
|
374
|
+
// Override in subclass
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Helper: Get attribute with default
|
|
379
|
+
*/
|
|
380
|
+
attr(name, defaultValue = '') {
|
|
381
|
+
return this.getAttribute(name) ?? defaultValue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Helper: Check if attribute exists
|
|
386
|
+
*/
|
|
387
|
+
has(name) {
|
|
388
|
+
return this.hasAttribute(name);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Helper: Emit a custom event
|
|
393
|
+
*/
|
|
394
|
+
emit(name, detail = {}) {
|
|
395
|
+
this.dispatchEvent(new CustomEvent(name, {
|
|
396
|
+
bubbles: true,
|
|
397
|
+
composed: true,
|
|
398
|
+
detail
|
|
399
|
+
}));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Safe addEventListener with automatic cleanup on disconnect.
|
|
404
|
+
* Uses AbortController signal for efficient removal.
|
|
405
|
+
*
|
|
406
|
+
* @param {string} type - Event type
|
|
407
|
+
* @param {EventListener} listener - Event handler
|
|
408
|
+
* @param {AddEventListenerOptions} options - Event options
|
|
409
|
+
*/
|
|
410
|
+
listen(target, type, listener, options = {}) {
|
|
411
|
+
if (!this._abortController) {
|
|
412
|
+
this._abortController = new AbortController();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const opts = {
|
|
416
|
+
...options,
|
|
417
|
+
signal: this._abortController.signal
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
target.addEventListener(type, listener, opts);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Safe setTimeout with automatic cleanup on disconnect.
|
|
425
|
+
* @param {Function} fn - Callback
|
|
426
|
+
* @param {number} delay - Delay in ms
|
|
427
|
+
* @returns {number} Timer ID
|
|
428
|
+
*/
|
|
429
|
+
setTimeout(fn, delay) {
|
|
430
|
+
let id;
|
|
431
|
+
id = setTimeout(() => {
|
|
432
|
+
this._timers.delete(id);
|
|
433
|
+
fn();
|
|
434
|
+
}, delay);
|
|
435
|
+
this._timers.add(id);
|
|
436
|
+
return id;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Safe setInterval with automatic cleanup on disconnect.
|
|
441
|
+
* @param {Function} fn - Callback
|
|
442
|
+
* @param {number} delay - Interval in ms
|
|
443
|
+
* @returns {number} Interval ID
|
|
444
|
+
*/
|
|
445
|
+
setInterval(fn, delay) {
|
|
446
|
+
const id = setInterval(fn, delay);
|
|
447
|
+
this._intervals.add(id);
|
|
448
|
+
return id;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Helper: Setup keyboard activation (Enter/Space triggers callback).
|
|
453
|
+
* Also sets up tabindex based on disabled state.
|
|
454
|
+
* Consolidates repeated pattern across interactive components.
|
|
455
|
+
*
|
|
456
|
+
* @param {Function} callback - Function to call on activation
|
|
457
|
+
*/
|
|
458
|
+
setupActivation(callback) {
|
|
459
|
+
this.updateTabindex();
|
|
460
|
+
this.addEventListener('keydown', (e) => {
|
|
461
|
+
if ((e.key === 'Enter' || e.key === ' ') && !this.has('disabled')) {
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
callback();
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Helper: Update tabindex based on disabled state.
|
|
470
|
+
* Interactive elements should be focusable unless disabled.
|
|
471
|
+
*/
|
|
472
|
+
updateTabindex() {
|
|
473
|
+
this.setAttribute('tabindex', this.has('disabled') ? '-1' : '0');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Helper: Set display style consistently.
|
|
478
|
+
* @param {string} value - CSS display value (flex, block, inline-flex, etc.)
|
|
479
|
+
*/
|
|
480
|
+
setDisplay(value) {
|
|
481
|
+
this.style.display = value;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Helper: Check if component is disabled.
|
|
486
|
+
* @returns {boolean}
|
|
487
|
+
*/
|
|
488
|
+
get isDisabled() {
|
|
489
|
+
return this.has('disabled');
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* SOTA 2026: Scheduler API-enhanced component registration.
|
|
495
|
+
* Yields to main thread between registrations to prevent long tasks (>50ms).
|
|
496
|
+
* Uses scheduler.yield() on Chrome 129+, falls back to setTimeout(0).
|
|
497
|
+
*
|
|
498
|
+
* @param {string} tagName - Custom element tag name
|
|
499
|
+
* @param {typeof HTMLElement} ComponentClass - Component class to register
|
|
500
|
+
* @param {Object} options - Registration options
|
|
501
|
+
* @param {string} options.priority - 'user-blocking' (default) | 'user-visible' | 'background'
|
|
502
|
+
*/
|
|
503
|
+
export function define(tagName, ComponentClass, options = {}) {
|
|
504
|
+
if (customElements.get(tagName)) return;
|
|
505
|
+
|
|
506
|
+
const priority = options.priority || 'user-blocking';
|
|
507
|
+
|
|
508
|
+
// SOTA 2026: Use Scheduler API for prioritized registration
|
|
509
|
+
if (typeof scheduler !== 'undefined' && scheduler.postTask) {
|
|
510
|
+
scheduler.postTask(() => {
|
|
511
|
+
if (!customElements.get(tagName)) {
|
|
512
|
+
customElements.define(tagName, ComponentClass);
|
|
513
|
+
}
|
|
514
|
+
}, { priority });
|
|
515
|
+
} else {
|
|
516
|
+
// Fallback: immediate registration for older browsers
|
|
517
|
+
customElements.define(tagName, ComponentClass);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* SOTA 2026: Batch component registration with yielding.
|
|
523
|
+
* Registers multiple components while yielding to main thread between each.
|
|
524
|
+
* Prevents long tasks and keeps UI responsive during initial load.
|
|
525
|
+
*
|
|
526
|
+
* @param {Array<[string, typeof HTMLElement]>} components - Array of [tagName, Class] pairs
|
|
527
|
+
* @param {Object} options - Registration options
|
|
528
|
+
* @param {number} options.batchSize - Components per batch before yield (default: 3)
|
|
529
|
+
* @returns {Promise<void>} Resolves when all components are registered
|
|
530
|
+
*/
|
|
531
|
+
export async function defineAll(components, options = {}) {
|
|
532
|
+
const batchSize = options.batchSize || 3;
|
|
533
|
+
const yieldToMain = getYieldFunction();
|
|
534
|
+
|
|
535
|
+
for (let i = 0; i < components.length; i++) {
|
|
536
|
+
const [tagName, ComponentClass] = components[i];
|
|
537
|
+
|
|
538
|
+
if (!customElements.get(tagName)) {
|
|
539
|
+
customElements.define(tagName, ComponentClass);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Yield to main thread after each batch to prevent long tasks
|
|
543
|
+
if ((i + 1) % batchSize === 0 && i < components.length - 1) {
|
|
544
|
+
await yieldToMain();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Get the best yield function available.
|
|
551
|
+
* SOTA 2026: scheduler.yield() > setTimeout(0)
|
|
552
|
+
* @returns {Function} Async yield function
|
|
553
|
+
*/
|
|
554
|
+
function getYieldFunction() {
|
|
555
|
+
// Chrome 129+: scheduler.yield() is the most efficient
|
|
556
|
+
if (typeof scheduler !== 'undefined' && scheduler.yield) {
|
|
557
|
+
return () => scheduler.yield();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Fallback: setTimeout(0) yields to event loop
|
|
561
|
+
return () => new Promise(resolve => setTimeout(resolve, 0));
|
|
562
|
+
}
|