@adobe/design-data-spec 1.1.0 → 1.3.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.
@@ -0,0 +1,29 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "component": "widget",
6
+ "style": "ghost",
7
+ "property": "background-color"
8
+ },
9
+ "value": "#0265dc"
10
+ }
11
+ ],
12
+ "components": [
13
+ {
14
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/widget.json",
15
+ "name": "widget",
16
+ "displayName": "Widget",
17
+ "meta": {
18
+ "category": "actions",
19
+ "documentationUrl": "https://spectrum.adobe.com/page/widget/"
20
+ },
21
+ "options": {
22
+ "style": {
23
+ "type": "enum",
24
+ "values": [{ "value": "fill" }, { "value": "outline" }]
25
+ }
26
+ }
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "layer": 2,
3
+ "errors": [
4
+ {
5
+ "rule_id": "SPEC-040",
6
+ "severity": "warning",
7
+ "message_pattern": ".*style.*ghost.*"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "tokens": [
3
+ {
4
+ "name": {
5
+ "component": "widget",
6
+ "style": "fill",
7
+ "property": "background-color"
8
+ },
9
+ "value": "#0265dc"
10
+ },
11
+ {
12
+ "name": {
13
+ "component": "widget",
14
+ "style": "outline",
15
+ "property": "border-color"
16
+ },
17
+ "value": "#0265dc"
18
+ }
19
+ ],
20
+ "components": [
21
+ {
22
+ "$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/components/widget.json",
23
+ "name": "widget",
24
+ "displayName": "Widget",
25
+ "meta": {
26
+ "category": "actions",
27
+ "documentationUrl": "https://spectrum.adobe.com/page/widget/"
28
+ },
29
+ "options": {
30
+ "style": {
31
+ "type": "enum",
32
+ "values": [{ "value": "fill" }, { "value": "outline" }]
33
+ }
34
+ }
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "layer": 2,
3
+ "errors": []
4
+ }
@@ -4,7 +4,7 @@
4
4
  "name": "property",
5
5
  "description": "The stylistic attribute being defined (e.g. color, width, padding, gap). The only required field on every name object.",
6
6
  "kind": "semantic",
7
- "registry": null,
7
+ "registry": "packages/design-system-registry/registry/property-terms.json",
8
8
  "validation": "advisory",
9
9
  "serialization": {
10
10
  "position": 6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/design-data-spec",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Design Data Specification — prose, JSON Schemas, rule catalog, and conformance fixtures for Spectrum design data",
5
5
  "type": "module",
6
6
  "repository": {
package/rules/rules.yaml CHANGED
@@ -398,3 +398,41 @@ rules:
398
398
  message: "Manifest {array}[{idx}] failed to parse as a query: {error}"
399
399
  spec_ref: spec/manifest.md#include--exclude
400
400
  introduced_in: "1.0.0-draft"
401
+
402
+ - id: SPEC-040
403
+ name: component-option-field-valid
404
+ severity: warning
405
+ layer: 2
406
+ category: component
407
+ rfc: "#806"
408
+ assert: >
409
+ For every token whose name object contains a key that is not a reserved name-object field
410
+ and that matches a declared component.options.<key> with a values[] list, the token's value
411
+ MUST appear in that values[] list. Reserved fields (component, variant, state, anatomy,
412
+ property, colorScheme, scale, contrast, uuid, object, category) are excluded; variant is
413
+ owned by SPEC-019. This rule generalises SPEC-019 to all remaining option-enum fields
414
+ (style, size, staticColor, etc.) at advisory severity.
415
+ message: "Token '{token}' has {field} '{value}' which is not declared on component '{component}'"
416
+ spec_ref: spec/component-format.md#options
417
+ introduced_in: "1.0.0-draft"
418
+
419
+ - id: SPEC-041
420
+ name: mode-set-restriction-coverage
421
+ severity: error
422
+ layer: 2
423
+ category: completeness
424
+ rfc: "#806"
425
+ assert: >
426
+ When a manifest declares modeSetRestrictions, every token group (tokens sharing the same
427
+ non-mode-set name object fields) MUST have at least one candidate that survives ALL
428
+ restrictions simultaneously — i.e. at least one token whose name object either omits
429
+ each restricted mode set field (wildcard) or sets it to an allowed mode value for every
430
+ restriction. Restrictions are applied as a conjunction (matching cascade step 0), so a
431
+ group that satisfies each restriction individually but has no single token satisfying
432
+ all restrictions at once is also a coverage gap.
433
+ Sub-checks: (a) a modeSetRestrictions key that names an unknown mode set MUST emit a
434
+ Warning; (b) an allowed list that excludes the mode set's declared default MUST emit
435
+ an Error, since the resolver would return None for the default context on that platform.
436
+ message: "Token group '{base_name}' has no resolvable candidate under manifest mode-set restrictions ({restrictions})"
437
+ spec_ref: spec/mode-sets.md#platform-restrictions
438
+ introduced_in: "1.0.0-draft"
@@ -62,6 +62,27 @@
62
62
  ]
63
63
  }
64
64
  },
65
+ "modeSetRestrictions": {
66
+ "type": "object",
67
+ "description": "Restricts the valid mode values for each named mode set on this platform. Keys are mode set names; values declare which modes are allowed.",
68
+ "additionalProperties": {
69
+ "type": "object",
70
+ "required": ["allowed"],
71
+ "properties": {
72
+ "allowed": {
73
+ "type": "array",
74
+ "items": {
75
+ "type": "string",
76
+ "minLength": 1
77
+ },
78
+ "minItems": 1,
79
+ "uniqueItems": true,
80
+ "description": "Allowed mode values for this mode set. Must be a subset of the mode set's declared modes and must include the mode set's default."
81
+ }
82
+ },
83
+ "additionalProperties": false
84
+ }
85
+ },
65
86
  "extensions": {
66
87
  "type": "object",
67
88
  "description": "Platform-local tokens, mode sets, and formatting rules.",
package/spec/cascade.md CHANGED
@@ -41,6 +41,7 @@ A **resolution context** is a set of mode set key/value pairs (e.g. `colorScheme
41
41
 
42
42
  The following outline is **RECOMMENDED** for conforming resolvers:
43
43
 
44
+ 0. If the manifest declares `modeSetRestrictions`, **drop any candidate** whose name object sets a mode set field to a value not in the manifest’s `allowed` list for that mode set. Candidates that omit a restricted mode set field (wildcard) are **not** dropped. See [Mode Sets — Platform restrictions](mode-sets.md#platform-restrictions).
44
45
  1. Collect all token candidates whose name object **matches** the context (every specified mode set in the context equals the name object’s mode set field, or the name object omits that mode set where omission means “matches any” per mode set rules).
45
46
  2. Filter to candidates at or below the requested layer.
46
47
  3. Select the maximum **layer** precedence.
@@ -110,7 +110,7 @@ Each entry in `values` is an object:
110
110
 
111
111
  **NORMATIVE:** Boolean option names **MUST** begin with `is` or `has` (e.g. `isDisabled`, `hasIcon`).
112
112
 
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.
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, Error). Token name-object keys matching any other declared option's `values` list **SHOULD** be drawn from that list (rule SPEC-040, Warning). Both rules are silent when no `values` array is declared for the option.
114
114
 
115
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
116
 
@@ -314,17 +314,18 @@ The `context` field is informative. It is used by `describe_component` (Phase 8
314
314
 
315
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).
316
316
 
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. |
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. |
328
+ | SPEC-040 | `component-option-field-valid` | warning | Token name-object keys that match a declared `options.<key>` with a `values[]` list **SHOULD** use a value drawn from that list. Generalises SPEC-019 to non-`variant` option fields (e.g. `style`, `size`, `staticColor`). Advisory; silent when no `values` declared. |
328
329
 
329
330
  ## Full example
330
331
 
package/spec/manifest.md CHANGED
@@ -17,12 +17,13 @@ A manifest **MUST** conform to [`manifest.schema.json`](../schemas/manifest.sche
17
17
 
18
18
  ## Optional fields
19
19
 
20
- | Field | Type | Description |
21
- | ------------ | --------------- | -------------------------------------------------------------------------------- |
22
- | `include` | array of string | Semantic **queries** selecting subsets of foundation tokens to materialize. |
23
- | `exclude` | array of string | Queries removing tokens from the included set. |
24
- | `overrides` | array of object | Typed overrides; each entry **MUST** preserve the target token’s **value type**. |
25
- | `extensions` | object | New tokens or mode sets introduced at the platform layer. |
20
+ | Field | Type | Description |
21
+ | --------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------- |
22
+ | `include` | array of string | Semantic **queries** selecting subsets of foundation tokens to materialize. |
23
+ | `exclude` | array of string | Queries removing tokens from the included set. |
24
+ | `overrides` | array of object | Typed overrides; each entry **MUST** preserve the target token’s **value type**. |
25
+ | `extensions` | object | New tokens or mode sets introduced at the platform layer. |
26
+ | `modeSetRestrictions` | object | Mode set restrictions for this platform; see [Mode Sets — Platform restrictions](mode-sets.md#platform-restrictions). |
26
27
 
27
28
  ### `include` / `exclude`
28
29
 
package/spec/mode-sets.md CHANGED
@@ -57,8 +57,25 @@ Additional mode sets (e.g. `language`, `motion`) **MAY** be declared in a datase
57
57
 
58
58
  **RECOMMENDED:** Explicit **combination** tokens are used for rare cross-mode-set cases instead of inferring Cartesian products.
59
59
 
60
+ ## Platform restrictions
61
+
62
+ A platform manifest **MAY** declare which mode values are valid for a given mode set on that platform. This allows a platform (e.g. iOS) to express that it only supports a subset of modes (e.g. `colorScheme: light`, not `dark`).
63
+
64
+ **NORMATIVE:** A manifest's `modeSetRestrictions` value **MUST** be an object whose keys are mode set names declared in the dataset. Each value **MUST** be an object with a required `allowed` array of mode value strings. Every mode value in `allowed` **MUST** be a member of the named mode set's `modes`. The mode set's `default` **MUST** be included in `allowed`.
65
+
66
+ ### Resolution semantics
67
+
68
+ **NORMATIVE:** At resolution time, any token candidate whose name object sets a mode set field to a value **not** in the manifest's `allowed` list for that mode set **MUST** be filtered out before specificity tie-breaking. Tokens whose name object **omits** a restricted mode set field (wildcard) are **not** affected.
69
+
70
+ This is a pre-filter step, inserted at the start of the [resolution algorithm](cascade.md#resolution-algorithm-informative-outline) before step 1 (context matching).
71
+
72
+ ### Coverage validation
73
+
74
+ **NORMATIVE:** Validators implementing rule **`SPEC-041`** (`mode-set-restriction-coverage`) **MUST** report an error when a platform manifest's mode set restrictions leave a token group with no resolvable candidate — i.e. every token sharing the same non-mode-set name object fields references a restricted mode value, with no wildcard or allowed-mode alternative available. See `rules/rules.yaml` for the full rule definition.
75
+
60
76
  ## References
61
77
 
62
78
  * [#646 — Token Schema Structure and Validation System](https://github.com/adobe/spectrum-design-data/discussions/646)
63
79
  * [#714 — Design Data Specification](https://github.com/adobe/spectrum-design-data/discussions/714)
64
80
  * [#746 — Phase 2: Mode Set declarations (machine-readable)](https://github.com/adobe/spectrum-design-data/issues/746)
81
+ * [#943 — RFC #806: platform mode-set restriction behavior](https://github.com/adobe/spectrum-design-data/issues/943)
package/spec/taxonomy.md CHANGED
@@ -54,21 +54,21 @@ Concept categories for name-object fields are declared in the design system's **
54
54
 
55
55
  The following concept categories are defined in Spectrum's foundation field catalog for semantic and layout tokens, ordered by default serialization position. This ordering is the **default serialization order** for legacy format output; it is not a conformance requirement for stored name objects.
56
56
 
57
- **NORMATIVE:** Each category listed below corresponds to an OPTIONAL field on the token [name object](token-format.md). Tokens **MAY** use any subset of these fields.
58
-
59
- | Category | Name object field | Answers | Description |
60
- | ------------- | ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
61
- | Structure | `structure` | What? | Individual objects or object categories that have shared styling. Distinctly different from "components" in that they represent structures and visual patterns that can or do occur across many varieties of components. |
62
- | Sub-structure | `substructure` | What? | A structure within an element that should only exist within the context of its parent structure. |
63
- | Component | `component` | What? | Component scope when the token is component-scoped. |
64
- | Anatomy | `anatomy` | What? | A visible, named part of a component as defined by designers. |
65
- | Object | `object` | Where? | The styling surface to which a visual property is applied (e.g. background, border, edge). |
66
- | Property | `property` | Where? | The stylistic attribute being defined (e.g. color, width, padding, gap). |
67
- | Orientation | `orientation` | When/Why? | The direction or order of structures and elements within a component or pattern. |
68
- | Position | `position` | When/Why? | The location of an object relative to another, with or without respect to directional order. |
69
- | Size | `size` | When/Why? | Relative terms used to create relationships and patterns of usage across multiple tokens and token types. |
70
- | Density | `density` | When/Why? | Options that create more or less space within or around the parts of a component. |
71
- | 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). |
57
+ **NORMATIVE:** Each category listed below corresponds to a field on the token [name object](token-format.md). Tokens **MAY** use any subset of these fields. Exception: `property` is REQUIRED on every name object — see [token-format.md](token-format.md#name-object).
58
+
59
+ | Category | Name object field | Answers | Description |
60
+ | ------------- | ----------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
+ | Structure | `structure` | What? | Individual objects or object categories that have shared styling. Distinctly different from "components" in that they represent structures and visual patterns that can or do occur across many varieties of components. |
62
+ | Sub-structure | `substructure` | What? | A structure within an element that should only exist within the context of its parent structure. |
63
+ | Component | `component` | What? | Component scope when the token is component-scoped. |
64
+ | Anatomy | `anatomy` | What? | A visible, named part of a component as defined by designers. |
65
+ | Object | `object` | Where? | The styling surface to which a visual property is applied (e.g. background, border, edge). |
66
+ | Property | `property` | Where? | The CSS/styling attribute or design-system abstraction being defined (e.g. color, width, padding, gap). REQUIRED — see exception in preamble. Values SHOULD come from [`property-terms.json`](../../packages/design-system-registry/registry/property-terms.json). Anatomy parts and styling surfaces do NOT belong here — they belong in `anatomy` and `object` respectively. See [token-format.md — Name-object migration policy](token-format.md#name-object-migration-policy) for migration guidance. |
67
+ | Orientation | `orientation` | When/Why? | The direction or order of structures and elements within a component or pattern. |
68
+ | Position | `position` | When/Why? | The location of an object relative to another, with or without respect to directional order. |
69
+ | Size | `size` | When/Why? | Relative terms used to create relationships and patterns of usage across multiple tokens and token types. |
70
+ | Density | `density` | When/Why? | Options that create more or less space within or around the parts of a component. |
71
+ | 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). |
72
72
 
73
73
  Additional categories for variant and state are inherited from the existing name object:
74
74
 
@@ -147,6 +147,43 @@ When migrating legacy-format tokens to cascade:
147
147
 
148
148
  **RECOMMENDED:** Root token documents (when stored as standalone JSON files) include `specVersion` with const `1.0.0-draft` for self-identification. Embedded tokens inside larger files **MAY** omit it if the parent document carries version metadata.
149
149
 
150
+ ### Name-object migration policy
151
+
152
+ This section defines the normative policy for migrating tokens from string-form names to structured name objects, and for narrowing the `property` field to its intended CSS/styling-attribute semantics.
153
+
154
+ #### String-name escape hatch — SPEC-017 severity schedule
155
+
156
+ String-named tokens (see [String-name escape hatch](#string-name-escape-hatch)) trigger SPEC-017 at **`warning`** severity through the current minor series. Authors **SHOULD** treat SPEC-017 warnings as actionable tech debt and maintain a remediation backlog (e.g. `packages/tokens/naming-exceptions.json`).
157
+
158
+ **NORMATIVE:** SPEC-017 **MUST** graduate from `warning` to `error` at spec version `2.0.0`, no earlier than two minor versions after the minor release that ships this section. This conforms to the [evolution policy](evolution.md) — rule severity tightening is a major change.
159
+
160
+ No string-named token may remain in a conforming dataset after the `2.0.0` cut without first being converted to a structured name object or removed.
161
+
162
+ #### Narrowed `property` semantics
163
+
164
+ The `property` field on a name object is the **CSS/styling attribute or design-system abstraction** being defined — not an anatomy part, not a styling surface, and not a legacy compound name string. Not all valid values are CSS property identifiers; design-system abstractions (e.g. `padding-horizontal`, `overlay-color`, `size`) are permitted.
165
+
166
+ **NORMATIVE:** Values for `property` **SHOULD** come from the [`property-terms`](../../packages/design-system-registry/registry/property-terms.json) registry. Non-registry values emit an advisory warning (SPEC-009 applied to the `property` field).
167
+
168
+ Examples of **valid** `property` values: `color`, `background-color`, `border-radius`, `font-size`, `gap`, `opacity`.
169
+
170
+ Examples of **invalid** `property` values (migration debt):
171
+
172
+ * Anatomy parts — use the `anatomy` field instead (`handle`, `icon`, `label`).
173
+ * Styling surfaces — use the `object` field instead (`background`, `border`, `edge`).
174
+ * Legacy compound names — split into structured fields (`focus-ring-color-key-focus` → `component + anatomy + object + property + state`).
175
+
176
+ #### Author migration guidance
177
+
178
+ When converting a string-named token to a structured name object:
179
+
180
+ 1. Parse the legacy name string into its constituent segments using the [default serialization order](taxonomy.md#default-serialization-legacy-format).
181
+ 2. Place the CSS/styling attribute in `property` (SHOULD be in `property-terms.json`).
182
+ 3. Route anatomy parts to `anatomy` (validated against `anatomy-terms.json`).
183
+ 4. Route styling surfaces (background, border, edge) to `object` (validated against `token-objects.json`).
184
+ 5. Retain component, variant, state, and other structural fields as-is.
185
+ 6. Remove the token from `naming-exceptions.json` after conversion.
186
+
150
187
  ## Document shape
151
188
 
152
189
  Cascade-format tokens are stored in **JSON files** that conform to [`cascade-file.schema.json`](../schemas/cascade-file.schema.json) (canonical `$id`: `https://opensource.adobe.com/spectrum-design-data/schemas/v0/cascade-file.schema.json`).