Skip to content

ADRs 042, 045–050: Composition, Slot Content, and Ready-Made Examples#111

Open
nathanacurtis wants to merge 52 commits into
mainfrom
examples-slots-instances
Open

ADRs 042, 045–050: Composition, Slot Content, and Ready-Made Examples#111
nathanacurtis wants to merge 52 commits into
mainfrom
examples-slots-instances

Conversation

@nathanacurtis
Copy link
Copy Markdown
Member

Supersedes #91 (auto-closed when the branch was renamed to examples-slots-instances; no commits changed).

Composition, slot-content, and examples model for the schema/types/CLI/docs (ADRs 042, 046–050). Base retargeted to release/schema-0.21.0-cli-0.16.0.

Schema / types (0.21.0)

  • Composition model (ADR-042/046): Composition, Compositions, SlotContent, and the universal SlotContentRef ({ $slotContent }) pointer.
  • Slot content + instance examples (ADR-047/048): Component.slotContentExamples, Component.instanceExamples / InstanceExample, SlotBinding (extends PropBinding with examples?), Children widened to SlotBinding, PropConfigurations value union widened.
  • Examples config (ADR-050): processing.instanceExamples { scope?: 'PAGE'|'FILE', match, exclude?, parentNames? } and include.slotContentExamples / include.instanceExamples gates — across Config, ResolvedConfig, and DEFAULT_CONFIG. (ADR-050 doc renamed parentparentNames with ranked-naming rationale.)
  • component.schema.json kept in lockstep with the types.

CLI (0.16.0)

  • ConfigLoader accepts the new include.*Examples flags and validates processing.instanceExamples (scope/match/exclude/parentNames), passing them to the engine.

Docs

  • New config pages (instance-examples, slot-content-examples), schema/config table updates, nav registration.

Notes

  • Type tests + JSON schema validated; CHANGELOGs updated (schema 0.21.0, cli 0.16.0).
  • Pairs with specs-from-figma compositions (detection/serialization) and specs-plugin-2 feature/examples-config (settings UI).

🤖 Generated with Claude Code

nathanacurtis and others added 30 commits April 29, 2026 07:35
Introduces Composition as a peer type to Component, covering slot
defaults, component examples, layout patterns, and page views.
Supersedes draft ADR-025 (nested slot API).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Component.examples: Record<string, Composition> (inline, kind-tagged)
- CompositionRef { $composition: string } in Children union for slot bindings
- Slot defaults live in variant/element layer, vary per variant
- PropConfigurations widening retained (consumer inline pattern)
- System-scoped compositions.yaml schema deferred to follow-on ADR

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…faults

- Rename CompositionRef → CompositionReference (then remove: not needed)
- Remove CompositionReference from Children union — Children unchanged
- Slot default composition lives in Element.$extensions['com.figma']
  following established provenance-metadata pattern on Props/TokenReference
- Add ElementExtensions + FigmaElementExtension types on Element
- Slot defaults are Figma provenance, not public component API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
defaultComposition is meaningful only when Element.children is a
PropBinding (slot-bound container / Figma SlotNode). Container elements
with string[] children are FrameNodes and must never carry it.
No new element type introduced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ComponentExample = SlotExample | InstanceExample (kind-discriminated)
- SlotExample: kind+'slot'+anatomy+elements+layout — no inline nesting
- InstanceExample: kind+propConfigurations (scalars)+slots (named refs)
- Composition retained as structural base for system-scoped follow-on
- PropConfigurations widens to PropBinding only; inline Composition deferred
- Remove CompositionKind; layout/page kinds moved to follow-on ADR
- All examples use aSlotProperty/aSlotElement naming

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ciple to ADR 042

- Replace Card/ProductCard examples with ActionList/ActionListItem throughout
- Add sensitizing example section: illustrates 56 to 16 entry reduction via
  one-level-deep principle and no cross-component references
- Add two new Decision Drivers: One level deep and No cross-component references
- Update Option A Pros to call out scale reduction explicitly
- Update Notes to explain the ActionListItem boundary and why it is intentional

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ADR-042 now covers only the Composition base type (anatomy, elements, layout).
The four-ADR breakdown:
  043 — Component Examples: InstanceExample + Component.examples
  044 — Slot Content: SlotExample + Element extensions
  045 — PropConfigurations PropBinding

Example anchors on ActionListItem with state/title/description scalar props;
slots are introduced in ADR-044.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…opBinding

043: InstanceExample + ComponentExamples + Component.examples
     ActionListItem anchors the example with state/title/description scalar props
     InstanceExample.slots forward-compatible; meaningful once 044 lands

044: SlotExample + ElementExtensions + Element.$extensions
     ActionListItem startVisual/endVisual slots; ActionList items slot one level deep
     16 entries on ActionList (not 56); one-level-deep principle; no cross-component refs
     Widens ComponentExamples to ComponentExample = InstanceExample | SlotExample

045: Widen PropConfigurations to include PropBinding
     Completes binding pattern already on Element.content, instanceOf, Styles.visible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…xample

- Replace thin two-option section with four substantive options exploring:
  - Anatomy/elements convergence (B — rejected: breaks SlotExample inheritance)
  - All three required (A — selected)
  - elements optional (C — rejected: anatomy-only is degenerate)
  - layout optional (D — rejected: implied order is invisible convention)
- Fix example: ActionListItem with root/label/description, not a single 'item'
- Add description? field alongside title?
- Note nested-instance-with-slot constraint explicitly in Notes
- Note anticipated metadata extensions (tags, deprecated, guidelines)
- Propagate required elements+layout to ADR-044 SlotExample

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 2x page grid padding and nav–content gutter at wide viewports
- Increase sidebar item spacing (+4px) and padding (+2px → 8px)
- Remove distinct surface colors and borders between nav/sidebar/content
- Force dark mode and hide theme toggle
- Move GitHub and Figma Plugin links from header to top of sidebar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lotBinding

Substantial revisions following review:

- Drop SlotExample type; reuse Composition directly
- Drop the per-entry `slot` field — content entries are slot-agnostic
- Make slot content a sibling field (`Component.slotContent`) rather than a
  discriminated-union peer of `InstanceExample` in `Component.examples`
- Move Figma default-fill reference into `SlotBinding.$extensions['com.figma'].default`
  (inside `Element.children`, not a sibling on `Element`) to reflect that it is
  design-tool authoring provenance that code consumers must correctly ignore
- Defer recursion (nested slot filling) and its motivating example to a
  follow-on ADR; keep this ADR scoped to one level deep
- Add rejected options for Element-sibling field, content widening
- Tighten Context and trim Option A example to the minimum needed to show
  both reference sites

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ionale

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ompositions

main owns ADR-043 (custom-color-format-config) and PR #60 owns ADR-044/045
(duplicate-layer-disambiguation, processing-provenance-signals). This branch's
three ADRs collide with both. Move ours to the next free range so PR #60 and
already-merged work remain valid:

- 043-component-examples           -> 046-component-examples
- 044-slot-content                 -> 047-slot-content
- 045-prop-configurations-binding  -> 048-prop-configurations-binding

Reserve 049 for the deferred recursion ADR (Nested Slot Compositions, called
out as a follow-on in ADR-047). Stub authored.

Updates all ADR-NNN cross-references and branch-name references inside our
four ADRs and INDEX.md. INDEX.md description for the slot-content row also
brought in line with the redesigned ADR-047 title (the prior description
referenced removed concepts like SlotExample / defaultComposition).

Indexing change only - no design decisions altered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…+cli-0.14.0

# Conflicts:
#	adr/INDEX.md
#	packages/cli/CHANGELOG.md
#	packages/cli/package.json
…type

# Conflicts:
#	adr/042-composition-type.md
#	adr/INDEX.md
Slot fill is unified under Element.propConfigurations per ADR-049, so
InstanceExample.slots becomes redundant. With slot fills handled
separately, Component.examples only ever holds InstanceExample entries
and the kind discriminator carries no information.

Updates Decision Drivers, Options A and B, Notes, Consequences, schema
definition, and parity check to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…search scratchpads

ADR-049 now compares four shapes for cross-boundary slot fill:
  A. Nested only (inline Composition under propConfigurations)
  B. Flat only (key reference, discriminated as { \$slotContent: <key> })
  C. Both forms accepted
  D. Sibling field (Element.slotFills)

Key decisions captured:
- Recursion depth is unbounded (Decision Driver, not Out of Scope)
- Cycle detection is a constraint, enforced by consumer validators
- Layout direction lives in styles.layoutMode, not at the slot boundary
- Named compositions can live in Component.slotContent (component-scoped)
  OR in 1+ external composition files (system-scoped, ADR-042 follow-on)
- Discriminated reference form { \$slotContent: <key> } parallels PropBinding

Scratchpads in adr/research/049/ demonstrate the design space concretely
through a deeply-nested filter results page (Page > Row > Accordion >
CheckboxGroup > Checkbox > custom-children) in both nested and flat
forms. The flat form is system-scoped (spans multiple components).

ADR-047 simplifications (drop \$extensions / SlotBinding) and field-naming
questions (slotContent vs compositions; \$slotContent vs \$composition)
flagged for follow-up rather than rolled in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mples; add Pill scratchpad

Three coordinated changes across the composition ADRs:

1. Reference form is JSON Pointer, paralleling ADR-008 PropBinding.
   - ADR-049's discriminated reference becomes { $composition: <pointer> }
     (rotated from $slotContent; pointer makes the registry home explicit).
   - ADR-047's SlotBinding.$extensions['com.figma'].default value becomes
     a JSON Pointer to a Composition (was a bare slotContent key).
   - Scratchpads updated: example.flat.yaml wraps records under a top-level
     `compositions:` namespace so absolute pointers resolve; example.pill.yaml
     (new) wraps under `components: pill:` for the same reason.

2. Rename ComponentExamples → InstanceExamples; Component.examples →
   Component.instanceExamples. Disambiguates against Props.examples and
   Anatomy.examples (which carry sample content, not InstanceExample
   entries). Cited in ADR-046 Semver section as the first ADR-side
   application of Constitution §VI rule 3 (no code-platform consensus
   on this specs-schema-specific authoring construct).

3. New cross-ADR scratchpad example.pill.yaml — a Pill component that
   exercises ADR-008 (PropBinding), ADR-046 (instanceExamples),
   ADR-047 (slotContent + SlotBinding with Figma authoring default),
   and ADR-049 (discriminated $composition reference) in one file.
   Three documented usages span the surface: configuredLabel
   (custom:false + label scalar), composedLabel (custom:true filled
   with Figma's default composition), removableLabel (custom:true
   filled with text + remove glyph composition).

Cleanup along the way: ADR-047 had stale references to the removed
InstanceExample.slots field (six sites in Notes / Pros / Consequences /
Out of scope / Option D rejection). All updated to point at the unified
propConfigurations.<slotName> mechanism per ADR-049. The Option A example
in ADR-047 was wrapped under `components: actionListItem:` and updated
to JSON Pointer references, replacing the pre-rename `examples.slots`
form with `instanceExamples.propConfigurations.<slot>: { $composition }`.

ADR-042 forward references (lines 25, 195, 206) updated from
Component.examples to Component.instanceExamples.

INDEX.md row 046 updated to reflect the new title and field name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…position-type

# Conflicts:
#	packages/cli/CHANGELOG.md
#	packages/cli/package.json
Introduces SlotContent, Composition, SlotContentRef, slotContentExamples,
InstanceExample (with SlotContentRef), and PropConfigurations widening.
Replaces the discarded groups/CompositionGroup/CompositionRef shapes with
the ADR-046 Option C selection: top-level triplet + slotContent bundling,
universal $slotContent pointer. Adds ADRs 046–049 and finalises ADR-042.
Replaces old research example files with option-named composition examples
and ADR-aligned component examples.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
isJson (starts with '{') now takes precedence over the '- [' manifest
heuristic, preventing false manifest detection when a Figma JSON file
contains markdown-like text in its document content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eExamples

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
nathanacurtis and others added 13 commits May 19, 2026 08:58
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new Option A that reuses the existing `examples` convention
(already used by StringProp.examples and NumberProp.examples, with
StringProp.default deprecated in its favor) at the slot-binding site,
as an array of SlotContentRef. Reorders prior options to B–G; the
$extensions-based approach remains Selected pending review.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adopts the `examples` convention (already used by StringProp.examples
and NumberProp.examples, with StringProp.default deprecated in its
favor) at the slot-binding site. SlotBinding now extends PropBinding
with optional `examples?: SlotContentRef[]`. Emitters currently write
a single entry at index 0 — Figma's authoring default for the slot
layer — but the array shape leaves room for additional authored
examples without further schema change.

Removes the `$extensions` / `FigmaSlotBindingExtension` /
`SlotBindingExtensions` machinery from Option B.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(adr): draft ADR-051 platform code-syntax token profiles

Add FIGMA_SYNTAX_WEB/IOS/ANDROID profiles to format.tokens (DRAFT).
Refs #103

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(adr): claim ADR-051 in INDEX

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(schema): implement ADR-051 platform code-syntax token profiles

Add FIGMA_SYNTAX_WEB/IOS/ANDROID to format.tokens (Config + ResolvedConfig)
and component.schema.json. Default unchanged (TOKEN); empty platform syntax
falls back to TOKEN output (transformer behavior). Folds into unreleased 0.21.0.
Update Config.test-d.ts, docs, and CHANGELOG. Refs #103

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(adr): mark ADR-051 ACCEPTED; move INDEX row to Accepted

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat(cli): accept FIGMA_SYNTAX_* token profiles (ADR 051)

Implement the CLI side of ADR 051, which adds three additive
`format.tokens` serialization profiles: FIGMA_SYNTAX_WEB,
FIGMA_SYNTAX_IOS, and FIGMA_SYNTAX_ANDROID.

- ConfigLoader: add the three values to the validTokens allow-list so
  they are no longer reset to the TOKEN default during validation.
- ConfigTemplates: list the new values in the init scaffold comment.
- Tests: cover all eight valid token values plus lowercase
  normalization for FIGMA_SYNTAX_IOS.
- Docs: document the platform code-syntax profiles in the token format
  guide (profile section, comparison table, when-to-use list).

The schema package and config/commands doc sections already carried the
new enum; generate passes the resolved config through unchanged and
applyCustomTokens is unaffected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(cli): changelog entry for FIGMA_SYNTAX_* token profiles (ADR-051)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
- Config/ResolvedConfig/DEFAULT_CONFIG: add include.slotContentExamples,
  include.instanceExamples, and processing.instanceExamples
  { scope, match, exclude?, parentNames? } (parentNames per ADR-050).
- component.schema.json: matching processing.instanceExamples object + include flags.
- Config.test-d.ts: ADR-050 type tests.
- CLI ConfigLoader: accept the new include flags (allowlist) + validate
  processing.instanceExamples (scope/match).
- Docs: config/instance-examples, config/slot-content-examples, schema/config
  table updates, nav registration. ADR-050 renamed parent→parentNames with
  ranked-naming rationale.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…' into examples-slots-instances

# Conflicts:
#	adr/INDEX.md
#	packages/cli/CHANGELOG.md
#	packages/cli/src/commands/GenerateCommand.ts
#	packages/schema/CHANGELOG.md
…amples

splitComponentByConcern bucketed only api (title/anatomy/props) and variants
(default/variants), so slotContentExamples and instanceExamples (component- and
subcomponent-level) belonged to neither concern and were silently discarded —
leaving the $slotContent references in default/variants dangling.

- Route examples into a third concern, written as examples.yaml (per-concern) or
  <component>/examples.yaml (combined). Emitted only when examples exist;
  components without examples are omitted.
- Add extractExamplesFromSubcomponents + hasExampleData; extend concern type.
- Update --split-concerns help/template text and docs (generate.md, output.md).
- Tests: +8 (DataTransformers, FileManifest); all 38 writer tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread adr/049-prop-configurations-bindings.md Outdated
nathanacurtis and others added 9 commits May 21, 2026 13:58
…tial names

- schema: remove include.instanceExamples (Config/ResolvedConfig/DEFAULT_CONFIG);
  presence of processing.instanceExamples is the on-switch, like subcomponents.
  include.slotContentExamples retained (structural, no detection block).
- CLI: drop instanceExamples from ConfigLoader include allowlist.
- docs: slotContentExamples solo page; presence-driven instanceExamples page;
  two new guides (Default Slot Content, Instance Examples) with Pro badges;
  sidebar/Pro-badge updates; output/generate/schema Pro notes.
- Replace confidential EGDS examples with the non-confidential DS demo library
  (dsAlert); genericize a pre-existing EGDS reference in the CLI changelog.
- CHANGELOGs (schema, cli) updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ning

Per review (PR #111): widening the PropConfigurations value union is source-breaking
for consumers that narrowed the value type (e.g. `value as number`). Reword the
Cons, Pros, decision driver, and Semver justification to say so accurately —
data stays schema-valid, but consumer code is not automatically forward-compatible.
Flag the MINOR-vs-MAJOR question (Constitution §III vs pre-1.0 convention) for review.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…en-format guide

Config reference pages now lead with an Example-first structure
(Configuration → Result) using real DS Alert / Text Area `generate`
output, with reference tables/Path/See Also below. Flatten heading
hierarchy and fold per-page context into intros.

- Add Result examples to subcomponents, glyphNamePattern, slotConstraints,
  codeOnlyProps (Text Area minRows/maxRows/minLength), inferNumberProps,
  instanceExamples, layout, tokens, defaultSlotContent
- Move Pro licensing notes out of alert callouts into a lower Licensing section
- Merge the Token Format guide into config/tokens (3-column profile table)
  and remove the standalone guide; repoint inbound links and sidebar

Carries related schema/ADR/CLI changes already present on this branch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lidation, output splitting, and $slotContent reference closure

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… true

A non-boolean value (e.g. the string "yes") or any truthy-but-not-true
value is now coerced to false with a warning, matching the boolean
handling of slotConstraints/inferNumberProps. Updates the unit test that
previously documented the passthrough gap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The primary relevance test for an instance example is structural identity
(the candidate is an instance of the component being generated); name
patterns are only a secondary filter. Requiring `match` excluded
legitimate examples whose frame names bear no relation to the component
name. `match` is now optional in Config/ResolvedConfig and the JSON
schema (no `required: [match]`); absence accepts every in-scope instance,
subject to exclude/parentNames.

Updates ADR-050 (still DRAFT), CHANGELOG (0.21.0), and the config docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The CLI ConfigLoader was dropping the whole processing.instanceExamples
block when match was absent. match is now an optional name filter
(presence of the block is the on-switch; identity is the primary relevance
test), so only reject an invalid match — and keep the block. Updates the
two tests that asserted the old removal behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Base automatically changed from release/schema-0.21.0-cli-0.16.0 to main May 22, 2026 18:26
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.

2 participants