@adobe/design-data-spec 2.8.0 → 3.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.
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "name": {
5
5
  "component": "button",
6
- "state": "jello",
6
+ "state": ["jello"],
7
7
  "property": "background-color"
8
8
  },
9
9
  "value": "#ff0000"
@@ -11,7 +11,7 @@
11
11
  {
12
12
  "name": {
13
13
  "component": "button",
14
- "state": "pressed",
14
+ "state": ["pressed"],
15
15
  "property": "background-color"
16
16
  },
17
17
  "value": "#cccccc"
@@ -4,7 +4,7 @@
4
4
  "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
5
5
  "name": {
6
6
  "property": "color",
7
- "state": "hover"
7
+ "state": ["hover"]
8
8
  },
9
9
  "value": "#0265dc"
10
10
  },
@@ -0,0 +1,13 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "structure": "accessory",
6
+ "anatomy": "wibble",
7
+ "property": "gap"
8
+ },
9
+ "value": "2px"
10
+ }
11
+ ],
12
+ "components": []
13
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "layer": 2,
3
+ "errors": [
4
+ {
5
+ "rule_id": "SPEC-049",
6
+ "severity": "error",
7
+ "message_pattern": ".*'wibble'.*not in the.*anatomy-terms.*"
8
+ }
9
+ ]
10
+ }
@@ -1,6 +1,6 @@
1
1
  [
2
2
  {
3
- "name": { "property": "bg", "component": "button", "state": "hover" },
3
+ "name": { "property": "bg", "component": "button", "state": ["hover"] },
4
4
  "value": "#aaaaaa",
5
5
  "uuid": "aaaaaaaa-0001-4000-8000-000000000001"
6
6
  },
@@ -10,7 +10,7 @@
10
10
  "uuid": "aaaaaaaa-0002-4000-8000-000000000001"
11
11
  },
12
12
  {
13
- "name": { "property": "bg", "component": "checkbox", "state": "hover" },
13
+ "name": { "property": "bg", "component": "checkbox", "state": ["hover"] },
14
14
  "value": "#cccccc",
15
15
  "uuid": "aaaaaaaa-0003-4000-8000-000000000001"
16
16
  }
@@ -1,21 +1,21 @@
1
1
  [
2
2
  {
3
- "name": { "property": "bg", "component": "button", "state": "hover" },
3
+ "name": { "property": "bg", "component": "button", "state": ["hover"] },
4
4
  "value": "#aaaaaa",
5
5
  "uuid": "aaaaaaaa-0001-4000-8000-000000000001"
6
6
  },
7
7
  {
8
- "name": { "property": "bg", "component": "button", "state": "default" },
8
+ "name": { "property": "bg", "component": "button", "state": ["default"] },
9
9
  "value": "#bbbbbb",
10
10
  "uuid": "aaaaaaaa-0002-4000-8000-000000000001"
11
11
  },
12
12
  {
13
- "name": { "property": "bg", "component": "checkbox", "state": "default" },
13
+ "name": { "property": "bg", "component": "checkbox", "state": ["default"] },
14
14
  "value": "#cccccc",
15
15
  "uuid": "aaaaaaaa-0003-4000-8000-000000000001"
16
16
  },
17
17
  {
18
- "name": { "property": "bg", "component": "slider", "state": "hover" },
18
+ "name": { "property": "bg", "component": "slider", "state": ["hover"] },
19
19
  "value": "#dddddd",
20
20
  "uuid": "aaaaaaaa-0004-4000-8000-000000000001"
21
21
  }
@@ -7,6 +7,23 @@
7
7
  "property": "color"
8
8
  },
9
9
  "value": "#ffffff"
10
+ },
11
+ {
12
+ "name": {
13
+ "structure": "accessory",
14
+ "anatomy": "item",
15
+ "property": "padding",
16
+ "size": "small",
17
+ "legacyKey": "accessory-item-padding-small"
18
+ },
19
+ "value": "4px"
20
+ },
21
+ {
22
+ "name": {
23
+ "anatomy": "focus-ring",
24
+ "property": "gap"
25
+ },
26
+ "value": "2px"
10
27
  }
11
28
  ],
12
29
  "components": [
@@ -20,7 +20,7 @@
20
20
  {
21
21
  "name": {
22
22
  "component": "button",
23
- "state": "hover",
23
+ "state": ["hover"],
24
24
  "property": "background-color"
25
25
  },
26
26
  "value": "#eeeeee"
@@ -28,7 +28,7 @@
28
28
  {
29
29
  "name": {
30
30
  "component": "button",
31
- "state": "pressed",
31
+ "state": ["pressed"],
32
32
  "property": "background-color"
33
33
  },
34
34
  "value": "#cccccc",
@@ -0,0 +1,43 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "structure": "accessory",
6
+ "anatomy": "item",
7
+ "property": "padding",
8
+ "size": "small",
9
+ "legacyKey": "accessory-item-padding-small"
10
+ },
11
+ "value": "4px"
12
+ },
13
+ {
14
+ "name": {
15
+ "anatomy": "focus-ring",
16
+ "property": "gap"
17
+ },
18
+ "value": "2px"
19
+ },
20
+ {
21
+ "name": {
22
+ "component": "button",
23
+ "anatomy": "wibble",
24
+ "property": "color"
25
+ },
26
+ "value": "#ffffff"
27
+ }
28
+ ],
29
+ "components": [
30
+ {
31
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/button.json",
32
+ "name": "button",
33
+ "displayName": "Button",
34
+ "meta": {
35
+ "category": "actions",
36
+ "documentationUrl": "https://spectrum.adobe.com/page/button/"
37
+ },
38
+ "anatomy": [
39
+ { "name": "wibble", "description": "Custom documented part." }
40
+ ]
41
+ }
42
+ ]
43
+ }
@@ -19,7 +19,7 @@
19
19
  {
20
20
  "name": {
21
21
  "component": "button",
22
- "state": "hover",
22
+ "state": ["hover"],
23
23
  "property": "background-color"
24
24
  },
25
25
  "value": "#0255be"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/design-data-spec",
3
- "version": "2.8.0",
3
+ "version": "3.0.0",
4
4
  "description": "Design Data Specification — prose, JSON Schemas, rule catalog, and conformance fixtures for the design data format",
5
5
  "type": "module",
6
6
  "repository": {
package/rules/rules.yaml CHANGED
@@ -223,8 +223,12 @@ rules:
223
223
  name: anatomy-requires-component
224
224
  severity: error
225
225
  category: reference-integrity
226
- assert: A token name object MUST NOT include an 'anatomy' field unless a 'component' field is also present.
227
- message: "Token '{token}' has 'anatomy' field without a 'component' field"
226
+ assert: >
227
+ A token name object MUST NOT include an 'anatomy' field unless a 'component' or
228
+ 'structure' field is also present, or the 'anatomy' value is a registry term
229
+ flagged 'standaloneScope: true' in anatomy-terms.json (cross-cutting parts with
230
+ no single owning component, e.g. 'focus-ring', 'focus-indicator').
231
+ message: "Token '{token}' has 'anatomy' field without a 'component' or 'structure' field, and '{anatomy}' is not a registry term flagged standaloneScope"
228
232
  spec_ref: spec/anatomy-format.md#cross-reference-with-token-name-objects
229
233
  introduced_in: "1.0.0-draft"
230
234
 
@@ -560,3 +564,17 @@ rules:
560
564
  message: "Anatomy part '{part}' on component '{component}' contains '{child}', which is not a declared anatomy part on this component"
561
565
  spec_ref: spec/anatomy-format.md#contains
562
566
  introduced_in: "1.0.0-draft"
567
+
568
+ - id: SPEC-049
569
+ name: anatomy-in-registry
570
+ severity: error
571
+ layer: 2
572
+ category: reference-integrity
573
+ assert: >
574
+ A token name-object 'anatomy' field with no 'component' (SPEC-020 validates that
575
+ case) MUST reference a known id in the anatomy-terms.json registry. Backstops the
576
+ two cases SPEC-025 allows anatomy without a component: 'structure'-scoped anatomy
577
+ and registry terms flagged 'standaloneScope: true'.
578
+ message: "Token '{token}' references anatomy part '{anatomy}' which is not in the spectrum-design-data registry/anatomy-terms vocabulary"
579
+ spec_ref: spec/anatomy-format.md#cross-reference-with-token-name-objects
580
+ introduced_in: "1.0.0-draft"
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "valueType": {
78
78
  "type": "string",
79
- "enum": ["string", "integer"],
79
+ "enum": ["string", "integer", "array"],
80
80
  "description": "Type of the field value. Default: 'string'.",
81
81
  "default": "string"
82
82
  },
@@ -66,6 +66,10 @@
66
66
  "type": "boolean",
67
67
  "description": "Whether this value is deprecated"
68
68
  },
69
+ "standaloneScope": {
70
+ "type": "boolean",
71
+ "description": "Anatomy-term only: whether this term may scope a token's name object on its own, without an accompanying component or structure field (e.g. cross-cutting parts like focus-ring/focus-indicator that have no single owner)"
72
+ },
69
73
  "usedIn": {
70
74
  "type": "array",
71
75
  "description": "Where this value is used (tokens, component-schemas, etc.)",
@@ -10,7 +10,7 @@
10
10
  "type": "string",
11
11
  "pattern": "^[a-z][a-z0-9-]*$",
12
12
  "minLength": 1,
13
- "description": "Kebab-case state identifier. Must match the value used in token name-object 'state' fields."
13
+ "description": "Kebab-case state identifier. Must match an element of the token name-object 'state' array."
14
14
  },
15
15
  "description": {
16
16
  "type": "string",
@@ -48,8 +48,13 @@
48
48
  "description": "Semantic: variant within a component (e.g. accent, negative, primary)."
49
49
  },
50
50
  "state": {
51
- "type": "string",
52
- "description": "Semantic: interactive or semantic state (e.g. hover, focus, disabled)."
51
+ "type": "array",
52
+ "items": {
53
+ "type": "string",
54
+ "pattern": "^[a-z][a-z0-9-]*$"
55
+ },
56
+ "minItems": 1,
57
+ "description": "Semantic: interactive or semantic state, as an ordered array of atomic state ids (e.g. [\"hover\"], [\"selected\", \"hover\"])."
53
58
  },
54
59
  "qualifier": {
55
60
  "type": "string",
package/spec/query.md CHANGED
@@ -77,6 +77,10 @@ The expression `a=x,b=y|c=z` is equivalent to `(a=x AND b=y) OR (c=z)`.
77
77
 
78
78
  **RATIONALE:** Negation matching absent fields follows the convention that "not equal to X" includes "does not exist" — the same semantics as label selectors in Kubernetes and CSS attribute selectors.
79
79
 
80
+ **NORMATIVE:** `state` (and any future array-valued key) resolves to each element of the array individually. For equality (`=`), a condition matches when **any** element equals the specified value. For negation (`!=`), a condition matches when **no** element equals the specified value (or the field is absent). For example, a token with `name.state: ["selected", "hover"]` matches `state=hover` and does **not** match `state!=hover`.
81
+
82
+ **RATIONALE:** A compound state (Proposal 006) represents a token that is simultaneously in multiple states; querying for one of those states should find it, consistent with treating the array as a set of active states rather than requiring an exact-array match.
83
+
80
84
  ## Glob matching
81
85
 
82
86
  **NORMATIVE:** The `*` character in a value is a **glob wildcard** matching zero or more characters.
@@ -10,7 +10,7 @@ Scoped under [RFC-A — Component Contract in Design Data Spec](https://github.c
10
10
 
11
11
  A **component state** is a named condition under which a component's visual presentation differs from its baseline. States drive token resolution: when a component is in a given state, the design system selects tokens scoped to that state name rather than (or layered on top of) the baseline tokens.
12
12
 
13
- State names appear in the `state` field of token name objects (see [Token format — Name object](token-format.md#name-object)). A token with `"state": "hover"` applies only when the component is in the `hover` state. For this cross-reference to be machine-enforceable, state declarations **MUST** be present on the component declaration.
13
+ State names appear in the `state` field of token name objects, an ordered array of one or more atomic state ids (see [Token format — Name object](token-format.md#name-object) and [Proposal 006](../../../docs/proposals/006-compound-states-as-array.md)). A token with `"state": ["hover"]` applies only when the component is in the `hover` state; `"state": ["selected", "hover"]` applies when both states are simultaneously active. For this cross-reference to be machine-enforceable, state declarations **MUST** be present on the component declaration.
14
14
 
15
15
  States fall into two trigger types:
16
16
 
@@ -188,7 +188,7 @@ See [Token format — Name object](token-format.md#name-object) for the full nam
188
188
  "component": "checkbox",
189
189
  "anatomy": "checkmark",
190
190
  "property": "color",
191
- "state": "selected"
191
+ "state": ["selected"]
192
192
  },
193
193
  "value": "#0265dc"
194
194
  }
@@ -55,25 +55,25 @@ The table below lists all semantic fields. Fields marked with a scope are domain
55
55
 
56
56
  **Universal semantic fields** (`scope: null` — apply to all token types):
57
57
 
58
- | Field | Status | Taxonomy category | Description |
59
- | -------------- | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
60
- | `property` | REQUIRED | Property | The stylistic attribute being defined (e.g. `color`, `width`, `padding`, `gap`). |
61
- | `component` | OPTIONAL | Component | Component name when the token is component-scoped. |
62
- | `structure` | OPTIONAL | Structure | Reusable visual pattern or object category (e.g. `base`, `container`, `list`, `accessory`). Distinct from `component`. |
63
- | `substructure` | OPTIONAL | Sub-structure | A structure that only exists within its parent structure (e.g. `item` in `list-item`). |
64
- | `anatomy` | OPTIONAL | Anatomy | A visible, named part of a component as defined by designers (e.g. `handle`, `icon`, `label`). See [Taxonomy — Component anatomy](taxonomy.md#component-anatomy). |
65
- | `object` | OPTIONAL | Object | Styling surface to which a visual property is applied (e.g. `background`, `border`, `edge`). See [Taxonomy — Token objects](taxonomy.md#token-objects-styling-surfaces). |
66
- | `variant` | OPTIONAL | Variant | Variant within a component (e.g. `accent`, `negative`, `primary`). |
67
- | `state` | OPTIONAL | State | Interactive or semantic state (e.g. `hover`, `focus`, `disabled`). |
68
- | `orientation` | OPTIONAL | Orientation | Direction or order of structures and elements (e.g. `vertical`, `horizontal`). |
69
- | `position` | OPTIONAL | Position | Location of an object relative to another (e.g. `affixed`). |
70
- | `size` | OPTIONAL | Size | Relative t-shirt sizing for relationships across tokens (e.g. `small`, `medium`, `large`). |
71
- | `density` | OPTIONAL | Density | Space within or around component parts (e.g. `spacious`, `compact`). |
72
- | `shape` | OPTIONAL | Shape | Relative to overall component shape (e.g. `uniform`). |
73
- | `role` | OPTIONAL | Role | An object's role within a nesting relationship (e.g. `container`, `control`), distinct from `size`. |
74
- | `scaleIndex` | OPTIONAL | — | Numeric scale index appended at the end of the serialized name (e.g. `100`, `200`, `900`). Used by color palette, spacing, font-size, and motion duration tokens. |
75
- | `from` | OPTIONAL | — | Starting endpoint of a `space-between` measurement (e.g. `top`, `edge`, `text`). See [Space-between endpoints](#space-between-endpoints). |
76
- | `to` | OPTIONAL | — | Ending endpoint of a `space-between` measurement (e.g. `text`, `visual`, `control`). See [Space-between endpoints](#space-between-endpoints). |
58
+ | Field | Status | Taxonomy category | Description |
59
+ | -------------- | -------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
60
+ | `property` | REQUIRED | Property | The stylistic attribute being defined (e.g. `color`, `width`, `padding`, `gap`). |
61
+ | `component` | OPTIONAL | Component | Component name when the token is component-scoped. |
62
+ | `structure` | OPTIONAL | Structure | Reusable visual pattern or object category (e.g. `base`, `container`, `list`, `accessory`). Distinct from `component`. |
63
+ | `substructure` | OPTIONAL | Sub-structure | A structure that only exists within its parent structure (e.g. `item` in `list-item`). |
64
+ | `anatomy` | OPTIONAL | Anatomy | A visible, named part of a component as defined by designers (e.g. `handle`, `icon`, `label`). See [Taxonomy — Component anatomy](taxonomy.md#component-anatomy). |
65
+ | `object` | OPTIONAL | Object | Styling surface to which a visual property is applied (e.g. `background`, `border`, `edge`). See [Taxonomy — Token objects](taxonomy.md#token-objects-styling-surfaces). |
66
+ | `variant` | OPTIONAL | Variant | Variant within a component (e.g. `accent`, `negative`, `primary`). |
67
+ | `state` | OPTIONAL | State | Ordered array of one or more interactive or semantic states (e.g. `["hover"]`, `["selected", "hover"]`). See [Proposal 006](../../../docs/proposals/006-compound-states-as-array.md). |
68
+ | `orientation` | OPTIONAL | Orientation | Direction or order of structures and elements (e.g. `vertical`, `horizontal`). |
69
+ | `position` | OPTIONAL | Position | Location of an object relative to another (e.g. `affixed`). |
70
+ | `size` | OPTIONAL | Size | Relative t-shirt sizing for relationships across tokens (e.g. `small`, `medium`, `large`). |
71
+ | `density` | OPTIONAL | Density | Space within or around component parts (e.g. `spacious`, `compact`). |
72
+ | `shape` | OPTIONAL | Shape | Relative to overall component shape (e.g. `uniform`). |
73
+ | `role` | OPTIONAL | Role | An object's role within a nesting relationship (e.g. `container`, `control`), distinct from `size`. |
74
+ | `scaleIndex` | OPTIONAL | — | Numeric scale index appended at the end of the serialized name (e.g. `100`, `200`, `900`). Used by color palette, spacing, font-size, and motion duration tokens. |
75
+ | `from` | OPTIONAL | — | Starting endpoint of a `space-between` measurement (e.g. `top`, `edge`, `text`). See [Space-between endpoints](#space-between-endpoints). |
76
+ | `to` | OPTIONAL | — | Ending endpoint of a `space-between` measurement (e.g. `text`, `visual`, `control`). See [Space-between endpoints](#space-between-endpoints). |
77
77
 
78
78
  #### Space-between endpoints
79
79
 
@@ -122,7 +122,7 @@ When **`$ref`** is present, the token is an **alias**. The value **MUST** be a n
122
122
 
123
123
  ```json
124
124
  // Cascade canonical form (recommended) — the UUID is stable across renames.
125
- { "name": { "property": "accent-background-color", "state": "default", "colorScheme": "dark" },
125
+ { "name": { "property": "accent-background-color", "state": ["default"], "colorScheme": "dark" },
126
126
  "$schema": "…/alias.json",
127
127
  "$ref": "87a2c8f0-54fd-4939-8f42-3124fde1e49e",
128
128
  "uuid": "f24eb871-6419-4cef-88a2-cca8548ae31e" }