ADRs 042, 045–050: Composition, Slot Content, and Ready-Made Examples#111
Open
nathanacurtis wants to merge 52 commits into
Open
ADRs 042, 045–050: Composition, Slot Content, and Ready-Made Examples#111nathanacurtis wants to merge 52 commits into
nathanacurtis wants to merge 52 commits into
Conversation
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>
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>
jordan-n-schmidt
approved these changes
May 21, 2026
…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>
…' into examples-slots-instances
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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,Compositions,SlotContent, and the universalSlotContentRef({ $slotContent }) pointer.Component.slotContentExamples,Component.instanceExamples/InstanceExample,SlotBinding(extendsPropBindingwithexamples?),Childrenwidened toSlotBinding,PropConfigurationsvalue union widened.processing.instanceExamples { scope?: 'PAGE'|'FILE', match, exclude?, parentNames? }andinclude.slotContentExamples/include.instanceExamplesgates — acrossConfig,ResolvedConfig, andDEFAULT_CONFIG. (ADR-050 doc renamedparent→parentNameswith ranked-naming rationale.)component.schema.jsonkept in lockstep with the types.CLI (0.16.0)
ConfigLoaderaccepts the newinclude.*Examplesflags and validatesprocessing.instanceExamples(scope/match/exclude/parentNames), passing them to the engine.Docs
instance-examples,slot-content-examples),schema/configtable updates, nav registration.Notes
compositions(detection/serialization) and specs-plugin-2feature/examples-config(settings UI).🤖 Generated with Claude Code