@adobe/design-data-spec 4.4.0 → 4.5.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 +47 -31
- package/conformance/manifest-extensions/base/dataset.json +36 -3
- package/conformance/manifest-extensions/invalid/implementations-remove-no-match/expected-errors.json +10 -0
- package/conformance/manifest-extensions/invalid/implementations-remove-no-match/extensions/implementations/button.json +9 -0
- package/conformance/manifest-extensions/invalid/implementations-remove-no-match/manifest.json +5 -0
- package/conformance/manifest-extensions/invalid/implementations-row-missing-reference/expected-errors.json +7 -0
- package/conformance/manifest-extensions/invalid/implementations-row-missing-reference/extensions/implementations/button.json +9 -0
- package/conformance/manifest-extensions/invalid/implementations-row-missing-reference/manifest.json +5 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-component/expected-errors.json +10 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-component/extensions/implementations/nope.json +12 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-component/manifest.json +5 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-op/expected-errors.json +7 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-op/extensions/implementations/button.json +9 -0
- package/conformance/manifest-extensions/invalid/implementations-unknown-op/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/implementations-later-file-wins/expected.json +19 -0
- package/conformance/manifest-extensions/valid/implementations-later-file-wins/extensions/implementations/a-button.json +11 -0
- package/conformance/manifest-extensions/valid/implementations-later-file-wins/extensions/implementations/b-button.json +11 -0
- package/conformance/manifest-extensions/valid/implementations-later-file-wins/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/implementations-other-owner-untouched/expected.json +26 -0
- package/conformance/manifest-extensions/valid/implementations-other-owner-untouched/extensions/implementations/button.json +18 -0
- package/conformance/manifest-extensions/valid/implementations-other-owner-untouched/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/implementations-platform-local-component/expected.json +12 -0
- package/conformance/manifest-extensions/valid/implementations-platform-local-component/extensions/components/tab-bar-ios.json +9 -0
- package/conformance/manifest-extensions/valid/implementations-platform-local-component/extensions/implementations/tab-bar-ios.json +10 -0
- package/conformance/manifest-extensions/valid/implementations-platform-local-component/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/implementations-remove-row/expected.json +11 -0
- package/conformance/manifest-extensions/valid/implementations-remove-row/extensions/implementations/button.json +10 -0
- package/conformance/manifest-extensions/valid/implementations-remove-row/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/implementations-upsert-foundation-row/expected.json +19 -0
- package/conformance/manifest-extensions/valid/implementations-upsert-foundation-row/extensions/implementations/button.json +12 -0
- package/conformance/manifest-extensions/valid/implementations-upsert-foundation-row/manifest.json +5 -0
- package/package.json +2 -1
- package/schemas/component.schema.json +8 -3
- package/schemas/implementation-mapping.schema.json +69 -0
- package/spec/component-format.md +40 -19
- package/spec/manifest.md +71 -19
|
@@ -4,12 +4,14 @@ 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/`, `mode-sets/`, `platform-extensions/`, `relationships
|
|
7
|
+
`guidelines/`, `mode-sets/`, `platform-extensions/`, `relationships/`,
|
|
8
|
+
`implementations/`) are discovered,
|
|
8
9
|
glob+merged in sorted path order, per-fragment schema-validated, and spliced
|
|
9
10
|
into the manifest before it's applied to the graph.
|
|
10
11
|
|
|
11
12
|
* `base/dataset.json` — a shared minimal seed graph (three foundation tokens:
|
|
12
|
-
`btn-bg`, `btn-fg`, `chk-bg` on the `button`/`checkbox` components
|
|
13
|
+
`btn-bg`, `btn-fg`, `chk-bg` on the `button`/`checkbox` components, plus a
|
|
14
|
+
foundation `button` component with two default `implementations` rows), loaded
|
|
13
15
|
once per case before that case's `manifest.json` is applied via
|
|
14
16
|
`apply_configured`.
|
|
15
17
|
* `valid/<case>/` — `manifest.json` + an `extensions/` (or custom-named) tree
|
|
@@ -19,13 +21,18 @@ into the manifest before it's applied to the graph.
|
|
|
19
21
|
{
|
|
20
22
|
"relationships": {
|
|
21
23
|
"byUuid": { "<uuid>": { "count": 1, "value": "8px" } },
|
|
22
|
-
"absent": ["<uuid>"]
|
|
24
|
+
"absent": ["<uuid>"],
|
|
23
25
|
},
|
|
24
26
|
"components": { "present": ["tab-bar-ios"] },
|
|
25
27
|
"fields": { "present": ["hapticStyle"] },
|
|
26
28
|
"modeSets": { "present": ["interfaceLevel"] },
|
|
27
29
|
"guidelines": { "present": ["ios-haptics"] },
|
|
28
|
-
"tokens": { "orderByUuid": ["<uuid-1>", "<uuid-2>"] }
|
|
30
|
+
"tokens": { "orderByUuid": ["<uuid-1>", "<uuid-2>"] },
|
|
31
|
+
"implementations": {
|
|
32
|
+
"<component>": [
|
|
33
|
+
/* exact merged rows */
|
|
34
|
+
],
|
|
35
|
+
},
|
|
29
36
|
}
|
|
30
37
|
```
|
|
31
38
|
A case that only needs to prove "loads clean" uses `{}`.
|
|
@@ -37,30 +44,39 @@ Rust SDK drives these fixtures in `sdk/core/src/lib.rs` via the
|
|
|
37
44
|
`manifest_extensions_conformance` (pass/fail + error message matching) and
|
|
38
45
|
`manifest_extensions_behavior` (post-apply graph predicates) test modules.
|
|
39
46
|
|
|
40
|
-
| Case
|
|
41
|
-
|
|
|
42
|
-
| `valid/injects-component`
|
|
43
|
-
| `valid/injects-platform-extension`
|
|
44
|
-
| `valid/injects-field`
|
|
45
|
-
| `valid/injects-guideline`
|
|
46
|
-
| `valid/injects-mode-set`
|
|
47
|
-
| `valid/injects-relationship`
|
|
48
|
-
| `valid/override-relationship-by-uuid`
|
|
49
|
-
| `valid/plain-add-uuid-collision-append`
|
|
50
|
-
| `valid/remove-relationship-by-uuid`
|
|
51
|
-
| `valid/tokens-sorted-order`
|
|
52
|
-
| `valid/later-file-wins`
|
|
53
|
-
| `valid/custom-extensions-dir`
|
|
54
|
-
| `valid/override-entry-skips-schema-validation`
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `invalid/
|
|
61
|
-
| `invalid/
|
|
62
|
-
| `invalid/
|
|
63
|
-
| `invalid/
|
|
64
|
-
| `invalid/
|
|
65
|
-
| `invalid/
|
|
66
|
-
| `invalid/
|
|
47
|
+
| Case | Intent |
|
|
48
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `valid/injects-component` | A `components/` fragment is injected as a Platform-layer component. |
|
|
50
|
+
| `valid/injects-platform-extension` | A `platform-extensions/` fragment is injected. |
|
|
51
|
+
| `valid/injects-field` | A `fields/` fragment is injected. |
|
|
52
|
+
| `valid/injects-guideline` | A `guidelines/` fragment is injected. |
|
|
53
|
+
| `valid/injects-mode-set` | A `mode-sets/` fragment is injected (declare-or-replace by name). |
|
|
54
|
+
| `valid/injects-relationship` | A `relationships/` plain-add fragment is injected. |
|
|
55
|
+
| `valid/override-relationship-by-uuid` | An `op: "override"` entry replaces a plain add sharing its `uuid`, regardless of file sort order. |
|
|
56
|
+
| `valid/plain-add-uuid-collision-append` | Two plain adds sharing a `uuid` both append rather than one overwriting the other. |
|
|
57
|
+
| `valid/remove-relationship-by-uuid` | An `op: "remove"` entry deletes the matching relationship. |
|
|
58
|
+
| `valid/tokens-sorted-order` | Multiple `tokens/*.tokens.json` files concatenate in sorted path order. |
|
|
59
|
+
| `valid/later-file-wins` | Two `components/` fragments declaring the same component name dedupe to one, later file wins. |
|
|
60
|
+
| `valid/custom-extensions-dir` | The manifest's `extensionsDir` field is honored in place of the default `extensions/` name. |
|
|
61
|
+
| `valid/override-entry-skips-schema-validation` | An `op: "override"` relationship entry is not schema-validated against `relationship.schema.json` (only plain adds are). |
|
|
62
|
+
| `valid/implementations-upsert-foundation-row` | An `implementations/` row replaces the foundation default sharing its `importPath` and is stamped with the manifest `platform`. |
|
|
63
|
+
| `valid/implementations-later-file-wins` | Two fragments upserting the same stamped row dedupe by `implementation` id; the later file wins. |
|
|
64
|
+
| `valid/implementations-remove-row` | An `op: "remove"` selector deletes the matching foundation default. |
|
|
65
|
+
| `valid/implementations-platform-local-component` | A fragment may target a component added by the same manifest's `components/`. |
|
|
66
|
+
| `valid/implementations-other-owner-untouched` | A row stamped with a different `implementation` id is never matched by another owner's upsert. |
|
|
67
|
+
| `invalid/override-missing-uuid` | An `op: "override"` relationship entry missing `uuid` fails loudly. |
|
|
68
|
+
| `invalid/unknown-term-id` | A `platform-extensions/` fragment referencing a non-existent `termId` fails loudly. |
|
|
69
|
+
| `invalid/component-missing-name` | A `components/` fragment missing `name` fails Layer 1 fragment schema validation. |
|
|
70
|
+
| `invalid/field-invalid-kind` | A `fields/` fragment with an invalid `kind` enum value fails schema validation. |
|
|
71
|
+
| `invalid/guideline-invalid-category` | A `guidelines/` fragment with an invalid `category` enum value fails schema validation. |
|
|
72
|
+
| `invalid/mode-set-missing-default` | A `mode-sets/` fragment missing the required `default` field fails Layer 1 fragment schema validation. |
|
|
73
|
+
| `invalid/platform-extension-missing-extends` | A `platform-extensions/` fragment missing `extends` fails schema validation. |
|
|
74
|
+
| `invalid/token-invalid-uuid` | A `tokens/*.tokens.json` fragment with a malformed `uuid` fails schema validation. |
|
|
75
|
+
| `invalid/relationship-missing-scope` | A `relationships/` plain-add fragment missing `scope` fails schema validation. |
|
|
76
|
+
| `invalid/extensions-dir-parent-traversal` | `extensionsDir` containing a `..` component is rejected. |
|
|
77
|
+
| `invalid/extensions-dir-absolute-path` | An absolute `extensionsDir` path is rejected. |
|
|
78
|
+
| `invalid/unknown-subdir-name` | An unrecognized subdirectory directly under `extensions/` (not one of the known categories) is rejected by name. |
|
|
79
|
+
| `invalid/implementations-unknown-component` | An `implementations/` fragment naming a component absent from the catalog fails loudly. |
|
|
80
|
+
| `invalid/implementations-remove-no-match` | An `op: "remove"` matching no owned row fails loudly. |
|
|
81
|
+
| `invalid/implementations-row-missing-reference` | A row with neither `package` nor `importPath` fails schema validation. |
|
|
82
|
+
| `invalid/implementations-unknown-op` | An `op` other than `"remove"` fails schema validation. |
|
|
@@ -2,21 +2,54 @@
|
|
|
2
2
|
"tokens": [
|
|
3
3
|
{
|
|
4
4
|
"key": "btn-bg",
|
|
5
|
-
"name": {
|
|
5
|
+
"name": {
|
|
6
|
+
"property": "background-color",
|
|
7
|
+
"component": "button"
|
|
8
|
+
},
|
|
6
9
|
"value": "#aaa",
|
|
7
10
|
"uuid": "u-btn-bg"
|
|
8
11
|
},
|
|
9
12
|
{
|
|
10
13
|
"key": "btn-fg",
|
|
11
|
-
"name": {
|
|
14
|
+
"name": {
|
|
15
|
+
"property": "color",
|
|
16
|
+
"component": "button"
|
|
17
|
+
},
|
|
12
18
|
"value": "#111",
|
|
13
19
|
"uuid": "u-btn-fg"
|
|
14
20
|
},
|
|
15
21
|
{
|
|
16
22
|
"key": "chk-bg",
|
|
17
|
-
"name": {
|
|
23
|
+
"name": {
|
|
24
|
+
"property": "background-color",
|
|
25
|
+
"component": "checkbox"
|
|
26
|
+
},
|
|
18
27
|
"value": "#bbb",
|
|
19
28
|
"uuid": "u-chk-bg"
|
|
20
29
|
}
|
|
30
|
+
],
|
|
31
|
+
"components": [
|
|
32
|
+
{
|
|
33
|
+
"$id": "https://example.com/components/button",
|
|
34
|
+
"name": "button",
|
|
35
|
+
"displayName": "Button",
|
|
36
|
+
"meta": {
|
|
37
|
+
"category": "actions",
|
|
38
|
+
"documentationUrl": "https://example.com"
|
|
39
|
+
},
|
|
40
|
+
"implementations": [
|
|
41
|
+
{
|
|
42
|
+
"platform": "web",
|
|
43
|
+
"componentName": "Button",
|
|
44
|
+
"package": "@react-spectrum/s2"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"platform": "web",
|
|
48
|
+
"componentName": "Button",
|
|
49
|
+
"importPath": "@adobe/spectrum-wc/components/button",
|
|
50
|
+
"notes": "Spectrum 2 web component custom element: swc-button."
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
21
54
|
]
|
|
22
55
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"implementations": {
|
|
3
|
+
"button": [
|
|
4
|
+
{
|
|
5
|
+
"platform": "web",
|
|
6
|
+
"componentName": "Button",
|
|
7
|
+
"package": "@react-spectrum/s2",
|
|
8
|
+
"notes": "second",
|
|
9
|
+
"implementation": "react-spectrum"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"platform": "web",
|
|
13
|
+
"componentName": "Button",
|
|
14
|
+
"importPath": "@adobe/spectrum-wc/components/button",
|
|
15
|
+
"notes": "Spectrum 2 web component custom element: swc-button."
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
package/conformance/manifest-extensions/valid/implementations-other-owner-untouched/expected.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"implementations": {
|
|
3
|
+
"button": [
|
|
4
|
+
{
|
|
5
|
+
"platform": "web",
|
|
6
|
+
"componentName": "Button",
|
|
7
|
+
"package": "@react-spectrum/s2",
|
|
8
|
+
"implementation": "react-spectrum",
|
|
9
|
+
"notes": "declared by another owner"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"platform": "web",
|
|
13
|
+
"componentName": "Button",
|
|
14
|
+
"importPath": "@adobe/spectrum-wc/components/button",
|
|
15
|
+
"notes": "Spectrum 2 web component custom element: swc-button."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"platform": "web",
|
|
19
|
+
"componentName": "Button",
|
|
20
|
+
"package": "@react-spectrum/s2",
|
|
21
|
+
"implementation": "web-components",
|
|
22
|
+
"notes": "web-components row with the same package"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"component": "button",
|
|
3
|
+
"implementations": [
|
|
4
|
+
{
|
|
5
|
+
"platform": "web",
|
|
6
|
+
"componentName": "Button",
|
|
7
|
+
"package": "@react-spectrum/s2",
|
|
8
|
+
"implementation": "react-spectrum",
|
|
9
|
+
"notes": "declared by another owner"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"platform": "web",
|
|
13
|
+
"componentName": "Button",
|
|
14
|
+
"package": "@react-spectrum/s2",
|
|
15
|
+
"notes": "web-components row with the same package"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/conformance/manifest-extensions/valid/implementations-upsert-foundation-row/expected.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"implementations": {
|
|
3
|
+
"button": [
|
|
4
|
+
{
|
|
5
|
+
"platform": "web",
|
|
6
|
+
"componentName": "Button",
|
|
7
|
+
"package": "@react-spectrum/s2"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"platform": "web",
|
|
11
|
+
"componentName": "Button",
|
|
12
|
+
"package": "@adobe/spectrum-wc",
|
|
13
|
+
"importPath": "@adobe/spectrum-wc/components/button",
|
|
14
|
+
"notes": "Custom element: swc-button.",
|
|
15
|
+
"implementation": "web-components"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/design-data-spec",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.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": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"./schemas/manifest.schema.json": "./schemas/manifest.schema.json",
|
|
27
27
|
"./schemas/value-types/color.schema.json": "./schemas/value-types/color.schema.json",
|
|
28
28
|
"./schemas/component.schema.json": "./schemas/component.schema.json",
|
|
29
|
+
"./schemas/implementation-mapping.schema.json": "./schemas/implementation-mapping.schema.json",
|
|
29
30
|
"./schemas/anatomy-part.schema.json": "./schemas/anatomy-part.schema.json",
|
|
30
31
|
"./schemas/state-declaration.schema.json": "./schemas/state-declaration.schema.json",
|
|
31
32
|
"./rules/rules.yaml": "./rules/rules.yaml",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"items": {
|
|
43
43
|
"$ref": "#/$defs/implementation"
|
|
44
44
|
},
|
|
45
|
-
"description": "Known platform implementations of this component. Foundation
|
|
45
|
+
"description": "Known platform implementations of this component. Foundation data carries canonical default mappings; a platform manifest refines its own rows through extensions/implementations/. See spec/component-format.md#implementations."
|
|
46
46
|
},
|
|
47
47
|
"options": {
|
|
48
48
|
"$ref": "#/$defs/optionsMap"
|
|
@@ -115,6 +115,11 @@
|
|
|
115
115
|
"minLength": 1,
|
|
116
116
|
"description": "Target platform identifier (for example, 'web', 'ios', or 'android'). Multiple implementations may target the same platform when they have distinct packages."
|
|
117
117
|
},
|
|
118
|
+
"implementation": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
121
|
+
"description": "Implementation project id from the platform-implementations registry (for example, 'react-spectrum' or 'web-components'). Distinguishes implementations that share a `platform` device target. A platform manifest stamps its own `platform` id here when merging extensions/implementations/ entries that omit it."
|
|
122
|
+
},
|
|
118
123
|
"componentName": {
|
|
119
124
|
"type": "string",
|
|
120
125
|
"minLength": 1,
|
|
@@ -123,7 +128,7 @@
|
|
|
123
128
|
"importPath": {
|
|
124
129
|
"type": "string",
|
|
125
130
|
"minLength": 1,
|
|
126
|
-
"description": "Importable module or source path for a platform implementation."
|
|
131
|
+
"description": "Importable module or source path for a platform implementation. When `package` is also set, this SHOULD be a subpath export of that package."
|
|
127
132
|
},
|
|
128
133
|
"package": {
|
|
129
134
|
"type": "string",
|
|
@@ -135,7 +140,7 @@
|
|
|
135
140
|
"description": "Optional implementation-specific usage or mapping notes."
|
|
136
141
|
}
|
|
137
142
|
},
|
|
138
|
-
"
|
|
143
|
+
"anyOf": [
|
|
139
144
|
{
|
|
140
145
|
"required": ["importPath"]
|
|
141
146
|
},
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/implementation-mapping.schema.json",
|
|
4
|
+
"title": "Platform implementation mapping",
|
|
5
|
+
"description": "Layer 1 schema for one platform manifest extensions/implementations/ fragment: the platform's own implementation rows for a single component, merged into that component's `implementations` array. See spec/manifest.md#extensionsimplementations.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["component", "implementations"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri"
|
|
12
|
+
},
|
|
13
|
+
"component": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
16
|
+
"description": "Name of the component (foundation or platform-local) whose `implementations` this fragment refines."
|
|
17
|
+
},
|
|
18
|
+
"implementations": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"minItems": 1,
|
|
21
|
+
"items": {
|
|
22
|
+
"if": {
|
|
23
|
+
"required": ["op"]
|
|
24
|
+
},
|
|
25
|
+
"then": {
|
|
26
|
+
"$ref": "#/$defs/removeEntry"
|
|
27
|
+
},
|
|
28
|
+
"else": {
|
|
29
|
+
"$ref": "component.schema.json#/$defs/implementation"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"description": "Rows to upsert (implementation objects) or remove (`op: \"remove\"` selectors), applied in order."
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"$defs": {
|
|
37
|
+
"removeEntry": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"description": "Removes every existing row of the component whose fields equal each selector field given here.",
|
|
40
|
+
"required": ["op", "componentName"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"op": {
|
|
43
|
+
"const": "remove"
|
|
44
|
+
},
|
|
45
|
+
"platform": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"minLength": 1
|
|
48
|
+
},
|
|
49
|
+
"implementation": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"pattern": "^[a-z][a-z0-9-]*$"
|
|
52
|
+
},
|
|
53
|
+
"componentName": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"minLength": 1
|
|
56
|
+
},
|
|
57
|
+
"package": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"minLength": 1
|
|
60
|
+
},
|
|
61
|
+
"importPath": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"minLength": 1
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"additionalProperties": false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
package/spec/component-format.md
CHANGED
|
@@ -84,30 +84,40 @@ where `{name}` matches the component's `name` field.
|
|
|
84
84
|
## Implementations
|
|
85
85
|
|
|
86
86
|
`implementations` declares the published platform implementations corresponding
|
|
87
|
-
to this design-system component
|
|
88
|
-
|
|
89
|
-
without platform-specific configuration.
|
|
87
|
+
to this design-system component, so consumers such as Code Connect generators
|
|
88
|
+
can resolve an implementation without platform-specific configuration.
|
|
90
89
|
|
|
91
|
-
Each entry **MUST** contain `platform` and `componentName`, plus
|
|
92
|
-
implementation reference: `package` for a published package or
|
|
93
|
-
for an importable module
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
Each entry **MUST** contain `platform` and `componentName`, plus at least one
|
|
91
|
+
implementation reference: `package` for a published package and/or
|
|
92
|
+
`importPath` for an importable module or source path. When both are present,
|
|
93
|
+
`importPath` **SHOULD** be a subpath export of `package`. `notes` is optional
|
|
94
|
+
context for consumers.
|
|
95
|
+
|
|
96
|
+
`platform` is a device target (`web`, `ios`, `android`), so several
|
|
97
|
+
implementations may share it. The optional `implementation` field names the
|
|
98
|
+
implementation project from the platform-implementations registry (for example
|
|
99
|
+
`react-spectrum` or `web-components`) to tell them apart.
|
|
96
100
|
|
|
97
101
|
```json
|
|
98
102
|
"implementations": [
|
|
99
103
|
{
|
|
100
104
|
"platform": "web",
|
|
105
|
+
"implementation": "web-components",
|
|
101
106
|
"componentName": "Button",
|
|
102
|
-
"package": "@spectrum-
|
|
107
|
+
"package": "@adobe/spectrum-wc",
|
|
108
|
+
"importPath": "@adobe/spectrum-wc/components/button"
|
|
103
109
|
}
|
|
104
110
|
]
|
|
105
111
|
```
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
### Layering
|
|
114
|
+
|
|
115
|
+
Foundation component data carries canonical **default** rows. A platform
|
|
116
|
+
manifest refines its own rows through
|
|
117
|
+
[`extensions/implementations/`](manifest.md#extensionsimplementations):
|
|
118
|
+
upserting rows it owns and removing stale ones, without restating the rest of
|
|
119
|
+
the component. Rows owned by another implementation are left untouched, so the
|
|
120
|
+
merged catalog still lists every implementation of the component.
|
|
111
121
|
|
|
112
122
|
## Options
|
|
113
123
|
|
|
@@ -426,13 +436,18 @@ A complete button component declaration:
|
|
|
426
436
|
}
|
|
427
437
|
],
|
|
428
438
|
"anatomy": [
|
|
429
|
-
{ "name": "icon",
|
|
439
|
+
{ "name": "icon", "description": "Leading icon." },
|
|
430
440
|
{ "name": "label", "description": "Button text.", "required": true }
|
|
431
441
|
],
|
|
432
442
|
"states": [
|
|
433
|
-
{ "name": "hover",
|
|
434
|
-
{
|
|
435
|
-
|
|
443
|
+
{ "name": "hover", "trigger": "interaction", "precedence": 50 },
|
|
444
|
+
{
|
|
445
|
+
"name": "focus",
|
|
446
|
+
"trigger": "interaction",
|
|
447
|
+
"precedence": 60,
|
|
448
|
+
"layered": true
|
|
449
|
+
},
|
|
450
|
+
{ "name": "disabled", "trigger": "prop", "precedence": 100 }
|
|
436
451
|
],
|
|
437
452
|
"lifecycle": {
|
|
438
453
|
"introduced": "1.0.0-draft"
|
|
@@ -448,7 +463,10 @@ A complete button component declaration:
|
|
|
448
463
|
{
|
|
449
464
|
"name": "button",
|
|
450
465
|
"displayName": "Button",
|
|
451
|
-
"meta": {
|
|
466
|
+
"meta": {
|
|
467
|
+
"category": "actions",
|
|
468
|
+
"documentationUrl": "https://spectrum.adobe.com/page/button/"
|
|
469
|
+
},
|
|
452
470
|
"accessibility": {
|
|
453
471
|
"role": "button",
|
|
454
472
|
"intents": ["trigger"],
|
|
@@ -479,7 +497,10 @@ A complete button component declaration:
|
|
|
479
497
|
{
|
|
480
498
|
"name": "button",
|
|
481
499
|
"displayName": "Button",
|
|
482
|
-
"meta": {
|
|
500
|
+
"meta": {
|
|
501
|
+
"category": "actions",
|
|
502
|
+
"documentationUrl": "https://spectrum.adobe.com/page/button/"
|
|
503
|
+
},
|
|
483
504
|
"documentBlocks": [
|
|
484
505
|
{
|
|
485
506
|
"type": "purpose",
|
package/spec/manifest.md
CHANGED
|
@@ -8,25 +8,26 @@ 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 | 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
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
| Override
|
|
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
|
+
| Upsert / remove own implementation mappings | Yes | `extensions/implementations/` | Component `implementations` |
|
|
27
|
+
| Restrict allowed mode-set values | Yes | `modeSetRestrictions` | Mode sets |
|
|
28
|
+
| Reformat name serialization | Schema-declared only, not yet applied by the reference SDK | `formatting` | Token name strings |
|
|
29
|
+
| Override/remove/alias translations | No | — | — |
|
|
30
|
+
| Override Layer-1 schemas | No (decided; see [spike](manifest-schema-override-spike.md)) | — | — |
|
|
30
31
|
|
|
31
32
|
## Manifest document
|
|
32
33
|
|
|
@@ -112,6 +113,7 @@ extensions/
|
|
|
112
113
|
relationships/ <component>.json one CTR set per file
|
|
113
114
|
guidelines/ <topic>.json one guideline per file
|
|
114
115
|
platform-extensions/ <platform>-<registry>.json
|
|
116
|
+
implementations/ <component>.json one component's implementation rows
|
|
115
117
|
```
|
|
116
118
|
|
|
117
119
|
**NORMATIVE:** Each subdirectory is discovered by a recursive glob for `*.json` files (for
|
|
@@ -131,6 +133,9 @@ or empty subdirectory contributes nothing and is not an error.
|
|
|
131
133
|
injected into the corresponding catalog **add-or-replace by name** (for
|
|
132
134
|
`platform-extensions/`, by `termId`; see below). When two files declare the same name,
|
|
133
135
|
**the entry from the later file (in sorted path order) wins.**
|
|
136
|
+
* **`implementations/`** — one component's implementation rows per file, merged row-by-row into
|
|
137
|
+
that component's existing `implementations` array (never whole-array replaced). See
|
|
138
|
+
[`extensions/implementations/`](#extensionsimplementations) below.
|
|
134
139
|
|
|
135
140
|
**NORMATIVE:** Each fragment file **MUST** validate against its category's real JSON schema at
|
|
136
141
|
load time — this is enforced reference-SDK behavior, not an aspirational goal:
|
|
@@ -142,6 +147,8 @@ load time — this is enforced reference-SDK behavior, not an aspirational goal:
|
|
|
142
147
|
* **`relationships/`** → `relationship.schema.json` (see the Add/Override/remove rules above)
|
|
143
148
|
* **`platform-extensions/`** → `platform-extension.json` (see
|
|
144
149
|
[`extensions/platform-extensions/`](#extensionsplatform-extensions) below)
|
|
150
|
+
* **`implementations/`** → `implementation-mapping.schema.json` (see
|
|
151
|
+
[`extensions/implementations/`](#extensionsimplementations) below)
|
|
145
152
|
* **`tokens/`** → `cascade-file.schema.json` (see above)
|
|
146
153
|
|
|
147
154
|
A fragment that fails validation against its category schema is a manifest error — the
|
|
@@ -214,6 +221,51 @@ example, platform-specific state names). **NORMATIVE:** each file **MUST** valid
|
|
|
214
221
|
foundation registry — this mechanism annotates existing ids, it does **NOT** introduce new
|
|
215
222
|
ones.
|
|
216
223
|
|
|
224
|
+
#### `extensions/implementations/`
|
|
225
|
+
|
|
226
|
+
Platform-owned refinements of a component's
|
|
227
|
+
[`implementations`](component-format.md#implementations) — the packages, import paths, and
|
|
228
|
+
exported names a platform ships. Foundation component data carries canonical **default** rows;
|
|
229
|
+
a platform manifest refines only its own rows, so the implementation team that owns the
|
|
230
|
+
manifest also owns its mappings, and they travel with the manifest when it is ejected.
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"component": "button",
|
|
235
|
+
"implementations": [
|
|
236
|
+
{
|
|
237
|
+
"platform": "web",
|
|
238
|
+
"componentName": "Button",
|
|
239
|
+
"package": "@react-spectrum/s2"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"op": "remove",
|
|
243
|
+
"componentName": "Button",
|
|
244
|
+
"package": "@react-spectrum/button"
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**NORMATIVE:** each file **MUST** validate against `implementation-mapping.schema.json`.
|
|
251
|
+
`component` **MUST** name a component in the catalog after `extensions/components/` has been
|
|
252
|
+
applied (so a fragment may target a platform-local component); an unknown component is a
|
|
253
|
+
manifest error. Entries apply in array order, files in sorted path order.
|
|
254
|
+
|
|
255
|
+
**NORMATIVE:** each entry has an *owner*: its own `implementation` field if present, otherwise
|
|
256
|
+
the manifest's top-level `platform` id. A manifest only matches rows its owner owns — rows
|
|
257
|
+
stamped with the same `implementation` id, or unstamped foundation defaults. Rows stamped with
|
|
258
|
+
a different `implementation` id are never modified or removed.
|
|
259
|
+
|
|
260
|
+
* **Upsert** (no `op`) — a full implementation row. When the entry omits `implementation` and
|
|
261
|
+
the manifest declares `platform`, the stored row is stamped with that id. The row replaces the
|
|
262
|
+
first existing row with the same `platform` and `componentName` that either carries the same
|
|
263
|
+
`implementation` id, or is an unstamped foundation default sharing a `package` or `importPath`
|
|
264
|
+
value. Otherwise it is appended.
|
|
265
|
+
* **Remove** (`"op": "remove"`) — a selector of `componentName` plus any of `platform`,
|
|
266
|
+
`implementation`, `package`, `importPath`. It deletes every owned row whose values equal every
|
|
267
|
+
selector field given. A remove that matches no owned row is a manifest error.
|
|
268
|
+
|
|
217
269
|
### `namingExceptions`
|
|
218
270
|
|
|
219
271
|
Platform-local overlay on the base naming-exceptions set used by naming validation.
|