@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/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)