@adobe/design-data-spec 0.9.0 → 0.11.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/components/accordion.json +18 -1
- package/components/action-bar.json +12 -1
- package/components/action-button.json +19 -1
- package/components/action-group.json +12 -1
- package/components/alert-banner.json +11 -1
- package/components/alert-dialog.json +19 -1
- package/components/avatar-group.json +4 -1
- package/components/avatar.json +4 -1
- package/components/badge.json +4 -1
- package/components/body.json +3 -0
- package/components/bottom-navigation-android.json +17 -0
- package/components/breadcrumbs.json +19 -2
- package/components/button-group.json +12 -1
- package/components/button.json +21 -3
- package/components/calendar.json +22 -0
- package/components/cards.json +18 -1
- package/components/checkbox-group.json +17 -1
- package/components/checkbox.json +24 -1
- package/components/close-button.json +19 -1
- package/components/coach-indicator.json +4 -1
- package/components/coach-mark.json +13 -1
- package/components/code.json +3 -0
- package/components/color-area.json +24 -1
- package/components/color-handle.json +13 -1
- package/components/color-loupe.json +4 -1
- package/components/color-slider.json +24 -1
- package/components/color-wheel.json +24 -1
- package/components/combo-box.json +24 -1
- package/components/contextual-help.json +18 -1
- package/components/date-picker.json +23 -1
- package/components/detail.json +3 -0
- package/components/divider.json +4 -1
- package/components/drop-zone.json +18 -1
- package/components/field-label.json +4 -1
- package/components/heading.json +3 -0
- package/components/help-text.json +5 -2
- package/components/illustrated-message.json +4 -1
- package/components/in-field-progress-button.json +18 -0
- package/components/in-field-progress-circle.json +4 -1
- package/components/in-line-alert.json +11 -1
- package/components/link.json +19 -1
- package/components/list-view.json +18 -1
- package/components/menu.json +19 -1
- package/components/meter.json +4 -1
- package/components/number-field.json +24 -1
- package/components/opacity-checkerboard.json +4 -1
- package/components/picker.json +24 -1
- package/components/popover.json +12 -1
- package/components/progress-bar.json +4 -1
- package/components/progress-circle.json +4 -1
- package/components/radio-button.json +24 -1
- package/components/radio-group.json +17 -1
- package/components/rating.json +24 -1
- package/components/scroll-zoom-bar.json +12 -0
- package/components/search-field.json +28 -1
- package/components/segmented-control.json +18 -1
- package/components/select-box.json +18 -1
- package/components/side-navigation.json +18 -1
- package/components/slider.json +24 -1
- package/components/standard-dialog.json +19 -1
- package/components/standard-panel.json +3 -0
- package/components/status-light.json +4 -1
- package/components/steplist.json +18 -1
- package/components/swatch-group.json +12 -1
- package/components/swatch.json +18 -1
- package/components/switch.json +19 -1
- package/components/tab-bar-ios.json +17 -0
- package/components/table.json +23 -1
- package/components/tabs.json +18 -1
- package/components/tag-field.json +18 -1
- package/components/tag-group.json +18 -1
- package/components/tag.json +18 -1
- package/components/takeover-dialog.json +19 -1
- package/components/text-area.json +28 -1
- package/components/text-field.json +28 -1
- package/components/thumbnail.json +4 -1
- package/components/title.json +40 -10
- package/components/toast.json +13 -1
- package/components/tooltip.json +17 -1
- package/components/tray.json +11 -0
- package/components/tree-view.json +19 -1
- package/conformance/README.md +7 -7
- package/conformance/invalid/SPEC-001/dataset.json +10 -0
- package/conformance/invalid/SPEC-001/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-002/dataset.json +16 -0
- package/conformance/invalid/SPEC-002/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-003/dataset.json +15 -0
- package/conformance/invalid/SPEC-003/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-004/dataset.json +15 -0
- package/conformance/invalid/SPEC-004/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-005/dataset.json +11 -0
- package/conformance/invalid/SPEC-005/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-006/dataset.json +15 -0
- package/conformance/invalid/SPEC-006/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-007/dataset.json +9 -0
- package/conformance/invalid/SPEC-007/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-008/dataset.json +25 -0
- package/conformance/invalid/SPEC-008/expected-errors.json +2 -1
- package/conformance/invalid/SPEC-009/dataset.json +12 -0
- package/conformance/invalid/SPEC-009/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-010/dataset.json +12 -0
- package/conformance/invalid/SPEC-011/dataset.json +25 -0
- package/conformance/invalid/SPEC-012/dataset.json +16 -0
- package/conformance/invalid/SPEC-013/dataset.json +11 -0
- package/conformance/invalid/SPEC-014/dataset.json +12 -0
- package/conformance/invalid/SPEC-014/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-015/dataset.json +22 -0
- package/conformance/invalid/SPEC-015/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-015/tokens.tokens.json +19 -0
- package/conformance/invalid/SPEC-016/dataset.json +11 -0
- package/conformance/invalid/SPEC-016/expected-errors.json +2 -2
- package/conformance/invalid/SPEC-017/dataset.json +10 -0
- package/conformance/invalid/SPEC-024/dataset.json +4 -3
- package/conformance/invalid/SPEC-024/expected-errors.json +2 -2
- package/conformance/invalid/SPEC-025/dataset.json +12 -0
- package/conformance/invalid/SPEC-025/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-026/dataset.json +18 -0
- package/conformance/invalid/SPEC-026/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-028/dataset.json +21 -0
- package/conformance/invalid/SPEC-028/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-029/dataset.json +20 -0
- package/conformance/invalid/SPEC-029/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-030/dataset.json +15 -0
- package/conformance/invalid/SPEC-030/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-031/dataset.json +17 -0
- package/conformance/invalid/SPEC-031/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-032/dataset.json +27 -0
- package/conformance/invalid/SPEC-032/expected-errors.json +15 -0
- package/conformance/resolution/base-fallback/expected.json +1 -1
- package/conformance/resolution/product-layer-wins/expected.json +5 -0
- package/conformance/resolution/product-layer-wins/input/tokens.tokens.json +7 -0
- package/conformance/resolution/product-layer-wins/product-context.json +11 -0
- package/conformance/resolution/product-layer-wins/query.json +4 -0
- package/conformance/resolution/specificity-wins/expected.json +1 -1
- package/conformance/valid/SPEC-014/dataset.json +12 -0
- package/conformance/valid/SPEC-016/dataset.json +16 -0
- package/conformance/valid/SPEC-025/dataset.json +24 -0
- package/conformance/valid/SPEC-026/dataset.json +15 -0
- package/conformance/valid/SPEC-028/dataset.json +21 -0
- package/conformance/valid/SPEC-029/dataset.json +24 -0
- package/conformance/valid/SPEC-030/dataset.json +17 -0
- package/conformance/valid/SPEC-031/dataset.json +24 -0
- package/conformance/valid/SPEC-032/dataset.json +16 -0
- package/conformance/valid/component-refs/README.md +5 -0
- package/conformance/valid/component-with-accessibility.json +32 -0
- package/fields/color-scheme.json +2 -2
- package/fields/contrast.json +2 -2
- package/fields/density.json +1 -1
- package/fields/scale.json +2 -2
- package/fields/size.json +1 -1
- package/package.json +4 -13
- package/rules/rules.yaml +57 -4
- package/schemas/accessibility.schema.json +60 -0
- package/schemas/component.schema.json +19 -0
- package/schemas/field.schema.json +2 -2
- package/schemas/manifest.schema.json +1 -1
- package/schemas/{dimension.schema.json → mode-set.schema.json} +3 -3
- package/schemas/token.schema.json +5 -5
- package/schemas/value-types/README.md +20 -0
- package/schemas/value-types/drop-shadow.schema.json +5 -5
- package/schemas/value-types/typography-scale.schema.json +2 -2
- package/schemas/value-types/typography.schema.json +5 -5
- package/spec/accessibility-adapters.md +219 -0
- package/spec/agent-surface.md +4 -4
- package/spec/cascade.md +7 -7
- package/spec/component-format.md +32 -0
- package/spec/document-blocks.md +1 -1
- package/spec/index.md +33 -29
- package/spec/manifest.md +2 -2
- package/spec/mode-sets.md +64 -0
- package/spec/query.md +18 -18
- package/spec/registry.md +93 -0
- package/spec/taxonomy.md +5 -5
- package/spec/token-format.md +12 -12
- package/spec/dimensions.md +0 -64
- package/src/canonical.js +0 -61
- package/src/validate.js +0 -190
- /package/conformance/resolution/alias-resolved-after-cascade/{dimensions → mode-sets}/color-scheme.json +0 -0
- /package/conformance/resolution/base-fallback/{dimensions → mode-sets}/color-scheme.json +0 -0
- /package/conformance/resolution/specificity-wins/{dimensions → mode-sets}/color-scheme.json +0 -0
package/spec/registry.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Registry
|
|
2
|
+
|
|
3
|
+
**Spec version:** `1.0.0-draft` (see [Overview](index.md))
|
|
4
|
+
|
|
5
|
+
This document defines the **design system registry**: the set of named value collections that supply allowed vocabulary for token name fields and component metadata. It describes which registries exist, what each one validates, and the packaging strategy for the current release.
|
|
6
|
+
|
|
7
|
+
## What a registry is
|
|
8
|
+
|
|
9
|
+
A **registry** is a JSON file in `@adobe/design-system-registry` that declares an ordered list of named values. Each value has at minimum an `id` (the canonical string used in token names and component files) and a `label` (a human-readable display name). Values **MAY** carry additional fields such as `description`, `aliases`, `deprecated`, and `usedIn`.
|
|
10
|
+
|
|
11
|
+
Registries are the authoritative source of truth for vocabulary validation. A validator SHOULD flag token field values that are not present in the corresponding registry (typically as a warning, not an error — see field declarations in the field catalog).
|
|
12
|
+
|
|
13
|
+
## Packaging strategy
|
|
14
|
+
|
|
15
|
+
All registries ship as a **single package**: `@adobe/design-system-registry`. The three semantically distinct registries described below are separate JSON files within that package. Independent sub-package splits are explicitly deferred.
|
|
16
|
+
|
|
17
|
+
**Rationale:** No external consumers currently require independent semver versioning of individual registries. A single package is cheaper to maintain, simpler to consume, and avoids the proliferation of tiny packages with coordinated versioning overhead. If independent versioning needs emerge in a future release, the split can be done with a standard deprecation window per [Evolution](evolution.md).
|
|
18
|
+
|
|
19
|
+
## Registries
|
|
20
|
+
|
|
21
|
+
### Component anatomy (`anatomy-terms.json`)
|
|
22
|
+
|
|
23
|
+
Validates the `anatomy` field on token name objects and the `id` field on anatomy part declarations in component schemas.
|
|
24
|
+
|
|
25
|
+
**What it contains:** Visible, named parts of components as defined in component specification diagrams — the elements called out when designers annotate a component. Examples: `label`, `icon`, `track`, `handle`, `thumbnail`, `drag-icon`.
|
|
26
|
+
|
|
27
|
+
Anatomy terms fall into three tiers:
|
|
28
|
+
|
|
29
|
+
| Tier | Description | Examples |
|
|
30
|
+
| ------------------ | -------------------------------------- | ------------------------------------------------------ |
|
|
31
|
+
| Primitive | Reusable across many components | `icon`, `label`, `track`, `handle`, `divider`, `title` |
|
|
32
|
+
| Composite | Another component used as a named part | `checkbox`, `close-button`, `popover`, `avatar` |
|
|
33
|
+
| Component-specific | Unique to one component | `loupe`, `gripper`, `hold-icon` |
|
|
34
|
+
|
|
35
|
+
**File:** `packages/design-system-registry/registry/anatomy-terms.json`\
|
|
36
|
+
**Validated by:** SPEC-020, SPEC-023, SPEC-024, SPEC-025\
|
|
37
|
+
**See also:** [Taxonomy — Component anatomy vs. token objects](taxonomy.md#component-anatomy-vs-token-objects), [Anatomy format](anatomy-format.md)
|
|
38
|
+
|
|
39
|
+
### Token objects (`token-objects.json`)
|
|
40
|
+
|
|
41
|
+
Validates the `object` field on token name objects.
|
|
42
|
+
|
|
43
|
+
**What it contains:** Abstract styling surfaces that describe *where* a visual property is applied. Token objects are not anatomy — they are not visible named parts of a component; they are targets for visual properties that exist on any element regardless of its type.
|
|
44
|
+
|
|
45
|
+
| ID | Description |
|
|
46
|
+
| ------------ | ----------------------------------------------------- |
|
|
47
|
+
| `background` | Background surface or fill |
|
|
48
|
+
| `border` | Border or outline |
|
|
49
|
+
| `edge` | Outer boundary (used in spacing tokens) |
|
|
50
|
+
| `visual` | Visible graphic element area (may be inset from edge) |
|
|
51
|
+
| `content` | Main content area |
|
|
52
|
+
|
|
53
|
+
**File:** `packages/design-system-registry/registry/token-objects.json`\
|
|
54
|
+
**Validated by:** SPEC-009 (advisory — `name.object` field values SHOULD match the token-objects registry)\
|
|
55
|
+
**See also:** [Taxonomy — Token objects (styling surfaces)](taxonomy.md#token-objects-styling-surfaces)
|
|
56
|
+
|
|
57
|
+
### Component categories (`categories.json`)
|
|
58
|
+
|
|
59
|
+
Validates the `category` field on component declarations.
|
|
60
|
+
|
|
61
|
+
**What it contains:** Top-level categories for organizing components by purpose and interaction type. Used for documentation navigation and tooling filters.
|
|
62
|
+
|
|
63
|
+
**File:** `packages/design-system-registry/registry/categories.json`\
|
|
64
|
+
**Validated by:** gap — no dedicated SPEC rule yet; component `category` field validation against this registry is untracked. A future rule SHOULD enforce advisory validation here.\
|
|
65
|
+
**See also:** [Component format](component-format.md)
|
|
66
|
+
|
|
67
|
+
## ID scoping
|
|
68
|
+
|
|
69
|
+
Registry IDs are scoped to their registry. The same ID **MAY** appear in multiple registries when the same word is a valid term in each registry's distinct validation context. For example, `actions` is a legitimate anatomy term (a group of action controls within a list item) and also a component category — these are unrelated concepts that happen to share a label.
|
|
70
|
+
|
|
71
|
+
**NORMATIVE (SPEC-033):** Cross-registry ID overlap is not an error. Validators MUST NOT flag an ID as invalid solely because it appears in another registry.
|
|
72
|
+
|
|
73
|
+
## Other registries in the package
|
|
74
|
+
|
|
75
|
+
The following registries exist in `@adobe/design-system-registry` but are not part of the three-registry boundary defined above. They validate other token name fields and component metadata fields:
|
|
76
|
+
|
|
77
|
+
| Registry | File | Validates |
|
|
78
|
+
| ----------------- | ------------------------ | ------------------------------------ |
|
|
79
|
+
| Sizes | `sizes.json` | `name.size` field |
|
|
80
|
+
| States | `states.json` | `name.state` field |
|
|
81
|
+
| Variants | `variants.json` | `name.variant` field |
|
|
82
|
+
| Structures | `structures.json` | `name.structure` field |
|
|
83
|
+
| Substructures | `substructures.json` | `name.substructure` field |
|
|
84
|
+
| Orientations | `orientations.json` | `name.orientation` field |
|
|
85
|
+
| Positions | `positions.json` | `name.position` field |
|
|
86
|
+
| Densities | `densities.json` | `name.density` field |
|
|
87
|
+
| Shapes | `shapes.json` | `name.shape` field |
|
|
88
|
+
| Scale values | `scale-values.json` | Numeric scale vocabulary |
|
|
89
|
+
| Platforms | `platforms.json` | Platform identifiers in manifests |
|
|
90
|
+
| Components | `components.json` | Component identifiers in token names |
|
|
91
|
+
| Navigation terms | `navigation-terms.json` | Navigation vocabulary |
|
|
92
|
+
| Token terminology | `token-terminology.json` | Human-readable token concept labels |
|
|
93
|
+
| Glossary | `glossary.json` | Design system glossary |
|
package/spec/taxonomy.md
CHANGED
|
@@ -139,15 +139,15 @@ Semantic fields describe identity, structure, and intent. They are used for quer
|
|
|
139
139
|
|
|
140
140
|
Semantic fields are those declared with `kind: "semantic"` in the field catalog. In Spectrum's foundation catalog, these are: `structure`, `substructure`, `component`, `anatomy`, `object`, `property`, `variant`, `state`, `orientation`, `position`, `size`, `density`, `shape`.
|
|
141
141
|
|
|
142
|
-
###
|
|
142
|
+
### Mode-set fields
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
Mode-set fields represent axes of variation that drive the [cascade](cascade.md) resolution algorithm and [specificity](cascade.md#semantic-specificity) calculation.
|
|
145
145
|
|
|
146
|
-
**NORMATIVE:**
|
|
146
|
+
**NORMATIVE:** Mode-set field values are validated against declared [mode set](mode-sets.md) modes with **strict** severity (error). An invalid mode value would silently fail to match any context during cascade resolution.
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
Mode-set fields are those declared with `kind: "mode-set"` in the field catalog, plus any additional mode set keys from the dataset's [mode set declarations](mode-sets.md). In Spectrum's foundation catalog, the standard mode-set fields are: `colorScheme`, `scale`, `contrast`.
|
|
149
149
|
|
|
150
|
-
See [
|
|
150
|
+
See [Mode Sets](mode-sets.md) for mode set declarations, modes, and defaults.
|
|
151
151
|
|
|
152
152
|
## Default serialization (legacy format)
|
|
153
153
|
|
package/spec/token-format.md
CHANGED
|
@@ -35,7 +35,7 @@ A token's `name` field **MAY** be a non-empty plain string instead of a name obj
|
|
|
35
35
|
|
|
36
36
|
**NORMATIVE:** String-named tokens **MUST** trigger rule SPEC-017 (severity: `warning`, category: `tech-debt`). The warning surfaces the token as tracked debt requiring future remediation.
|
|
37
37
|
|
|
38
|
-
**NORMATIVE:** String-named tokens **MUST NOT** participate in name-object cascade
|
|
38
|
+
**NORMATIVE:** String-named tokens **MUST NOT** participate in name-object cascade mode-set matching, specificity calculation, or registry vocabulary checks (SPEC-009 does not apply).
|
|
39
39
|
|
|
40
40
|
**RECOMMENDED:** Authors **SHOULD** treat string names as a temporary escape hatch and track a remediation plan. Each string-named token **SHOULD** eventually be given a structured name object, at which point SPEC-017 no longer fires.
|
|
41
41
|
|
|
@@ -45,9 +45,9 @@ The **name object** identifies the token in a structured way. Implementations us
|
|
|
45
45
|
|
|
46
46
|
**NORMATIVE fields** (all string unless noted):
|
|
47
47
|
|
|
48
|
-
The set of available name-object fields is declared in the design system's **field catalog** (`fields/` directory). Each field declaration conforms to [`field.schema.json`](../schemas/field.schema.json) and specifies its kind (`semantic` or `
|
|
48
|
+
The set of available name-object fields is declared in the design system's **field catalog** (`fields/` directory). Each field declaration conforms to [`field.schema.json`](../schemas/field.schema.json) and specifies its kind (`semantic` or `mode-set`), vocabulary registry, validation severity, and default serialization position. See [Taxonomy](taxonomy.md) for the full concept category hierarchy, component anatomy vs. token objects, and serialization rules.
|
|
49
49
|
|
|
50
|
-
Fields are divided into **semantic fields** (identity, structure, intent) and **
|
|
50
|
+
Fields are divided into **semantic fields** (identity, structure, intent) and **mode-set fields** (axes of variation for cascade resolution). The tables below list Spectrum's foundation-standard fields as declared in the catalog.
|
|
51
51
|
|
|
52
52
|
#### Semantic fields
|
|
53
53
|
|
|
@@ -67,16 +67,16 @@ Fields are divided into **semantic fields** (identity, structure, intent) and **
|
|
|
67
67
|
| `density` | OPTIONAL | Density | Space within or around component parts (e.g. `spacious`, `compact`). |
|
|
68
68
|
| `shape` | OPTIONAL | Shape | Relative to overall component shape (e.g. `uniform`). |
|
|
69
69
|
|
|
70
|
-
####
|
|
70
|
+
#### Mode-set fields
|
|
71
71
|
|
|
72
|
-
| Field | Status | Description
|
|
73
|
-
| --------------- | -------- |
|
|
74
|
-
| `colorScheme` | OPTIONAL |
|
|
75
|
-
| `scale` | OPTIONAL |
|
|
76
|
-
| `contrast` | OPTIONAL |
|
|
77
|
-
| Additional keys | OPTIONAL | Other
|
|
72
|
+
| Field | Status | Description |
|
|
73
|
+
| --------------- | -------- | ------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `colorScheme` | OPTIONAL | Mode set: light / dark / wireframe / etc. |
|
|
75
|
+
| `scale` | OPTIONAL | Mode set: platform density scale (e.g. `desktop`, `mobile`). Distinct from semantic `size`. |
|
|
76
|
+
| `contrast` | OPTIONAL | Mode set: contrast level (e.g. `regular`, `high`). |
|
|
77
|
+
| Additional keys | OPTIONAL | Other mode sets declared in the dataset’s mode set catalog (see [Mode Sets](mode-sets.md)). |
|
|
78
78
|
|
|
79
|
-
**NORMATIVE:** Each field is validated according to the `validation` severity declared in its field declaration. Semantic fields typically use **advisory** severity (warning);
|
|
79
|
+
**NORMATIVE:** Each field is validated according to the `validation` severity declared in its field declaration. Semantic fields typically use **advisory** severity (warning); mode-set fields use **strict** severity (error). See [Taxonomy — Name object field categories](taxonomy.md#name-object-field-categories).
|
|
80
80
|
|
|
81
81
|
**RECOMMENDED:** Name objects use a consistent key ordering in authored files for diffs; this is not a conformance requirement. Concept ordering for serialized names is defined in [Taxonomy — Default serialization](taxonomy.md#default-serialization-legacy-format).
|
|
82
82
|
|
|
@@ -249,7 +249,7 @@ The current `@adobe/spectrum-tokens` JSON uses **sets** (`color-set`, `scale-set
|
|
|
249
249
|
| ------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
250
250
|
| Identity field | `id` | `uuid` |
|
|
251
251
|
| Name model | `name.original` (string) + `name.structure` (nested object) | Flat fields directly on `name` (`property`, `component`, `colorScheme`, …) |
|
|
252
|
-
| Complexity tracking | `name.semanticComplexity` (stored on token) | Computed at validation time from
|
|
252
|
+
| Complexity tracking | `name.semanticComplexity` (stored on token) | Computed at validation time from mode set declarations |
|
|
253
253
|
|
|
254
254
|
**NORMATIVE:** The flat `name` object defined in this spec is the authoritative serialization format. RFC [#646](https://github.com/adobe/spectrum-design-data/issues/646)'s `name.structure` / `name.original` shape is not a conformance target; it remains a useful reference for the analytical model that informed this design.
|
|
255
255
|
|
package/spec/dimensions.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Dimensions
|
|
2
|
-
|
|
3
|
-
**Spec version:** `1.0.0-draft` (see [Overview](index.md))
|
|
4
|
-
|
|
5
|
-
This document defines how **dimensions** (modes such as color scheme, scale, contrast) are **declared**, assigned **defaults**, and validated for **coverage**.
|
|
6
|
-
|
|
7
|
-
## Dimension declaration
|
|
8
|
-
|
|
9
|
-
A **dimension declaration** is a JSON object describing one axis of variation. It **MUST** conform to [`dimension.schema.json`](../schemas/dimension.schema.json) (canonical `$id`: `https://opensource.adobe.com/spectrum-design-data/schemas/v0/dimension.schema.json`).
|
|
10
|
-
|
|
11
|
-
### Required fields
|
|
12
|
-
|
|
13
|
-
| Field | Description |
|
|
14
|
-
| --------- | --------------------------------------------------------- |
|
|
15
|
-
| `name` | Stable identifier for the dimension (e.g. `colorScheme`). |
|
|
16
|
-
| `modes` | Array of allowed mode values (strings). |
|
|
17
|
-
| `default` | Default mode; **MUST** be a member of `modes`. |
|
|
18
|
-
|
|
19
|
-
### Optional fields
|
|
20
|
-
|
|
21
|
-
| Field | Description |
|
|
22
|
-
| ------------- | ------------------------------------ |
|
|
23
|
-
| `description` | Human-readable documentation. |
|
|
24
|
-
| `coverage` | Rules for mode coverage (see below). |
|
|
25
|
-
|
|
26
|
-
## Built-in dimensions
|
|
27
|
-
|
|
28
|
-
These dimensions are declared in the `dimensions/` catalog (see [Dimension catalog](#dimension-catalog)) and **SHOULD** be used consistently across Spectrum-compatible datasets:
|
|
29
|
-
|
|
30
|
-
| `name` | `modes` | `default` | Notes |
|
|
31
|
-
| ------------- | ---------------------------- | --------- | --------------------------------------------------------------------------------- |
|
|
32
|
-
| `colorScheme` | `light`, `dark`, `wireframe` | `light` | Theme / appearance. |
|
|
33
|
-
| `scale` | `desktop`, `mobile` | `desktop` | Density scale. Legacy names; desktop = medium, mobile = large in W3C terminology. |
|
|
34
|
-
| `contrast` | `regular`, `high` | `regular` | Accessibility contrast level. |
|
|
35
|
-
|
|
36
|
-
## Dimension catalog
|
|
37
|
-
|
|
38
|
-
The Spectrum foundation publishes dimension declarations as JSON files under `packages/design-data-spec/dimensions/`. Each file conforms to [`dimension.schema.json`](../schemas/dimension.schema.json).
|
|
39
|
-
|
|
40
|
-
**NORMATIVE:** Tooling (validators, resolution engine) **MUST** load dimension declarations from the dataset’s dimension catalog before performing specificity calculations or coverage validation.
|
|
41
|
-
|
|
42
|
-
**RECOMMENDED:** The catalog directory is named `dimensions/` and is co-located with the dataset’s spec package or manifest.
|
|
43
|
-
|
|
44
|
-
## Optional dimensions
|
|
45
|
-
|
|
46
|
-
Additional dimensions (e.g. `language`, `motion`) **MAY** be declared in a dataset’s dimension catalog. Token name objects **MAY** include keys matching declared dimension names.
|
|
47
|
-
|
|
48
|
-
## Defaults and specificity
|
|
49
|
-
|
|
50
|
-
**NORMATIVE:** A token name object **omitting** a dimension field implies the token applies under the dimension’s **`default`** mode for specificity and matching purposes unless the spec for that dimension states otherwise.
|
|
51
|
-
|
|
52
|
-
**NORMATIVE:** Only **non-default** dimension fields on the name object increase **semantic specificity** (see [Cascade](cascade.md)).
|
|
53
|
-
|
|
54
|
-
## Coverage validation
|
|
55
|
-
|
|
56
|
-
**RECOMMENDED:** If a dimension’s `coverage` requires **peer modes** (e.g. defining `dark` requires `light`), validators implement rule **`SPEC-005`** (see `rules/rules.yaml`).
|
|
57
|
-
|
|
58
|
-
**RECOMMENDED:** Explicit **combination** tokens are used for rare cross-dimensional cases instead of inferring Cartesian products.
|
|
59
|
-
|
|
60
|
-
## References
|
|
61
|
-
|
|
62
|
-
* [#646 — Token Schema Structure and Validation System](https://github.com/adobe/spectrum-design-data/discussions/646)
|
|
63
|
-
* [#714 — Design Data Specification](https://github.com/adobe/spectrum-design-data/discussions/714)
|
|
64
|
-
* [#746 — Phase 2: Dimension declarations (machine-readable)](https://github.com/adobe/spectrum-design-data/issues/746)
|
package/src/canonical.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2026 Adobe. All rights reserved.
|
|
3
|
-
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
|
|
7
|
-
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Canonical vocabulary sets derived from spec chapters.
|
|
14
|
-
// Sources: spec/component-format.md, spec/anatomy-format.md, spec/state-model.md
|
|
15
|
-
|
|
16
|
-
export const CANONICAL_SLOTS = new Set([
|
|
17
|
-
"default",
|
|
18
|
-
"icon",
|
|
19
|
-
"label",
|
|
20
|
-
"help-text",
|
|
21
|
-
"negative-help-text",
|
|
22
|
-
"action",
|
|
23
|
-
"heading",
|
|
24
|
-
"description",
|
|
25
|
-
"hero",
|
|
26
|
-
"footer",
|
|
27
|
-
"tooltip",
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
|
-
export const CANONICAL_ANATOMY_PARTS = new Set([
|
|
31
|
-
"body",
|
|
32
|
-
"checkmark",
|
|
33
|
-
"disclosure-triangle",
|
|
34
|
-
"field",
|
|
35
|
-
"handle",
|
|
36
|
-
"header",
|
|
37
|
-
"icon",
|
|
38
|
-
"label",
|
|
39
|
-
"picker",
|
|
40
|
-
"progress-bar",
|
|
41
|
-
"swatch",
|
|
42
|
-
"thumbnail",
|
|
43
|
-
"track",
|
|
44
|
-
"value",
|
|
45
|
-
]);
|
|
46
|
-
|
|
47
|
-
export const CANONICAL_STATES = new Set([
|
|
48
|
-
"default",
|
|
49
|
-
"hover",
|
|
50
|
-
"focus",
|
|
51
|
-
"focus-visible",
|
|
52
|
-
"active",
|
|
53
|
-
"pressed",
|
|
54
|
-
"selected",
|
|
55
|
-
"indeterminate",
|
|
56
|
-
"disabled",
|
|
57
|
-
"read-only",
|
|
58
|
-
"invalid",
|
|
59
|
-
"valid",
|
|
60
|
-
"dragging",
|
|
61
|
-
]);
|
package/src/validate.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2026 Adobe. All rights reserved.
|
|
3
|
-
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
|
|
7
|
-
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
-
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
-
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
-
governing permissions and limitations under the License.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Layer 2 cross-reference validator for design-data-spec.
|
|
15
|
-
*
|
|
16
|
-
* Implements SPEC-018 through SPEC-027: semantic rules that validate token
|
|
17
|
-
* name-object fields against component declarations, validate component
|
|
18
|
-
* declarations internally, and validate tokenBindings references.
|
|
19
|
-
*
|
|
20
|
-
* @see spec/component-format.md#spec-rules
|
|
21
|
-
* @see spec/anatomy-format.md#spec-rules
|
|
22
|
-
* @see spec/state-model.md#spec-rules
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import {
|
|
26
|
-
CANONICAL_SLOTS,
|
|
27
|
-
CANONICAL_ANATOMY_PARTS,
|
|
28
|
-
CANONICAL_STATES,
|
|
29
|
-
} from "./canonical.js";
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {{ ruleId: string, severity: 'error'|'warning', message: string, tokenName?: string, componentName?: string }} Diagnostic
|
|
33
|
-
* @typedef {{ name: string|object, [key: string]: unknown }} Token
|
|
34
|
-
* @typedef {{ name: string, options?: object, anatomy?: Array<{name:string,description?:string}>, slots?: Array<{name:string,description?:string}>, states?: Array<{name:string,trigger?:string,precedence?:number,layered?:boolean,description?:string}> }} ComponentDeclaration
|
|
35
|
-
* @typedef {{ tokens?: Token[], components?: ComponentDeclaration[] }} Dataset
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Validate a dataset for SPEC-018 through SPEC-024 compliance.
|
|
40
|
-
*
|
|
41
|
-
* @param {Dataset} dataset
|
|
42
|
-
* @returns {Diagnostic[]}
|
|
43
|
-
*/
|
|
44
|
-
export function validateDataset(dataset) {
|
|
45
|
-
const tokens = dataset.tokens ?? [];
|
|
46
|
-
const components = dataset.components ?? [];
|
|
47
|
-
|
|
48
|
-
// Build component lookup map keyed by name.
|
|
49
|
-
const componentMap = new Map(components.map((c) => [c.name, c]));
|
|
50
|
-
|
|
51
|
-
const diagnostics = [];
|
|
52
|
-
|
|
53
|
-
// --- Token cross-reference rules ---
|
|
54
|
-
for (const token of tokens) {
|
|
55
|
-
const name = token.name;
|
|
56
|
-
// String names (SPEC-017 escape hatch) skip cross-reference checks.
|
|
57
|
-
if (typeof name !== "object" || name === null) continue;
|
|
58
|
-
|
|
59
|
-
const tokenLabel = JSON.stringify(name);
|
|
60
|
-
|
|
61
|
-
if (name.component != null) {
|
|
62
|
-
// SPEC-018: component name must be declared
|
|
63
|
-
if (!componentMap.has(name.component)) {
|
|
64
|
-
diagnostics.push({
|
|
65
|
-
ruleId: "SPEC-018",
|
|
66
|
-
severity: "error",
|
|
67
|
-
message: `Token '${tokenLabel}' references undeclared component '${name.component}'`,
|
|
68
|
-
tokenName: tokenLabel,
|
|
69
|
-
});
|
|
70
|
-
// Can't validate further fields without a component declaration.
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const component = componentMap.get(name.component);
|
|
75
|
-
|
|
76
|
-
// SPEC-019: variant must be in component's variant option enum
|
|
77
|
-
if (name.variant != null) {
|
|
78
|
-
const variantEnum = component.options?.variant?.enum;
|
|
79
|
-
if (Array.isArray(variantEnum) && !variantEnum.includes(name.variant)) {
|
|
80
|
-
diagnostics.push({
|
|
81
|
-
ruleId: "SPEC-019",
|
|
82
|
-
severity: "error",
|
|
83
|
-
message: `Token '${tokenLabel}' has variant '${name.variant}' which is not declared on component '${name.component}'`,
|
|
84
|
-
tokenName: tokenLabel,
|
|
85
|
-
componentName: name.component,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// SPEC-020: anatomy must match a declared anatomy part name
|
|
91
|
-
if (name.anatomy != null) {
|
|
92
|
-
const declaredParts = new Set(
|
|
93
|
-
(component.anatomy ?? []).map((p) => p.name),
|
|
94
|
-
);
|
|
95
|
-
if (declaredParts.size > 0 && !declaredParts.has(name.anatomy)) {
|
|
96
|
-
diagnostics.push({
|
|
97
|
-
ruleId: "SPEC-020",
|
|
98
|
-
severity: "error",
|
|
99
|
-
message: `Token '${tokenLabel}' references undeclared anatomy part '${name.anatomy}' on component '${name.component}'`,
|
|
100
|
-
tokenName: tokenLabel,
|
|
101
|
-
componentName: name.component,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// SPEC-022: state must match a declared state name (only when states are declared)
|
|
107
|
-
if (name.state != null) {
|
|
108
|
-
const declaredStates = new Set(
|
|
109
|
-
(component.states ?? []).map((s) => s.name),
|
|
110
|
-
);
|
|
111
|
-
if (declaredStates.size > 0 && !declaredStates.has(name.state)) {
|
|
112
|
-
diagnostics.push({
|
|
113
|
-
ruleId: "SPEC-022",
|
|
114
|
-
severity: "error",
|
|
115
|
-
message: `Token '${tokenLabel}' references undeclared state '${name.state}' on component '${name.component}'`,
|
|
116
|
-
tokenName: tokenLabel,
|
|
117
|
-
componentName: name.component,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// --- Component declaration internal rules ---
|
|
125
|
-
for (const component of components) {
|
|
126
|
-
const cName = component.name;
|
|
127
|
-
|
|
128
|
-
// SPEC-021: custom slot names should have descriptions
|
|
129
|
-
for (const slot of component.slots ?? []) {
|
|
130
|
-
if (!CANONICAL_SLOTS.has(slot.name) && !slot.description) {
|
|
131
|
-
diagnostics.push({
|
|
132
|
-
ruleId: "SPEC-021",
|
|
133
|
-
severity: "warning",
|
|
134
|
-
message: `Component '${cName}' has custom slot '${slot.name}' with no description — add a description or use a canonical slot name`,
|
|
135
|
-
componentName: cName,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// SPEC-023: custom anatomy part names should have descriptions
|
|
141
|
-
for (const part of component.anatomy ?? []) {
|
|
142
|
-
if (!CANONICAL_ANATOMY_PARTS.has(part.name) && !part.description) {
|
|
143
|
-
diagnostics.push({
|
|
144
|
-
ruleId: "SPEC-023",
|
|
145
|
-
severity: "warning",
|
|
146
|
-
message: `Component '${cName}' has custom anatomy part '${part.name}' with no description`,
|
|
147
|
-
componentName: cName,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// SPEC-024: custom state names should have descriptions
|
|
153
|
-
for (const state of component.states ?? []) {
|
|
154
|
-
if (!CANONICAL_STATES.has(state.name) && !state.description) {
|
|
155
|
-
diagnostics.push({
|
|
156
|
-
ruleId: "SPEC-024",
|
|
157
|
-
severity: "warning",
|
|
158
|
-
message: `Component '${cName}' has custom state '${state.name}' with no description`,
|
|
159
|
-
componentName: cName,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// --- Token binding rules ---
|
|
166
|
-
|
|
167
|
-
// SPEC-027: each tokenBindings[].token must resolve to a known token name.
|
|
168
|
-
// String-named tokens are matched directly. Name-object tokens are skipped
|
|
169
|
-
// here because tokenBindings always reference tokens by their string name.
|
|
170
|
-
const tokenNameSet = new Set(
|
|
171
|
-
tokens
|
|
172
|
-
.map((t) => (typeof t.name === "string" ? t.name : null))
|
|
173
|
-
.filter(Boolean),
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
for (const component of components) {
|
|
177
|
-
for (const binding of component.tokenBindings ?? []) {
|
|
178
|
-
if (!tokenNameSet.has(binding.token)) {
|
|
179
|
-
diagnostics.push({
|
|
180
|
-
ruleId: "SPEC-027",
|
|
181
|
-
severity: "error",
|
|
182
|
-
message: `Component '${component.name}' tokenBindings references unknown token '${binding.token}'`,
|
|
183
|
-
componentName: component.name,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return diagnostics;
|
|
190
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|