@canonical/code-standards 0.1.0 → 0.1.1
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/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- package/.github/workflows/ci.yml +40 -0
- package/biome.json +6 -0
- package/bun.lock +200 -0
- package/data/code.ttl +208 -167
- package/data/css.ttl +110 -91
- package/data/icons.ttl +186 -150
- package/data/packaging.ttl +428 -170
- package/data/react.ttl +306 -244
- package/data/rust.ttl +563 -467
- package/data/storybook.ttl +108 -90
- package/data/styling.ttl +40 -40
- package/data/tsdoc.ttl +111 -86
- package/data/turtle.ttl +89 -68
- package/definitions/CodeStandard.ttl +28 -20
- package/docs/code.md +37 -327
- package/docs/css.md +20 -19
- package/docs/icons.md +37 -41
- package/docs/index.md +2 -1
- package/docs/packaging.md +643 -0
- package/docs/react.md +54 -58
- package/docs/rust.md +92 -158
- package/docs/storybook.md +18 -20
- package/docs/styling.md +8 -8
- package/docs/tsdoc.md +16 -16
- package/docs/turtle.md +15 -15
- package/package.json +16 -2
- package/skills/add-standard/SKILL.md +83 -47
- package/src/scripts/generate-docs.ts +95 -13
- package/src/scripts/index.ts +4 -2
- package/tsconfig.json +8 -0
package/docs/css.md
CHANGED
|
@@ -8,7 +8,7 @@ Component styles must be encapsulated using the component's root class as a boun
|
|
|
8
8
|
|
|
9
9
|
### Do
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Scope internal element styles using the component's namespace.
|
|
12
12
|
```css
|
|
13
13
|
.ds.button {
|
|
14
14
|
/* Component root styles */
|
|
@@ -22,7 +22,7 @@ Component styles must be encapsulated using the component's root class as a boun
|
|
|
22
22
|
|
|
23
23
|
### Don't
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Don't style internal elements without the component namespace.
|
|
26
26
|
```css
|
|
27
27
|
/* Bad: Internal element not scoped to component */
|
|
28
28
|
.icon {
|
|
@@ -38,7 +38,7 @@ Component states must be handled using attribute selectors for native states and
|
|
|
38
38
|
|
|
39
39
|
### Do
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Use attribute selectors for native element states.
|
|
42
42
|
```css
|
|
43
43
|
.ds.button {
|
|
44
44
|
&[disabled] {
|
|
@@ -49,7 +49,7 @@ Component states must be handled using attribute selectors for native states and
|
|
|
49
49
|
|
|
50
50
|
### Don't
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Use class modifiers for native states.
|
|
53
53
|
```css
|
|
54
54
|
/* Bad: Using class for native state */
|
|
55
55
|
.ds.button.disabled {
|
|
@@ -65,14 +65,15 @@ CSS properties must use design tokens for design decisions (see styling/tokens/c
|
|
|
65
65
|
|
|
66
66
|
### Do
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Use design tokens for design decisions.
|
|
69
69
|
```css
|
|
70
70
|
.ds.button {
|
|
71
71
|
/* Design decision uses token */
|
|
72
72
|
background: var(--button-background);
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
|
-
|
|
75
|
+
|
|
76
|
+
Use raw values for unthemable properties (independent of design decisions).
|
|
76
77
|
```css
|
|
77
78
|
.ds.skip-link {
|
|
78
79
|
visibility: hidden;
|
|
@@ -81,7 +82,7 @@ CSS properties must use design tokens for design decisions (see styling/tokens/c
|
|
|
81
82
|
|
|
82
83
|
### Don't
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
Use raw values for design decisions.
|
|
85
86
|
```css
|
|
86
87
|
.ds.button {
|
|
87
88
|
/* Bad: Design decision using raw value */
|
|
@@ -97,7 +98,7 @@ Child elements within components must use simple, role-based class names (e.g.,
|
|
|
97
98
|
|
|
98
99
|
### Do
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
Use simple role-based class names scoped by the parent.
|
|
101
102
|
```css
|
|
102
103
|
.ds.accordion-item {
|
|
103
104
|
& > .header {
|
|
@@ -130,7 +131,7 @@ Child elements within components must use simple, role-based class names (e.g.,
|
|
|
130
131
|
|
|
131
132
|
### Don't
|
|
132
133
|
|
|
133
|
-
|
|
134
|
+
Use verbose prefixed class names that repeat the component name.
|
|
134
135
|
```css
|
|
135
136
|
/* Bad: Redundant component prefix in child class names */
|
|
136
137
|
.ds.accordion-item .accordion-item-header {
|
|
@@ -154,7 +155,7 @@ All component selectors must be prefixed with the `.ds` namespace (e.g., `.ds.bu
|
|
|
154
155
|
|
|
155
156
|
### Do
|
|
156
157
|
|
|
157
|
-
|
|
158
|
+
Prefix all component selectors with `.ds`.
|
|
158
159
|
```css
|
|
159
160
|
/* Component root with namespace */
|
|
160
161
|
.ds.button {
|
|
@@ -164,7 +165,7 @@ All component selectors must be prefixed with the `.ds` namespace (e.g., `.ds.bu
|
|
|
164
165
|
|
|
165
166
|
### Don't
|
|
166
167
|
|
|
167
|
-
|
|
168
|
+
Omit the `.ds` namespace from component selectors.
|
|
168
169
|
```css
|
|
169
170
|
/* Bad: Missing .ds namespace */
|
|
170
171
|
.button {
|
|
@@ -180,14 +181,14 @@ Component CSS class names must be the kebab-case version of the component's Pasc
|
|
|
180
181
|
|
|
181
182
|
### Do
|
|
182
183
|
|
|
183
|
-
|
|
184
|
+
Convert PascalCase component names to kebab-case for CSS classes:
|
|
184
185
|
- `MyComponent` -> `.ds.my-component`
|
|
185
186
|
- `UserProfile` -> `.ds.user-profile`
|
|
186
187
|
- `Button` -> `.ds.button`
|
|
187
188
|
|
|
188
189
|
### Don't
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
Use PascalCase or other formats in CSS class names:
|
|
191
192
|
- `.ds.MyComponent` (Bad: Not kebab-case)
|
|
192
193
|
- `.ds.user_profile` (Bad: Not kebab-case)
|
|
193
194
|
|
|
@@ -199,7 +200,7 @@ CSS class names must describe the purpose or state of an element, not its appear
|
|
|
199
200
|
|
|
200
201
|
### Do
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
Use semantic modifier classes to represent component variations.
|
|
203
204
|
```css
|
|
204
205
|
/* Semantic modifier for a primary button */
|
|
205
206
|
.ds.button.primary {
|
|
@@ -209,7 +210,7 @@ CSS class names must describe the purpose or state of an element, not its appear
|
|
|
209
210
|
|
|
210
211
|
### Don't
|
|
211
212
|
|
|
212
|
-
|
|
213
|
+
Use non-semantic or presentational class names.
|
|
213
214
|
```css
|
|
214
215
|
/* Bad: 'big' describes appearance, not purpose */
|
|
215
216
|
.ds.button.big {
|
|
@@ -228,7 +229,7 @@ CSS selectors must follow a strict specificity pattern:
|
|
|
228
229
|
|
|
229
230
|
### Do
|
|
230
231
|
|
|
231
|
-
|
|
232
|
+
Use a single modifier class for component variants.
|
|
232
233
|
```css
|
|
233
234
|
.ds.button.primary {
|
|
234
235
|
/* Variant: root + modifier (3 classes) */
|
|
@@ -238,7 +239,7 @@ CSS selectors must follow a strict specificity pattern:
|
|
|
238
239
|
|
|
239
240
|
### Don't
|
|
240
241
|
|
|
241
|
-
|
|
242
|
+
Combine multiple modifiers or mix states with variants.
|
|
242
243
|
```css
|
|
243
244
|
/* Bad: Mixing variant with state */
|
|
244
245
|
.ds.button.primary[disabled].large {
|
|
@@ -254,7 +255,7 @@ Theme tokens must be activated through CSS classes on container elements. See st
|
|
|
254
255
|
|
|
255
256
|
### Do
|
|
256
257
|
|
|
257
|
-
|
|
258
|
+
Define semantic tokens within theme classes.
|
|
258
259
|
```css
|
|
259
260
|
.canonical {
|
|
260
261
|
--spacing-vertical-medium: var(--spacing-unit-2x);
|
|
@@ -264,7 +265,7 @@ Theme tokens must be activated through CSS classes on container elements. See st
|
|
|
264
265
|
|
|
265
266
|
### Don't
|
|
266
267
|
|
|
267
|
-
|
|
268
|
+
Hardcode theme names in component styles.
|
|
268
269
|
```css
|
|
269
270
|
/* Bad: Component locked to specific theme */
|
|
270
271
|
.ds.button {
|
package/docs/icons.md
CHANGED
|
@@ -10,7 +10,7 @@ Icon files must:
|
|
|
10
10
|
|
|
11
11
|
### Do
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Use kebab-case and a semantic identifier for the icon file name.
|
|
14
14
|
```
|
|
15
15
|
warning.svg
|
|
16
16
|
user-profile.svg
|
|
@@ -19,7 +19,7 @@ arrow-down.svg
|
|
|
19
19
|
|
|
20
20
|
### Don't
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Include size, theme, or redundant suffixes in the file name.
|
|
23
23
|
```
|
|
24
24
|
warning-16.svg
|
|
25
25
|
warning-dark.svg
|
|
@@ -27,7 +27,7 @@ warning_icon.svg
|
|
|
27
27
|
WARNING.svg
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Use non-semantic or ambiguous names that do not describe the icon.
|
|
31
31
|
```
|
|
32
32
|
icon1.svg
|
|
33
33
|
shape.svg
|
|
@@ -41,7 +41,7 @@ Each icon shall be stored as a single SVG file in the `icons/` directory.
|
|
|
41
41
|
|
|
42
42
|
### Do
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Store each icon as an individual SVG file in the designated `icons/` directory.
|
|
45
45
|
```
|
|
46
46
|
icons/
|
|
47
47
|
├── warning.svg
|
|
@@ -51,7 +51,7 @@ icons/
|
|
|
51
51
|
|
|
52
52
|
### Don't
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Store icons in nested directories or use incorrect file extensions.
|
|
55
55
|
```
|
|
56
56
|
icons/
|
|
57
57
|
├── variants/
|
|
@@ -61,7 +61,7 @@ icons/
|
|
|
61
61
|
└── warning.svg.txt
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Combine multiple icons into a single SVG file.
|
|
65
65
|
```
|
|
66
66
|
icons/
|
|
67
67
|
└── all-icons.svg
|
|
@@ -75,7 +75,7 @@ Icon must use `fill` with `currentColor` for their paths and shapes.
|
|
|
75
75
|
|
|
76
76
|
### Do
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Use `currentColor` for the `fill` of paths in non-branded icons.
|
|
79
79
|
```svg
|
|
80
80
|
<!-- Non-branded icon -->
|
|
81
81
|
<svg viewBox="0 0 16 16">
|
|
@@ -87,12 +87,12 @@ Icon must use `fill` with `currentColor` for their paths and shapes.
|
|
|
87
87
|
|
|
88
88
|
### Don't
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
Use hard-coded colors in icons.
|
|
91
91
|
```svg
|
|
92
92
|
<path fill="#000000" d="..." />
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
Use `opacity` to create different shades of a color.
|
|
96
96
|
```svg
|
|
97
97
|
<path fill="currentColor" opacity="0.5" d="..." />
|
|
98
98
|
```
|
|
@@ -105,7 +105,7 @@ Each icon's SVG markup must contain a single `<g>` element with an `id` matching
|
|
|
105
105
|
|
|
106
106
|
### Do
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
Include a single `<g>` element with an `id` that matches the filename.
|
|
109
109
|
```svg
|
|
110
110
|
<!-- warning.svg -->
|
|
111
111
|
<svg>
|
|
@@ -117,7 +117,7 @@ Each icon's SVG markup must contain a single `<g>` element with an `id` matching
|
|
|
117
117
|
|
|
118
118
|
### Don't
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Use multiple `<g>` elements or an `id` that does not match the filename.
|
|
121
121
|
```svg
|
|
122
122
|
<!-- warning.svg -->
|
|
123
123
|
<svg>
|
|
@@ -138,8 +138,8 @@ Icons may use SVG masks to negate or partially negate paths, enabling advanced v
|
|
|
138
138
|
|
|
139
139
|
### Do
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
Example
|
|
141
|
+
Use SVG <mask> elements to create negative space or overlays in icons.
|
|
142
|
+
Example
|
|
143
143
|
```svg
|
|
144
144
|
<svg width='16' height='16' xmlns='http://www.w3.org/2000/svg'>
|
|
145
145
|
<defs>
|
|
@@ -154,8 +154,7 @@ Example:
|
|
|
154
154
|
</svg>
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
Example:
|
|
157
|
+
Use <rect> with fill=
|
|
159
158
|
```svg
|
|
160
159
|
<mask id="mask">
|
|
161
160
|
<rect width="16" height="16" fill="white"/>
|
|
@@ -163,8 +162,8 @@ Example:
|
|
|
163
162
|
</mask>
|
|
164
163
|
```
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
Example
|
|
165
|
+
Use opacity on mask paths to achieve partial negation (e.g., faded or semi-transparent cutouts).
|
|
166
|
+
Example
|
|
168
167
|
```svg
|
|
169
168
|
<mask id="progress-mask">
|
|
170
169
|
<rect width="16" height="16" fill="white"/>
|
|
@@ -172,16 +171,15 @@ Example:
|
|
|
172
171
|
</mask>
|
|
173
172
|
```
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
Example:
|
|
174
|
+
Reference the mask in the icon's main shape using mask=
|
|
177
175
|
```svg
|
|
178
176
|
<circle fill='currentColor' cx='8' cy='8' r='7' mask="url(#mask-id)"/>
|
|
179
177
|
```
|
|
180
178
|
|
|
181
179
|
### Don't
|
|
182
180
|
|
|
183
|
-
|
|
184
|
-
Example
|
|
181
|
+
Use masks without clear purpose or visual benefit.
|
|
182
|
+
Example
|
|
185
183
|
```svg
|
|
186
184
|
<!-- Bad: Mask used but has no effect -->
|
|
187
185
|
<mask id="empty-mask">
|
|
@@ -190,8 +188,8 @@ Example:
|
|
|
190
188
|
<circle fill='currentColor' cx='8' cy='8' r='7' mask="url(#empty-mask)"/>
|
|
191
189
|
```
|
|
192
190
|
|
|
193
|
-
|
|
194
|
-
Example
|
|
191
|
+
use non-semantic mask ids or omit mask references in the main shape.
|
|
192
|
+
Example
|
|
195
193
|
```svg
|
|
196
194
|
<!-- Bad: Non-semantic mask id -->
|
|
197
195
|
<mask id="123">
|
|
@@ -200,8 +198,8 @@ Example:
|
|
|
200
198
|
</mask>
|
|
201
199
|
```
|
|
202
200
|
|
|
203
|
-
|
|
204
|
-
Example
|
|
201
|
+
rely on masks for simple icons that do not require negative space or overlays.
|
|
202
|
+
Example
|
|
205
203
|
```svg
|
|
206
204
|
<!-- Bad: Mask used for a simple shape -->
|
|
207
205
|
<mask id="simple-mask">
|
|
@@ -218,7 +216,7 @@ All icon SVGs must use a `viewBox` of `0 0 16 16`.
|
|
|
218
216
|
|
|
219
217
|
### Do
|
|
220
218
|
|
|
221
|
-
|
|
219
|
+
Set the `viewBox` attribute to `0 0 16 16` in the `<svg>` element.
|
|
222
220
|
```svg
|
|
223
221
|
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'>
|
|
224
222
|
<g id="icon">
|
|
@@ -229,7 +227,7 @@ All icon SVGs must use a `viewBox` of `0 0 16 16`.
|
|
|
229
227
|
|
|
230
228
|
### Don't
|
|
231
229
|
|
|
232
|
-
|
|
230
|
+
Use a `viewBox` with dimensions other than `16 16`.
|
|
233
231
|
```svg
|
|
234
232
|
<!-- Bad: Different viewBox size -->
|
|
235
233
|
<svg viewBox="0 0 24 24">
|
|
@@ -237,7 +235,7 @@ All icon SVGs must use a `viewBox` of `0 0 16 16`.
|
|
|
237
235
|
</svg>
|
|
238
236
|
```
|
|
239
237
|
|
|
240
|
-
|
|
238
|
+
Use a non-square `viewBox`.
|
|
241
239
|
```svg
|
|
242
240
|
<!-- Bad: Non-square viewBox -->
|
|
243
241
|
<svg viewBox="0 0 16 24">
|
|
@@ -245,7 +243,7 @@ All icon SVGs must use a `viewBox` of `0 0 16 16`.
|
|
|
245
243
|
</svg>
|
|
246
244
|
```
|
|
247
245
|
|
|
248
|
-
|
|
246
|
+
Omit the `viewBox` attribute.
|
|
249
247
|
```svg
|
|
250
248
|
<!-- Bad: Missing viewBox -->
|
|
251
249
|
<svg width="16" height="16">
|
|
@@ -264,7 +262,7 @@ Icon names must be:
|
|
|
264
262
|
|
|
265
263
|
### Do
|
|
266
264
|
|
|
267
|
-
|
|
265
|
+
Define a constant array of icon names and derive the `IconName` type from it in the icon exporter package.
|
|
268
266
|
```typescript
|
|
269
267
|
// In the icon exporter package
|
|
270
268
|
export const ICON_NAMES = [
|
|
@@ -276,7 +274,7 @@ export const ICON_NAMES = [
|
|
|
276
274
|
export type IconName = typeof ICON_NAMES[number];
|
|
277
275
|
```
|
|
278
276
|
|
|
279
|
-
|
|
277
|
+
Import the `IconName` type in consumer code to ensure type safety.
|
|
280
278
|
```typescript
|
|
281
279
|
// In consumer code
|
|
282
280
|
import type { IconName } from '@canonical/ds-assets';
|
|
@@ -286,8 +284,7 @@ export interface ComponentProps {
|
|
|
286
284
|
}
|
|
287
285
|
```
|
|
288
286
|
|
|
289
|
-
|
|
290
|
-
|
|
287
|
+
Use `Pick` to restrict choices from `IconName` when necessary.
|
|
291
288
|
```typescript
|
|
292
289
|
// In consumer code
|
|
293
290
|
import type { IconName } from '@canonical/ds-assets';
|
|
@@ -299,7 +296,7 @@ export interface ComponentProps {
|
|
|
299
296
|
|
|
300
297
|
### Don't
|
|
301
298
|
|
|
302
|
-
|
|
299
|
+
Define icon name types or values on the consumer side.
|
|
303
300
|
```typescript
|
|
304
301
|
// Bad: String literal type defined in consumer code
|
|
305
302
|
type ComponentIconName = "warning" | "search";
|
|
@@ -309,7 +306,7 @@ export interface ComponentProps {
|
|
|
309
306
|
}
|
|
310
307
|
```
|
|
311
308
|
|
|
312
|
-
|
|
309
|
+
Use a generic `string` type for icon names.
|
|
313
310
|
```typescript
|
|
314
311
|
// Bad: No type safety for icon names
|
|
315
312
|
export interface ComponentProps {
|
|
@@ -317,7 +314,7 @@ export interface ComponentProps {
|
|
|
317
314
|
}
|
|
318
315
|
```
|
|
319
316
|
|
|
320
|
-
|
|
317
|
+
Maintain separate type and value definitions.
|
|
321
318
|
```typescript
|
|
322
319
|
// Bad: Duplication of icon names
|
|
323
320
|
const ICONS = ["warning", "search"];
|
|
@@ -332,7 +329,7 @@ Each icon concept must have exactly one SVG file. Size and theme variants are no
|
|
|
332
329
|
|
|
333
330
|
### Do
|
|
334
331
|
|
|
335
|
-
|
|
332
|
+
Use a single SVG file for each icon and control its size and color with CSS.
|
|
336
333
|
```svg
|
|
337
334
|
<!-- Single icon file -->
|
|
338
335
|
<svg viewBox="0 0 16 16">
|
|
@@ -340,8 +337,7 @@ Each icon concept must have exactly one SVG file. Size and theme variants are no
|
|
|
340
337
|
<path fill="currentColor" d="..." />
|
|
341
338
|
</g>
|
|
342
339
|
</svg>
|
|
343
|
-
|
|
344
|
-
```css
|
|
340
|
+
|
|
345
341
|
/* CSS usage */
|
|
346
342
|
.small-icon { font-size: 1em; } /* 16px */
|
|
347
343
|
.large-icon { font-size: 2em; } /* 32px */
|
|
@@ -350,14 +346,14 @@ Each icon concept must have exactly one SVG file. Size and theme variants are no
|
|
|
350
346
|
|
|
351
347
|
### Don't
|
|
352
348
|
|
|
353
|
-
|
|
349
|
+
Create multiple files for different icon sizes.
|
|
354
350
|
```
|
|
355
351
|
warning.svg
|
|
356
352
|
warning-small.svg
|
|
357
353
|
warning-large.svg
|
|
358
354
|
```
|
|
359
355
|
|
|
360
|
-
|
|
356
|
+
Create multiple files for different themes.
|
|
361
357
|
```
|
|
362
358
|
warning.svg
|
|
363
359
|
warning-dark.svg
|
package/docs/index.md
CHANGED
|
@@ -4,9 +4,10 @@ Standards documentation generated from the code-standards ontology.
|
|
|
4
4
|
|
|
5
5
|
## Categories
|
|
6
6
|
|
|
7
|
-
- [Code](./code.md) (
|
|
7
|
+
- [Code](./code.md) (7)
|
|
8
8
|
- [CSS](./css.md) (9)
|
|
9
9
|
- [Icons](./icons.md) (8)
|
|
10
|
+
- [Packaging](./packaging.md) (7)
|
|
10
11
|
- [React](./react.md) (14)
|
|
11
12
|
- [Rust](./rust.md) (11)
|
|
12
13
|
- [Storybook](./storybook.md) (9)
|