Skip to content

Show the whole component kit in OS Settings, and make it searchable - #451

Merged
AllTerrainDeveloper merged 1 commit into
trunkfrom
fix/components-tab-full-kit
Jul 30, 2026
Merged

Show the whole component kit in OS Settings, and make it searchable#451
AllTerrainDeveloper merged 1 commit into
trunkfrom
fix/components-tab-full-kit

Conversation

@AllTerrainDeveloper

@AllTerrainDeveloper AllTerrainDeveloper commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

The bug

<wpd-number-field> doesn't appear in OS Settings → Components. Neither do 24 other components.

The tab iterates WPD_COMPONENT_TAGS, looks each tag up with customElements.get(), and skips anything unregistered:

const ctor = customElements.get( tag ) as CtorWithHelp | undefined;
if ( ! ctor ) {
    continue;
}

Feature code imports components one file at a time (import '../ui/components/wpd-button/wpd-button') and nothing imported the barrel. So any component that no screen happened to use was tree-shaken out of every bundle, never reached the custom-element registry, and got silently dropped from a list whose own description promises "every <wpd-*> web component shipped by this plugin".

The tab was showing components some other screen loaded, not components this plugin ships. 38 of 63.

Invisible before this change: badge, body, card, category-picker, checkbox, chip, cluster, code, crumb-chain, display, flyout, form, grid, key, log, multiselect, number-field, rating-summary, relative-time, row, stack, step, steps, table, tag-input.

WpdNumberField was in zero built bundles — the tag was inert everywhere in the shell, not merely absent from the tab.

The fix

Side-effect-import the barrel from the tab. Verified in the built bundle: defineComponent(...) calls in os-settings-panel.js went 21 → 63.

Search

A <wpd-text-field type="search"> above the list, filtering a haystack flattened once per entry in collectEntries() — so each keystroke is a substring scan, not a walk of the descriptor tree.

Matches on tag, title, summary, status, static props names, and the name and description of every documented prop, slot, event, part, and CSS custom property. Descriptions are in deliberately: searching clamp should reach <wpd-number-field> through its min/max prop docs even though the word appears in no name.

Terms are ANDed and order-independent — field number and number field return the same set. The count line switches to "N of 63 components match", selection follows the filter instead of blanking the detail pane, and an empty result renders a message rather than an empty column.

On "are other components undocumented?"

Checked, and no: tags.ts ↔ source tree is exactly in sync (63/63, no orphans in either direction), every one of the 63 classes carries a static help descriptor, and docs/components-reference.md covers them all — the 8 that look absent from its table are child tags (<wpd-option>, <wpd-segment>, <wpd-tabpanel>, …) documented on their parent's row. Tree-shaking was the entire gap.

Trade-off worth a look

os-settings-panel.min.js grows 40.2 → 88.0 KB gzip, and that bundle loads whenever anyone opens OS Settings — to serve a tab that's admin-only and developer-facing.

The alternative is a separate build:components-help target loaded on demand when the tab opens; loadOsSettingsPanelBundle() in src/settings/index.ts is an existing pattern to copy. That's a new Vite target, PHP asset registration, and an async section builder, so I didn't fold it into this PR. Happy to do it as a follow-up if the 48 KB is unwelcome.

Tests

12 new tests in tests/vitest/os-settings-components-tab.test.ts. One pins the regression directly:

test( 'every declared tag is registered on customElements', () => {
    const unregistered = WPD_COMPONENT_TAGS.filter(
        ( tag ) => ! customElements.get( tag ),
    );
    expect( unregistered ).toEqual( [] );
} );

Full suite: 2511 passed / 257 files. typecheck, lint, and build all clean (the single CSS minify warning reproduces on trunk — pre-existing).

Manual test steps

OS Settings → Components:

  1. Count line reads 63 components registered (was 38).
  2. Type number — list narrows, <wpd-number-field> present with a live rendered example.
  3. Type clamp — still finds it, matched only via prop descriptions.
  4. Type field number, then number field — identical results.
  5. Type nonsense — "No components match." and the detail pane empty-states.

🤖 Generated with Claude Code

Open WordPress Playground Preview

The Components tab iterated WPD_COMPONENT_TAGS and looked each tag up
via customElements.get(), skipping anything unregistered. Feature code
imports components one file at a time and nothing imported the barrel,
so any component no screen happened to use was tree-shaken out of every
bundle, never reached the registry, and was silently dropped from a list
whose own description promises every <wpd-*> the plugin ships.

25 of 63 components were invisible, WpdNumberField among them — it was
in zero built bundles, so the tag was inert everywhere in the shell, not
just absent from the tab.

Side-effect-import the barrel from the tab so all 63 tags register, and
add a search box above the list. It filters a haystack flattened once
per entry: tag, title, summary, status, static props names, plus the
name and description of every documented prop, slot, event, part, and
CSS custom property. Terms are ANDed and order-independent, so both
"field number" and "number clamp" reach <wpd-number-field>. The count
line reports matches while filtering, and an empty result renders a
message rather than a blank column.

tags.ts, the source tree, and components-reference.md were already in
sync (63/63, every class carrying a static help descriptor) — the
tree-shaking was the whole gap.

One test pins the regression: every tag in WPD_COMPONENT_TAGS must be
registered on customElements.

Trade-off worth knowing: os-settings-panel.min.js grows 40.2 -> 88.0 KB
gzip, and that bundle loads whenever anyone opens OS Settings to serve
an admin-only tab. Splitting the kit into its own lazily-loaded target
is the follow-up if that cost bites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@AllTerrainDeveloper
AllTerrainDeveloper merged commit 45fea56 into trunk Jul 30, 2026
5 checks passed
@AllTerrainDeveloper
AllTerrainDeveloper deleted the fix/components-tab-full-kit branch July 30, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant