@adobe/design-data-spec 4.1.0 → 4.2.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/conformance/manifest-extensions/README.md +4 -1
- package/conformance/manifest-extensions/invalid/mode-set-missing-default/expected-errors.json +7 -0
- package/conformance/manifest-extensions/invalid/mode-set-missing-default/extensions/mode-sets/broken.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-missing-default/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/mode-set-remove-mode-of-default/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/mode-set-remove-mode-of-default/extensions/mode-sets/remove-desktop.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-remove-mode-of-default/extensions/mode-sets/scale.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-remove-mode-of-default/manifest.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-set-default-nonmember/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/mode-set-set-default-nonmember/extensions/mode-sets/default-tv.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-set-default-nonmember/extensions/mode-sets/scale.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-set-default-nonmember/manifest.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-target-not-found/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/mode-set-target-not-found/extensions/mode-sets/add-tv.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-target-not-found/manifest.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-unknown-op/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/mode-set-unknown-op/extensions/mode-sets/bogus.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-unknown-op/extensions/mode-sets/scale.json +1 -0
- package/conformance/manifest-extensions/invalid/mode-set-unknown-op/manifest.json +1 -0
- package/conformance/manifest-extensions/valid/injects-mode-set/expected.json +1 -0
- package/conformance/manifest-extensions/valid/injects-mode-set/extensions/mode-sets/interface-level.json +5 -0
- package/conformance/manifest-extensions/valid/injects-mode-set/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/mode-set-add-mode/expected.json +8 -0
- package/conformance/manifest-extensions/valid/mode-set-add-mode/extensions/mode-sets/add-tv.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-add-mode/extensions/mode-sets/scale.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-add-mode/manifest.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove/expected.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove/extensions/mode-sets/contrast.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove/extensions/mode-sets/remove-contrast.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove/manifest.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove-mode/expected.json +8 -0
- package/conformance/manifest-extensions/valid/mode-set-remove-mode/extensions/mode-sets/color-scheme.json +5 -0
- package/conformance/manifest-extensions/valid/mode-set-remove-mode/extensions/mode-sets/remove-wireframe.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-remove-mode/manifest.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-set-default/expected.json +6 -0
- package/conformance/manifest-extensions/valid/mode-set-set-default/extensions/mode-sets/default-tv.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-set-default/extensions/mode-sets/scale.json +1 -0
- package/conformance/manifest-extensions/valid/mode-set-set-default/manifest.json +1 -0
- package/package.json +1 -1
- package/spec/manifest.md +61 -18
- package/spec/mode-sets.md +10 -0
|
@@ -4,7 +4,7 @@ Exercises the Layer 2 platform manifest's `extensions/` **directory** loader
|
|
|
4
4
|
(`packages/design-data-spec/spec/manifest.md#extensions-directory`): a sibling
|
|
5
5
|
`extensions/` tree (or a custom name via the manifest's `extensionsDir` field)
|
|
6
6
|
whose category subdirectories (`tokens/`, `components/`, `fields/`,
|
|
7
|
-
`guidelines/`, `platform-extensions/`, `relationships/`) are discovered,
|
|
7
|
+
`guidelines/`, `mode-sets/`, `platform-extensions/`, `relationships/`) are discovered,
|
|
8
8
|
glob+merged in sorted path order, per-fragment schema-validated, and spliced
|
|
9
9
|
into the manifest before it's applied to the graph.
|
|
10
10
|
|
|
@@ -23,6 +23,7 @@ into the manifest before it's applied to the graph.
|
|
|
23
23
|
},
|
|
24
24
|
"components": { "present": ["tab-bar-ios"] },
|
|
25
25
|
"fields": { "present": ["hapticStyle"] },
|
|
26
|
+
"modeSets": { "present": ["interfaceLevel"] },
|
|
26
27
|
"guidelines": { "present": ["ios-haptics"] },
|
|
27
28
|
"tokens": { "orderByUuid": ["<uuid-1>", "<uuid-2>"] }
|
|
28
29
|
}
|
|
@@ -42,6 +43,7 @@ Rust SDK drives these fixtures in `sdk/core/src/lib.rs` via the
|
|
|
42
43
|
| `valid/injects-platform-extension` | A `platform-extensions/` fragment is injected. |
|
|
43
44
|
| `valid/injects-field` | A `fields/` fragment is injected. |
|
|
44
45
|
| `valid/injects-guideline` | A `guidelines/` fragment is injected. |
|
|
46
|
+
| `valid/injects-mode-set` | A `mode-sets/` fragment is injected (declare-or-replace by name). |
|
|
45
47
|
| `valid/injects-relationship` | A `relationships/` plain-add fragment is injected. |
|
|
46
48
|
| `valid/override-relationship-by-uuid` | An `op: "override"` entry replaces a plain add sharing its `uuid`, regardless of file sort order. |
|
|
47
49
|
| `valid/plain-add-uuid-collision-append` | Two plain adds sharing a `uuid` both append rather than one overwriting the other. |
|
|
@@ -55,6 +57,7 @@ Rust SDK drives these fixtures in `sdk/core/src/lib.rs` via the
|
|
|
55
57
|
| `invalid/component-missing-name` | A `components/` fragment missing `name` fails Layer 1 fragment schema validation. |
|
|
56
58
|
| `invalid/field-invalid-kind` | A `fields/` fragment with an invalid `kind` enum value fails schema validation. |
|
|
57
59
|
| `invalid/guideline-invalid-category` | A `guidelines/` fragment with an invalid `category` enum value fails schema validation. |
|
|
60
|
+
| `invalid/mode-set-missing-default` | A `mode-sets/` fragment missing the required `default` field fails Layer 1 fragment schema validation. |
|
|
58
61
|
| `invalid/platform-extension-missing-extends` | A `platform-extensions/` fragment missing `extends` fails schema validation. |
|
|
59
62
|
| `invalid/token-invalid-uuid` | A `tokens/*.tokens.json` fragment with a malformed `uuid` fails schema validation. |
|
|
60
63
|
| `invalid/relationship-missing-scope` | A `relationships/` plain-add fragment missing `scope` fails schema validation. |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "interfaceLevel", "modes": ["base", "elevated"] }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "removeMode", "mode": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "modes": ["desktop", "mobile"], "default": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "setDefault", "default": "tv" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "modes": ["desktop", "mobile"], "default": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "addMode", "mode": "tv" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
package/conformance/manifest-extensions/invalid/mode-set-unknown-op/extensions/mode-sets/bogus.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "bogus" }
|
package/conformance/manifest-extensions/invalid/mode-set-unknown-op/extensions/mode-sets/scale.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "modes": ["desktop", "mobile"], "default": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "modeSets": { "present": ["interfaceLevel"] } }
|
package/conformance/manifest-extensions/valid/mode-set-add-mode/extensions/mode-sets/add-tv.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "addMode", "mode": "tv" }
|
package/conformance/manifest-extensions/valid/mode-set-add-mode/extensions/mode-sets/scale.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "modes": ["desktop", "mobile"], "default": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "modeSets": { "absent": ["contrast"] } }
|
package/conformance/manifest-extensions/valid/mode-set-remove/extensions/mode-sets/contrast.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "contrast", "modes": ["regular", "high"], "default": "regular" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "contrast", "op": "remove" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "colorScheme", "op": "removeMode", "mode": "wireframe" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "op": "setDefault", "default": "tv" }
|
package/conformance/manifest-extensions/valid/mode-set-set-default/extensions/mode-sets/scale.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "scale", "modes": ["desktop", "mobile", "tv"], "default": "desktop" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "specVersion": "1.0.0-draft", "foundationVersion": "1.0.0" }
|
package/package.json
CHANGED
package/spec/manifest.md
CHANGED
|
@@ -8,23 +8,25 @@ This document defines the **platform manifest**: how a platform implementation r
|
|
|
8
8
|
|
|
9
9
|
The manifest supports a fixed, enumerated set of operations against the foundation — it does **not** allow overriding, aliasing, or removing arbitrary foundation artifacts. Support is concentrated on tokens; translations and schemas have no manifest-level override mechanism at all.
|
|
10
10
|
|
|
11
|
-
| Operation
|
|
12
|
-
|
|
|
13
|
-
| Remove / exclude
|
|
14
|
-
| Include / whitelist
|
|
15
|
-
| Override value (type-preserving)
|
|
16
|
-
| Override → re-alias
|
|
17
|
-
| Add new tokens (may alias via `$ref`)
|
|
18
|
-
| Add / replace components
|
|
19
|
-
| Add / replace field declarations
|
|
20
|
-
| Add / replace guideline documents
|
|
21
|
-
|
|
|
22
|
-
| Add / remove
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
11
|
+
| Operation | Supported? | Field | Applies to |
|
|
12
|
+
| --------------------------------------------------- | ------------------------------------------------------------ | --------------------------------- | --------------------- |
|
|
13
|
+
| Remove / exclude | Yes | `exclude` | Tokens only |
|
|
14
|
+
| Include / whitelist | Yes | `include` | Tokens only |
|
|
15
|
+
| Override value (type-preserving) | Yes | `overrides[].value` | Tokens only |
|
|
16
|
+
| Override → re-alias | Yes | `overrides[].$ref` | Tokens only |
|
|
17
|
+
| Add new tokens (may alias via `$ref`) | Yes | `extensions/tokens/` | Tokens |
|
|
18
|
+
| Add / replace components | Yes | `extensions/components/` | Components |
|
|
19
|
+
| Add / replace field declarations | Yes | `extensions/fields/` | Fields |
|
|
20
|
+
| Add / replace guideline documents | Yes | `extensions/guidelines/` | Guidelines |
|
|
21
|
+
| Declare / replace platform-local mode set | Yes | `extensions/mode-sets/` | Mode sets |
|
|
22
|
+
| Add / remove / retarget a single mode; remove a set | Yes | `extensions/mode-sets/` (`op`) | Mode sets |
|
|
23
|
+
| Add relationships/CTRs; override/remove by `uuid` | Yes | `extensions/relationships/` | Relationships (CTRs) |
|
|
24
|
+
| Add / remove naming exceptions | Yes | `namingExceptions` | Naming validation |
|
|
25
|
+
| Annotate existing terminology (cannot add new ids) | Yes | `extensions/platform-extensions/` | Existing registry ids |
|
|
26
|
+
| Restrict allowed mode-set values | Yes | `modeSetRestrictions` | Mode sets |
|
|
27
|
+
| Reformat name serialization | Schema-declared only, not yet applied by the reference SDK | `formatting` | Token name strings |
|
|
28
|
+
| Override/remove/alias translations | No | — | — |
|
|
29
|
+
| Override Layer-1 schemas | No (decided; see [spike](manifest-schema-override-spike.md)) | — | — |
|
|
28
30
|
|
|
29
31
|
## Manifest document
|
|
30
32
|
|
|
@@ -86,6 +88,7 @@ extensions/
|
|
|
86
88
|
tokens/ *.tokens.json cascade-format token files
|
|
87
89
|
components/ <component>.json one component per file
|
|
88
90
|
fields/ <field>.json one field declaration per file
|
|
91
|
+
mode-sets/ <mode-set>.json one mode set per file
|
|
89
92
|
relationships/ <component>.json one CTR set per file
|
|
90
93
|
guidelines/ <topic>.json one guideline per file
|
|
91
94
|
platform-extensions/ <platform>-<registry>.json
|
|
@@ -103,7 +106,7 @@ or empty subdirectory contributes nothing and is not an error.
|
|
|
103
106
|
cascade token file) and **MUST** validate against `cascade-file.schema.json`. Files are
|
|
104
107
|
**deep-merged** into one tokens object, in sorted path order. Entries **MAY** carry a `$ref`
|
|
105
108
|
to alias an existing token instead of a literal value.
|
|
106
|
-
* **`components/`, `fields/`, `guidelines/`, `platform-extensions/`** — one artifact per file.
|
|
109
|
+
* **`components/`, `fields/`, `guidelines/`, `mode-sets/`, `platform-extensions/`** — one artifact per file.
|
|
107
110
|
Entries across all files in the subdirectory are concatenated, in sorted path order, and
|
|
108
111
|
injected into the corresponding catalog **add-or-replace by name** (for
|
|
109
112
|
`platform-extensions/`, by `termId`; see below). When two files declare the same name,
|
|
@@ -115,6 +118,7 @@ load time — this is enforced reference-SDK behavior, not an aspirational goal:
|
|
|
115
118
|
* **`components/`** → `component.schema.json`
|
|
116
119
|
* **`fields/`** → `field.schema.json` (see [`extensions/fields/`](#extensionsfields) below)
|
|
117
120
|
* **`guidelines/`** → `guideline.schema.json`
|
|
121
|
+
* **`mode-sets/`** → `mode-set.schema.json` (see [`extensions/mode-sets/`](#extensionsmode-sets) below)
|
|
118
122
|
* **`relationships/`** → `relationship.schema.json` (see the Add/Override/remove rules above)
|
|
119
123
|
* **`platform-extensions/`** → `platform-extension.json` (see
|
|
120
124
|
[`extensions/platform-extensions/`](#extensionsplatform-extensions) below)
|
|
@@ -143,6 +147,45 @@ declared) references field names by string — a platform that renames or remove
|
|
|
143
147
|
also references there is self-inconsistent; that is a manifest-authoring concern, not enforced
|
|
144
148
|
by the reference SDK.
|
|
145
149
|
|
|
150
|
+
#### `extensions/mode-sets/`
|
|
151
|
+
|
|
152
|
+
Platform-local mode-set declarations and edits, injected into the mode-set catalog for this
|
|
153
|
+
platform's resolution. A mode set's `name` is its stable key (there is no separate `uuid`, unlike
|
|
154
|
+
relationships) — every entry, add or op alike, identifies its target by `name`:
|
|
155
|
+
|
|
156
|
+
* **Add / replace:** an entry with no `op` field is a full mode-set object (**NORMATIVE:** MUST
|
|
157
|
+
validate against `mode-set.schema.json`, requiring `name`, `modes`, `default`). A `name` not
|
|
158
|
+
already in the foundation catalog is a clean new platform axis (e.g. `interfaceLevel: [base,
|
|
159
|
+
elevated]`); a `name` matching a foundation mode set replaces it, for this platform only — the
|
|
160
|
+
foundation catalog is untouched.
|
|
161
|
+
* **`"op": "addMode"`** — appends one mode value (`mode`) to an existing set, without restating its
|
|
162
|
+
other modes. **NORMATIVE:** the target set (by `name`) MUST already exist and MUST NOT already
|
|
163
|
+
contain `mode`; either condition failing is a manifest error.
|
|
164
|
+
* **`"op": "removeMode"`** — drops one mode value (`mode`) from an existing set. **NORMATIVE:** the
|
|
165
|
+
target MUST exist, MUST contain `mode`, `mode` MUST NOT be the set's current default (retarget the
|
|
166
|
+
default first with `setDefault`), the set MUST have more than one mode remaining afterward, and no
|
|
167
|
+
token in the resolved graph MAY still carry `mode` as that mode set's value — each violation is a
|
|
168
|
+
manifest error. (This mirrors the reference SDK's authoring-time `remove_mode` guard, which checks
|
|
169
|
+
the same "still referenced" condition against cascade token files.)
|
|
170
|
+
* **`"op": "setDefault"`** — retargets an existing set's default mode (`default`). **NORMATIVE:**
|
|
171
|
+
the target MUST exist and `default` MUST already be one of its modes.
|
|
172
|
+
* **`"op": "remove"`** — drops the whole set (by `name`) from this platform's resolution.
|
|
173
|
+
**NORMATIVE:** the target MUST exist, and no token in the resolved graph MAY still carry this mode
|
|
174
|
+
set's `name` as a key — either violation is a manifest error.
|
|
175
|
+
|
|
176
|
+
Add/replace entries are applied before op entries, regardless of file sort order, so a set declared
|
|
177
|
+
in one file can be edited by an op in another file within the same `extensions/mode-sets/`
|
|
178
|
+
directory. Ops within each group apply in sorted path order. Any other `op` value, or an op entry
|
|
179
|
+
missing its required field (`mode` for `addMode`/`removeMode`, `default` for `setDefault`), is a
|
|
180
|
+
manifest error — the reference SDK rejects the load rather than silently skipping it, consistent
|
|
181
|
+
with `extensions/relationships/`'s override/remove ops above. `default ∈ modes` remains a Layer 2
|
|
182
|
+
concern for the resolved graph as a whole, enforced by SPEC-005 against whichever mode sets end up
|
|
183
|
+
there, foundation or platform-declared alike.
|
|
184
|
+
|
|
185
|
+
Contrast with `modeSetRestrictions` ([Mode Sets — Platform restrictions](mode-sets.md#platform-restrictions)), a top-level manifest field that only *narrows* the allowed values of an
|
|
186
|
+
existing mode set at resolution time — it cannot add, remove, or retarget a mode value, or declare
|
|
187
|
+
a new axis.
|
|
188
|
+
|
|
146
189
|
#### `extensions/platform-extensions/`
|
|
147
190
|
|
|
148
191
|
Platform terminology annotations layered onto **existing** foundation registry entries (for
|
package/spec/mode-sets.md
CHANGED
|
@@ -45,6 +45,16 @@ The Spectrum foundation publishes mode set declarations as JSON files under `pac
|
|
|
45
45
|
|
|
46
46
|
Additional mode sets (e.g. `language`, `motion`) **MAY** be declared in a dataset's mode set catalog. Token name objects **MAY** include keys matching declared mode set names.
|
|
47
47
|
|
|
48
|
+
A platform manifest **MAY** also declare or edit mode sets local to that platform, one entry per
|
|
49
|
+
file under `extensions/mode-sets/` (see [Platform manifest — `extensions/`
|
|
50
|
+
directory](manifest.md#extensions-directory)). An entry with no `op` uses **declare-or-replace-by-name** semantics, same as `extensions/fields/`: a new `name` adds a platform-local axis (e.g.
|
|
51
|
+
`interfaceLevel`), while a `name` matching a foundation mode set replaces it for that platform only,
|
|
52
|
+
leaving the foundation catalog untouched. `op: "addMode"` / `"removeMode"` / `"setDefault"` /
|
|
53
|
+
`"remove"` instead edit an existing set in place — adding or dropping a single mode value,
|
|
54
|
+
retargeting its default, or dropping the whole set — without restating its other modes. This is
|
|
55
|
+
distinct from `modeSetRestrictions` (below), which only *narrows* the allowed values of an existing
|
|
56
|
+
mode set at resolution time rather than editing the declared set itself.
|
|
57
|
+
|
|
48
58
|
## Defaults and specificity
|
|
49
59
|
|
|
50
60
|
**NORMATIVE:** A token name object **omitting** a mode set field implies the token applies under the mode set's **`default`** mode for specificity and matching purposes unless the spec for that mode set states otherwise.
|