Repository navigation
feat(core): support scoped custom element registries - #6843
rubencarvalho wants to merge 1 commit into
Conversation
Let independently built apps on one page each use their own version of gen2 components with the same swc-* tag names. - add static define(registry), tagName, and dependencies to SpectrumElement - create shadow roots and clone Lit templates with the host's registry - add the @adobe/spectrum-wc/registry entry with the package registry, ScopedElementMixin, and scopedRenderOptions - declare rendered elements in static dependencies instead of importing swc-*.js files from class modules, and lint against those imports - generate the @adobe/spectrum-wc version that keys the registry index - add a scoped registries guide, tests, and a changeset BREAKING CHANGE: importing a component class no longer defines the elements it renders in the global registry. Call Component.define() or import the component's swc-*.js file.
|
📚 Branch Preview Links🔍 Gen1 Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
Description
Draft: experimental support for scoped custom element registries in gen2. Independently built apps on one page can each use their own version of Spectrum Web Components with the same
swc-*tag names. Pages that use one version keep today's imports and behavior.Core (
@adobe/spectrum-wc-core)SpectrumElementhas a staticdefine(registry = customElements). It defines the class'sdependenciesfirst, then the class under its own statictagName.SpectrumElementuses the newScopedElementMixin. An element created in a scoped registry attaches its shadow root with that registry and clones Lit templates with it. Elements created in the global registry render exactly as before.defineElement(name, constructor, registry?)takes an optional registry and does nothing when the same constructor is already defined. Shared dependencies, such as<swc-ui-icon>, can then be defined from several components.createScopedRegistry(version)creates the package registry, publishes it atwindow.__swc.scopedRegistries, and throws a clear error when the browser lacks support. The first copy of a version keeps the index entry. Later copies warn in development.SWC (
@adobe/spectrum-wc)@adobe/spectrum-wc/registry:registry,version,ScopedElementMixin,scopedRenderOptions.static tagName. Eachswc-*.tsregistration file is nowComponent.define().swc-*.jsfiles. Composite classes list the classes they render instatic dependencies(Close Button, Accordion Item, Color Handle, and the AI toolkit patterns).no-restricted-importsrule keepsswc-*.jsimports out of class modules. Workflow icon element modules get their own message that points to theIcon_*SVG functions.scripts/generate-versions.jsalso writesgen2/packages/swc/registry/version.ts, so the index uses the@adobe/spectrum-wcversion. Core's version can differ, because changesets links the gen2 package versions rather than fixing them.Docs and tooling
VITEST_BROWSER_CHANNEL=chromeruns the Vitest suite in system Chrome. Playwright 1.53 bundles Chromium 138, which predates native support (Chrome 146).Breaking (beta): Importing a class, for example
CloseButtonfrom@adobe/spectrum-wc/close-button, no longer defines<swc-ui-icon>globally. Consumers that callcustomElements.define()on a class themselves should callCloseButton.define()or import theswc-*.jsfile instead. The changeset documents this.Not in this PR:
@adobe/spectrum-wc-icons. Their generator writes the class and its global definition in one module. The guide points scoped apps to theIcon_*SVG functions inside<swc-icon>.:root, :host, so onetokens.cssalso works inside an app's shadow root.Motivation and context
Today every gen2 component registers in the single global registry, so a page can run one version of
<swc-button>. Hosts that compose independently versioned apps need each app's SWC version, including the elements components render internally, to resolve from that app's registry.Scoped registries ship in Chrome and Edge 146+ and Safari 26+. Firefox has them in Nightly. A polyfill for the standard API is in review in webcomponents/polyfills#668. Production use waits for that release. Lit support is in review in lit/lit#5246 and lit/lit#5260.
ScopedElementMixinandscopedRenderOptionsbridge that gap and will be deprecated when Lit releases it.Related issue(s)
Screenshots (if appropriate)
Not applicable. No visual changes.
Author's checklist
Validation
Run from the repository root unless noted:
yarn type-check:gen2: passed.yarn eslint <changed files>: passed, 0 errors.yarn prettier --check <changed files>: passed.yarn lint:ai: passed.yarn lint:docs-pages: passed.node scripts/generate-versions.js --check: passed.yarn buildingen2/packages/coreand ingen2/packages/swc: passed.dist/registry/index.jsanddist/registry/index.d.tsare emitted.yarn vitest --run --project storybookingen2/packages/swc, bundled Chromium 138: 1254 passed. One earlier run had 3 timing failures inmenu.test.tsandtabs.test.ts. They passed in isolation and on the rerun.VITEST_BROWSER_CHANNEL=chrome yarn vitest --run --project storybookingen2/packages/swc, Chrome 155: 1254 passed. This includes the native scoped-registry tests.attachShadowignores the host registry, if Close Button dropsdependencies, or if a class module importsswc-ui-icon.jsagain.Reviewer's checklist
patch,minor, ormajorfeaturesManual review test cases
Global registration is unchanged
yarn storybookingen2/packages/swc).main.Scoped registries work natively
gen2/packages/swc, runVITEST_BROWSER_CHANNEL=chrome yarn vitest --run --project storybook scoped-registrywith Chrome 146+ installed.Unsupported browsers fail loudly
gen2/packages/swc, runyarn vitest --run --project storybook scoped-registry. This uses the bundled Chromium 138.createScopedRegistry()throws a clear error.The lint rule blocks global imports in class modules
import '../ui-icons/swc-ui-icon.js';togen2/packages/swc/components/close-button/CloseButton.ts.yarn eslint gen2/packages/swc/components/close-button/CloseButton.ts.no-restricted-importserror that points tostatic dependencies.Guide reads correctly
Device review
Accessibility testing checklist
This PR changes registration only. Markup, ARIA, and focus handling don't change. Spot-check the composite components whose internal elements now register through
dependencies.Keyboard (required — document steps below) — What to test for: Focus order is logical; Tab reaches the component and all interactive descendants; Enter/Space activate where appropriate; arrow keys work for tabs, menus, sliders, etc.; no focus traps; Escape dismisses when applicable; focus indicator is visible.
main.Screen reader (required — document steps below) — What to test for: Role and name are announced correctly; state changes (e.g. expanded, selected) are announced; labels and relationships are clear; no unnecessary or duplicate announcements.
main. The UI icons stay hidden from assistive technology.