@canonical/code-standards 0.1.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/.mcp.json +8 -0
- package/README.md +297 -0
- package/data/code.ttl +437 -0
- package/data/css.ttl +265 -0
- package/data/icons.ttl +359 -0
- package/data/packaging.ttl +464 -0
- package/data/react.ttl +752 -0
- package/data/rust.ttl +1806 -0
- package/data/storybook.ttl +403 -0
- package/data/styling.ttl +165 -0
- package/data/tsdoc.ttl +216 -0
- package/data/turtle.ttl +179 -0
- package/definitions/CodeStandard.ttl +80 -0
- package/docs/code.md +720 -0
- package/docs/css.md +275 -0
- package/docs/icons.md +367 -0
- package/docs/index.md +15 -0
- package/docs/react.md +766 -0
- package/docs/rust.md +1784 -0
- package/docs/storybook.md +413 -0
- package/docs/styling.md +163 -0
- package/docs/tsdoc.md +213 -0
- package/docs/turtle.md +179 -0
- package/package.json +9 -0
- package/skills/add-standard/SKILL.md +288 -0
- package/src/scripts/generate-docs.ts +131 -0
- package/src/scripts/index.ts +19 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
@prefix cs: <http://pragma.canonical.com/codestandards#> .
|
|
2
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
3
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
4
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
5
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
6
|
+
|
|
7
|
+
# Storybook Category
|
|
8
|
+
cs:StorybookCategory a cs:Category ;
|
|
9
|
+
rdfs:label "Storybook"@en ;
|
|
10
|
+
rdfs:comment "Standards for documenting components using Storybook"@en ;
|
|
11
|
+
cs:slug "storybook" .
|
|
12
|
+
|
|
13
|
+
# Documentation Source Standard
|
|
14
|
+
cs:DocumentationSource a cs:CodeStandard ;
|
|
15
|
+
cs:name "storybook/documentation/source" ;
|
|
16
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
17
|
+
cs:description "Component documentation must primarily come from TSDoc comments on the component signature and props. Storybook docs overrides should only be used when the documentation needs to differ between code and Storybook contexts." ;
|
|
18
|
+
cs:dos """
|
|
19
|
+
(Do) Use TSDoc comments for primary documentation.
|
|
20
|
+
```typescript
|
|
21
|
+
|
|
22
|
+
// ContextualMenu/types.ts
|
|
23
|
+
export interface ContextualMenuProps extends HTMLAttributes<HTMLDivElement> {
|
|
24
|
+
/** The element that triggers the contextual menu */
|
|
25
|
+
children: ReactElement;
|
|
26
|
+
/** The items to display in the contextual menu */
|
|
27
|
+
items: MenuItem[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ContextualMenu/ContextualMenu.tsx
|
|
31
|
+
/**
|
|
32
|
+
* A wrapper component that adds a contextual menu to its children.
|
|
33
|
+
* The menu appears when the children are clicked or activated via keyboard.
|
|
34
|
+
*/
|
|
35
|
+
const ContextualMenu = ({
|
|
36
|
+
children,
|
|
37
|
+
items,
|
|
38
|
+
}: ContextualMenuProps): ReactElement => {
|
|
39
|
+
// ...
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
""" ;
|
|
43
|
+
cs:donts """
|
|
44
|
+
(Don't) Add documentation in Storybook parameters when TSDoc is sufficient.
|
|
45
|
+
```typescript
|
|
46
|
+
export const Default: Story = {
|
|
47
|
+
parameters: {
|
|
48
|
+
docs: {
|
|
49
|
+
description: {
|
|
50
|
+
component: "A wrapper component that adds a contextual menu to its children" // Covered in TSDoc
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
""" .
|
|
57
|
+
|
|
58
|
+
# Story Visibility Standard
|
|
59
|
+
cs:StoryVisibility a cs:CodeStandard ;
|
|
60
|
+
cs:name "storybook/story/visibility" ;
|
|
61
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
62
|
+
cs:description "Stories that exist solely for testing or visual coverage but don't represent valid usage patterns must be hidden from documentation and the sidebar using tags." ;
|
|
63
|
+
cs:dos """
|
|
64
|
+
(Do) Hide test-only stories that don't represent valid usage.
|
|
65
|
+
```typescript
|
|
66
|
+
export const FocusedState: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
isOpen: true,
|
|
69
|
+
children: "Test Content"
|
|
70
|
+
},
|
|
71
|
+
tags: ["!dev", "!autodocs"],
|
|
72
|
+
play: async ({ canvasElement }) => {
|
|
73
|
+
const element = canvasElement.querySelector(".component");
|
|
74
|
+
element.focus();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
""" ;
|
|
79
|
+
cs:donts """
|
|
80
|
+
(Don't) Show implementation details or test states in documentation.
|
|
81
|
+
```typescript
|
|
82
|
+
export const InternalTestState: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
_internalProp: true, // Bad: Exposing internal state
|
|
85
|
+
children: "Test"
|
|
86
|
+
},
|
|
87
|
+
parameters: {
|
|
88
|
+
docs: {
|
|
89
|
+
description: { story: "Tests internal state" } // Bad: Implementation detail
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
""" .
|
|
95
|
+
|
|
96
|
+
# Story Format Standard
|
|
97
|
+
cs:StoryFormat a cs:CodeStandard ;
|
|
98
|
+
cs:name "storybook/story/format" ;
|
|
99
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
100
|
+
cs:description """Stories must use one of three formats, each serving specific needs:
|
|
101
|
+
1. CSF3 (object-based) format must be used for standard component variations where args define the component state.
|
|
102
|
+
2. Function-based format must be used when the story needs to directly control component rendering or wrap the component with custom elements.
|
|
103
|
+
3. Template-based format must be used when multiple stories share the same logic but differ in their args, and the template differs from the component markup.""" ;
|
|
104
|
+
cs:dos """
|
|
105
|
+
(Do) Use the format that matches your specific use case.
|
|
106
|
+
```typescript
|
|
107
|
+
// CSF3: For standard component variations through args
|
|
108
|
+
type Story = StoryObj<typeof meta>;
|
|
109
|
+
|
|
110
|
+
export const Default: Story = {
|
|
111
|
+
args: {
|
|
112
|
+
variant: "primary",
|
|
113
|
+
children: "Click me",
|
|
114
|
+
disabled: false
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Function-based: When story needs dynamic rendering logic
|
|
119
|
+
export const WithDynamicChildren = (args: ComponentProps) => {
|
|
120
|
+
const [items] = useState(["Item 1", "Item 2"]);
|
|
121
|
+
return (
|
|
122
|
+
<Component {...args}>
|
|
123
|
+
{items.map((item) => (
|
|
124
|
+
<ListItem key={item}>{item}</ListItem>
|
|
125
|
+
))}
|
|
126
|
+
</Component>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Template-based: When multiple stories share logic
|
|
131
|
+
const Template: StoryFn<typeof Component> = (args) => (
|
|
132
|
+
<div className="button-container">
|
|
133
|
+
<Label>Button:</Label>
|
|
134
|
+
<Component {...args} />
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
export const Primary = Template.bind({});
|
|
139
|
+
Primary.args = { variant: "primary" };
|
|
140
|
+
```
|
|
141
|
+
""" ;
|
|
142
|
+
cs:donts """
|
|
143
|
+
(Don't) Use a format that doesn't match your use case.
|
|
144
|
+
```typescript
|
|
145
|
+
// Bad: Using function format for simple args variation
|
|
146
|
+
export const SimpleButton = () => (
|
|
147
|
+
<Component variant="primary" disabled={false}>
|
|
148
|
+
Click me
|
|
149
|
+
</Component>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Bad: Duplicating complex logic without template
|
|
153
|
+
export const First: Story = {
|
|
154
|
+
decorators: [(Story) => (
|
|
155
|
+
<div className="button-container">
|
|
156
|
+
<Label>Button:</Label>
|
|
157
|
+
<Story />
|
|
158
|
+
</div>
|
|
159
|
+
)]
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
""" .
|
|
163
|
+
|
|
164
|
+
# Story Decorator Standard
|
|
165
|
+
cs:StoryDecorator a cs:CodeStandard ;
|
|
166
|
+
cs:name "storybook/story/decorator" ;
|
|
167
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
168
|
+
cs:description "Decorators must be used to wrap stories in common context providers or layout elements. Decorators should generally be defined in `storybook/decorators.tsx` and be imported as `decorators` in the storybook file. Decorators may be defined inline in story files in limited circumstances when it would be difficult to globally define a semantic decorator (e.g., a decorator that provides mock data specific to that component)." ;
|
|
169
|
+
cs:dos """
|
|
170
|
+
(Do) Use decorators for static context or layout wrapping.
|
|
171
|
+
```typescript
|
|
172
|
+
|
|
173
|
+
// storybook/decorators.tsx
|
|
174
|
+
|
|
175
|
+
export const theme = (Story: StoryFn<typeof Component>) => (
|
|
176
|
+
<ThemeProvider theme="dark">
|
|
177
|
+
<Story />
|
|
178
|
+
</ThemeProvider>
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
export const config = (Story: StoryFn<typeof Component>) => (
|
|
182
|
+
<ConfigProvider locale="en">
|
|
183
|
+
<Story />
|
|
184
|
+
</ConfigProvider>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// src/ui/<ComponentName>/<ComponentName>.stories.tsx
|
|
188
|
+
|
|
189
|
+
import * as decorators from "storybook/decorators.js";
|
|
190
|
+
export const WithTheme: Story = {
|
|
191
|
+
decorators: [decorators.theme],
|
|
192
|
+
args: {
|
|
193
|
+
variant: "primary"
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Component-level decorator in meta, applies to all stories in this file.
|
|
198
|
+
const meta = {
|
|
199
|
+
decorators: [decorators.config],
|
|
200
|
+
} satisfies Meta<typeof Component>;
|
|
201
|
+
|
|
202
|
+
export default meta;
|
|
203
|
+
```
|
|
204
|
+
""" ;
|
|
205
|
+
cs:donts """
|
|
206
|
+
(Don't) Use function-based stories for static wrapping that could be done with decorators.
|
|
207
|
+
```typescript
|
|
208
|
+
// Bad: Using function-based story for static wrapping
|
|
209
|
+
export const WithTheme = (args: ComponentProps) => (
|
|
210
|
+
<ThemeProvider theme="dark">
|
|
211
|
+
<Component {...args} />
|
|
212
|
+
</ThemeProvider>
|
|
213
|
+
);
|
|
214
|
+
```
|
|
215
|
+
""" .
|
|
216
|
+
|
|
217
|
+
# Story Import Standard
|
|
218
|
+
cs:StoryImport a cs:CodeStandard ;
|
|
219
|
+
cs:name "storybook/story/import" ;
|
|
220
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
221
|
+
cs:description "Stories must import their component as 'Component' to maintain a consistent, generic reference that is decoupled from the specific component name." ;
|
|
222
|
+
cs:dos """
|
|
223
|
+
(Do) Import the component generically as 'Component'.
|
|
224
|
+
```typescript
|
|
225
|
+
import Component from "./SkipLink.js";
|
|
226
|
+
|
|
227
|
+
const meta = {
|
|
228
|
+
title: "SkipLink",
|
|
229
|
+
component: Component,
|
|
230
|
+
} satisfies Meta<typeof Component>;
|
|
231
|
+
|
|
232
|
+
export const Default: Story = {
|
|
233
|
+
args: {
|
|
234
|
+
children: "Skip to main content"
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
```
|
|
238
|
+
""" ;
|
|
239
|
+
cs:donts """
|
|
240
|
+
(Don't) Import the component using its specific name.
|
|
241
|
+
```typescript
|
|
242
|
+
import SkipLink from "./SkipLink.js";
|
|
243
|
+
|
|
244
|
+
const meta = {
|
|
245
|
+
title: "SkipLink",
|
|
246
|
+
component: SkipLink, // Bad: Using specific component name
|
|
247
|
+
} satisfies Meta<typeof SkipLink>;
|
|
248
|
+
```
|
|
249
|
+
""" .
|
|
250
|
+
|
|
251
|
+
# Story Organization Standard
|
|
252
|
+
cs:StoryOrganization a cs:CodeStandard ;
|
|
253
|
+
cs:name "storybook/story/organization" ;
|
|
254
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
255
|
+
cs:description "Stories must be organized into logical groups that demonstrate related features and variations. Each story should focus on a specific use case or feature, with clear naming that indicates what aspect of the component it demonstrates." ;
|
|
256
|
+
cs:dos """
|
|
257
|
+
(Do) Group related features with clear, descriptive names.
|
|
258
|
+
```typescript
|
|
259
|
+
// Basic usage
|
|
260
|
+
export const Default: Story = {
|
|
261
|
+
args: {
|
|
262
|
+
mainId: "main",
|
|
263
|
+
children: "Skip to main content"
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Custom element targeting
|
|
268
|
+
export const CustomMainElement: Story = {
|
|
269
|
+
args: {
|
|
270
|
+
mainId: "my-main-element",
|
|
271
|
+
children: "Skip to main content"
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Content customization
|
|
276
|
+
export const CustomText: Story = {
|
|
277
|
+
args: {
|
|
278
|
+
mainId: "main",
|
|
279
|
+
children: "Jump to content"
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
```
|
|
283
|
+
""" ;
|
|
284
|
+
cs:donts """
|
|
285
|
+
(Don't) Use unclear names or mix unrelated features in a single story.
|
|
286
|
+
```typescript
|
|
287
|
+
// Bad: Unclear what this story demonstrates
|
|
288
|
+
export const Variant1: Story = {
|
|
289
|
+
args: {
|
|
290
|
+
mainId: "custom",
|
|
291
|
+
children: "Skip",
|
|
292
|
+
className: "special",
|
|
293
|
+
onClick: () => {},
|
|
294
|
+
style: { color: "red" }
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
""" .
|
|
299
|
+
|
|
300
|
+
# Story Testing Standard
|
|
301
|
+
cs:StoryTesting a cs:CodeStandard ;
|
|
302
|
+
cs:name "storybook/story/testing" ;
|
|
303
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
304
|
+
cs:description "Stories that test component behavior must use the `play` function to simulate user interactions and verify expected outcomes." ;
|
|
305
|
+
cs:dos """
|
|
306
|
+
(Do) Use play functions to test interactive behavior.
|
|
307
|
+
```typescript
|
|
308
|
+
export const InteractionTest: Story = {
|
|
309
|
+
args: {
|
|
310
|
+
children: "Click Me",
|
|
311
|
+
onClick: () => {}
|
|
312
|
+
},
|
|
313
|
+
play: async ({ canvasElement, args }) => {
|
|
314
|
+
const button = canvasElement.querySelector("button");
|
|
315
|
+
await userEvent.click(button);
|
|
316
|
+
await expect(args.onClick).toHaveBeenCalled();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
```
|
|
320
|
+
""" ;
|
|
321
|
+
cs:donts """
|
|
322
|
+
(Don't) Test implementation details or internal state.
|
|
323
|
+
```typescript
|
|
324
|
+
export const InternalTest: Story = {
|
|
325
|
+
play: async ({ component }) => {
|
|
326
|
+
// Bad: Testing internal implementation
|
|
327
|
+
expect(component._internalState).toBe(true);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
```
|
|
331
|
+
""" .
|
|
332
|
+
|
|
333
|
+
# Story Documentation Standard
|
|
334
|
+
cs:StoryDocumentation a cs:CodeStandard ;
|
|
335
|
+
cs:name "storybook/story/documentation" ;
|
|
336
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
337
|
+
cs:description "Story documentation must focus on usage patterns and variations, not implementation details. Each story should demonstrate a specific use case or variation." ;
|
|
338
|
+
cs:dos """
|
|
339
|
+
(Do) Document usage patterns and variations.
|
|
340
|
+
```typescript
|
|
341
|
+
export const WithCustomTrigger: Story = {
|
|
342
|
+
args: {
|
|
343
|
+
trigger: <button>Custom Trigger</button>
|
|
344
|
+
},
|
|
345
|
+
parameters: {
|
|
346
|
+
docs: {
|
|
347
|
+
description: {
|
|
348
|
+
story: "The component accepts a custom trigger element to replace the default button."
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
```
|
|
354
|
+
""" ;
|
|
355
|
+
cs:donts """
|
|
356
|
+
(Don't) Document implementation details or internal behavior.
|
|
357
|
+
```typescript
|
|
358
|
+
export const Default: Story = {
|
|
359
|
+
parameters: {
|
|
360
|
+
docs: {
|
|
361
|
+
description: {
|
|
362
|
+
story: "Uses React.createPortal internally to render the popup" // Bad: Implementation detail
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
```
|
|
368
|
+
""" .
|
|
369
|
+
|
|
370
|
+
# Story Naming Standard
|
|
371
|
+
cs:StoryNaming a cs:CodeStandard ;
|
|
372
|
+
cs:name "storybook/story/naming" ;
|
|
373
|
+
cs:hasCategory cs:StorybookCategory ;
|
|
374
|
+
cs:description "Story names must be descriptive and follow a consistent pattern. Use PascalCase for story exports and natural language for story titles." ;
|
|
375
|
+
cs:dos """
|
|
376
|
+
(Do) Use clear, descriptive names that indicate the variation.
|
|
377
|
+
```typescript
|
|
378
|
+
export const WithCustomStyles: Story = {
|
|
379
|
+
args: {
|
|
380
|
+
className: "custom",
|
|
381
|
+
children: "Styled Content"
|
|
382
|
+
},
|
|
383
|
+
parameters: {
|
|
384
|
+
docs: {
|
|
385
|
+
description: {
|
|
386
|
+
story: "Demonstrates custom styling options"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
```
|
|
392
|
+
""" ;
|
|
393
|
+
cs:donts """
|
|
394
|
+
(Don't) Use technical or implementation-focused names.
|
|
395
|
+
```typescript
|
|
396
|
+
export const TestCase1: Story = { // Bad: Non-descriptive name
|
|
397
|
+
args: {
|
|
398
|
+
_testFlag: true, // Bad: Implementation detail
|
|
399
|
+
children: "Content"
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
```
|
|
403
|
+
""" .
|
package/data/styling.ttl
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
@prefix cs: <http://pragma.canonical.com/codestandards#> .
|
|
2
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
3
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
4
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
5
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
6
|
+
|
|
7
|
+
# Styling Category
|
|
8
|
+
cs:StylingCategory a cs:Category ;
|
|
9
|
+
rdfs:label "Styling"@en ;
|
|
10
|
+
rdfs:comment "Standards for implementing design system styling patterns"@en ;
|
|
11
|
+
cs:slug "styling" .
|
|
12
|
+
|
|
13
|
+
cs:TokenTypes a cs:CodeStandard ;
|
|
14
|
+
cs:name "styling/tokens/types" ;
|
|
15
|
+
cs:hasCategory cs:StylingCategory ;
|
|
16
|
+
cs:description """Design tokens follow a strict hierarchy:
|
|
17
|
+
- Primitive tokens: Raw values that form the foundation of the design system
|
|
18
|
+
- Semantic tokens: Map semantic concepts to primitive token values
|
|
19
|
+
- Component tokens: Map component properties to semantic token values
|
|
20
|
+
""" ;
|
|
21
|
+
cs:dos """
|
|
22
|
+
(Do) Define semantic tokens that map to primitive tokens.
|
|
23
|
+
```
|
|
24
|
+
{
|
|
25
|
+
"color": {
|
|
26
|
+
"background": {
|
|
27
|
+
"default": {
|
|
28
|
+
"$type": "color",
|
|
29
|
+
"$value": "{color.neutral.100}"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
""" ;
|
|
36
|
+
cs:donts """
|
|
37
|
+
(Don't) Skip the semantic layer by mapping component tokens directly to primitives.
|
|
38
|
+
```
|
|
39
|
+
{
|
|
40
|
+
"button": {
|
|
41
|
+
"padding": {
|
|
42
|
+
"vertical": {
|
|
43
|
+
"$type": "dimension",
|
|
44
|
+
"$value": "{spacing.unit}" # Should reference semantic token like {spacing.vertical.medium}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
""" .
|
|
51
|
+
|
|
52
|
+
# Design Token Creation Standard
|
|
53
|
+
cs:DesignTokenCreation a cs:CodeStandard ;
|
|
54
|
+
cs:name "styling/tokens/creation" ;
|
|
55
|
+
cs:hasCategory cs:StylingCategory ;
|
|
56
|
+
cs:description """Design tokens must be created for all design decisions in a component. See css/properties/values for how these tokens are used in CSS implementation.""" ;
|
|
57
|
+
cs:dos """
|
|
58
|
+
(Do) Create component tokens that reference semantic tokens for design decisions.
|
|
59
|
+
```
|
|
60
|
+
{
|
|
61
|
+
"button": {
|
|
62
|
+
"background": {
|
|
63
|
+
"$type": "color",
|
|
64
|
+
"$value": "{color.background.primary}"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
""" ;
|
|
70
|
+
cs:donts """
|
|
71
|
+
(Don't) Use raw values for design decisions.
|
|
72
|
+
```
|
|
73
|
+
{
|
|
74
|
+
"button": {
|
|
75
|
+
"background": {
|
|
76
|
+
"$type": "color",
|
|
77
|
+
"$value": "#0066CC" # Should reference semantic token like {color.background.primary}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
""" .
|
|
83
|
+
|
|
84
|
+
# Theme Definition Standard
|
|
85
|
+
cs:ThemeDefinition a cs:CodeStandard ;
|
|
86
|
+
cs:name "styling/themes/definition" ;
|
|
87
|
+
cs:hasCategory cs:StylingCategory ;
|
|
88
|
+
cs:description """Themes are collections of semantic tokens that provide consistent styling across components. See css/themes/activation for implementation details.""" ;
|
|
89
|
+
cs:dos """
|
|
90
|
+
(Do) Define a theme as a complete set of semantic tokens.
|
|
91
|
+
```
|
|
92
|
+
{
|
|
93
|
+
"theme": {
|
|
94
|
+
"canonical": {
|
|
95
|
+
"color": {
|
|
96
|
+
"background": {
|
|
97
|
+
"default": {
|
|
98
|
+
"$type": "color",
|
|
99
|
+
"$value": "{color.neutral.100}"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
""" ;
|
|
108
|
+
cs:donts """
|
|
109
|
+
(Don't) Mix implementation details into theme definitions.
|
|
110
|
+
```
|
|
111
|
+
{
|
|
112
|
+
"theme": {
|
|
113
|
+
"canonical": {
|
|
114
|
+
"class": "canonical", // Bad: CSS implementation detail
|
|
115
|
+
"container": "div", // Bad: HTML implementation detail
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
""" .
|
|
121
|
+
|
|
122
|
+
# Token Scoping Standard
|
|
123
|
+
cs:TokenScoping a cs:CodeStandard ;
|
|
124
|
+
cs:name "styling/tokens/scoping" ;
|
|
125
|
+
cs:hasCategory cs:StylingCategory ;
|
|
126
|
+
cs:description """Design tokens must be scoped according to their type:
|
|
127
|
+
- Primitive tokens: Global scope (system-wide base values)
|
|
128
|
+
- Semantic tokens: Theme scope (theme-specific bindings to primitive tokens)
|
|
129
|
+
- Component tokens: Component scope (bindings to semantic tokens)
|
|
130
|
+
""" ;
|
|
131
|
+
cs:dos """
|
|
132
|
+
(Do) Define primitive tokens in global scope.
|
|
133
|
+
```
|
|
134
|
+
{
|
|
135
|
+
"color": {
|
|
136
|
+
"neutral": {
|
|
137
|
+
"100": {
|
|
138
|
+
"$type": "color",
|
|
139
|
+
"$value": "#FFFFFF"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
""" ;
|
|
146
|
+
cs:donts """
|
|
147
|
+
(Don't) Define primitive tokens in theme scope.
|
|
148
|
+
```
|
|
149
|
+
{
|
|
150
|
+
"theme": {
|
|
151
|
+
"canonical": {
|
|
152
|
+
"color": {
|
|
153
|
+
"neutral": {
|
|
154
|
+
"100": {
|
|
155
|
+
"$type": "color",
|
|
156
|
+
"$value": "#FFFFFF" # Should be defined in global scope
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
""" .
|
|
165
|
+
|