@adobe/design-data-spec 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/components/accordion.json +87 -0
- package/components/action-bar.json +21 -0
- package/components/action-button.json +75 -0
- package/components/action-group.json +68 -0
- package/components/alert-banner.json +33 -0
- package/components/alert-dialog.json +46 -0
- package/components/avatar-group.json +26 -0
- package/components/avatar.json +54 -0
- package/components/badge.json +73 -0
- package/components/body.json +29 -0
- package/components/bottom-navigation-android.json +41 -0
- package/components/breadcrumbs.json +89 -0
- package/components/button-group.json +37 -0
- package/components/button.json +70 -0
- package/components/calendar.json +104 -0
- package/components/cards.json +30 -0
- package/components/checkbox-group.json +53 -0
- package/components/checkbox.json +61 -0
- package/components/close-button.json +48 -0
- package/components/coach-indicator.json +38 -0
- package/components/coach-mark.json +55 -0
- package/components/code.json +25 -0
- package/components/color-area.json +77 -0
- package/components/color-handle.json +35 -0
- package/components/color-loupe.json +20 -0
- package/components/color-slider.json +79 -0
- package/components/color-wheel.json +60 -0
- package/components/combo-box.json +94 -0
- package/components/contextual-help.json +80 -0
- package/components/date-picker.json +161 -0
- package/components/detail.json +30 -0
- package/components/divider.json +27 -0
- package/components/drop-zone.json +45 -0
- package/components/field-label.json +43 -0
- package/components/heading.json +33 -0
- package/components/help-text.json +40 -0
- package/components/illustrated-message.json +49 -0
- package/components/in-field-progress-button.json +44 -0
- package/components/in-field-progress-circle.json +26 -0
- package/components/in-line-alert.json +47 -0
- package/components/link.json +45 -0
- package/components/list-view.json +93 -0
- package/components/menu.json +76 -0
- package/components/meter.json +48 -0
- package/components/number-field.json +70 -0
- package/components/opacity-checkerboard.json +25 -0
- package/components/picker.json +92 -0
- package/components/popover.json +69 -0
- package/components/progress-bar.json +68 -0
- package/components/progress-circle.json +45 -0
- package/components/radio-button.json +43 -0
- package/components/radio-group.json +62 -0
- package/components/rating.json +47 -0
- package/components/scroll-zoom-bar.json +53 -0
- package/components/search-field.json +72 -0
- package/components/segmented-control.json +76 -0
- package/components/select-box.json +62 -0
- package/components/side-navigation.json +71 -0
- package/components/slider.json +92 -0
- package/components/standard-dialog.json +53 -0
- package/components/standard-panel.json +53 -0
- package/components/status-light.json +54 -0
- package/components/steplist.json +56 -0
- package/components/swatch-group.json +48 -0
- package/components/swatch.json +59 -0
- package/components/switch.json +55 -0
- package/components/tab-bar-ios.json +41 -0
- package/components/table.json +122 -0
- package/components/tabs.json +79 -0
- package/components/tag-field.json +53 -0
- package/components/tag-group.json +35 -0
- package/components/tag.json +54 -0
- package/components/takeover-dialog.json +58 -0
- package/components/text-area.json +103 -0
- package/components/text-field.json +91 -0
- package/components/thumbnail.json +27 -0
- package/components/toast.json +33 -0
- package/components/tooltip.json +54 -0
- package/components/tray.json +21 -0
- package/components/tree-view.json +63 -0
- package/conformance/README.md +26 -26
- package/conformance/invalid/SPEC-014/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-014/tokens.tokens.json +9 -0
- package/conformance/invalid/SPEC-018/dataset.json +9 -0
- package/conformance/invalid/SPEC-018/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-019/dataset.json +29 -0
- package/conformance/invalid/SPEC-019/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-020/dataset.json +27 -0
- package/conformance/invalid/SPEC-020/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-021/dataset.json +18 -0
- package/conformance/invalid/SPEC-021/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-022/dataset.json +33 -0
- package/conformance/invalid/SPEC-022/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-023/dataset.json +18 -0
- package/conformance/invalid/SPEC-023/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-024/dataset.json +18 -0
- package/conformance/invalid/SPEC-024/expected-errors.json +10 -0
- package/conformance/valid/component-refs/dataset.json +63 -0
- package/conformance/valid/lifecycle-with-last-modified.json +12 -0
- package/package.json +19 -6
- package/rules/rules.yaml +81 -0
- package/schemas/anatomy-part.schema.json +35 -0
- package/schemas/component.schema.json +267 -0
- package/schemas/state-declaration.schema.json +36 -0
- package/spec/agent-surface.md +116 -0
- package/spec/anatomy-format.md +167 -0
- package/spec/component-format.md +326 -0
- package/spec/evolution.md +32 -32
- package/spec/index.md +27 -21
- package/spec/manifest.md +3 -1
- package/spec/state-model.md +245 -0
- package/spec/taxonomy.md +17 -1
- package/spec/token-format.md +1 -1
- package/src/canonical.js +61 -0
- package/src/validate.js +166 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/component.schema.json",
|
|
4
|
+
"title": "Design data component declaration",
|
|
5
|
+
"description": "Layer 1 structural schema for a component declaration. Semantic cross-reference rules (component-name-exists, component-variant-valid, etc.) are Layer 2.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["$id", "name", "displayName", "meta"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri"
|
|
12
|
+
},
|
|
13
|
+
"specVersion": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Spec version this document targets (e.g. '1.0.0-draft')."
|
|
16
|
+
},
|
|
17
|
+
"$id": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"format": "uri",
|
|
20
|
+
"description": "Canonical identifier for this component declaration."
|
|
21
|
+
},
|
|
22
|
+
"name": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"description": "Machine identifier (kebab-case). Must match the value used in token name-object 'component' fields."
|
|
27
|
+
},
|
|
28
|
+
"displayName": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"minLength": 1,
|
|
31
|
+
"description": "Human-readable component name (e.g. 'Button')."
|
|
32
|
+
},
|
|
33
|
+
"description": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Plain-text description of the component's purpose."
|
|
36
|
+
},
|
|
37
|
+
"meta": {
|
|
38
|
+
"$ref": "#/$defs/meta"
|
|
39
|
+
},
|
|
40
|
+
"options": {
|
|
41
|
+
"$ref": "#/$defs/optionsMap"
|
|
42
|
+
},
|
|
43
|
+
"slots": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"$ref": "#/$defs/slotDeclaration"
|
|
47
|
+
},
|
|
48
|
+
"description": "Named content injection points. See spec/component-format.md#slots."
|
|
49
|
+
},
|
|
50
|
+
"anatomy": {
|
|
51
|
+
"type": "array",
|
|
52
|
+
"items": {
|
|
53
|
+
"$ref": "#/$defs/anatomyPart"
|
|
54
|
+
},
|
|
55
|
+
"description": "Named visible parts of the component. Full spec in spec/anatomy-format.md (Phase 6.2)."
|
|
56
|
+
},
|
|
57
|
+
"states": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"$ref": "#/$defs/stateDeclaration"
|
|
61
|
+
},
|
|
62
|
+
"description": "Per-component state declarations. Full spec in spec/state-model.md (Phase 6.3)."
|
|
63
|
+
},
|
|
64
|
+
"lifecycle": {
|
|
65
|
+
"$ref": "#/$defs/lifecycle"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"$defs": {
|
|
70
|
+
"meta": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"required": ["category", "documentationUrl"],
|
|
73
|
+
"properties": {
|
|
74
|
+
"category": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"enum": [
|
|
77
|
+
"actions",
|
|
78
|
+
"containers",
|
|
79
|
+
"data visualization",
|
|
80
|
+
"feedback",
|
|
81
|
+
"inputs",
|
|
82
|
+
"navigation",
|
|
83
|
+
"status",
|
|
84
|
+
"typography"
|
|
85
|
+
],
|
|
86
|
+
"description": "Design system category for this component."
|
|
87
|
+
},
|
|
88
|
+
"documentationUrl": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"format": "uri",
|
|
91
|
+
"description": "URL of the component's documentation page."
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"additionalProperties": false
|
|
95
|
+
},
|
|
96
|
+
"optionsMap": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"description": "Component API options. Each key is a camelCase option name; each value is an option descriptor.",
|
|
99
|
+
"additionalProperties": {
|
|
100
|
+
"$ref": "#/$defs/optionDescriptor"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"optionDescriptor": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"description": "JSON Schema-compatible descriptor for a single component option. Standard JSON Schema keywords (type, enum, default, description, pattern, minimum, maximum, items, properties, etc.) are all permitted.",
|
|
106
|
+
"properties": {
|
|
107
|
+
"type": {
|
|
108
|
+
"oneOf": [
|
|
109
|
+
{
|
|
110
|
+
"type": "string",
|
|
111
|
+
"enum": [
|
|
112
|
+
"string",
|
|
113
|
+
"boolean",
|
|
114
|
+
"number",
|
|
115
|
+
"integer",
|
|
116
|
+
"object",
|
|
117
|
+
"array",
|
|
118
|
+
"null"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "array",
|
|
123
|
+
"items": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"enum": [
|
|
126
|
+
"string",
|
|
127
|
+
"boolean",
|
|
128
|
+
"number",
|
|
129
|
+
"integer",
|
|
130
|
+
"object",
|
|
131
|
+
"array",
|
|
132
|
+
"null"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
"minItems": 1
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
"enum": {
|
|
140
|
+
"type": "array",
|
|
141
|
+
"minItems": 1,
|
|
142
|
+
"description": "Exhaustive list of permitted values."
|
|
143
|
+
},
|
|
144
|
+
"default": {
|
|
145
|
+
"description": "Default value when the option is not specified."
|
|
146
|
+
},
|
|
147
|
+
"description": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"description": "Plain-text description of what the option controls."
|
|
150
|
+
},
|
|
151
|
+
"$ref": {
|
|
152
|
+
"type": "string",
|
|
153
|
+
"format": "uri-reference",
|
|
154
|
+
"description": "Reference to a shared type schema."
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"additionalProperties": true
|
|
158
|
+
},
|
|
159
|
+
"slotDeclaration": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"required": ["name"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"name": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"minLength": 1,
|
|
166
|
+
"description": "Slot identifier. Should come from the canonical slot vocabulary."
|
|
167
|
+
},
|
|
168
|
+
"description": {
|
|
169
|
+
"type": "string",
|
|
170
|
+
"description": "What content belongs in this slot."
|
|
171
|
+
},
|
|
172
|
+
"required": {
|
|
173
|
+
"type": "boolean",
|
|
174
|
+
"default": false,
|
|
175
|
+
"description": "Whether consumers must populate this slot."
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"additionalProperties": false
|
|
179
|
+
},
|
|
180
|
+
"anatomyPart": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"required": ["name"],
|
|
183
|
+
"description": "Named visible part of a component. Full spec in spec/anatomy-format.md (Phase 6.2).",
|
|
184
|
+
"properties": {
|
|
185
|
+
"name": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"minLength": 1,
|
|
188
|
+
"description": "Anatomy part identifier (e.g. 'icon', 'label', 'handle')."
|
|
189
|
+
},
|
|
190
|
+
"description": {
|
|
191
|
+
"type": "string"
|
|
192
|
+
},
|
|
193
|
+
"required": {
|
|
194
|
+
"type": "boolean",
|
|
195
|
+
"default": false
|
|
196
|
+
},
|
|
197
|
+
"contains": {
|
|
198
|
+
"type": "array",
|
|
199
|
+
"items": { "type": "string" },
|
|
200
|
+
"description": "Informative: anatomy part names nested within this part."
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"additionalProperties": false
|
|
204
|
+
},
|
|
205
|
+
"stateDeclaration": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"required": ["name"],
|
|
208
|
+
"description": "Per-component state declaration. Full spec in spec/state-model.md.",
|
|
209
|
+
"properties": {
|
|
210
|
+
"name": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"minLength": 1,
|
|
213
|
+
"description": "State identifier (e.g. 'hover', 'focus', 'disabled')."
|
|
214
|
+
},
|
|
215
|
+
"description": {
|
|
216
|
+
"type": "string"
|
|
217
|
+
},
|
|
218
|
+
"trigger": {
|
|
219
|
+
"type": "string",
|
|
220
|
+
"enum": ["prop", "interaction"],
|
|
221
|
+
"description": "'prop' for persistent prop-driven states (isDisabled); 'interaction' for runtime states (hover, focus, pressed)."
|
|
222
|
+
},
|
|
223
|
+
"precedence": {
|
|
224
|
+
"type": "integer",
|
|
225
|
+
"minimum": 0,
|
|
226
|
+
"description": "Resolution precedence; higher integer wins when multiple states are active simultaneously."
|
|
227
|
+
},
|
|
228
|
+
"layered": {
|
|
229
|
+
"type": "boolean",
|
|
230
|
+
"default": false,
|
|
231
|
+
"description": "true for states that compose with others (e.g. focus ring layered over hover)."
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"additionalProperties": false
|
|
235
|
+
},
|
|
236
|
+
"lifecycle": {
|
|
237
|
+
"type": "object",
|
|
238
|
+
"description": "Version lifecycle metadata, mirroring the token lifecycle pattern.",
|
|
239
|
+
"properties": {
|
|
240
|
+
"introduced": {
|
|
241
|
+
"type": "string",
|
|
242
|
+
"description": "Spec version when this component declaration was added (e.g. '1.0.0-draft')."
|
|
243
|
+
},
|
|
244
|
+
"deprecated": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"description": "Spec version when this component was deprecated. Truthy = deprecated."
|
|
247
|
+
},
|
|
248
|
+
"deprecatedComment": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "Human-readable explanation of the deprecation and migration path."
|
|
251
|
+
},
|
|
252
|
+
"replacedBy": {
|
|
253
|
+
"oneOf": [
|
|
254
|
+
{ "type": "string", "minLength": 1 },
|
|
255
|
+
{
|
|
256
|
+
"type": "array",
|
|
257
|
+
"items": { "type": "string", "minLength": 1 },
|
|
258
|
+
"minItems": 1
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
"description": "name value(s) of the replacement component(s)."
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"additionalProperties": false
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/state-declaration.schema.json",
|
|
4
|
+
"title": "State declaration",
|
|
5
|
+
"description": "Layer 1 structural schema for a single state declaration object within a component declaration. Semantic rules (component-state-valid, state-custom-name-documented) are Layer 2.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"name": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"description": "Kebab-case state identifier. Must match the value used in token name-object 'state' fields."
|
|
14
|
+
},
|
|
15
|
+
"description": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Plain-text description of the state's semantics and the conditions under which it is active."
|
|
18
|
+
},
|
|
19
|
+
"trigger": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"enum": ["prop", "interaction"],
|
|
22
|
+
"description": "'prop' for persistent prop-driven states (e.g. isDisabled); 'interaction' for transient runtime interaction states (hover, focus, pressed)."
|
|
23
|
+
},
|
|
24
|
+
"precedence": {
|
|
25
|
+
"type": "integer",
|
|
26
|
+
"minimum": 0,
|
|
27
|
+
"description": "Resolution precedence. Higher value wins when multiple non-layered states are active simultaneously. Defaults to 0 when omitted."
|
|
28
|
+
},
|
|
29
|
+
"layered": {
|
|
30
|
+
"type": "boolean",
|
|
31
|
+
"default": false,
|
|
32
|
+
"description": "When true, this state composes on top of the winning non-layered state rather than competing with it. Use for focus rings, selection overlays, and similar compositing states."
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Agent-readable surface
|
|
2
|
+
|
|
3
|
+
**Spec version:** `1.0.0-draft` (see [Overview](index.md))\
|
|
4
|
+
**Status:** Draft — RFC-C / Phase 8. Surface and tool list are subject to change. No reference implementation exists yet.
|
|
5
|
+
|
|
6
|
+
This document defines the **agent-readable surface**: the contract an external AI agent uses to consume design data conformant with this specification. It standardizes a small set of operations exposed through three transports — a CLI, a Model Context Protocol (MCP) server, and a Claude Code Agent Skill — all backed by the same resolver, validator, and query implementations that power the rest of the SDK.
|
|
7
|
+
|
|
8
|
+
## Goals
|
|
9
|
+
|
|
10
|
+
The surface targets three consumer shapes:
|
|
11
|
+
|
|
12
|
+
1. **Authoring an external system.** A non-Spectrum design system being constructed inside an AI tool (e.g. a finance-dashboard prototype tool) wants to produce spec-conformant tokens, dimensions, and components without re-deriving the format from prose.
|
|
13
|
+
2. **Extending Spectrum.** A product or platform team adds tokens, components, or overrides on top of the published Spectrum foundation and needs to validate that the additions cascade and resolve correctly.
|
|
14
|
+
3. **Adhering to Spectrum.** A prototyping tool generates UI that should match Spectrum even where no bound component exists (e.g. CSS for a custom card). The agent needs to look up tokens by intent, validate proposed property values against the foundation, and report drift.
|
|
15
|
+
|
|
16
|
+
**NORMATIVE:** A conforming agent surface implementation MUST support all three consumer shapes, parameterized by the manifest provided at session start (see [Session primer](#session-primer)).
|
|
17
|
+
|
|
18
|
+
## Non-goals
|
|
19
|
+
|
|
20
|
+
* Generating finished platform code (Swift, CSS, etc.). Output formatting is the consumer's responsibility; the surface returns structured tokens.
|
|
21
|
+
* Hosting design data. The surface operates on local datasets reachable from the consumer's filesystem, plus optionally a remote published manifest.
|
|
22
|
+
* Replacing the existing Spectrum-bound tools (`@adobe/spectrum-design-data-mcp`, `@adobe/s2-docs-mcp`). Those expose Spectrum-specific shapes; this surface is generic to any spec-conformant dataset.
|
|
23
|
+
|
|
24
|
+
## Tool catalog
|
|
25
|
+
|
|
26
|
+
**NORMATIVE:** A conforming implementation MUST expose the following operations. Transport-specific naming (CLI subcommand vs MCP tool name vs skill action) MAY differ; the semantics MUST NOT.
|
|
27
|
+
|
|
28
|
+
| Operation | Reads | Returns | Backed by |
|
|
29
|
+
| -------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
|
|
30
|
+
| `resolve_token` | property + dimension context | winning token (literal or resolved alias) with file/UUID/specificity | `cascade::resolve` |
|
|
31
|
+
| `query_tokens` | filter expression (see [Query](query.md)) | matching token list | `query::filter` |
|
|
32
|
+
| `validate_usage` | candidate token document or fragment | `ValidationReport` (Layer 1 + Layer 2 diagnostics) | `validate::validate_*` |
|
|
33
|
+
| `describe_component` | component identifier | component contract (anatomy, options, states); see [#832](https://github.com/adobe/spectrum-design-data/discussions/832) | (Phase 6 contract) |
|
|
34
|
+
| `suggest_token` | natural-language intent + optional property hint | ranked candidate tokens with rationale (RECOMMENDED, not NORMATIVE in v1) | registry + query |
|
|
35
|
+
| `get_guidance` | token UUID, component identifier, or anatomy reference | attached document blocks (Phase 9 / RFC-D); falls back to empty list pre-RFC-D | document blocks |
|
|
36
|
+
| `diff_datasets` | two dataset roots | `DiffReport` per [Diff](diff.md) | `diff::semantic_diff` |
|
|
37
|
+
|
|
38
|
+
**NORMATIVE:** `validate_usage`, `resolve_token`, `query_tokens`, and `diff_datasets` MUST be implemented in a conforming agent surface. `suggest_token` and `get_guidance` are RECOMMENDED. `describe_component` becomes NORMATIVE once [#832](https://github.com/adobe/spectrum-design-data/discussions/832) reaches implemented status.
|
|
39
|
+
|
|
40
|
+
## Session primer
|
|
41
|
+
|
|
42
|
+
An agent loop benefits from a small, structural overview at session start so that subsequent calls are well-scoped. The **session primer** is a single operation that returns a serialized summary of the active dataset.
|
|
43
|
+
|
|
44
|
+
**NORMATIVE:** A conforming implementation MUST expose a `primer` operation returning a JSON object with at least:
|
|
45
|
+
|
|
46
|
+
| Field | Type | Meaning |
|
|
47
|
+
| ---------------- | -------------- | ----------------------------------------------------------------- |
|
|
48
|
+
| `specVersion` | string | The spec version the dataset declares (see [Overview](index.md)). |
|
|
49
|
+
| `manifest` | object \| null | Resolved platform manifest, if any (see [Manifest](manifest.md)). |
|
|
50
|
+
| `dimensions` | array | Declared dimensions with modes and defaults. |
|
|
51
|
+
| `components` | array | Component identifiers exposed by the dataset (post Phase 6). |
|
|
52
|
+
| `taxonomyFields` | array | Active name-object fields and their declared vocabulary. |
|
|
53
|
+
| `tokenCount` | integer | Total tokens in the merged cascade. |
|
|
54
|
+
|
|
55
|
+
**RECOMMENDED:** The primer payload SHOULD fit within 2,000 tokens of LLM context for typical Spectrum-scale datasets. Implementations that produce larger payloads SHOULD provide a `--summary` mode.
|
|
56
|
+
|
|
57
|
+
**RATIONALE:** The primer replaces the "DESIGN.md emit" approach explored in earlier RFC-C drafts. A live, queryable primer keeps the agent's session context current without requiring the agent to maintain a frozen prose summary that can drift from the dataset.
|
|
58
|
+
|
|
59
|
+
## Transports
|
|
60
|
+
|
|
61
|
+
**NORMATIVE:** A conforming implementation MUST expose the [Tool catalog](#tool-catalog) through at least one of the following transports.
|
|
62
|
+
|
|
63
|
+
### CLI
|
|
64
|
+
|
|
65
|
+
The reference CLI is `design-data` (see [`sdk/cli/`](../../../sdk/cli/)). RFC-C extends the existing subcommands (`validate`, `resolve`, `diff`, `query`) with:
|
|
66
|
+
|
|
67
|
+
* `design-data primer [PATH]` — emit the [Session primer](#session-primer) payload.
|
|
68
|
+
* `design-data suggest "<intent>" [--property <hint>]` — invoke `suggest_token`.
|
|
69
|
+
* `design-data explain <token-uuid|component-id>` — invoke `get_guidance`.
|
|
70
|
+
|
|
71
|
+
**NORMATIVE:** All RFC-C CLI output MUST default to JSON when stdout is not a TTY, and MUST emit human-friendly output when stdout is a TTY. This makes the CLI directly composable from agent shells without per-call format flags.
|
|
72
|
+
|
|
73
|
+
### MCP server
|
|
74
|
+
|
|
75
|
+
A reference MCP server is RECOMMENDED to ship as `@adobe/design-data-agent-mcp` (separate from the existing Spectrum-bound `@adobe/spectrum-design-data-mcp` to avoid coupling to a specific dataset).
|
|
76
|
+
|
|
77
|
+
**NORMATIVE:** The MCP server MUST register one tool per [Tool catalog](#tool-catalog) operation. Tool names MUST match the operation name in the table verbatim. Each tool's input schema MUST mirror the CLI flag set; agents that learn one transport SHOULD work with the other.
|
|
78
|
+
|
|
79
|
+
### Agent skill
|
|
80
|
+
|
|
81
|
+
A reference Claude Code Agent Skill is RECOMMENDED at `tools/design-data-agent-mcp/skills/design-data/SKILL.md`. The skill SHOULD trigger on intent words covering all three [Goals](#goals) — for example "design system", "design tokens", "drift", "spec-conformant", and explicit Spectrum mentions when the active manifest binds Spectrum.
|
|
82
|
+
|
|
83
|
+
**RECOMMENDED:** The skill SHOULD shell out to the CLI rather than embedding tool calls, so its description (the only persistent context cost) stays small and the heavy lifting happens out-of-band.
|
|
84
|
+
|
|
85
|
+
## Conformance
|
|
86
|
+
|
|
87
|
+
**NORMATIVE:** An agent surface implementation that claims conformance MUST:
|
|
88
|
+
|
|
89
|
+
1. Implement all NORMATIVE operations in the [Tool catalog](#tool-catalog).
|
|
90
|
+
2. Implement the [Session primer](#session-primer) operation.
|
|
91
|
+
3. Expose the catalog through at least one transport in [Transports](#transports).
|
|
92
|
+
4. Emit `validate_usage` diagnostics that match the structure produced by `validate::validate_all_with_options` (see `sdk/core/src/report.rs`): each diagnostic MUST include `rule_id`, `severity`, `message`, `instance_path`, `schema_path`, `file`, and `token` where applicable.
|
|
93
|
+
5. Honor manifest-based filtering: when a manifest is present in the session, `query_tokens` and `resolve_token` MUST respect `include`/`exclude` and MUST apply manifest overrides before returning results.
|
|
94
|
+
|
|
95
|
+
## Worked example
|
|
96
|
+
|
|
97
|
+
The following sketch shows an agent loop that adheres-to-Spectrum while authoring a non-bound component.
|
|
98
|
+
|
|
99
|
+
1. Agent calls `primer ./spectrum-data` and learns that `colorScheme` and `scale` are the active dimensions and that `button`, `picker`, and `card` are exposed components.
|
|
100
|
+
2. User asks for a "subtle hover background for a card on dark mode".
|
|
101
|
+
3. Agent calls `suggest_token "subtle hover background for card" --property background-color`.
|
|
102
|
+
4. Surface returns a ranked list including `background-color-hover` from Spectrum foundation and `background-color-card-hover` from a card component group.
|
|
103
|
+
5. Agent calls `resolve_token background-color-card-hover --color-scheme dark`.
|
|
104
|
+
6. Surface returns the resolved literal value for the dark-mode card hover background.
|
|
105
|
+
7. Agent emits CSS using that value and calls `validate_usage` against the proposed token document fragment to confirm no SPEC-NNN diagnostics fire.
|
|
106
|
+
|
|
107
|
+
The same loop, with a different manifest passed at primer time, authors a non-Spectrum system: the surface returns whatever tokens that dataset declares, and `validate_usage` enforces the same spec rules independent of which design system is in play.
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
* [#714 — Design Data Specification (umbrella)](https://github.com/adobe/spectrum-design-data/discussions/714)
|
|
112
|
+
* [#625 — Token Authoring Workflow](https://github.com/adobe/spectrum-design-data/discussions/625)
|
|
113
|
+
* [#832 — Component Contract in Design Data Spec](https://github.com/adobe/spectrum-design-data/discussions/832) — supplies `describe_component` once implemented
|
|
114
|
+
* [Document blocks](document-blocks.md) (forthcoming, RFC-D / Phase 9) — supplies `get_guidance` payloads
|
|
115
|
+
* [`sdk/cli/src/main.rs`](../../../sdk/cli/src/main.rs) — CLI surface to extend
|
|
116
|
+
* [`sdk/core/src/report.rs`](../../../sdk/core/src/report.rs) — diagnostic shape
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Anatomy format
|
|
2
|
+
|
|
3
|
+
**Spec version:** `1.0.0-draft` (see [Overview](index.md))
|
|
4
|
+
|
|
5
|
+
This document defines the normative **anatomy part declaration** object: the named visual sub-parts of a component that appear as values of the `anatomy` field in token name objects. Anatomy declarations complete the machine-readable contract introduced by the component declaration (see [Component format — Anatomy stub](component-format.md#anatomy-stub)) and enable cross-reference validation between tokens and component surfaces.
|
|
6
|
+
|
|
7
|
+
Scoped under [RFC-A — Component Contract in Design Data Spec](https://github.com/adobe/spectrum-design-data/discussions/832). See also [Component format](component-format.md).
|
|
8
|
+
|
|
9
|
+
## Anatomy part object
|
|
10
|
+
|
|
11
|
+
An anatomy part is a **JSON object** that appears as an element of a component declaration's `anatomy` array. Each anatomy part object **MUST** validate against the standalone schema [`anatomy-part.schema.json`](../schemas/anatomy-part.schema.json) (canonical `$id`: `https://opensource.adobe.com/spectrum-design-data/schemas/v0/anatomy-part.schema.json`).
|
|
12
|
+
|
|
13
|
+
**NORMATIVE:** `anatomy` **MUST** be a JSON array within the component declaration. Each element **MUST** be an anatomy part object.
|
|
14
|
+
|
|
15
|
+
### Fields
|
|
16
|
+
|
|
17
|
+
| Field | Type | Required | Description |
|
|
18
|
+
| ------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
19
|
+
| `name` | string | REQUIRED | Kebab-case identifier. **MUST** match the pattern `^[a-z][a-z0-9-]*$`. |
|
|
20
|
+
| `description` | string | OPTIONAL | Plain-text description of the part's visual role and boundaries. |
|
|
21
|
+
| `required` | boolean | OPTIONAL | Whether this part is always rendered regardless of configuration. Default: `false`. |
|
|
22
|
+
| `contains` | array of strings | OPTIONAL | Informative list of child anatomy part names nested within this part (e.g. a `field` contains `["label", "help-text"]`). |
|
|
23
|
+
|
|
24
|
+
**NORMATIVE:** No properties beyond those listed above are permitted in an anatomy part object. Additional fields **MUST** cause a Layer 1 schema error.
|
|
25
|
+
|
|
26
|
+
### `name`
|
|
27
|
+
|
|
28
|
+
**NORMATIVE:** `name` **MUST** match the pattern `^[a-z][a-z0-9-]*$` — lower-case kebab-case, non-empty.
|
|
29
|
+
|
|
30
|
+
**NORMATIVE:** `name` **MUST** be unique within the `anatomy` array of a single component declaration (rule SPEC-024). Duplicate `name` values on the same component are a validation error.
|
|
31
|
+
|
|
32
|
+
**NORMATIVE:** Token name-object `anatomy` field values referencing a component **MUST** match the `name` of a declared anatomy part on that component (rule SPEC-020). An undeclared `anatomy` value is a validation error.
|
|
33
|
+
|
|
34
|
+
### `description`
|
|
35
|
+
|
|
36
|
+
**OPTIONAL.** A plain-text description of the anatomy part's visual role (e.g. `"Background fill track behind the progress indicator."`).
|
|
37
|
+
|
|
38
|
+
**RECOMMENDED:** Custom anatomy part names (those outside the [canonical anatomy vocabulary](#canonical-anatomy-vocabulary)) **SHOULD** include a `description` to document intent (rule SPEC-023 fires a warning for undocumented custom names).
|
|
39
|
+
|
|
40
|
+
### `required`
|
|
41
|
+
|
|
42
|
+
**OPTIONAL.** A boolean indicating whether the anatomy part is always present in the component's rendered output, regardless of its configuration options. Defaults to `false`.
|
|
43
|
+
|
|
44
|
+
When `required` is `true`, the anatomy part is unconditionally rendered (e.g. a `label` that cannot be hidden). When `false` or omitted, the part may or may not appear depending on component props.
|
|
45
|
+
|
|
46
|
+
### `contains`
|
|
47
|
+
|
|
48
|
+
**OPTIONAL.** An informative list of child anatomy part `name` values that are visually or structurally nested within this part. This field is for documentation and tooling assistance; it does not carry enforcement semantics.
|
|
49
|
+
|
|
50
|
+
**RECOMMENDED:** When a part logically encloses other declared anatomy parts, authors **SHOULD** use `contains` to make the nesting explicit.
|
|
51
|
+
|
|
52
|
+
Each string in `contains` **MUST** match the pattern `^[a-z][a-z0-9-]*$`. References to anatomy part names not declared on the same component are permitted (they may refer to sub-component anatomy in layered designs) but validators **MAY** surface a warning for unresolved references.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
"anatomy": [
|
|
56
|
+
{
|
|
57
|
+
"name": "field",
|
|
58
|
+
"description": "Input field wrapper enclosing the label and help text.",
|
|
59
|
+
"contains": ["label", "help-text"]
|
|
60
|
+
},
|
|
61
|
+
{ "name": "label", "description": "Primary text label.", "required": true },
|
|
62
|
+
{ "name": "help-text", "description": "Guidance text below the field." }
|
|
63
|
+
]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Canonical anatomy vocabulary
|
|
67
|
+
|
|
68
|
+
The following anatomy part names are defined by the cross-platform design audit and **SHOULD** be used in preference to custom names when their semantics match. Using canonical names enables cross-component tooling, documentation generation, and token audits.
|
|
69
|
+
|
|
70
|
+
| Name | Semantics |
|
|
71
|
+
| --------------------- | ------------------------------------------------------------------------ |
|
|
72
|
+
| `body` | Primary content area of a component (e.g. card body, dialog body). |
|
|
73
|
+
| `checkmark` | Selection indicator used in checkbox or radio components. |
|
|
74
|
+
| `disclosure-triangle` | Expand/collapse indicator for accordion, tree, or disclosure components. |
|
|
75
|
+
| `field` | Input field wrapper (encloses label, input surface, and help text). |
|
|
76
|
+
| `handle` | Drag handle for resizable or sortable components. |
|
|
77
|
+
| `header` | Top section of a panel, card, or dialog. |
|
|
78
|
+
| `icon` | Decorative or semantic icon placed within a component. |
|
|
79
|
+
| `label` | Primary text label identifying the component or its value. |
|
|
80
|
+
| `picker` | Dropdown trigger area (the visible affordance, not the overlay). |
|
|
81
|
+
| `progress-bar` | Visual progress fill track indicating completion level. |
|
|
82
|
+
| `swatch` | Color or pattern preview area. |
|
|
83
|
+
| `thumbnail` | Image preview area within a component. |
|
|
84
|
+
| `track` | Background rail for slider or progress bar components. |
|
|
85
|
+
| `value` | Numeric or text display value shown within a component. |
|
|
86
|
+
|
|
87
|
+
Custom part names are permitted. When a custom name is used, the anatomy part object **SHOULD** include a `description` field explaining its visual role (rule SPEC-023).
|
|
88
|
+
|
|
89
|
+
## Cross-reference with token name objects
|
|
90
|
+
|
|
91
|
+
Token name objects use an `anatomy` field to scope a token to a specific visible part of a component. The `anatomy` field value must correspond to a part declared in the component's `anatomy` array.
|
|
92
|
+
|
|
93
|
+
**NORMATIVE:** A token name-object `anatomy` field value **MUST** match the `name` of a declared anatomy part on the component identified by the token's `component` field (rule SPEC-020). An `anatomy` value that does not match any declared part name is a validation error.
|
|
94
|
+
|
|
95
|
+
See [Token format — Name object](token-format.md#name-object) for the full name object field catalog.
|
|
96
|
+
|
|
97
|
+
**NORMATIVE:** The `anatomy` field in a token name object **MUST NOT** be present unless the token's `component` field is also present (rule SPEC-025). Anatomy is always scoped to a component.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"name": {
|
|
102
|
+
"component": "slider",
|
|
103
|
+
"anatomy": "handle",
|
|
104
|
+
"property": "background-color",
|
|
105
|
+
"state": "hover"
|
|
106
|
+
},
|
|
107
|
+
"value": "#0265dc"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## SPEC rules
|
|
112
|
+
|
|
113
|
+
The following rules in the Layer 2 rule catalog (`rules/rules.yaml`) apply to anatomy part declarations. SPEC-020 was introduced in Phase 6.1 (component-format); SPEC-023, SPEC-024, and SPEC-025 are introduced by this chapter.
|
|
114
|
+
|
|
115
|
+
| Rule ID | Name | Severity | Assert |
|
|
116
|
+
| -------- | -------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| SPEC-020 | `component-anatomy-valid` | error | Token `anatomy` field value **MUST** match the `name` of a declared anatomy part on the referenced component. |
|
|
118
|
+
| SPEC-023 | `anatomy-custom-part-documented` | warning | Anatomy part declarations with a `name` outside the canonical anatomy vocabulary **SHOULD** include a `description` field documenting the part's purpose. |
|
|
119
|
+
| SPEC-024 | `anatomy-part-name-unique` | error | Anatomy part `name` values **MUST** be unique within a single component's `anatomy` array. |
|
|
120
|
+
| SPEC-025 | `anatomy-requires-component` | error | A token name object **MUST NOT** include an `anatomy` field unless a `component` field is also present. |
|
|
121
|
+
|
|
122
|
+
## Full example
|
|
123
|
+
|
|
124
|
+
A complete `anatomy` array for a slider component, demonstrating canonical names, a custom name, and `contains` usage:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
"anatomy": [
|
|
128
|
+
{
|
|
129
|
+
"name": "track",
|
|
130
|
+
"description": "Background rail spanning the slider's full range.",
|
|
131
|
+
"required": true
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "progress-bar",
|
|
135
|
+
"description": "Filled portion of the track indicating the current value.",
|
|
136
|
+
"required": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "handle",
|
|
140
|
+
"description": "Draggable thumb positioned at the current value.",
|
|
141
|
+
"required": true
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "label",
|
|
145
|
+
"description": "Text label identifying the slider.",
|
|
146
|
+
"required": false
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"name": "value",
|
|
150
|
+
"description": "Numeric display of the current slider value.",
|
|
151
|
+
"required": false
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "tick-marks",
|
|
155
|
+
"description": "Discrete step indicators along the track. Present only when step markers are enabled.",
|
|
156
|
+
"required": false
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "range-group",
|
|
160
|
+
"description": "Wrapper grouping the track and both handles for a range slider variant.",
|
|
161
|
+
"required": false,
|
|
162
|
+
"contains": ["track", "progress-bar", "handle"]
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
In this example, `tick-marks` and `range-group` are custom names outside the canonical vocabulary. Both include a `description` to satisfy rule SPEC-023. The `range-group` part uses `contains` to declare that it encloses `track`, `progress-bar`, and `handle`.
|