@adobe/design-data-spec 0.14.0 → 1.0.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/components/accordion.json +27 -4
- package/components/action-button.json +27 -4
- package/components/action-group.json +51 -10
- package/components/alert-banner.json +15 -2
- package/components/alert-dialog.json +18 -8
- package/components/avatar-group.json +24 -2
- package/components/avatar.json +72 -13
- package/components/badge.json +120 -31
- package/components/body.json +24 -2
- package/components/bottom-navigation-android.json +18 -4
- package/components/breadcrumbs.json +34 -7
- package/components/button-group.json +32 -5
- package/components/button.json +50 -10
- package/components/calendar.json +9 -2
- package/components/cards.json +21 -9
- package/components/checkbox-group.json +27 -6
- package/components/checkbox.json +15 -2
- package/components/close-button.json +24 -4
- package/components/coach-indicator.json +40 -14
- package/components/code.json +18 -2
- package/components/color-handle.json +24 -10
- package/components/color-slider.json +33 -12
- package/components/combo-box.json +48 -8
- package/components/contextual-help.json +78 -27
- package/components/date-picker.json +12 -2
- package/components/detail.json +24 -4
- package/components/divider.json +21 -4
- package/components/drop-zone.json +12 -2
- package/components/field-label.json +33 -6
- package/components/heading.json +36 -4
- package/components/help-text.json +25 -5
- package/components/illustrated-message.json +21 -4
- package/components/in-field-progress-button.json +29 -3
- package/components/in-field-progress-circle.json +23 -3
- package/components/in-line-alert.json +33 -11
- package/components/link.json +18 -4
- package/components/list-view.json +12 -2
- package/components/menu.json +42 -5
- package/components/meter.json +30 -4
- package/components/number-field.json +32 -5
- package/components/opacity-checkerboard.json +25 -2
- package/components/picker.json +41 -7
- package/components/popover.json +69 -25
- package/components/progress-bar.json +39 -8
- package/components/progress-circle.json +21 -4
- package/components/radio-group.json +42 -8
- package/components/scroll-zoom-bar.json +21 -4
- package/components/search-field.json +15 -2
- package/components/segmented-control.json +27 -6
- package/components/select-box.json +9 -2
- package/components/side-navigation.json +12 -2
- package/components/slider.json +17 -3
- package/components/standard-dialog.json +12 -2
- package/components/standard-panel.json +33 -6
- package/components/status-light.json +87 -28
- package/components/steplist.json +9 -2
- package/components/swatch-group.json +48 -8
- package/components/swatch.json +39 -9
- package/components/switch.json +15 -2
- package/components/tab-bar-ios.json +18 -4
- package/components/table.json +24 -4
- package/components/tabs.json +9 -2
- package/components/tag-field.json +27 -4
- package/components/tag-group.json +21 -4
- package/components/takeover-dialog.json +9 -2
- package/components/text-area.json +50 -7
- package/components/text-field.json +32 -5
- package/components/thumbnail.json +38 -1
- package/components/title.json +24 -2
- package/components/toast.json +15 -2
- package/components/tooltip.json +27 -4
- package/components/tree-view.json +42 -8
- package/conformance/invalid/SPEC-019/dataset.json +14 -1
- package/conformance/invalid/SPEC-037/dataset.json +86 -0
- package/conformance/invalid/SPEC-037/expected-errors.json +20 -0
- package/conformance/invalid/SPEC-038/dataset.json +20 -0
- package/conformance/invalid/SPEC-038/expected-errors.json +10 -0
- package/conformance/valid/SPEC-037/dataset.json +119 -0
- package/conformance/valid/SPEC-038/dataset.json +29 -0
- package/conformance/valid/component-refs/dataset.json +41 -7
- package/package.json +1 -1
- package/rules/rules.yaml +29 -1
- package/schemas/anatomy-part.schema.json +4 -0
- package/schemas/component.schema.json +33 -3
- package/schemas/state-declaration.schema.json +4 -0
- package/spec/agent-surface.md +1 -1
- package/spec/anatomy-format.md +14 -0
- package/spec/component-format.md +84 -28
- package/spec/state-model.md +18 -4
package/rules/rules.yaml
CHANGED
|
@@ -168,7 +168,7 @@ rules:
|
|
|
168
168
|
name: component-variant-valid
|
|
169
169
|
severity: error
|
|
170
170
|
category: reference-integrity
|
|
171
|
-
assert: Token name-object 'variant' field value MUST match a value in the declared 'variant' option
|
|
171
|
+
assert: Token name-object 'variant' field value MUST match a value in the declared 'variant' option `values` list for the referenced component, when that list exists.
|
|
172
172
|
message: "Token '{token}' has variant '{variant}' which is not declared on component '{component}'"
|
|
173
173
|
spec_ref: spec/component-format.md#options
|
|
174
174
|
introduced_in: "1.0.0-draft"
|
|
@@ -355,3 +355,31 @@ rules:
|
|
|
355
355
|
message: "Token '{token}' references deprecated component '{component}' (deprecated since {version}); update the reference or mark the token deprecated"
|
|
356
356
|
spec_ref: spec/component-format.md#lifecycle
|
|
357
357
|
introduced_in: "1.0.0-draft"
|
|
358
|
+
|
|
359
|
+
- id: SPEC-037
|
|
360
|
+
name: sub-entity-deprecation-cascade
|
|
361
|
+
severity: warning
|
|
362
|
+
category: reference-integrity
|
|
363
|
+
assert: >
|
|
364
|
+
Tokens SHOULD NOT reference a deprecated anatomy part, deprecated component state, or
|
|
365
|
+
deprecated option value via their `name` object unless the token is itself deprecated.
|
|
366
|
+
Non-deprecated tokens referencing deprecated sub-entities are surfaced as warnings to
|
|
367
|
+
prompt authors to update the reference or mark the token deprecated.
|
|
368
|
+
Deprecation is declared via `lifecycle.deprecated` on anatomy parts, states, and individual
|
|
369
|
+
option values within the `values` array on option descriptors.
|
|
370
|
+
message: "Token '{token}' references deprecated {kind} '{value}' on component '{component}' (deprecated since {version}); update the reference or mark the token deprecated"
|
|
371
|
+
spec_ref: spec/component-format.md#lifecycle
|
|
372
|
+
introduced_in: "1.0.0-draft"
|
|
373
|
+
|
|
374
|
+
- id: SPEC-038
|
|
375
|
+
name: option-enum-obsolete
|
|
376
|
+
severity: warning
|
|
377
|
+
category: component-contract
|
|
378
|
+
assert: >
|
|
379
|
+
Option descriptors SHOULD NOT use the JSON Schema `enum` keyword. The `enum` field is
|
|
380
|
+
silently accepted at Layer 1 (optionDescriptor uses additionalProperties: true) but has
|
|
381
|
+
no effect on SDK rules or lifecycle cascade. Use `values` instead so per-value lifecycle
|
|
382
|
+
metadata can be attached to individual values.
|
|
383
|
+
message: "Component '{component}' option '{option}' uses the obsolete `enum` keyword; replace with a `values` array so per-value lifecycle metadata can be expressed"
|
|
384
|
+
spec_ref: spec/component-format.md#option-descriptor
|
|
385
|
+
introduced_in: "1.0.0-draft"
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"items": { "$ref": "document-block.schema.json" },
|
|
36
36
|
"minItems": 1,
|
|
37
37
|
"description": "Typed prose blocks for this anatomy part. See spec/document-blocks.md (Phase 9)."
|
|
38
|
+
},
|
|
39
|
+
"lifecycle": {
|
|
40
|
+
"$ref": "component.schema.json#/$defs/lifecycle",
|
|
41
|
+
"description": "Version lifecycle metadata for this anatomy part. Set lifecycle.deprecated to signal that tokens referencing this part should migrate."
|
|
38
42
|
}
|
|
39
43
|
},
|
|
40
44
|
"additionalProperties": false
|
|
@@ -108,7 +108,8 @@
|
|
|
108
108
|
},
|
|
109
109
|
"optionDescriptor": {
|
|
110
110
|
"type": "object",
|
|
111
|
-
"description": "
|
|
111
|
+
"description": "Descriptor for a single component option. The `type` keyword follows JSON Schema conventions. Use `values` (not `enum`) to declare permitted values — the structured array allows per-value lifecycle metadata. Other JSON Schema keywords (default, description, pattern, minimum, maximum, items, properties, $ref) are permitted as needed.",
|
|
112
|
+
"$comment": "additionalProperties: true is required to allow JSON Schema passthrough keywords (pattern, minimum, etc.). This means the legacy `enum` keyword is silently accepted at Layer 1; SPEC-038 closes the gap at Layer 2 by warning when `enum` is present.",
|
|
112
113
|
"properties": {
|
|
113
114
|
"type": {
|
|
114
115
|
"oneOf": [
|
|
@@ -142,10 +143,12 @@
|
|
|
142
143
|
}
|
|
143
144
|
]
|
|
144
145
|
},
|
|
145
|
-
"
|
|
146
|
+
"values": {
|
|
146
147
|
"type": "array",
|
|
147
148
|
"minItems": 1,
|
|
148
|
-
"
|
|
149
|
+
"uniqueItems": true,
|
|
150
|
+
"items": { "$ref": "#/$defs/optionValue" },
|
|
151
|
+
"description": "Exhaustive list of permitted values for this option, each with optional per-value metadata. Use this instead of the JSON Schema `enum` keyword so that lifecycle annotations can be attached to individual values. Consumed by SPEC-019 (variant validation) and SPEC-037 (deprecation cascade)."
|
|
149
152
|
},
|
|
150
153
|
"default": {
|
|
151
154
|
"description": "Default value when the option is not specified."
|
|
@@ -162,6 +165,25 @@
|
|
|
162
165
|
},
|
|
163
166
|
"additionalProperties": true
|
|
164
167
|
},
|
|
168
|
+
"optionValue": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"required": ["value"],
|
|
171
|
+
"description": "A single permitted value for a component option, with optional per-value metadata.",
|
|
172
|
+
"properties": {
|
|
173
|
+
"value": {
|
|
174
|
+
"description": "The permitted option value. Typically a string; the schema does not constrain the type so booleans and numbers remain expressible."
|
|
175
|
+
},
|
|
176
|
+
"description": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"description": "Plain-text description of what this value means."
|
|
179
|
+
},
|
|
180
|
+
"lifecycle": {
|
|
181
|
+
"$ref": "#/$defs/lifecycle",
|
|
182
|
+
"description": "Version lifecycle metadata for this value. Set lifecycle.deprecated to signal that tokens referencing this value should migrate (SPEC-037)."
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"additionalProperties": false
|
|
186
|
+
},
|
|
165
187
|
"slotDeclaration": {
|
|
166
188
|
"type": "object",
|
|
167
189
|
"required": ["name"],
|
|
@@ -209,6 +231,10 @@
|
|
|
209
231
|
"type": "array",
|
|
210
232
|
"items": { "$ref": "document-block.schema.json" },
|
|
211
233
|
"description": "Typed prose blocks for this anatomy part. See spec/document-blocks.md (Phase 9)."
|
|
234
|
+
},
|
|
235
|
+
"lifecycle": {
|
|
236
|
+
"$ref": "#/$defs/lifecycle",
|
|
237
|
+
"description": "Version lifecycle metadata for this anatomy part. Set lifecycle.deprecated to signal that tokens referencing this part should migrate."
|
|
212
238
|
}
|
|
213
239
|
},
|
|
214
240
|
"additionalProperties": false
|
|
@@ -255,6 +281,10 @@
|
|
|
255
281
|
"type": "boolean",
|
|
256
282
|
"default": false,
|
|
257
283
|
"description": "Whether this state prevents all user interaction. See spec/accessibility.md."
|
|
284
|
+
},
|
|
285
|
+
"lifecycle": {
|
|
286
|
+
"$ref": "#/$defs/lifecycle",
|
|
287
|
+
"description": "Version lifecycle metadata for this state. Set lifecycle.deprecated to signal that tokens referencing this state should migrate."
|
|
258
288
|
}
|
|
259
289
|
},
|
|
260
290
|
"additionalProperties": false
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
"type": "boolean",
|
|
31
31
|
"default": false,
|
|
32
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
|
+
"lifecycle": {
|
|
35
|
+
"$ref": "component.schema.json#/$defs/lifecycle",
|
|
36
|
+
"description": "Version lifecycle metadata for this state. Set lifecycle.deprecated to signal that tokens referencing this state should migrate."
|
|
33
37
|
}
|
|
34
38
|
},
|
|
35
39
|
"additionalProperties": false
|
package/spec/agent-surface.md
CHANGED
|
@@ -96,7 +96,7 @@ The `describe_component` tool returns the component declaration object as stored
|
|
|
96
96
|
"displayName": "Button",
|
|
97
97
|
"meta": { "category": "actions", "documentationUrl": "https://spectrum.adobe.com/page/button/" },
|
|
98
98
|
"options": {
|
|
99
|
-
"variant": { "type": "string", "
|
|
99
|
+
"variant": { "type": "string", "values": [{"value": "accent"}, {"value": "negative"}, {"value": "primary"}, {"value": "secondary"}], "default": "accent" }
|
|
100
100
|
},
|
|
101
101
|
"anatomy": [
|
|
102
102
|
{ "name": "icon", "description": "Leading icon." },
|
package/spec/anatomy-format.md
CHANGED
|
@@ -20,6 +20,7 @@ An anatomy part is a **JSON object** that appears as an element of a component d
|
|
|
20
20
|
| `description` | string | OPTIONAL | Plain-text description of the part's visual role and boundaries. |
|
|
21
21
|
| `required` | boolean | OPTIONAL | Whether this part is always rendered regardless of configuration. Default: `false`. |
|
|
22
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
|
+
| `lifecycle` | object | OPTIONAL | Version lifecycle metadata for this anatomy part — see [lifecycle](#lifecycle). |
|
|
23
24
|
|
|
24
25
|
**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
|
|
|
@@ -51,6 +52,18 @@ When `required` is `true`, the anatomy part is unconditionally rendered (e.g. a
|
|
|
51
52
|
|
|
52
53
|
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
|
|
|
55
|
+
### `lifecycle`
|
|
56
|
+
|
|
57
|
+
**OPTIONAL.** A version lifecycle object tracking the history of this anatomy part. Uses the same shape as the component-level `lifecycle` block (see [Component format — Lifecycle](component-format.md#lifecycle)).
|
|
58
|
+
|
|
59
|
+
| Field | Type | Description |
|
|
60
|
+
| ------------------- | ------ | ---------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `deprecated` | string | Spec version when this anatomy part was deprecated. A truthy string signals deprecation. |
|
|
62
|
+
| `deprecatedComment` | string | Human-readable explanation of the deprecation and migration path (e.g. `"Renamed to thumb."`). |
|
|
63
|
+
| `replacedBy` | string | `name` of the replacement anatomy part. |
|
|
64
|
+
|
|
65
|
+
**ADVISORY:** When an anatomy part carries a `lifecycle.deprecated` value, non-deprecated tokens that reference this anatomy part via `name.anatomy` **SHOULD** be updated to remove or replace the reference. Rule SPEC-037 fires an advisory warning for such references to prompt migration.
|
|
66
|
+
|
|
54
67
|
```json
|
|
55
68
|
"anatomy": [
|
|
56
69
|
{
|
|
@@ -121,6 +134,7 @@ The following rules in the Layer 2 rule catalog (`rules/rules.yaml`) apply to an
|
|
|
121
134
|
| SPEC-024 | `anatomy-part-name-unique` | error | Anatomy part `name` values **MUST** be unique within a single component's `anatomy` array. |
|
|
122
135
|
| SPEC-025 | `anatomy-requires-component` | error | A token name object **MUST NOT** include an `anatomy` field unless a `component` field is also present. |
|
|
123
136
|
| SPEC-035 | `anatomy-part-name-registry-sync` | warning | A component anatomy part's `name` **SHOULD** appear in the canonical anatomy-terms registry (`anatomy-terms.json`). |
|
|
137
|
+
| SPEC-037 | `sub-entity-deprecation-cascade` | warning | A non-deprecated token **SHOULD NOT** reference a deprecated anatomy part via `name.anatomy`. Advisory warning prompts migration. |
|
|
124
138
|
|
|
125
139
|
## Full example
|
|
126
140
|
|
package/spec/component-format.md
CHANGED
|
@@ -88,31 +88,72 @@ The `options` block declares the component's API surface — the configurable pr
|
|
|
88
88
|
|
|
89
89
|
An option descriptor is a JSON object with the following fields:
|
|
90
90
|
|
|
91
|
-
| Field | Type | Required | Description
|
|
92
|
-
| ------------- | --------------- | -------- |
|
|
93
|
-
| `type` | string or array | OPTIONAL | JSON Schema primitive type(s): `"string"`, `"boolean"`, `"number"`, `"integer"`.
|
|
94
|
-
| `
|
|
95
|
-
| `default` | any | OPTIONAL | Default value when the option is not specified.
|
|
96
|
-
| `description` | string | OPTIONAL | Plain-text description of what the option controls.
|
|
97
|
-
| `$ref` | URI string | OPTIONAL | Reference to a shared type schema (e.g. `workflow-icon.json`).
|
|
91
|
+
| Field | Type | Required | Description |
|
|
92
|
+
| ------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `type` | string or array | OPTIONAL | JSON Schema primitive type(s): `"string"`, `"boolean"`, `"number"`, `"integer"`. |
|
|
94
|
+
| `values` | array | OPTIONAL | Exhaustive list of permitted values, each an [`optionValue`](#optionvalue) object. Use this instead of JSON Schema's `enum` keyword so per-value lifecycle metadata can be expressed without a separate sidecar map. |
|
|
95
|
+
| `default` | any | OPTIONAL | Default value when the option is not specified. |
|
|
96
|
+
| `description` | string | OPTIONAL | Plain-text description of what the option controls. |
|
|
97
|
+
| `$ref` | URI string | OPTIONAL | Reference to a shared type schema (e.g. `workflow-icon.json`). |
|
|
98
|
+
|
|
99
|
+
### optionValue
|
|
100
|
+
|
|
101
|
+
Each entry in `values` is an object:
|
|
102
|
+
|
|
103
|
+
| Field | Type | Required | Description |
|
|
104
|
+
| ------------- | ------ | -------- | ---------------------------------------------------------------------------------------- |
|
|
105
|
+
| `value` | any | REQUIRED | The permitted option value. |
|
|
106
|
+
| `description` | string | OPTIONAL | Plain-text description of what this value means. |
|
|
107
|
+
| `lifecycle` | object | OPTIONAL | Version lifecycle metadata. Set `lifecycle.deprecated` to signal migration via SPEC-037. |
|
|
98
108
|
|
|
99
109
|
**NORMATIVE:** Each key in `options` **MUST** be camelCase.
|
|
100
110
|
|
|
101
111
|
**NORMATIVE:** Boolean option names **MUST** begin with `is` or `has` (e.g. `isDisabled`, `hasIcon`).
|
|
102
112
|
|
|
103
|
-
**NORMATIVE:** When `
|
|
113
|
+
**NORMATIVE:** When `values` is present, token name-object `variant` field values referencing this component **MUST** be drawn from the declared `variant` option `values` list (rule SPEC-019). Other option `values` lists are informative for tooling but do not currently drive SPEC rules.
|
|
114
|
+
|
|
115
|
+
**ADVISORY:** When a value in `values` carries a `lifecycle.deprecated` string and a non-deprecated token references that value via its `name` object field, SPEC-037 fires an advisory warning prompting migration or token deprecation.
|
|
116
|
+
|
|
117
|
+
Example with a deprecated option value:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
"variant": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"values": [
|
|
123
|
+
{ "value": "primary" },
|
|
124
|
+
{ "value": "secondary" },
|
|
125
|
+
{
|
|
126
|
+
"value": "cta",
|
|
127
|
+
"lifecycle": {
|
|
128
|
+
"deprecated": "1.0.0-draft",
|
|
129
|
+
"deprecatedComment": "Use primary instead."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
104
135
|
|
|
105
136
|
```json
|
|
106
137
|
"options": {
|
|
107
138
|
"variant": {
|
|
108
139
|
"type": "string",
|
|
109
|
-
"
|
|
140
|
+
"values": [
|
|
141
|
+
{ "value": "accent" },
|
|
142
|
+
{ "value": "negative" },
|
|
143
|
+
{ "value": "primary" },
|
|
144
|
+
{ "value": "secondary" }
|
|
145
|
+
],
|
|
110
146
|
"default": "accent",
|
|
111
147
|
"description": "Visual emphasis level."
|
|
112
148
|
},
|
|
113
149
|
"size": {
|
|
114
150
|
"type": "string",
|
|
115
|
-
"
|
|
151
|
+
"values": [
|
|
152
|
+
{ "value": "s" },
|
|
153
|
+
{ "value": "m" },
|
|
154
|
+
{ "value": "l" },
|
|
155
|
+
{ "value": "xl" }
|
|
156
|
+
],
|
|
116
157
|
"default": "m"
|
|
117
158
|
},
|
|
118
159
|
"isDisabled": {
|
|
@@ -186,12 +227,13 @@ The `anatomy` block declares the component's named **visual parts** — the anat
|
|
|
186
227
|
|
|
187
228
|
Each anatomy part carries at minimum:
|
|
188
229
|
|
|
189
|
-
| Field | Type | Required | Description
|
|
190
|
-
| ------------- | ---------------- | -------- |
|
|
191
|
-
| `name` | string | REQUIRED | Anatomy part identifier (e.g. `icon`, `label`, `handle`).
|
|
192
|
-
| `description` | string | OPTIONAL | Plain-text description of the part.
|
|
193
|
-
| `required` | boolean | OPTIONAL | Whether this part is always present. Default: `false`.
|
|
194
|
-
| `contains` | array of strings | OPTIONAL | Informative: other anatomy part names nested within this part.
|
|
230
|
+
| Field | Type | Required | Description |
|
|
231
|
+
| ------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
232
|
+
| `name` | string | REQUIRED | Anatomy part identifier (e.g. `icon`, `label`, `handle`). |
|
|
233
|
+
| `description` | string | OPTIONAL | Plain-text description of the part. |
|
|
234
|
+
| `required` | boolean | OPTIONAL | Whether this part is always present. Default: `false`. |
|
|
235
|
+
| `contains` | array of strings | OPTIONAL | Informative: other anatomy part names nested within this part. |
|
|
236
|
+
| `lifecycle` | object | OPTIONAL | Version lifecycle metadata for this part. When `lifecycle.deprecated` is set, SPEC-037 fires on referencing tokens. |
|
|
195
237
|
|
|
196
238
|
See [`spec/anatomy-format.md`](anatomy-format.md) for constraints, cross-field validation, and the full anatomy part schema.
|
|
197
239
|
|
|
@@ -216,6 +258,7 @@ Each state carries at minimum:
|
|
|
216
258
|
| `trigger` | string | OPTIONAL | `"prop"` for persistent prop-driven states (e.g. `isDisabled`) or `"interaction"` for runtime interaction states (hover, focus, pressed). |
|
|
217
259
|
| `precedence` | integer | OPTIONAL | Resolution precedence; higher integer wins when multiple states are active. |
|
|
218
260
|
| `layered` | boolean | OPTIONAL | `true` for states that compose with others (e.g. focus ring over hover). Default: `false`. |
|
|
261
|
+
| `lifecycle` | object | OPTIONAL | Version lifecycle metadata for this state. When `lifecycle.deprecated` is set, SPEC-037 fires on referencing tokens. |
|
|
219
262
|
|
|
220
263
|
See [`spec/state-model.md`](state-model.md) for the full state resolution algorithm, trigger semantics, and precedence rules.
|
|
221
264
|
|
|
@@ -271,14 +314,17 @@ The `context` field is informative. It is used by `describe_component` (Phase 8
|
|
|
271
314
|
|
|
272
315
|
The following rules are added to the Layer 2 rule catalog (`rules/rules.yaml`) by this chapter. New component cross-reference rules start at SPEC-018 to avoid collision with existing token rules (SPEC-001–SPEC-017).
|
|
273
316
|
|
|
274
|
-
| Rule ID | Name
|
|
275
|
-
| -------- |
|
|
276
|
-
| SPEC-018 | `component-name-exists`
|
|
277
|
-
| SPEC-019 | `component-variant-valid`
|
|
278
|
-
| SPEC-020 | `component-anatomy-valid`
|
|
279
|
-
| SPEC-021 | `component-slot-vocabulary`
|
|
280
|
-
| SPEC-022 | `component-state-valid`
|
|
281
|
-
| SPEC-027 | `token-binding-token-exists`
|
|
317
|
+
| Rule ID | Name | Severity | Assert |
|
|
318
|
+
| -------- | -------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
319
|
+
| SPEC-018 | `component-name-exists` | error | Token `component` field value **MUST** match the `name` of a declared component in the dataset. |
|
|
320
|
+
| SPEC-019 | `component-variant-valid` | error | Token `variant` field value **MUST** match a value in the declared `variant` option `values` list for the referenced component (when that list exists). |
|
|
321
|
+
| SPEC-020 | `component-anatomy-valid` | error | Token `anatomy` field value **MUST** match the `name` of a declared anatomy part on the referenced component. |
|
|
322
|
+
| SPEC-021 | `component-slot-vocabulary` | warning | Component `slots` entries with a `name` outside the canonical vocabulary **SHOULD** include a `description`. Custom slot names without descriptions are surfaced as warnings. |
|
|
323
|
+
| SPEC-022 | `component-state-valid` | error | Token `state` field value **MUST** match the `name` of a declared state on the referenced component (when state declarations are present). |
|
|
324
|
+
| SPEC-027 | `token-binding-token-exists` | error | Each `tokenBindings[].token` value **MUST** match the name of a declared token in the dataset (Phase 6.7). |
|
|
325
|
+
| SPEC-036 | `component-deprecation-cascade` | warning | A non-deprecated token **SHOULD NOT** reference a deprecated component via `name.component`. Advisory warning prompts updating the component reference or marking the token deprecated. |
|
|
326
|
+
| SPEC-037 | `sub-entity-deprecation-cascade` | warning | A non-deprecated token **SHOULD NOT** reference a deprecated anatomy part, state, or option value via `name.*`. Advisory warning prompts migration. Requires `lifecycle` on anatomy/state or `lifecycle` on the matching `values` entry on the option descriptor. |
|
|
327
|
+
| SPEC-038 | `option-enum-obsolete` | warning | An option descriptor **SHOULD NOT** use the JSON Schema `enum` keyword. `additionalProperties: true` silently accepts `enum` at Layer 1; SPEC-038 flags it at Layer 2 so authors replace it with the `values` array. |
|
|
282
328
|
|
|
283
329
|
## Full example
|
|
284
330
|
|
|
@@ -299,18 +345,28 @@ A complete button component declaration:
|
|
|
299
345
|
"options": {
|
|
300
346
|
"variant": {
|
|
301
347
|
"type": "string",
|
|
302
|
-
"
|
|
348
|
+
"values": [
|
|
349
|
+
{ "value": "accent" },
|
|
350
|
+
{ "value": "negative" },
|
|
351
|
+
{ "value": "primary" },
|
|
352
|
+
{ "value": "secondary" }
|
|
353
|
+
],
|
|
303
354
|
"default": "accent",
|
|
304
355
|
"description": "Visual emphasis level."
|
|
305
356
|
},
|
|
306
357
|
"style": {
|
|
307
358
|
"type": "string",
|
|
308
|
-
"
|
|
359
|
+
"values": [{ "value": "fill" }, { "value": "outline" }],
|
|
309
360
|
"default": "fill"
|
|
310
361
|
},
|
|
311
362
|
"size": {
|
|
312
363
|
"type": "string",
|
|
313
|
-
"
|
|
364
|
+
"values": [
|
|
365
|
+
{ "value": "s" },
|
|
366
|
+
{ "value": "m" },
|
|
367
|
+
{ "value": "l" },
|
|
368
|
+
{ "value": "xl" }
|
|
369
|
+
],
|
|
314
370
|
"default": "m"
|
|
315
371
|
},
|
|
316
372
|
"isDisabled": { "type": "boolean", "default": false },
|
|
@@ -322,7 +378,7 @@ A complete button component declaration:
|
|
|
322
378
|
},
|
|
323
379
|
"staticColor": {
|
|
324
380
|
"type": "string",
|
|
325
|
-
"
|
|
381
|
+
"values": [{ "value": "white" }, { "value": "black" }],
|
|
326
382
|
"description": "Static color for use on colored backgrounds. Must not be set for the default variant."
|
|
327
383
|
}
|
|
328
384
|
},
|
package/spec/state-model.md
CHANGED
|
@@ -34,6 +34,7 @@ A state declaration is a **JSON object** that appears as an element of a compone
|
|
|
34
34
|
| `trigger` | string | OPTIONAL | `"prop"` for persistent prop-driven states; `"interaction"` for runtime interaction states. See [Trigger semantics](#trigger-semantics). |
|
|
35
35
|
| `precedence` | integer | OPTIONAL | Resolution precedence; higher value wins when multiple non-layered states are active simultaneously. Defaults to `0` if omitted. |
|
|
36
36
|
| `layered` | boolean | OPTIONAL | When `true`, this state composes on top of the winning non-layered state rather than competing with it. Default: `false`. |
|
|
37
|
+
| `lifecycle` | object | OPTIONAL | Version lifecycle metadata for this state — see [lifecycle](#lifecycle). |
|
|
37
38
|
|
|
38
39
|
**NORMATIVE:** No properties beyond those listed above are permitted in a state declaration object. Additional fields **MUST** cause a Layer 1 schema error.
|
|
39
40
|
|
|
@@ -76,6 +77,18 @@ When `layered: true`, the state does not participate in the non-layered preceden
|
|
|
76
77
|
|
|
77
78
|
Typical use: focus ring states (`focus`, `focus-visible`) that must be visible regardless of whether the component is also in a `hover` or `selected` state.
|
|
78
79
|
|
|
80
|
+
### `lifecycle`
|
|
81
|
+
|
|
82
|
+
**OPTIONAL.** A version lifecycle object tracking the history of this state declaration. Uses the same shape as the component-level `lifecycle` block (see [Component format — Lifecycle](component-format.md#lifecycle)).
|
|
83
|
+
|
|
84
|
+
| Field | Type | Description |
|
|
85
|
+
| ------------------- | ------ | ------------------------------------------------------------------------------------------------ |
|
|
86
|
+
| `deprecated` | string | Spec version when this state was deprecated. A truthy string signals deprecation. |
|
|
87
|
+
| `deprecatedComment` | string | Human-readable explanation of the deprecation and migration path (e.g. `"Use active instead."`). |
|
|
88
|
+
| `replacedBy` | string | `name` of the replacement state. |
|
|
89
|
+
|
|
90
|
+
**ADVISORY:** When a state carries a `lifecycle.deprecated` value, non-deprecated tokens that reference this state via `name.state` **SHOULD** be updated to remove or replace the reference. Rule SPEC-037 fires an advisory warning for such references to prompt migration.
|
|
91
|
+
|
|
79
92
|
## Trigger semantics
|
|
80
93
|
|
|
81
94
|
### `prop` trigger
|
|
@@ -185,10 +198,11 @@ See [Token format — Name object](token-format.md#name-object) for the full nam
|
|
|
185
198
|
|
|
186
199
|
The following rules in the Layer 2 rule catalog (`rules/rules.yaml`) apply to state declarations. SPEC-022 was introduced in Phase 6.1 (component-format); SPEC-026 is introduced by this chapter.
|
|
187
200
|
|
|
188
|
-
| Rule ID | Name
|
|
189
|
-
| -------- |
|
|
190
|
-
| SPEC-022 | `component-state-valid`
|
|
191
|
-
| SPEC-026 | `state-custom-name-documented`
|
|
201
|
+
| Rule ID | Name | Severity | Assert |
|
|
202
|
+
| -------- | -------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
203
|
+
| SPEC-022 | `component-state-valid` | error | Token `state` field value **MUST** match the `name` of a declared state on the referenced component (when state declarations are present). |
|
|
204
|
+
| SPEC-026 | `state-custom-name-documented` | warning | State declarations with a `name` outside the canonical state vocabulary **SHOULD** include a `description` field documenting the state's semantics. |
|
|
205
|
+
| SPEC-037 | `sub-entity-deprecation-cascade` | warning | A non-deprecated token **SHOULD NOT** reference a deprecated state via `name.state`. Advisory warning prompts migration. |
|
|
192
206
|
|
|
193
207
|
## Full example
|
|
194
208
|
|