@canonical/anatomy-dsl 0.3.0 → 0.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/README.md +63 -28
- package/definitions/lift.fixture.json +216 -0
- package/definitions/ontology.ttl +110 -11
- package/definitions/registry.ttl +659 -0
- package/definitions/shapes.ttl +461 -7
- package/definitions/style-keys.yaml +391 -0
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -9,12 +9,11 @@ A YAML-based DSL for representing design system component anatomies — platform
|
|
|
9
9
|
node:
|
|
10
10
|
uri: global.component.button
|
|
11
11
|
styles:
|
|
12
|
-
layout.type:
|
|
13
|
-
layout.direction: horizontal
|
|
12
|
+
layout.type: inline-flex
|
|
14
13
|
layout.align: center
|
|
15
|
-
spacing.internal: spacing
|
|
16
|
-
appearance.background: color
|
|
17
|
-
appearance.radius: radius
|
|
14
|
+
spacing.internal.inline.start: spacing.inset.action.inline
|
|
15
|
+
appearance.background: [modifier.color.foreground.primary, color.foreground.primary]
|
|
16
|
+
appearance.radius: dimension.radius.medium
|
|
18
17
|
edges:
|
|
19
18
|
- node:
|
|
20
19
|
uri: global.subcomponent.button-icon
|
|
@@ -28,7 +27,30 @@ node:
|
|
|
28
27
|
slotName: default
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
Style values are **
|
|
30
|
+
Style values are **token symbols**, written in the symbol's own dotted
|
|
31
|
+
spelling: `dimension.radius.medium`, `color.foreground.primary`. A list is
|
|
32
|
+
the **fallback order** — a one-to-one transcription of the implementation's
|
|
33
|
+
own `var()` chain, so `[modifier.color.foreground.primary,
|
|
34
|
+
color.foreground.primary]` says "read the primary-foreground channel, and
|
|
35
|
+
fall back to the primary foreground token", which is what the reference CSS
|
|
36
|
+
does. A **channel** (`modifier.*`, `surface.*`) is a symbol like any other:
|
|
37
|
+
the anatomy consumes it by name where the implementation reads the channel,
|
|
38
|
+
and the semantic token by name where it reads the token — nothing is
|
|
39
|
+
inferred. Primitives like `inline-flex` and `center` are used for layout
|
|
40
|
+
semantics that do not vary across themes, and one may end a list where the
|
|
41
|
+
implementation's chain ends in a literal
|
|
42
|
+
(`[modifier.color.icon, modifier.color.text, currentColor]`).
|
|
43
|
+
|
|
44
|
+
Keys come from a **closed roster** — `definitions/style-keys.yaml`, from
|
|
45
|
+
which `definitions/registry.ttl` is generated. The roster is measured, not
|
|
46
|
+
designed: its 111 keys are the right-hand column of a table whose left-hand
|
|
47
|
+
column was every CSS property bound on a component selector across 89
|
|
48
|
+
published component stylesheets, so a key exists because an implementation
|
|
49
|
+
binds the property. That measurement lives in `canonical/design-system`,
|
|
50
|
+
where the reference stylesheets are an input; this package reads no CSS and
|
|
51
|
+
holds the roster, with its provenance stated in both files. The
|
|
52
|
+
slash-delimited path and the trailing `?` marker of earlier versions are
|
|
53
|
+
retired — see `docs/api-reference.md` §5, §11 and §12.
|
|
32
54
|
|
|
33
55
|
## Projections
|
|
34
56
|
|
|
@@ -138,13 +160,13 @@ usage in anatomies splits into exactly two cases:
|
|
|
138
160
|
Semantics:
|
|
139
161
|
|
|
140
162
|
- Pins live on **named nodes only** — anonymous nodes have no prop surface.
|
|
141
|
-
This is enforced in the types, the parser,
|
|
163
|
+
This is enforced in the types, the parser, and SHACL.
|
|
142
164
|
- The DSL **never defines a prop surface** (names, types, optionality live in
|
|
143
165
|
the design system ontology); it only asserts values. Whether a pinned prop
|
|
144
166
|
exists on the component, and whether a value is admissible (e.g. a glyph
|
|
145
167
|
name in the icon set), are consumer-side checks against the DS graph — the
|
|
146
168
|
same posture as projection checking against the provider SDL.
|
|
147
|
-
- Values are scalars, coerced to strings — no
|
|
169
|
+
- Values are scalars, coerced to strings — no symbols and no fallback lists: a pin is a value, not a style.
|
|
148
170
|
Pins are *values with meaning*, not styles: a theme may reskin what
|
|
149
171
|
`chevron-down` looks like (asset layer), but never remap which glyph an
|
|
150
172
|
anatomy means.
|
|
@@ -166,10 +188,11 @@ key is the default state:
|
|
|
166
188
|
styles:
|
|
167
189
|
interaction.cursor: pointer
|
|
168
190
|
interaction.cursor@disabled: not-allowed
|
|
169
|
-
appearance.background: color
|
|
170
|
-
appearance.background@hover: color
|
|
171
|
-
appearance.background@disabled: color
|
|
172
|
-
|
|
191
|
+
appearance.background: [modifier.color.foreground.primary, color.foreground.primary]
|
|
192
|
+
appearance.background@hover: color.foreground.primary.hover
|
|
193
|
+
appearance.background@disabled: color.foreground.primary.disabled
|
|
194
|
+
# A slot may read a channel only in one state.
|
|
195
|
+
appearance.outline.color@focus: [modifier.color.focusRing, color.focusRing, currentColor]
|
|
173
196
|
```
|
|
174
197
|
|
|
175
198
|
The state vocabulary is **closed and registry-governed**: `hover`, `active`,
|
|
@@ -188,15 +211,16 @@ The boundaries that keep "state machines out of scope" true:
|
|
|
188
211
|
transitions, triggers, or logic.
|
|
189
212
|
- **Gate vs appearance**: `props: { disabled: true }` (or the consumer) puts
|
|
190
213
|
a node in the disabled state; `…@disabled` styles say how it looks there.
|
|
191
|
-
-
|
|
192
|
-
|
|
193
|
-
|
|
214
|
+
- A state-scoped value that differs from its base state's is a **lint, not a
|
|
215
|
+
constraint**: it is reported with the ranks at which they differ and never
|
|
216
|
+
rejected, because the reference does it — Button's `:disabled` reads
|
|
217
|
+
`color.text.disabled`, a different symbol from its resting `color.text`.
|
|
194
218
|
- The grammar reserves repeatable markers for compound states
|
|
195
219
|
(`@selected@hover`, canonical order: value/control state before user-action
|
|
196
220
|
state); v1 permits a single `@`.
|
|
197
221
|
|
|
198
222
|
In TTL, the Style tuple gains one optional dimension:
|
|
199
|
-
`[ styleKey "appearance.background" ; styleState "hover" ; styleValue "…" ]`.
|
|
223
|
+
`[ a :Style ; :styleKey "appearance.background" ; :styleState "hover" ; :styleValue "…" ]`.
|
|
200
224
|
See `examples/yaml/stateful-button.anatomy.yaml`.
|
|
201
225
|
|
|
202
226
|
## Install
|
|
@@ -219,19 +243,19 @@ const ttl = anatomyToTTL(spec);
|
|
|
219
243
|
The button example above produces:
|
|
220
244
|
|
|
221
245
|
```turtle
|
|
222
|
-
@prefix : <
|
|
246
|
+
@prefix : <https://anatomy.canonical.com/> .
|
|
247
|
+
@prefix dt: <https://dt.canonical.com/> .
|
|
223
248
|
|
|
224
249
|
[] a :Specification ;
|
|
225
250
|
:rootNode [
|
|
226
251
|
a :NamedNode ;
|
|
227
252
|
:uri "global.component.button" ;
|
|
228
253
|
:hasStyle
|
|
229
|
-
[ :styleKey "layout.type" ; :styleValue "
|
|
230
|
-
[ :styleKey "layout.
|
|
231
|
-
[ :styleKey "
|
|
232
|
-
[ :styleKey "
|
|
233
|
-
[ :styleKey "appearance.
|
|
234
|
-
[ :styleKey "appearance.radius" ; :styleValue "radius/button" ] ;
|
|
254
|
+
[ a :Style ; :styleKey "layout.type" ; :styleValue "inline-flex" ] ,
|
|
255
|
+
[ a :Style ; :styleKey "layout.align" ; :styleValue "center" ] ,
|
|
256
|
+
[ a :Style ; :styleKey "spacing.internal.inline.start" ; :styleValue "spacing.inset.action.inline" ; :consumes ( dt:spacing.inset.action.inline ) ] ,
|
|
257
|
+
[ a :Style ; :styleKey "appearance.background" ; :styleValue "[modifier.color.foreground.primary, color.foreground.primary]" ; :consumes ( dt:modifier.color.foreground.primary dt:color.foreground.primary ) ] ,
|
|
258
|
+
[ a :Style ; :styleKey "appearance.radius" ; :styleValue "dimension.radius.medium" ; :consumes ( dt:dimension.radius.medium ) ] ;
|
|
235
259
|
:hasEdge [
|
|
236
260
|
a :Edge ;
|
|
237
261
|
:edgeTarget [
|
|
@@ -290,11 +314,14 @@ All types mirror the [OWL ontology](definitions/ontology.ttl) exactly:
|
|
|
290
314
|
## Repository Structure
|
|
291
315
|
|
|
292
316
|
```
|
|
293
|
-
definitions/ Turtle ontology (OWL) + SHACL shapes
|
|
294
|
-
|
|
317
|
+
definitions/ Turtle ontology (OWL) + SHACL shapes, the style-key roster and
|
|
318
|
+
the registry generated from it, and the lift fixture — all of
|
|
319
|
+
it public API, since exports lists it
|
|
295
320
|
docs/ API reference (WD404 + WD404.1 + WD404.2 + WD404.3)
|
|
296
|
-
examples/ Example anatomy files (YAML + Turtle pairs)
|
|
297
|
-
|
|
321
|
+
examples/ Example anatomy files (YAML + Turtle pairs), the corpus the
|
|
322
|
+
round-trip and SHACL tests read
|
|
323
|
+
src/ TypeScript types, parser, value grammar, transform and the
|
|
324
|
+
generators
|
|
298
325
|
```
|
|
299
326
|
|
|
300
327
|
## Scope
|
|
@@ -313,7 +340,15 @@ component configuration at a position), and **state-scoped styles**
|
|
|
313
340
|
|
|
314
341
|
## Design Notes
|
|
315
342
|
|
|
316
|
-
Styles are modelled as reified key-value tuples
|
|
343
|
+
Styles are modelled as reified key-value tuples
|
|
344
|
+
(`hasStyle [ a :Style ; :styleKey "…" ; :styleValue "…" ]`), which stays
|
|
345
|
+
lossless whatever the key roster becomes. Since 0.4.0 a tuple whose key takes
|
|
346
|
+
a token also carries `:consumes`, an ordered `rdf:List` of the `dt:` symbols
|
|
347
|
+
it reads: `:styleValue` is the authored spelling kept verbatim as evidence —
|
|
348
|
+
it is where a terminal literal lives, since a literal is not a symbol — and
|
|
349
|
+
`:consumes` is the form a query can walk. The key vocabulary is no longer
|
|
350
|
+
open: `anatomy:styleKey`'s `sh:in` is projected from the registry, so a key
|
|
351
|
+
outside the roster is a SHACL violation rather than a silent addition.
|
|
317
352
|
|
|
318
353
|
Projections and pinned props reuse the same reification idiom (`hasProjection [ projectionType "…" ; projectionField "…" ]`, `hasProp [ propName "…" ; propValue "…" ]`). Projections attach to both nodes and relations — the reified `Relation` is precisely what makes slot-level traversal annotations possible without changing the `Edge` class; pins attach to named nodes only.
|
|
319
354
|
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": [
|
|
3
|
+
"The committed lift fixture (ADR J §4.1, §8.2). Both TypeScript repositories assert against it, so anatomy-dsl and design-system lift identically and cannot drift apart without a failing test.",
|
|
4
|
+
"`values` is the value lift this package implements: `liftSymbols(value)` over what the YAML parser holds for a style value — a scalar or a sequence of scalars — returning the symbols in fallback order. A primitive is not a symbol: it resolves against nothing by design, so it is never lifted.",
|
|
5
|
+
"`rejections` is the retired notation, with the rule each breaks. Every one throws an AnatomyValueError naming the value and the rule.",
|
|
6
|
+
"`names` is the CSS-name lift of §5.1 step 5d, which design-system implements because it needs S4 to run: a custom-property name to the dotted symbol it lifts to, or null where it names no symbol in any stratum and is kept as consumed with a register row (AT.09). It is DATA here, not an implementation — this package ships it so the two repositories agree on the expected pairs."
|
|
7
|
+
],
|
|
8
|
+
"values": [
|
|
9
|
+
{ "case": "a symbol", "value": "color.text", "symbols": ["color.text"] },
|
|
10
|
+
{
|
|
11
|
+
"case": "a camelCase segment is the symbol's own spelling, not renamed",
|
|
12
|
+
"value": "color.focusRing",
|
|
13
|
+
"symbols": ["color.focusRing"]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"case": "a numeric segment",
|
|
17
|
+
"value": "dimension.100",
|
|
18
|
+
"symbols": ["dimension.100"]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"case": "a deep camelCase symbol",
|
|
22
|
+
"value": "typography.weight.semiBold",
|
|
23
|
+
"symbols": ["typography.weight.semiBold"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"case": "a channel symbol, consumed by name where the implementation reads the channel",
|
|
27
|
+
"value": "modifier.color.text",
|
|
28
|
+
"symbols": ["modifier.color.text"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"case": "the surface channel spelling",
|
|
32
|
+
"value": "surface.color.background",
|
|
33
|
+
"symbols": ["surface.color.background"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"case": "the programme's central binding: a channel then the semantic token",
|
|
37
|
+
"value": ["modifier.color.text", "color.text"],
|
|
38
|
+
"symbols": ["modifier.color.text", "color.text"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"case": "three ranks, in the reference's own order",
|
|
42
|
+
"value": ["modifier.color.border", "color.border.highlighted", "color.border"],
|
|
43
|
+
"symbols": [
|
|
44
|
+
"modifier.color.border",
|
|
45
|
+
"color.border.highlighted",
|
|
46
|
+
"color.border"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"case": "a terminal literal is kept in the value and lifted from none of it",
|
|
51
|
+
"value": ["modifier.color.icon", "modifier.color.text", "currentColor"],
|
|
52
|
+
"symbols": ["modifier.color.icon", "modifier.color.text"]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"case": "a dimension tail",
|
|
56
|
+
"value": ["dimension.stroke.thickness.large", "2px"],
|
|
57
|
+
"symbols": ["dimension.stroke.thickness.large"]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"case": "a bare keyword, for a key the registry says takes a primitive",
|
|
61
|
+
"value": "flow",
|
|
62
|
+
"symbols": []
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"case": "a hyphenated CSS keyword, which the reference uses throughout",
|
|
66
|
+
"value": "not-allowed",
|
|
67
|
+
"symbols": []
|
|
68
|
+
},
|
|
69
|
+
{ "case": "a number", "value": "1.6", "symbols": [] },
|
|
70
|
+
{ "case": "a percentage", "value": "0%", "symbols": [] },
|
|
71
|
+
{ "case": "a colour", "value": "#ccc", "symbols": [] },
|
|
72
|
+
{
|
|
73
|
+
"case": "a literal holding a slash between spaces: the slash ban is on symbol spellings, never on literals",
|
|
74
|
+
"value": "1 / -1",
|
|
75
|
+
"symbols": []
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"case": "a literal a bare YAML would read as an alias",
|
|
79
|
+
"value": "*",
|
|
80
|
+
"symbols": []
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"case": "an undeclared name is still a symbol by grammar: whether it resolves is the register's question, not the parser's",
|
|
84
|
+
"value": ["modifier.surface", "color.foreground.primary"],
|
|
85
|
+
"symbols": ["modifier.surface", "color.foreground.primary"]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"case": "a computed state variable, kept as consumed under the hover.X spelling",
|
|
89
|
+
"value": ["hover.color.foreground.secondary", "color.foreground.secondary.hover"],
|
|
90
|
+
"symbols": [
|
|
91
|
+
"hover.color.foreground.secondary",
|
|
92
|
+
"color.foreground.secondary.hover"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"rejections": [
|
|
97
|
+
{ "case": "a slash path", "value": "spacing/medium", "rule": "slashPath" },
|
|
98
|
+
{
|
|
99
|
+
"case": "a slash path with a camelCase-bearing segment",
|
|
100
|
+
"value": "color/focus-ring",
|
|
101
|
+
"rule": "slashPath"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"case": "a slash path inside a sequence",
|
|
105
|
+
"value": ["modifier/color/foreground", "color/foreground/primary"],
|
|
106
|
+
"rule": "slashPath"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"case": "the retired optional marker on a slash path",
|
|
110
|
+
"value": "color/surface/button?",
|
|
111
|
+
"rule": "slashPath"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"case": "the retired optional marker on a dotted symbol",
|
|
115
|
+
"value": "color.surface.button?",
|
|
116
|
+
"rule": "marker"
|
|
117
|
+
},
|
|
118
|
+
{ "case": "the reserved root segment", "value": "$root", "rule": "root" },
|
|
119
|
+
{
|
|
120
|
+
"case": "the reserved root segment inside a dotted name",
|
|
121
|
+
"value": "color.$root.text",
|
|
122
|
+
"rule": "root"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"case": "a bare root segment",
|
|
126
|
+
"value": "color.root.text",
|
|
127
|
+
"rule": "root"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"case": "a primitive before the end: the sequence is the fallback order and a literal is what the chain ends in",
|
|
131
|
+
"value": ["2px", "dimension.stroke.thickness.large"],
|
|
132
|
+
"rule": "primitiveNotLast"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"case": "a primitive in the middle",
|
|
136
|
+
"value": ["modifier.color.text", "currentColor", "color.text"],
|
|
137
|
+
"rule": "primitiveNotLast"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"case": "a one-element sequence: a fallback order needs two",
|
|
141
|
+
"value": ["color.text"],
|
|
142
|
+
"rule": "singleton"
|
|
143
|
+
},
|
|
144
|
+
{ "case": "an empty sequence", "value": [], "rule": "empty" },
|
|
145
|
+
{ "case": "an empty scalar", "value": "", "rule": "empty" }
|
|
146
|
+
],
|
|
147
|
+
"names": [
|
|
148
|
+
{
|
|
149
|
+
"case": "a plain semantic token",
|
|
150
|
+
"variable": "--color-text",
|
|
151
|
+
"symbol": "color.text"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"case": "camelCase is restored from the kebab spelling S4 emits",
|
|
155
|
+
"variable": "--color-focus-ring",
|
|
156
|
+
"symbol": "color.focusRing"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"case": "the drift spelling S4 also emits for the same symbol",
|
|
160
|
+
"variable": "--color-focusRing",
|
|
161
|
+
"symbol": "color.focusRing"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"case": "a modifier channel",
|
|
165
|
+
"variable": "--modifier-color-text",
|
|
166
|
+
"symbol": "modifier.color.text"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"case": "a surface channel",
|
|
170
|
+
"variable": "--surface-color-background",
|
|
171
|
+
"symbol": "surface.color.background"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"case": "a channel with no base symbol: kept as consumed, register row X7",
|
|
175
|
+
"variable": "--modifier-surface",
|
|
176
|
+
"symbol": "modifier.surface",
|
|
177
|
+
"resolves": false
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"case": "a state variant of a channel: register row X5",
|
|
181
|
+
"variable": "--modifier-surface-hover",
|
|
182
|
+
"symbol": "modifier.surface.hover",
|
|
183
|
+
"resolves": false
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"case": "a computed state variable: the double dash lifts to a dot, register row X15",
|
|
187
|
+
"variable": "--hover--color-foreground-secondary",
|
|
188
|
+
"symbol": "hover.color.foreground.secondary",
|
|
189
|
+
"resolves": false
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"case": "a component-local variable is followed through its :root definition and replaced by what it consumes",
|
|
193
|
+
"variable": "--button-color-text",
|
|
194
|
+
"symbol": "color.text",
|
|
195
|
+
"via": "--button-color-text: var(--color-text)"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"case": "a component-local variable whose definition is itself a chain",
|
|
199
|
+
"variable": "--button-color-background",
|
|
200
|
+
"symbol": "modifier.color.foreground.primary",
|
|
201
|
+
"via": "--button-color-background: var(--modifier-color-foreground-primary, var(--color-foreground-primary))"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"case": "an undeclared name: kept as consumed with a comment, register row X1",
|
|
205
|
+
"variable": "--motion-duration-fast",
|
|
206
|
+
"symbol": "motion.duration.fast",
|
|
207
|
+
"resolves": false
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"case": "a composite typography slot no stratum declares",
|
|
211
|
+
"variable": "--typography-text-secondary-font-size",
|
|
212
|
+
"symbol": "typography.text.secondary.fontSize",
|
|
213
|
+
"resolves": false
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}
|
package/definitions/ontology.ttl
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
@prefix anatomy: <
|
|
1
|
+
@prefix anatomy: <https://anatomy.canonical.com/> .
|
|
2
2
|
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
3
3
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
4
4
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
5
5
|
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
6
6
|
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
|
|
7
7
|
@prefix graphql: <https://pragma.canonical.com/graphql#> .
|
|
8
|
+
# The two graphs this one is read beside. `dt:` is the token graph
|
|
9
|
+
# (@canonical/token-ontology): a style value's symbols are dt:TokenSymbol
|
|
10
|
+
# individuals, and anatomy:consumes names them. `ds:` is the design system
|
|
11
|
+
# graph (canonical/design-system), whose ds:TokenBinding record reuses
|
|
12
|
+
# anatomy:styleKey and anatomy:styleState — which is why neither carries an
|
|
13
|
+
# rdfs:domain any more.
|
|
14
|
+
@prefix dt: <https://dt.canonical.com/> .
|
|
15
|
+
@prefix ds: <https://ds.canonical.com/> .
|
|
8
16
|
|
|
9
17
|
# ═══════════════════════════════════════════════════════════════
|
|
10
18
|
# ONTOLOGY DECLARATION
|
|
11
19
|
# ═══════════════════════════════════════════════════════════════
|
|
12
20
|
|
|
13
|
-
<
|
|
14
|
-
owl:versionInfo "0.
|
|
21
|
+
<https://anatomy.canonical.com/> a owl:Ontology ;
|
|
22
|
+
owl:versionInfo "0.4.0" ;
|
|
15
23
|
rdfs:label "Anatomy DSL Ontology" ;
|
|
16
24
|
rdfs:comment "Compliant with OWL DL profile" ;
|
|
17
25
|
skos:definition """Meta-model for the Anatomy DSL — a YAML-based language
|
|
@@ -101,6 +109,57 @@ anatomy:SwitchCase a owl:Class ;
|
|
|
101
109
|
rdfs:label "Switch Case" ;
|
|
102
110
|
skos:definition "One alternative within a Switch." .
|
|
103
111
|
|
|
112
|
+
# ═══════════════════════════════════════════════════════════════
|
|
113
|
+
# THE STYLE-KEY REGISTRY
|
|
114
|
+
# ═══════════════════════════════════════════════════════════════
|
|
115
|
+
#
|
|
116
|
+
# The individuals live in registry.ttl, projected from the roster in
|
|
117
|
+
# style-keys.yaml by `bun run generate:registry`; the same roster closes
|
|
118
|
+
# anatomy:styleKey's sh:in in shapes.ttl. The vocabulary was open until
|
|
119
|
+
# 0.4.0 — "about 14 keys" documented against 39 the corpus used — and an
|
|
120
|
+
# open roster is what admitted `background.color` on a component whose
|
|
121
|
+
# stylesheet says `background-color`.
|
|
122
|
+
|
|
123
|
+
anatomy:StyleKey a owl:Class ;
|
|
124
|
+
rdfs:label "Style Key" ;
|
|
125
|
+
skos:definition """One canonical style key: a platform-agnostic property
|
|
126
|
+
the anatomy may bind. The roster was measured, not designed: it is the
|
|
127
|
+
right-hand column of a table whose left-hand column was every CSS property
|
|
128
|
+
the reference implementations bind, so a key exists because an
|
|
129
|
+
implementation binds the property, never because the vocabulary looked
|
|
130
|
+
incomplete. registry.ttl states where that measurement lives.""" ;
|
|
131
|
+
skos:example "appearance.background" ,
|
|
132
|
+
"spacing.internal.inline.start" ,
|
|
133
|
+
"typography.color" .
|
|
134
|
+
|
|
135
|
+
anatomy:valueKind a owl:DatatypeProperty ;
|
|
136
|
+
rdfs:label "value kind" ;
|
|
137
|
+
rdfs:domain anatomy:StyleKey ;
|
|
138
|
+
rdfs:range xsd:string ;
|
|
139
|
+
skos:definition """What the key admits: "token" (a symbol, or a list of
|
|
140
|
+
symbols ending at most in one primitive), "primitive" (a literal the
|
|
141
|
+
implementation writes as it stands), or "either". Measured from the
|
|
142
|
+
reference declarations mapped onto the key when the roster was taken —
|
|
143
|
+
all reading a var() is token, none is primitive, mixed is either. An
|
|
144
|
+
"either" key compiles to an sh:or in StyleShape: it carries
|
|
145
|
+
anatomy:consumes, or it carries a primitive styleValue.""" ;
|
|
146
|
+
skos:example "token" , "primitive" , "either" .
|
|
147
|
+
|
|
148
|
+
anatomy:tokenNamespace a owl:DatatypeProperty ;
|
|
149
|
+
rdfs:label "token namespace" ;
|
|
150
|
+
rdfs:domain anatomy:StyleKey ;
|
|
151
|
+
rdfs:range xsd:string ;
|
|
152
|
+
skos:definition """A dotted prefix, ending in a dot, whose symbols the key
|
|
153
|
+
admits — matched against a symbol's dotted NAME with STRSTARTS, never
|
|
154
|
+
against its IRI. Multi-valued, and a key whose base namespace is `N.`
|
|
155
|
+
carries `N.`, `modifier.N.` and `surface.N.`: a channel of a symbol in
|
|
156
|
+
`N.` is exactly what the anatomy consumes where the implementation reads
|
|
157
|
+
the channel, so without the channel spellings every channel binding in
|
|
158
|
+
the corpus would be a namespace violation. It is the single declaration of
|
|
159
|
+
which symbols a key admits, and the inverse question — which keys admit
|
|
160
|
+
this symbol — is the query over it (dt:appliesTo is retired).""" ;
|
|
161
|
+
skos:example "color." , "modifier.color." , "spacing." .
|
|
162
|
+
|
|
104
163
|
# ═══════════════════════════════════════════════════════════════
|
|
105
164
|
# OBJECT PROPERTIES
|
|
106
165
|
# ═══════════════════════════════════════════════════════════════
|
|
@@ -165,6 +224,31 @@ anatomy:hasProp a owl:ObjectProperty ;
|
|
|
165
224
|
rdfs:range anatomy:Prop ;
|
|
166
225
|
skos:definition "Attaches a pinned prop value to a named node. Named nodes only: anonymous nodes have no prop surface to pin." .
|
|
167
226
|
|
|
227
|
+
anatomy:consumes a owl:ObjectProperty ;
|
|
228
|
+
rdfs:label "consumes" ;
|
|
229
|
+
rdfs:domain anatomy:Style ;
|
|
230
|
+
rdfs:range rdf:List ;
|
|
231
|
+
skos:definition """The token symbols this style binding consumes, as an
|
|
232
|
+
ordered rdf:List whose elements are dt:TokenSymbol individuals in FALLBACK
|
|
233
|
+
ORDER: rdf:first is the primary symbol, and each rest is what the
|
|
234
|
+
implementation falls back to when the one before it is undefined. It is
|
|
235
|
+
the RDF form of the authored value — a one-to-one transcription of the
|
|
236
|
+
implementation's `var(a, var(b, …))` chain — and the reason the list and
|
|
237
|
+
not a single symbol is that the fallback is a per-slot choice: a
|
|
238
|
+
component's background and its text fall back differently, so no rule
|
|
239
|
+
declared once on a symbol can carry it.
|
|
240
|
+
|
|
241
|
+
A slot consumes a CHANNEL by name where the implementation reads the
|
|
242
|
+
channel (`modifier.color.text`) and the semantic token by name where it
|
|
243
|
+
reads the token; nothing is inferred from the spelling. A terminal
|
|
244
|
+
literal the chain ends in (`currentColor`, `0`, `1em`) is NOT an element
|
|
245
|
+
here — it resolves against nothing by design — and is carried in
|
|
246
|
+
anatomy:styleValue, which keeps the authored spelling verbatim as
|
|
247
|
+
evidence. Whether a key carries this at all is anatomy:valueKind's
|
|
248
|
+
business, and whether a symbol RESOLVES is the consumer's: a name no
|
|
249
|
+
stratum declares is kept as consumed with a register row.""" ;
|
|
250
|
+
skos:example "( dt:modifier.color.text dt:color.text )" .
|
|
251
|
+
|
|
168
252
|
# ═══════════════════════════════════════════════════════════════
|
|
169
253
|
# DATATYPE PROPERTIES
|
|
170
254
|
# ═══════════════════════════════════════════════════════════════
|
|
@@ -217,11 +301,17 @@ anatomy:slotName a owl:DatatypeProperty ;
|
|
|
217
301
|
|
|
218
302
|
anatomy:styleKey a owl:DatatypeProperty ;
|
|
219
303
|
rdfs:label "style key" ;
|
|
220
|
-
rdfs:domain
|
|
304
|
+
# No rdfs:domain, deliberately. design-system's ds:TokenBinding record
|
|
305
|
+
# (one per consumed symbol per rank) carries the key and the state of the
|
|
306
|
+
# tuple it was derived from, so a domain of anatomy:Style would type every
|
|
307
|
+
# record an anatomy:Style. The constraint that a tuple carries exactly one
|
|
308
|
+
# key lives in shapes.ttl, where it belongs. Stays an
|
|
309
|
+
# owl:DatatypeProperty: pragma asserts every term a lookup selects is a
|
|
310
|
+
# declared datatype or object property.
|
|
221
311
|
rdfs:range xsd:string ;
|
|
222
312
|
skos:definition "Platform-agnostic style property identifier." ;
|
|
223
313
|
skos:example "layout.type" ,
|
|
224
|
-
"spacing.internal" ,
|
|
314
|
+
"spacing.internal.inline.start" ,
|
|
225
315
|
"appearance.background" ,
|
|
226
316
|
"typography.weight" .
|
|
227
317
|
|
|
@@ -229,15 +319,24 @@ anatomy:styleValue a owl:DatatypeProperty ;
|
|
|
229
319
|
rdfs:label "style value" ;
|
|
230
320
|
rdfs:domain anatomy:Style ;
|
|
231
321
|
rdfs:range xsd:string ;
|
|
232
|
-
skos:definition "
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
322
|
+
skos:definition """The AUTHORED SPELLING of the value, verbatim: a scalar
|
|
323
|
+
as written, a sequence in its flow form. It is the evidence of what the
|
|
324
|
+
reference says, and it is kept even where anatomy:consumes carries the
|
|
325
|
+
same symbols in a form a query can walk — the terminal literal of a
|
|
326
|
+
fallback chain lives only here, because a literal is not a symbol.
|
|
327
|
+
|
|
328
|
+
A value is a symbol, a primitive, or a sequence whose elements are
|
|
329
|
+
symbols with at most one primitive and only as the last element. The
|
|
330
|
+
slash-delimited path and the trailing '?' marker are RETIRED: an element
|
|
331
|
+
that resolves nowhere is a register row and a comment, not a sigil.""" ;
|
|
332
|
+
skos:example "flow" ,
|
|
333
|
+
"dimension.100" ,
|
|
334
|
+
"[modifier.color.text, color.text]" ,
|
|
335
|
+
"[modifier.color.icon, modifier.color.text, currentColor]" .
|
|
237
336
|
|
|
238
337
|
anatomy:styleState a owl:DatatypeProperty ;
|
|
239
338
|
rdfs:label "style state" ;
|
|
240
|
-
rdfs:domain anatomy:
|
|
339
|
+
# No rdfs:domain, for the reason anatomy:styleKey gives.
|
|
241
340
|
rdfs:range xsd:string ;
|
|
242
341
|
skos:definition """Interaction state this style value applies in. Absent
|
|
243
342
|
means the default state. Closed vocabulary (hover, active, focus,
|