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