@adobe/design-data-spec 2.6.0 → 2.8.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.
@@ -12,18 +12,41 @@ generation/<case>/
12
12
  expected/ — expected legacy output (keyed-object format, one file per input file)
13
13
  ```
14
14
 
15
- ## Running
15
+ ## Automated driver
16
+
17
+ These fixtures are exercised automatically by the `generation_conformance` module in
18
+ `sdk/core/src/lib.rs`. Each test case runs `legacy::convert_dir` twice and asserts:
19
+
20
+ 1. **Byte-identical output** — the generated files match `expected/` exactly.
21
+ 2. **Determinism** — pass 1 and pass 2 output are identical.
16
22
 
17
23
  ```bash
18
- design-data migrate legacy-output --output <out-dir> <input-dir>/
19
- diff <out-dir>/tokens.json expected/tokens.json
24
+ # Run all generation conformance tests:
25
+ moon run sdk:test
26
+ # or directly:
27
+ cd sdk && cargo test generation_conformance
20
28
  ```
21
29
 
22
- Byte-identical output with no diff = conformance. Run twice to verify determinism.
30
+ To regenerate `expected/` after changing conversion logic, run the CLI and commit the result:
31
+
32
+ ```bash
33
+ design-data migrate legacy-output <case>/input --output <case>/expected
34
+ ```
35
+
36
+ ## Cases
37
+
38
+ | Case | What it exercises |
39
+ | ------------------ | ----------------------------------------------------------------------------------------------------------- |
40
+ | `flat-token` | Basic flat token conversion (property key derivation, field passthrough) |
41
+ | `mode-set-token` | Color-set reconstruction from per-mode cascade records (`set_uuid`/`set_schema`) |
42
+ | `deprecated-token` | `deprecated: "version"` string → `true` boolean; `deprecated_comment` passthrough; `plannedRemoval` dropped |
43
+ | `renamed-token` | `replaced_by: "<uuid>"` → `renamed: "<property-name>"` via global UUID→name map |
44
+ | `alias-rewire` | `$ref: "<uuid>"` → `value: "{<property-name>}"` (alias denormalization with UUID resolution) |
45
+ | `mode-set-edit` | `deprecated`/`renamed` hoisted to outer set level when consistent across all mode entries |
23
46
 
24
47
  ## Cascade grouping fields (`set_uuid` / `set_schema`)
25
48
 
26
- The `mode-set-token` fixture input uses two cascade-internal grouping fields:
49
+ The `mode-set-token` and `mode-set-edit` fixtures use two cascade-internal grouping fields:
27
50
 
28
51
  | Field | Type | Role |
29
52
  | ------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,12 @@
1
+ {
2
+ "background": {
3
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
4
+ "value": "{gray-100}",
5
+ "uuid": "ffffffff-0001-4000-8000-000000000001"
6
+ },
7
+ "gray-100": {
8
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
9
+ "value": "rgb(255, 255, 255)",
10
+ "uuid": "ffffffff-0002-4000-8000-000000000002"
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "name": { "property": "color", "colorFamily": "background" },
4
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
5
+ "$ref": "ffffffff-0002-4000-8000-000000000002",
6
+ "uuid": "ffffffff-0001-4000-8000-000000000001"
7
+ },
8
+ {
9
+ "name": { "property": "color", "colorFamily": "gray-100" },
10
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
11
+ "value": "rgb(255, 255, 255)",
12
+ "uuid": "ffffffff-0002-4000-8000-000000000002"
13
+ }
14
+ ]
@@ -0,0 +1,9 @@
1
+ {
2
+ "red": {
3
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
4
+ "value": "rgb(255, 0, 0)",
5
+ "uuid": "dddddddd-0001-4000-8000-000000000001",
6
+ "deprecated": true,
7
+ "deprecated_comment": "Use color-blue-100 instead"
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ [
2
+ {
3
+ "name": { "property": "color", "colorFamily": "red" },
4
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
5
+ "value": "rgb(255, 0, 0)",
6
+ "uuid": "dddddddd-0001-4000-8000-000000000001",
7
+ "deprecated": "2.0",
8
+ "deprecated_comment": "Use color-blue-100 instead",
9
+ "plannedRemoval": "3.0"
10
+ }
11
+ ]
@@ -0,0 +1,25 @@
1
+ {
2
+ "accent-400": {
3
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
4
+ "uuid": "11111111-0003-4000-8000-000000000003",
5
+ "deprecated": true,
6
+ "sets": {
7
+ "light": {
8
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
9
+ "value": "rgb(20, 115, 230)",
10
+ "uuid": "11111111-0001-4000-8000-000000000001"
11
+ },
12
+ "dark": {
13
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
14
+ "value": "rgb(56, 145, 254)",
15
+ "uuid": "11111111-0002-4000-8000-000000000002"
16
+ }
17
+ },
18
+ "renamed": "accent-new-400"
19
+ },
20
+ "accent-new-400": {
21
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
22
+ "value": "rgb(20, 115, 230)",
23
+ "uuid": "11111111-0004-4000-8000-000000000004"
24
+ }
25
+ }
@@ -0,0 +1,40 @@
1
+ [
2
+ {
3
+ "name": {
4
+ "property": "color",
5
+ "colorFamily": "accent",
6
+ "scaleIndex": 400,
7
+ "colorScheme": "light"
8
+ },
9
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
10
+ "value": "rgb(20, 115, 230)",
11
+ "uuid": "11111111-0001-4000-8000-000000000001",
12
+ "set_uuid": "11111111-0003-4000-8000-000000000003",
13
+ "set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
14
+ "deprecated": true,
15
+ "replaced_by": "11111111-0004-4000-8000-000000000004"
16
+ },
17
+ {
18
+ "name": {
19
+ "property": "color",
20
+ "colorFamily": "accent",
21
+ "scaleIndex": 400,
22
+ "colorScheme": "dark"
23
+ },
24
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
25
+ "value": "rgb(56, 145, 254)",
26
+ "uuid": "11111111-0002-4000-8000-000000000002",
27
+ "set_uuid": "11111111-0003-4000-8000-000000000003",
28
+ "set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
29
+ "deprecated": true,
30
+ "replaced_by": "11111111-0004-4000-8000-000000000004"
31
+ },
32
+ {
33
+ "name": { "property": "color", "colorFamily": "accent-new-400" },
34
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
35
+ "value": "rgb(20, 115, 230)",
36
+ "uuid": "11111111-0004-4000-8000-000000000004",
37
+ "set_uuid": "11111111-0005-4000-8000-000000000005",
38
+ "set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json"
39
+ }
40
+ ]
@@ -0,0 +1,14 @@
1
+ {
2
+ "gray": {
3
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
4
+ "value": "rgb(128, 128, 128)",
5
+ "uuid": "eeeeeeee-0001-4000-8000-000000000001",
6
+ "deprecated": true,
7
+ "renamed": "neutral"
8
+ },
9
+ "neutral": {
10
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
11
+ "value": "rgb(128, 128, 128)",
12
+ "uuid": "eeeeeeee-0002-4000-8000-000000000002"
13
+ }
14
+ }
@@ -0,0 +1,16 @@
1
+ [
2
+ {
3
+ "name": { "property": "color", "colorFamily": "gray" },
4
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
5
+ "value": "rgb(128, 128, 128)",
6
+ "uuid": "eeeeeeee-0001-4000-8000-000000000001",
7
+ "deprecated": true,
8
+ "replaced_by": "eeeeeeee-0002-4000-8000-000000000002"
9
+ },
10
+ {
11
+ "name": { "property": "color", "colorFamily": "neutral" },
12
+ "$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
13
+ "value": "rgb(128, 128, 128)",
14
+ "uuid": "eeeeeeee-0002-4000-8000-000000000002"
15
+ }
16
+ ]
@@ -0,0 +1,25 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "component": "accordion",
6
+ "property": "space-between",
7
+ "from": "top",
8
+ "to": "banana"
9
+ },
10
+ "value": "8px"
11
+ }
12
+ ],
13
+ "components": [
14
+ {
15
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/accordion.json",
16
+ "name": "accordion",
17
+ "displayName": "Accordion",
18
+ "meta": {
19
+ "category": "containers",
20
+ "documentationUrl": "https://spectrum.adobe.com/page/accordion/"
21
+ },
22
+ "anatomy": [{ "name": "handle", "description": "Drag handle." }]
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "layer": 2,
3
+ "errors": [
4
+ {
5
+ "rule_id": "SPEC-047",
6
+ "severity": "error",
7
+ "message_pattern": ".*space-between endpoint.*banana.*"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "tokens": [],
3
+ "components": [
4
+ {
5
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/menu.json",
6
+ "name": "menu",
7
+ "displayName": "Menu",
8
+ "meta": {
9
+ "category": "collections",
10
+ "documentationUrl": "https://spectrum.adobe.com/page/menu/"
11
+ },
12
+ "anatomy": [
13
+ {
14
+ "name": "menu-item",
15
+ "description": "A single row within the menu.",
16
+ "contains": ["item-checkbox"]
17
+ }
18
+ ]
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "layer": 2,
3
+ "errors": [
4
+ {
5
+ "rule_id": "SPEC-048",
6
+ "severity": "warning",
7
+ "message_pattern": ".*menu-item.*item-checkbox.*"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "component": "accordion",
6
+ "property": "space-between",
7
+ "from": "bottom",
8
+ "to": "handle"
9
+ },
10
+ "value": "8px"
11
+ }
12
+ ],
13
+ "components": [
14
+ {
15
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/accordion.json",
16
+ "name": "accordion",
17
+ "displayName": "Accordion",
18
+ "meta": {
19
+ "category": "containers",
20
+ "documentationUrl": "https://spectrum.adobe.com/page/accordion/"
21
+ },
22
+ "anatomy": [{ "name": "handle", "description": "Drag handle." }]
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "tokens": [],
3
+ "components": [
4
+ {
5
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/menu.json",
6
+ "name": "menu",
7
+ "displayName": "Menu",
8
+ "meta": {
9
+ "category": "collections",
10
+ "documentationUrl": "https://spectrum.adobe.com/page/menu/"
11
+ },
12
+ "anatomy": [
13
+ {
14
+ "name": "menu-item",
15
+ "description": "A single row within the menu.",
16
+ "contains": ["item-icon", "item-label"]
17
+ },
18
+ { "name": "item-icon", "description": "Leading icon of a menu item." },
19
+ { "name": "item-label", "description": "Label text of a menu item." }
20
+ ]
21
+ }
22
+ ]
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/design-data-spec",
3
- "version": "2.6.0",
3
+ "version": "2.8.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
@@ -527,3 +527,36 @@ rules:
527
527
  message: "Guideline '{name}' references '{ref}' which is not a known component or guideline"
528
528
  spec_ref: spec/guideline-format.md#related-references
529
529
  introduced_in: "1.0.0-draft"
530
+
531
+ - id: SPEC-047
532
+ name: space-between-endpoint-valid
533
+ severity: error
534
+ layer: 2
535
+ category: reference-integrity
536
+ assert: >
537
+ A token name-object with `property` "space-between" MUST carry both `from` and
538
+ `to` fields, and `from`/`to` MUST NOT appear unless `property` is "space-between".
539
+ Each of `from`/`to` MUST be one of: an edge position (`positions.json`), a generic
540
+ anatomy term (`anatomy-terms.json`), or — when `component` is present and declares
541
+ an `anatomy` array — the `name` of a declared anatomy part on that component.
542
+ Mirrors SPEC-020's component→anatomy resolution, unioned with the position and
543
+ generic-anatomy vocabularies.
544
+ message: "Token '{token}' has space-between endpoint '{endpoint}' that is not a known position, anatomy term, or declared anatomy part on component '{component}'"
545
+ spec_ref: spec/token-format.md#space-between-endpoints
546
+ introduced_in: "1.0.0-draft"
547
+
548
+ - id: SPEC-048
549
+ name: anatomy-contains-resolves
550
+ severity: warning
551
+ layer: 2
552
+ category: completeness
553
+ assert: >
554
+ Each string in an anatomy part's `contains` array SHOULD match the `name` of
555
+ another anatomy part declared on the same component. Unresolved references are
556
+ advisory rather than an error: `contains` may legitimately point at sub-component
557
+ anatomy in layered designs (anatomy-format.md#contains), so this rule only warns
558
+ when a `contains` entry cannot be resolved against the same component's declared
559
+ parts.
560
+ message: "Anatomy part '{part}' on component '{component}' contains '{child}', which is not a declared anatomy part on this component"
561
+ spec_ref: spec/anatomy-format.md#contains
562
+ introduced_in: "1.0.0-draft"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/anatomy-part.schema.json",
4
4
  "title": "Anatomy part declaration",
5
- "description": "Layer 1 structural schema for a single anatomy part object within a component declaration. Semantic rules (component-anatomy-valid, anatomy-custom-part-documented, anatomy-part-name-unique, anatomy-requires-component) are Layer 2.",
5
+ "description": "Layer 1 structural schema for a single anatomy part object within a component declaration. Semantic rules (component-anatomy-valid, anatomy-custom-part-documented, anatomy-part-name-unique, anatomy-requires-component, anatomy-contains-resolves) are Layer 2.",
6
6
  "type": "object",
7
7
  "required": ["name"],
8
8
  "properties": {
@@ -28,7 +28,7 @@
28
28
  "pattern": "^[a-z][a-z0-9-]*$"
29
29
  },
30
30
  "uniqueItems": true,
31
- "description": "Informative list of child anatomy part names nested within this part. Does not carry enforcement semantics."
31
+ "description": "List of child anatomy part names nested within this part. SHOULD reference a `name` declared elsewhere in the same component's anatomy array; unresolved references are permitted (they may point at sub-component anatomy in layered designs) but rule anatomy-contains-resolves fires an advisory warning."
32
32
  },
33
33
  "documentBlocks": {
34
34
  "type": "array",
@@ -225,7 +225,7 @@
225
225
  "contains": {
226
226
  "type": "array",
227
227
  "items": { "type": "string" },
228
- "description": "Informative: anatomy part names nested within this part."
228
+ "description": "Anatomy part names nested within this part. SHOULD reference a `name` declared elsewhere in this component's anatomy array (see anatomy-contains-resolves)."
229
229
  },
230
230
  "documentBlocks": {
231
231
  "type": "array",
@@ -79,6 +79,11 @@
79
79
  "enum": ["string", "integer"],
80
80
  "description": "Type of the field value. Default: 'string'.",
81
81
  "default": "string"
82
+ },
83
+ "excludeFromLegacyKey": {
84
+ "type": "boolean",
85
+ "description": "When true, this field is omitted from legacy key generation in naming.rs. Opt-in: absence means false. Use for mode-set selectors, color-domain fields, and legacy-annotation fields that must not appear in the serialized token name.",
86
+ "default": false
82
87
  }
83
88
  },
84
89
  "additionalProperties": false
@@ -51,6 +51,10 @@
51
51
  "type": "string",
52
52
  "description": "Semantic: interactive or semantic state (e.g. hover, focus, disabled)."
53
53
  },
54
+ "qualifier": {
55
+ "type": "string",
56
+ "description": "Semantic: behavioral or layout modifier that narrows a property/anatomy without being a state, variant, or position (e.g. stacked, multiline, precision, collapsed, expanded, drag, highlight)."
57
+ },
54
58
  "orientation": {
55
59
  "type": "string",
56
60
  "description": "Semantic: direction or order (e.g. vertical, horizontal)."
@@ -71,6 +75,18 @@
71
75
  "type": "string",
72
76
  "description": "Semantic: overall component shape (e.g. uniform)."
73
77
  },
78
+ "role": {
79
+ "type": "string",
80
+ "description": "Semantic: an object's role within a nesting relationship (e.g. container, control), distinct from `size`."
81
+ },
82
+ "from": {
83
+ "type": "string",
84
+ "description": "Semantic: starting endpoint of a space-between measurement (e.g. top, edge, text). Paired with `to`; used with property `space-between`."
85
+ },
86
+ "to": {
87
+ "type": "string",
88
+ "description": "Semantic: ending endpoint of a space-between measurement (e.g. text, visual, control). Paired with `from`; used with property `space-between`."
89
+ },
74
90
  "colorScheme": {
75
91
  "type": "string",
76
92
  "description": "Mode set: color scheme mode (e.g. light, dark, wireframe)."
@@ -82,6 +98,11 @@
82
98
  "contrast": {
83
99
  "type": "string",
84
100
  "description": "Mode set: contrast level (e.g. regular, high)."
101
+ },
102
+ "legacyKey": {
103
+ "type": "string",
104
+ "minLength": 1,
105
+ "description": "Escape hatch: pins the exact flat key written to legacy output (packages/tokens/src), overriding reconstruction from the rest of this name object. Use when correcting or extending a token's decomposition would otherwise change its published legacy key."
85
106
  }
86
107
  },
87
108
  "additionalProperties": {
@@ -46,11 +46,13 @@ When `required` is `true`, the anatomy part is unconditionally rendered (e.g. a
46
46
 
47
47
  ### `contains`
48
48
 
49
- **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
+ **OPTIONAL.** A list of child anatomy part `name` values that are visually or structurally nested within this part.
50
50
 
51
- **RECOMMENDED:** When a part logically encloses other declared anatomy parts, authors **SHOULD** use `contains` to make the nesting explicit.
51
+ **RECOMMENDED:** When a part logically encloses other declared anatomy parts, authors **SHOULD** use `contains` to make the nesting explicit, rather than declaring the children only as flat, unrelated parts.
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
+ 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 a reference that cannot be resolved against the same component's declared parts triggers an advisory warning (rule SPEC-048, `anatomy-contains-resolves`) — it is not an error.
54
+
55
+ **Authoring convention — flat vs. nested:** declare a part as a flat leaf when it has no meaningful internal sub-structure of its own (e.g. `label`, `icon`). Declare a part with `contains` when it is a composite that visually groups other declared parts (e.g. a `menu-item` row containing an `icon` and a `label`, or a `list-item` row containing a `checkbox`, `thumbnail`, and `label`). Prefer the canonical vocabulary (below) for children where the semantics match, falling back to a documented custom name (SPEC-023) otherwise.
54
56
 
55
57
  ### `lifecycle`
56
58
 
@@ -135,6 +137,7 @@ The following rules in the Layer 2 rule catalog (`rules/rules.yaml`) apply to an
135
137
  | SPEC-025 | `anatomy-requires-component` | error | A token name object **MUST NOT** include an `anatomy` field unless a `component` field is also present. |
136
138
  | 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
139
  | 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. |
140
+ | SPEC-048 | `anatomy-contains-resolves` | warning | An anatomy part's `contains` entries **SHOULD** match the `name` of another part declared on the same component. Advisory warning for unresolved entries. |
138
141
 
139
142
  ## Full example
140
143
 
package/spec/taxonomy.md CHANGED
@@ -73,6 +73,7 @@ The following concept categories are defined in Spectrum's foundation field cata
73
73
  | Size | `size` | When/Why? | Relative terms used to create relationships and patterns of usage across multiple tokens and token types. |
74
74
  | Density | `density` | When/Why? | Options that create more or less space within or around the parts of a component. |
75
75
  | Shape | `shape` | When/Why? | Relative to the overall shape of a component (e.g. "uniform" creates a 1:1 padding ratio between horizontal and vertical padding). |
76
+ | Role | `role` | When/Why? | An object's role within a nesting relationship (e.g. `container`, `control`), distinct from `size` — e.g. corner-radius tokens where a container and its nested control each need an independently-scaled rounding step. |
76
77
 
77
78
  Additional categories for variant and state are inherited from the existing name object:
78
79
 
@@ -70,7 +70,27 @@ The table below lists all semantic fields. Fields marked with a scope are domain
70
70
  | `size` | OPTIONAL | Size | Relative t-shirt sizing for relationships across tokens (e.g. `small`, `medium`, `large`). |
71
71
  | `density` | OPTIONAL | Density | Space within or around component parts (e.g. `spacious`, `compact`). |
72
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`. |
73
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
+
78
+ #### Space-between endpoints
79
+
80
+ A token whose `property` is **`space-between`** represents the spacing between two named endpoints (e.g. an edge and an anatomy part, or two anatomy parts) and **MUST** carry both the `from` and `to` fields; conversely, `from`/`to` **MUST NOT** appear unless `property` is `space-between` (rule `SPEC-047`).
81
+
82
+ Each of `from`/`to` **MUST** be one of:
83
+
84
+ * an edge position from `registry/positions.json` (e.g. `top`, `bottom`, `start`, `end`, `affixed`);
85
+ * a generic anatomy term from `registry/anatomy-terms.json` (e.g. `text`, `icon`, `label`);
86
+ * when `component` is present and declares an `anatomy` array, the `name` of a declared anatomy part on that component (e.g. `handle` on `accordion`).
87
+
88
+ ```json
89
+ { "name": { "component": "accordion", "property": "space-between", "from": "bottom", "to": "handle" },
90
+ "value": "8px" }
91
+ ```
92
+
93
+ The `space-between` property term does not itself appear in the serialized legacy key; the key is reconstructed from the endpoints as `{component}-{from}-to-{to}` (e.g. `accordion-bottom-to-handle`).
74
94
 
75
95
  **Domain-scoped semantic fields** (only valid on the indicated token type):
76
96