Skip to content

feat(design-data-spec): add componentOptions to platform-extension.json - #1483

Draft
GarthDB wants to merge 7 commits into
mainfrom
feat/component-option-platform-extensions
Draft

GarthDB wants to merge 7 commits into
mainfrom
feat/component-option-platform-extensions

Conversation

@GarthDB

@GarthDB GarthDB commented Sep 19, 2026

Copy link
Copy Markdown
Member

Summary

  • Platform implementations sometimes name a component's own option/prop differently for reasons that aren't backed by a shared registry (e.g. Button's style option is fillStyle in React, and the reflected HTML attribute fill-style in Web Components). The existing platform-extension.json mechanism only aliases shared registry terms (states, sizes, variants) via extends/extensions — there was no way to alias a component-specific option.
  • Adds an optional componentOptions[] array (sibling to extends/extensions, validated via anyOf) scoped to one component's own options map: platformProp, platformAttribute (when the JS prop and HTML attribute differ), platformAliases, per-value aliasing (values[]), and platformOnlyValues[] for platform-only extras that have no canonical/Figma counterpart — recorded explicitly rather than silently mapped to the nearest lookalike.
  • Implements the reference-SDK support this needs: ComponentOptionExtensionRecord + TokenGraph.component_option_extensions in sdk/core/src/graph.rs, mirroring the existing PlatformExtensionRecord pattern, plus a componentOptionExtensions.present conformance-behavior predicate in sdk/core/src/lib.rs.
  • Adds two example instances grounded in real source (not guessed), verified against Button.ts/Button.types.ts (Spectrum Web Components) and Button.tsx (@react-spectrum/button, S2): web-components-button.json and react-spectrum-button.json. The React instance records premium/genai as platformOnlyValues since neither Figma nor Web Components has them.
  • Adds matching conformance fixtures (valid/injects-component-option-extension, invalid/component-option-extension-missing-component) and a README table update.

Motivation

Working through hooking Figma Code Connect up to spectrum-design-data's component declarations (see #1482) surfaced that per-platform naming drift is real and currently has nowhere durable to live. This gives it a home consistent with the existing platform-manifest extension pattern, rather than hardcoding aliases inside any one downstream tool.

Test plan

  • cargo test manifest_extensions — all 4 relevant tests pass, including the 2 new fixtures
  • cargo test (full suite) — 782 + 10 + 5 tests pass, no regressions
  • New schema validated against both new instance files and the pre-existing web-components-states.json (backward compatible)
  • Design review from design-data-spec owners on the componentOptions shape before merging

🤖 Generated with Claude Code

Prop/value naming differs across platform implementations for reasons
that aren't backed by a shared registry (e.g. Button's `style` option
is `fillStyle` in React, `fill-style` as a Web Components attribute).
The existing platform-extension mechanism only aliases shared registry
terms (states, sizes, variants); this adds a sibling `componentOptions`
array scoped to one component's own `options` map, including explicit
`platformOnlyValues` so platform-only extras (e.g. Button's React-only
`premium`/`genai` variants) are recorded rather than silently mapped to
a lookalike.

Implements the loader/record support in the Rust reference SDK
(ComponentOptionExtensionRecord, TokenGraph.component_option_extensions)
and matching conformance fixtures, mirroring the existing
PlatformExtensionRecord pattern. Includes grounded example instances for
Button on Web Components and React Spectrum, verified against their
actual source (Button.ts/Button.types.ts, Button.tsx).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 22df09f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@adobe/design-data-spec Minor
@adobe/spectrum-design-data Minor
@adobe/spectrum-component-api-schemas Patch
@adobe/design-system-registry Patch
@adobe/design-data-agent-mcp Patch
@adobe/design-data-mcp Patch
markdown-generator Patch
@adobe/token-corpus-migrate Patch
@adobe/token-naming-audit Patch
component-options-editor Patch
@adobe/spectrum-design-data-mcp Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Run report for 22df09f8

Total time: 2m 6s | Comparison time: 4m 49s | Estimated savings: 2m 42s (56.3% faster)

Action Time Status Info
⬛️ SetupProto(0.57.4) 0ms Skipped
🟩 SyncWorkspace 6.9ms Passed
🟩 SyncProject(sdk) 0.4ms Passed
🟩 SyncProject(root) 0.5ms Passed
⬛️ SetupToolchain(node:20.17.0) 509.4ms Skipped
⬛️ SetupToolchain(rust:1.88.0) 613.9ms Skipped
🟩 SetupEnvironment(rust, sdk) 72.1ms Passed
⬛️ InstallDependencies(rust, sdk) 2ms Skipped
⬛️ SetupToolchain(pnpm:10.17.1) 317.4ms Skipped
⬛️ SetupToolchain(javascript) 0ms Skipped
🟩 SetupEnvironment(javascript) 0.9ms Passed
⬛️ InstallDependencies(javascript) 0.1ms Skipped
⬛️ SetupEnvironment(javascript, sdk) 0.9ms Skipped
🟩 RunTask(sdk:fmt-check) 562.1ms Passed
🟩 InstallDependencies(javascript, sdk) 4.3s Passed
🟩 RunTask(sdk:codegen-check) 139ms Passed
🟩 RunTask(sdk:lint) 39.1s Passed
🟩 RunTask(sdk:test-doc) 1m 20s Passed
🟩 RunTask(sdk:build) 1m 30s Passed
🟩 RunTask(root:validate-platforms) 2.4s Passed
And 1 more...
Expanded report
Action Time Status Info
🟩 RunTask(sdk:test) 2m 1s Passed SLOW
Changed files
.changeset/bright-buttons-alias.md
packages/design-data-spec/conformance/manifest-extensions/README.md
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-missing-component/expected-errors.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-missing-component/extensions/platform-extensions/broken.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-missing-component/manifest.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-canonical-value/expected-errors.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-canonical-value/extensions/components/button.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-canonical-value/extensions/platform-extensions/broken.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-canonical-value/manifest.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-component/expected-errors.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-component/extensions/platform-extensions/broken.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-component/manifest.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-option/expected-errors.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-option/extensions/components/button.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-option/extensions/platform-extensions/broken.json
packages/design-data-spec/conformance/manifest-extensions/invalid/component-option-extension-unknown-option/manifest.json
packages/design-data-spec/conformance/manifest-extensions/valid/injects-component-option-extension/expected.json
packages/design-data-spec/conformance/manifest-extensions/valid/injects-component-option-extension/extensions/components/button.json
packages/design-data-spec/conformance/manifest-extensions/valid/injects-component-option-extension/extensions/platform-extensions/web-components-button.json
packages/design-data-spec/conformance/manifest-extensions/valid/injects-component-option-extension/manifest.json
packages/design-data-spec/schemas/platform-extension.json
platforms/react-spectrum/extensions/platform-extensions/react-spectrum-button.json
platforms/web-components/extensions/platform-extensions/web-components-button.json
sdk/core/src/graph.rs
sdk/core/src/lib.rs
sdk/core/src/primer.rs

@github-actions

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

🎨 Token Changes Report

Tokens Changed (0)

Original Branch: main


This comment was automatically generated by the token diff tool. 🤖

@github-actions

Copy link
Copy Markdown
Contributor

🧩 Component Schema Changes Report

No component schema changes detected.

This comment was automatically generated by the component schema diff tool. 🤖

GarthDB and others added 6 commits September 18, 2026 19:07
- primer.rs: the primer's platform_extensions summary only counted
  graph.platform_extensions, silently ignoring componentOptions-only
  manifests (reported as "Platform ext.: 0"). Now chains in
  "{platform}:{component}.{option}" entries from
  graph.component_option_extensions.
- graph.rs: the componentOptions loader didn't validate that the
  referenced component/option actually exist, unlike the sibling
  extends/termId path — a typo silently produced a dangling alias
  instead of failing fast. Now looks up the component in the already-
  loaded component catalog and checks the option exists in its
  `options` map, erroring loudly on either miss.
- Adds two invalid conformance fixtures exercising the new checks
  (unknown component, unknown option on a known component), and a
  components/ fragment in the existing valid fixture so it has a real
  "button" component with a "style" option to reference.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The componentOptions existence check in platform-extension parsing used
!x.is_some() instead of x.is_none(), which clippy -D warnings flags as
nonminimal_bool. This was failing the Rust CI job on PR #1483.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
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