@canonical/code-standards 0.1.0 → 0.1.2

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/data/react.ttl CHANGED
@@ -15,9 +15,10 @@ cs:ComponentTSDoc a cs:CodeStandard ;
15
15
  cs:name "react/component/tsdoc" ;
16
16
  cs:hasCategory cs:ReactCategory ;
17
17
  cs:description """Component TSDoc documentation must use the description from the design system ontology (DSL). The TSDoc should NOT include @example blocks since stories serve as the examples. The description should be copied verbatim from the DSL, maintaining the original wording and meaning.""" ;
18
- cs:dos """
19
- (Do) Use the description from the DSL ontology verbatim.
20
- ```typescript
18
+ cs:do [
19
+ cs:description "Use the description from the DSL ontology verbatim." ;
20
+ cs:language "typescript" ;
21
+ cs:code """
21
22
  /**
22
23
  * The label component is a compact, non-interactive visual element used to
23
24
  * categorize content or indicate a status. Its primary role is metadata
@@ -31,41 +32,44 @@ const Label = ({ children, criticality, className, ...props }: LabelProps) => (
31
32
  {children}
32
33
  </span>
33
34
  );
34
- ```
35
- """ ;
36
- cs:donts """
37
- (Don't) Write custom descriptions that deviate from the DSL.
38
- ```typescript
35
+ """
36
+ ] ;
37
+ cs:dont [
38
+ cs:description "Write custom descriptions that deviate from the DSL." ;
39
+ cs:language "typescript" ;
40
+ cs:code """
39
41
  // Bad: Custom title and paraphrased description
40
42
  /**
41
43
  * Label component
42
44
  *
43
45
  * A compact visual element for status indication.
44
46
  */
45
- ```
46
-
47
- (Don't) Include @example blocks - stories fulfill this role.
48
- ```typescript
47
+ """
48
+ ] ;
49
+ cs:dont [
50
+ cs:description "Include @example blocks - stories fulfill this role." ;
51
+ cs:language "typescript" ;
52
+ cs:code """
49
53
  // Bad: Examples belong in stories, not TSDoc
50
54
  /**
51
55
  * The label component is a compact...
52
56
  *
53
57
  * @example
54
- * ```tsx
55
58
  * <Label>Default</Label>
56
59
  * <Label criticality="warning">Warning</Label>
57
- * ```
58
60
  */
59
- ```
60
-
61
- (Don't) Omit the @implements tag that links to the DSL.
62
- ```typescript
61
+ """
62
+ ] ;
63
+ cs:dont [
64
+ cs:description "Omit the @implements tag that links to the DSL." ;
65
+ cs:language "typescript" ;
66
+ cs:code """
63
67
  // Bad: Missing @implements tag
64
68
  /**
65
69
  * The label component is a compact...
66
70
  */
67
- ```
68
- """ .
71
+ """
72
+ ] .
69
73
 
70
74
  # Component Folder Structure Standard
71
75
  cs:ComponentFolderStructure a cs:CodeStandard ;
@@ -73,9 +77,10 @@ cs:ComponentFolderStructure a cs:CodeStandard ;
73
77
  cs:extends cs:ComponentFolderStructure ;
74
78
  cs:hasCategory cs:ReactCategory ;
75
79
  cs:description "Each component must reside in its own folder, which contains all related files: component implementation, tests, type definitions, and optionally stories and styles. Some components may be styleless or may not have stories; in these cases, styles.css and [MyComponent].stories.tsx are optional. Context providers follow a different structure (see react/component/structure/context)." ;
76
- cs:dos """
77
- (Do) Place all component-related files within a single folder named after the component.
78
- ```bash
80
+ cs:do [
81
+ cs:description "Place all component-related files within a single folder named after the component." ;
82
+ cs:language "bash" ;
83
+ cs:code """
79
84
  [MyComponent]/
80
85
  ├── [MyComponent].tsx
81
86
  ├── [MyComponent].stories.tsx
@@ -83,11 +88,12 @@ cs:ComponentFolderStructure a cs:CodeStandard ;
83
88
  ├── index.ts
84
89
  ├── styles.css
85
90
  └── types.ts
86
- ```
87
- """ ;
88
- cs:donts """
89
- (Don't) Scatter component files across different parts of the application.
90
- ```bash
91
+ """
92
+ ] ;
93
+ cs:dont [
94
+ cs:description "Scatter component files across different parts of the application." ;
95
+ cs:language "bash" ;
96
+ cs:code """
91
97
  # Bad: Files are not co-located
92
98
  components/
93
99
  ├── [MyComponent].tsx
@@ -95,46 +101,50 @@ stories/
95
101
  └── [MyComponent].stories.tsx
96
102
  styles/
97
103
  └── [MyComponent].css
98
- ```
99
- """ .
104
+ """
105
+ ] .
100
106
 
101
107
  # Barrel Exports Standard
102
108
  cs:BarrelExports a cs:CodeStandard ;
103
109
  cs:name "react/component/barrel-exports" ;
104
110
  cs:hasCategory cs:ReactCategory ;
105
111
  cs:description "The index.ts file must be a complete barrel export for the component folder, re-exporting all public APIs." ;
106
- cs:dos """
107
- (Do) Create an index.ts file that re-exports all public APIs from the component folder.
108
- ```typescript
112
+ cs:do [
113
+ cs:description "Create an index.ts file that re-exports all public APIs from the component folder." ;
114
+ cs:language "typescript" ;
115
+ cs:code """
109
116
  // index.ts
110
117
  export { default as [MyComponent] } from './[MyComponent].js';
111
118
  export type * from './types.js';
112
119
  // If you have multiple components:
113
120
  export { default as SubComponent } from './SubComponent.js';
114
- ```
115
- """ ;
116
- cs:donts """
117
- (Don't) Omit the index.ts file or fail to re-export all public APIs.
118
- ```typescript
121
+ """
122
+ ] ;
123
+ cs:dont [
124
+ cs:description "Omit the index.ts file or fail to re-export all public APIs." ;
125
+ cs:language "typescript" ;
126
+ cs:code """
119
127
  // Bad: index.ts only exports default, omits types and named exports
120
128
  export { default } from './[MyComponent].js';
121
- ```
122
-
123
- (Don't) Use `export * from './types.js'` as it allows value exports, which is not expected for types files.
124
- ```typescript
129
+ """
130
+ ] ;
131
+ cs:dont [
132
+ cs:description "Use `export * from './types.js'` as it allows value exports, which is not expected for types files." ;
133
+ cs:language "typescript" ;
134
+ cs:code """
125
135
  // Bad: Using export * from './types.js' allows value exports, which is not allowed
126
136
  export * from './types.js';
127
- ```
128
- """ .
137
+ """
138
+ ] .
129
139
 
130
140
  # Component File Naming Standard
131
141
  cs:ComponentFileNaming a cs:CodeStandard ;
132
142
  cs:name "react/component/file-naming" ;
133
143
  cs:hasCategory cs:ReactCategory ;
134
144
  cs:description "Component folder and file naming is based on scope. Component-specific files (implementation, stories, tests) must be prefixed with the component's name (e.g., `MyComponent.tsx`, `MyComponent.stories.tsx`). Domain-level files that serve the entire folder (e.g., `Context.tsx`, `styles.css`, `types.ts`) should use generic, descriptive names, as the folder already provides the domain context." ;
135
- cs:dos """
136
- (Do) Prefix component-specific files and use generic names for domain-level files.
137
- ```
145
+ cs:do [
146
+ cs:description "Prefix component-specific files and use generic names for domain-level files." ;
147
+ cs:code """
138
148
  [MyComponent]/
139
149
  ├── [MyComponent].tsx # Component-specific
140
150
  ├── [MyComponent].stories.tsx # Component-specific
@@ -142,17 +152,17 @@ cs:ComponentFileNaming a cs:CodeStandard ;
142
152
  ├── Context.tsx # Domain-level
143
153
  ├── types.ts # Domain-level
144
154
  └── styles.css # Domain-level
145
- ```
146
- """ ;
147
- cs:donts """
148
- (Don't) Add redundant prefixes to domain-level files.
149
- ```
155
+ """
156
+ ] ;
157
+ cs:dont [
158
+ cs:description "Add redundant prefixes to domain-level files." ;
159
+ cs:code """
150
160
  [MyComponent]/
151
161
  ├── [MyComponent].Context.tsx # Bad: Redundant prefix
152
162
  ├── [MyComponent].types.ts # Bad: Redundant prefix
153
163
  └── [MyComponent].styles.css # Bad: Redundant prefix
154
- ```
155
- """ .
164
+ """
165
+ ] .
156
166
 
157
167
  # Component Props Standard
158
168
  cs:ComponentProps a cs:CodeStandard ;
@@ -163,9 +173,10 @@ cs:ComponentProps a cs:CodeStandard ;
163
173
  - Be destructured when used in markup
164
174
  - Be spread to the root element when unused
165
175
  - Follow type-specific patterns based on what the component renders""" ;
166
- cs:dos """
167
- (Do) Document props with TSDoc comments and use proper destructuring and spreading.
168
- ```typescript
176
+ cs:do [
177
+ cs:description "Document props with TSDoc comments and use proper destructuring and spreading." ;
178
+ cs:language "typescript" ;
179
+ cs:code """
169
180
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
170
181
  /** The button's text content */
171
182
  label: string;
@@ -190,11 +201,12 @@ const Button = ({
190
201
  <span>{label}</span>
191
202
  </button>
192
203
  );
193
- ```
194
- """ ;
195
- cs:donts """
196
- (Don't) Mix explicit and spread props or destructure props unnecessarily.
197
- ```typescript
204
+ """
205
+ ] ;
206
+ cs:dont [
207
+ cs:description "Mix explicit and spread props or destructure props unnecessarily." ;
208
+ cs:language "typescript" ;
209
+ cs:code """
198
210
  // Bad: Mixing explicit props with spread
199
211
  const Button = (props: ButtonProps) => (
200
212
  <button
@@ -225,8 +237,8 @@ const Button = ({
225
237
  {label}
226
238
  </button>
227
239
  );
228
- ```
229
- """ .
240
+ """
241
+ ] .
230
242
 
231
243
  # HTML Rendering Components Props Standard
232
244
  cs:HTMLRenderingProps a cs:CodeStandard ;
@@ -234,66 +246,70 @@ cs:HTMLRenderingProps a cs:CodeStandard ;
234
246
  cs:hasCategory cs:ReactCategory ;
235
247
  cs:extends cs:ComponentProps ;
236
248
  cs:description "Components that render HTML markup must extend the base HTML element props interface to enable passing native properties through spreading." ;
237
- cs:dos """
238
- (Do) Extend the appropriate React HTML props interface and add component-specific props.
239
- ```typescript
249
+ cs:do [
250
+ cs:description "Extend the appropriate React HTML props interface and add component-specific props." ;
251
+ cs:language "typescript" ;
252
+ cs:code """
240
253
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
241
254
  /** The button label */
242
255
  label: string;
243
256
  }
244
- ```
245
- """ ;
246
- cs:donts """
247
- (Don't) Manually redefine standard HTML attributes that are already available through the base interface.
248
- ```typescript
257
+ """
258
+ ] ;
259
+ cs:dont [
260
+ cs:description "Manually redefine standard HTML attributes that are already available through the base interface." ;
261
+ cs:language "typescript" ;
262
+ cs:code """
249
263
  export interface ButtonProps {
250
264
  /** The button label */
251
265
  label: string;
252
266
  onClick?: () => void; // Bad: Duplicates HTML button props
253
267
  disabled?: boolean; // Bad: Duplicates HTML button props
254
268
  }
255
- ```
256
- """ .
269
+ """
270
+ ] .
257
271
 
258
272
  # Component Naming Standard
259
273
  cs:ComponentNaming a cs:CodeStandard ;
260
274
  cs:name "react/component/naming" ;
261
275
  cs:hasCategory cs:ReactCategory ;
262
276
  cs:description "Components must use PascalCase naming and be descriptive of their purpose." ;
263
- cs:dos """
264
- (Do) Use PascalCase and descriptive names for components:
277
+ cs:do [
278
+ cs:description """Use PascalCase and descriptive names for components:
265
279
  UserProfile
266
280
  NavigationBar
267
- SearchResultList
268
- """ ;
269
- cs:donts """
270
- (Don't) Use non-PascalCase or unclear names:
281
+ SearchResultList"""
282
+ ] ;
283
+ cs:dont [
284
+ cs:description """Use non-PascalCase or unclear names:
271
285
  userProfile
272
286
  navigation_bar
273
- searchresultlist
274
- """ .
287
+ searchresultlist"""
288
+ ] .
275
289
 
276
290
  # Hook Naming Standard
277
291
  cs:HookNaming a cs:CodeStandard ;
278
292
  cs:name "react/hooks/naming" ;
279
293
  cs:hasCategory cs:ReactCategory ;
280
294
  cs:description "The hook name must start with 'use' and clearly describe its purpose." ;
281
- cs:dos """
282
- (Do) Name custom hooks so the hook name starts with 'use' and is descriptive:
283
- ```typescript
295
+ cs:do [
296
+ cs:description "Name custom hooks so the hook name starts with 'use' and is descriptive" ;
297
+ cs:language "typescript" ;
298
+ cs:code """
284
299
  useWindowSize()
285
300
  useAuthentication()
286
301
  useFormValidation()
287
- ```
288
- """ ;
289
- cs:donts """
290
- (Don't) Name hooks without the 'use' prefix at the start of the hook name:
291
- ```typescript
302
+ """
303
+ ] ;
304
+ cs:dont [
305
+ cs:description "Name hooks without the 'use' prefix at the start of the hook name" ;
306
+ cs:language "typescript" ;
307
+ cs:code """
292
308
  windowSize()
293
309
  getAuth()
294
310
  formValidation()
295
- ```
296
- """ .
311
+ """
312
+ ] .
297
313
 
298
314
  # Component Dependencies Standard
299
315
  cs:ComponentDependencies a cs:CodeStandard ;
@@ -303,9 +319,9 @@ cs:ComponentDependencies a cs:CodeStandard ;
303
319
  - Subcomponents must be in a `common/` folder within the parent component's directory
304
320
  - Dependencies can flow downwards (parent to subcomponent) or sideways (between siblings)
305
321
  - Dependencies must not flow upwards (subcomponent to parent)""" ;
306
- cs:dos """
307
- (Do) Place subcomponents in a `common/` folder inside the parent component directory.
308
- ```
322
+ cs:do [
323
+ cs:description "Place subcomponents in a `common/` folder inside the parent component directory." ;
324
+ cs:code """
309
325
  Card/
310
326
  ├── Card.tsx
311
327
  ├── common/
@@ -316,30 +332,35 @@ Card/
316
332
  │ └── utils/
317
333
  │ └── helpers.ts
318
334
  └── index.ts
319
- ```
320
-
321
- (Do) Allow subcomponents to depend on siblings or shared utilities within the same component scope.
322
- ```typescript
335
+ """
336
+ ] ;
337
+ cs:do [
338
+ cs:description "Allow subcomponents to depend on siblings or shared utilities within the same component scope." ;
339
+ cs:language "typescript" ;
340
+ cs:code """
323
341
  // Header.tsx can import from utils/
324
342
  import { helper } from '../utils/helpers.js';
325
343
 
326
344
  // Footer.tsx can import from Header.tsx
327
345
  import Header from '../Header.js';
328
- ```
329
- """ ;
330
- cs:donts """
331
- (Don't) Create dependencies that flow upwards from a subcomponent to its parent.
332
- ```typescript
346
+ """
347
+ ] ;
348
+ cs:dont [
349
+ cs:description "Create dependencies that flow upwards from a subcomponent to its parent." ;
350
+ cs:language "typescript" ;
351
+ cs:code """
333
352
  // Bad: Header.tsx in Card/common/ should not import from Card.tsx
334
353
  import Card from '../../Card.js';
335
- ```
336
-
337
- (Don't) Allow external components to depend on the internal structure of another component.
338
- ```typescript
354
+ """
355
+ ] ;
356
+ cs:dont [
357
+ cs:description "Allow external components to depend on the internal structure of another component." ;
358
+ cs:language "typescript" ;
359
+ cs:code """
339
360
  // Bad: AnotherComponent should not import from Card's internal common folder
340
361
  import Header from '../Card/common/Header.js';
341
- ```
342
- """ .
362
+ """
363
+ ] .
343
364
 
344
365
  # Subcomponents Export and Consumption API Standard
345
366
  cs:SubcomponentsExportAPI a cs:CodeStandard ;
@@ -355,65 +376,77 @@ Public subcomponents must be:
355
376
  - Kept to a single level of nesting.
356
377
 
357
378
  Private subcomponents must remain internal to the component's implementation and not be exported by any file.""" ;
358
- cs:dos """
359
- (Do) Export public subcomponents by attaching them to the parent component using dot notation:
360
- ```typescript
379
+ cs:do [
380
+ cs:description "Export public subcomponents by attaching them to the parent component using dot notation" ;
381
+ cs:language "typescript" ;
382
+ cs:code """
361
383
  const Item = (props: ItemProps) => { /* ... */ };
362
384
  const Accordion = (props: AccordionProps) => { /* ... */ };
363
385
  Accordion.Item = Item;
364
386
  export default Accordion;
365
- ```
366
-
367
- (Do) Use semantic, self-descriptive names for subcomponents:
368
- ```typescript
387
+ """
388
+ ] ;
389
+ cs:do [
390
+ cs:description "Use semantic, self-descriptive names for subcomponents" ;
391
+ cs:language "typescript" ;
392
+ cs:code """
369
393
  Accordion.Item
370
394
  Card.Header
371
395
  Card.Footer
372
- ```
373
-
374
- (Do) Keep subcomponent nesting to a single level:
375
- ```typescript
396
+ """
397
+ ] ;
398
+ cs:do [
399
+ cs:description "Keep subcomponent nesting to a single level" ;
400
+ cs:language "typescript" ;
401
+ cs:code """
376
402
  <Card>
377
403
  <Card.Header />
378
404
  <Card.Footer />
379
405
  </Card>
380
- ```
381
-
382
- """ ;
383
- cs:donts """
384
- (Don't) Repeat the parent component name in subcomponent names:
385
- ```typescript
406
+ """
407
+ ] ;
408
+ cs:dont [
409
+ cs:description "Repeat the parent component name in subcomponent names" ;
410
+ cs:language "typescript" ;
411
+ cs:code """
386
412
  Card.CardHeader = Header; // Bad: Redundant 'Card' prefix
387
- ```
388
-
389
- (Don't) Map a subcomponent to a different name (renaming):
390
- ```typescript
413
+ """
414
+ ] ;
415
+ cs:dont [
416
+ cs:description "Map a subcomponent to a different name (renaming)" ;
417
+ cs:language "typescript" ;
418
+ cs:code """
391
419
  Card.Top = Header; // Bad: Mapping 'Header' to 'Top' is not allowed
392
- ```
393
-
394
- (Don't) Use non-semantic or unclear subcomponent names:
395
- ```
420
+ """
421
+ ] ;
422
+ cs:dont [
423
+ cs:description "Use non-semantic or unclear subcomponent names" ;
424
+ cs:code """
396
425
  Card/
397
426
  └── common/
398
427
  ├── Part/ # Bad: Too vague, not semantic - what part?
399
428
  ├── Element/ # Bad: Too vague, not semantic - what element?
400
- ```
401
-
402
- (Don't) Nest subcomponents more than one level deep:
403
- ```typescript
429
+ """
430
+ ] ;
431
+ cs:dont [
432
+ cs:description "Nest subcomponents more than one level deep" ;
433
+ cs:language "typescript" ;
434
+ cs:code """
404
435
  <Card>
405
436
  <Card.Header>
406
437
  <Card.Header.Title />
407
438
  </Card.Header>
408
439
  </Card>
409
- ```
410
-
411
- (Don't) Export private subcomponents that are not intended for public use.
412
- ```typescript
440
+ """
441
+ ] ;
442
+ cs:dont [
443
+ cs:description "Export private subcomponents that are not intended for public use." ;
444
+ cs:language "typescript" ;
445
+ cs:code """
413
446
  // Bad: Exporting internal-only subcomponents
414
447
  export { InternalHelper };
415
- ```
416
- """ .
448
+ """
449
+ ] .
417
450
 
418
451
  # CSS ClassName Construction Standard
419
452
  cs:ClassNameConstruction a cs:CodeStandard ;
@@ -428,9 +461,10 @@ cs:ClassNameConstruction a cs:CodeStandard ;
428
461
  b. Modifier Classes: Classes derived from component props (e.g., `emphasis`, `severity`).
429
462
  c. Consumer Classes: The `className` prop passed by the consumer.
430
463
  4. Filtering and Joining: The array must be processed with `.filter(Boolean).join(" ")` to remove any falsy values (e.g., undefined props, expressions that evaluate to false) and create the final space-delimited string.""" ;
431
- cs:dos """
432
- (Do) Follow the complete pattern for class name construction.
433
- ```tsx
464
+ cs:do [
465
+ cs:description "Follow the complete pattern for class name construction." ;
466
+ cs:language "tsx" ;
467
+ cs:code """
434
468
  const componentCssClassName = "ds badge";
435
469
 
436
470
  const Badge = ({
@@ -450,27 +484,32 @@ const Badge = ({
450
484
  </span>
451
485
  );
452
486
  };
453
- ```
454
- """ ;
455
- cs:donts """
456
- (Don't) Hardcode the base class name inside the JSX.
457
- ```tsx
487
+ """
488
+ ] ;
489
+ cs:dont [
490
+ cs:description "Hardcode the base class name inside the JSX." ;
491
+ cs:language "tsx" ;
492
+ cs:code """
458
493
  // Bad: Base class "ds badge" is hardcoded.
459
494
  <span className={["ds badge", severity, className].filter(Boolean).join(" ")}>
460
- ```
461
-
462
- (Don't) Place the consumer `className` prop before other classes.
463
- ```tsx
495
+ """
496
+ ] ;
497
+ cs:dont [
498
+ cs:description "Place the consumer `className` prop before other classes." ;
499
+ cs:language "tsx" ;
500
+ cs:code """
464
501
  // Bad: Consumer class is first
465
502
  <span className={[className, componentCssClassName, severity].filter(Boolean).join(" ")}>
466
- ```
467
-
468
- (Don't) Use string concatenation or template literals to add class names.
469
- ```tsx
503
+ """
504
+ ] ;
505
+ cs:dont [
506
+ cs:description "Use string concatenation or template literals to add class names." ;
507
+ cs:language "tsx" ;
508
+ cs:code """
470
509
  // Bad: Harder to read and maintain, vulnerable to inconsistent formatting
471
510
  <span className={`${componentCssClassName} ${severity} ${className}`}>
472
- ```
473
- """ .
511
+ """
512
+ ] .
474
513
 
475
514
  # Wrapper Component Props Standard
476
515
  cs:WrapperComponentProps a cs:CodeStandard ;
@@ -478,9 +517,10 @@ cs:WrapperComponentProps a cs:CodeStandard ;
478
517
  cs:hasCategory cs:ReactCategory ;
479
518
  cs:extends cs:ComponentProps ;
480
519
  cs:description "Wrapper components must use namespaced props for inner components and accept unscoped props for the wrapper element." ;
481
- cs:dos """
482
- (Do) Use namespaced props for inner components and unscoped props for the wrapper element.
483
- ```tsx
520
+ cs:do [
521
+ cs:description "Use namespaced props for inner components and unscoped props for the wrapper element." ;
522
+ cs:language "tsx" ;
523
+ cs:code """
484
524
  interface ThumbnailSectionProps extends SectionProps {
485
525
  /** Props for the thumbnail image */
486
526
  imageProps: Omit<React.ImgHTMLAttributes<HTMLImageElement>, "alt"> & {
@@ -497,11 +537,12 @@ const ThumbnailSection = ({
497
537
  <img {...imageProps} />
498
538
  </Section>
499
539
  );
500
- ```
501
- """ ;
502
- cs:donts """
503
- (Don't) Mix prop scopes between wrapper and inner components.
504
- ```tsx
540
+ """
541
+ ] ;
542
+ cs:dont [
543
+ cs:description "Mix prop scopes between wrapper and inner components." ;
544
+ cs:language "tsx" ;
545
+ cs:code """
505
546
  interface ThumbnailSectionProps {
506
547
  src: string; // Bad: Unscoped image props
507
548
  alt: string; // Bad: Unscoped image props
@@ -513,8 +554,8 @@ const ThumbnailSection = ({ src, alt, width, ...props }: ThumbnailSectionProps)
513
554
  <img src={src} alt={alt} width={width} />
514
555
  </Section>
515
556
  );
516
- ```
517
- """ .
557
+ """
558
+ ] .
518
559
 
519
560
  # Custom Hooks Standard
520
561
  cs:CustomHooks a cs:CodeStandard ;
@@ -528,17 +569,21 @@ cs:CustomHooks a cs:CodeStandard ;
528
569
 
529
570
  All of the types for a domain level's hooks must be defined in the `hooks/types.ts` file of that folder.
530
571
  Each hook must define a [HookName]Props and [HookName]Result type in `hooks/types.ts`.""" ;
531
- cs:dos """
532
- (Do) Create a custom hook that focuses on a single concern within the domain.
533
- ```typescript
572
+ cs:do [
573
+ cs:description "Create a custom hook that focuses on a single concern within the domain." ;
574
+ cs:language "typescript" ;
575
+ cs:code """
534
576
  // [MyComponent]/hooks/useWindowFitment.ts
535
577
  const useWindowFitment = ({
536
578
  onBestPositionChange,
537
579
  autoFit = false,
538
580
  }: UseWindowFitmentProps): UseWindowFitmentResult => {
539
- ```
540
- (Do) Create hook types in `hooks/types.ts`.
541
- ```typescript
581
+ """
582
+ ] ;
583
+ cs:do [
584
+ cs:description "Create hook types in `hooks/types.ts`." ;
585
+ cs:language "typescript" ;
586
+ cs:code """
542
587
  // [MyComponent]/hooks/types.ts
543
588
  export interface UseWindowFitmentProps {
544
589
  /**
@@ -571,21 +616,23 @@ export interface UseWindowFitmentResult {
571
616
  */
572
617
  popupPositionStyle: CSSProperties;
573
618
  }
574
- ```
575
-
576
- """ ;
577
- cs:donts """
578
- (Don't) Create a custom hook for simple, non-reusable state.
579
- ```tsx
619
+ """
620
+ ] ;
621
+ cs:dont [
622
+ cs:description "Create a custom hook for simple, non-reusable state." ;
623
+ cs:language "tsx" ;
624
+ cs:code """
580
625
  // Bad: Unnecessary abstraction for a simple counter
581
626
  const useCounter = () => {
582
627
  const [count, setCount] = useState(0);
583
628
  return { count, setCount };
584
629
  };
585
- ```
586
-
587
- (Don't) Mix multiple concerns in a single hook
588
- ```typescript
630
+ """
631
+ ] ;
632
+ cs:dont [
633
+ cs:description "Mix multiple concerns in a single hook" ;
634
+ cs:language "typescript" ;
635
+ cs:code """
589
636
  // Bad: Multiple concerns in one hook
590
637
  const useUserData = () => {
591
638
  const [isAuthenticated, setIsAuthenticated] = useState(false);
@@ -594,8 +641,8 @@ const useUserData = () => {
594
641
  const [notifications, setNotifications] = useState([]);
595
642
  return { isAuthenticated, profile, settings, notifications };
596
643
  };
597
- ```
598
- """ .
644
+ """
645
+ ] .
599
646
 
600
647
  # Context Provider Structure Standard
601
648
  cs:ContextProviderStructure a cs:CodeStandard ;
@@ -603,9 +650,9 @@ cs:ContextProviderStructure a cs:CodeStandard ;
603
650
  cs:extends cs:ComponentFolderStructure ;
604
651
  cs:hasCategory cs:ReactCategory ;
605
652
  cs:description "Context providers must use `Provider.tsx` as the main component file instead of the standard component naming pattern `[MyComponent].tsx`. Provider prop and return types must be defined in the hook-level types file `hooks/types.ts` with `UseProviderStateProps` (containing all `ProviderProps` minus `children`) and `UseProviderStateResult` (matching the context options)." ;
606
- cs:dos """
607
- (Do) Organize provider-related files by separating concerns into distinct files: place the context definition in `Context.tsx`, the provider implementation in `Provider.tsx`, and provider-specific hooks in a `hooks/` directory. Create a `hooks/useProviderState.ts` file to centrally manage the state of the provider.`
608
- ```
653
+ cs:do [
654
+ cs:description "Organize provider-related files by separating concerns into distinct files: place the context definition in `Context.tsx`, the provider implementation in `Provider.tsx`, and provider-specific hooks in a `hooks/` directory. Create a `hooks/useProviderState.ts` file to centrally manage the state of the provider.`" ;
655
+ cs:code """
609
656
  [MyComponent]/
610
657
  ├── Context.tsx
611
658
  ├── Provider.tsx
@@ -620,10 +667,12 @@ cs:ContextProviderStructure a cs:CodeStandard ;
620
667
  ├── index.ts
621
668
  ├── types.ts
622
669
  └── useProviderState.ts
623
- ```
624
- (Do) Create the context type within `types.ts`.
625
-
626
- ```typescript
670
+ """
671
+ ] ;
672
+ cs:do [
673
+ cs:description "Create the context type within `types.ts`." ;
674
+ cs:language "typescript" ;
675
+ cs:code """
627
676
  // [MyComponent]/types.ts
628
677
  /** The value of the config context */
629
678
  export interface ContextOptions {
@@ -632,11 +681,12 @@ export interface ContextOptions {
632
681
  /** Toggles the baseline grid's visibility. */
633
682
  toggleShowBaselineGrid: () => void;
634
683
  }
635
- ```
636
-
637
- (Do) create the provider props type within `types.ts`, accepting `children` at a minimum and more props as needed.
638
-
639
- ```typescript
684
+ """
685
+ ] ;
686
+ cs:do [
687
+ cs:description "create the provider props type within `types.ts`, accepting `children` at a minimum and more props as needed." ;
688
+ cs:language "typescript" ;
689
+ cs:code """
640
690
  // [MyComponent]/types.ts
641
691
 
642
692
  export interface ProviderProps {
@@ -644,10 +694,12 @@ export interface ProviderProps {
644
694
  children: React.ReactNode;
645
695
  // ...other props...
646
696
  }
647
- ```
648
-
649
- (Do) Create a `Context.tsx` file for the context definition.
650
- ```tsx
697
+ """
698
+ ] ;
699
+ cs:do [
700
+ cs:description "Create a `Context.tsx` file for the context definition." ;
701
+ cs:language "tsx" ;
702
+ cs:code """
651
703
  // [MyComponent]/Context.tsx
652
704
  import { createContext } from "react";
653
705
  import type { ContextOptions } from "./types.js";
@@ -655,11 +707,12 @@ import type { ContextOptions } from "./types.js";
655
707
  const Context = createContext<ContextOptions | undefined>(undefined);
656
708
 
657
709
  export default Context;
658
- ```
659
-
660
-
661
- (Do) Use `Provider.tsx` as the main component file. The provider is responsible for wrapping children with the context.
662
- ```tsx
710
+ """
711
+ ] ;
712
+ cs:do [
713
+ cs:description "Use `Provider.tsx` as the main component file. The provider is responsible for wrapping children with the context." ;
714
+ cs:language "tsx" ;
715
+ cs:code """
663
716
  // [MyComponent]/Provider.tsx
664
717
  import Context from "./Context.js";
665
718
  import { useProviderState } from "./hooks/useProviderState.js";
@@ -671,10 +724,12 @@ const Provider = ({ children }: ProviderProps) => {
671
724
  };
672
725
 
673
726
  export default Provider;
674
- ```
675
-
676
- (Do) Use `index.ts` to export the `Provider` as a named component that matches the folder name, casting it to the component type.
677
- ```typescript
727
+ """
728
+ ] ;
729
+ cs:do [
730
+ cs:description "Use `index.ts` to export the `Provider` as a named component that matches the folder name, casting it to the component type." ;
731
+ cs:language "typescript" ;
732
+ cs:code """
678
733
  // [MyComponent]/types.ts
679
734
  import type { ReactElement } from "react";
680
735
 
@@ -688,10 +743,12 @@ import type { [MyComponent] } from "./types.js";
688
743
 
689
744
  export const [MyComponent] = Provider as [MyComponent]Component;
690
745
  export default [MyComponent];
691
- ```
692
-
693
- (Do) Create provider state hook types in `hooks/types.ts` for context providers.
694
- ```typescript
746
+ """
747
+ ] ;
748
+ cs:do [
749
+ cs:description "Create provider state hook types in `hooks/types.ts` for context providers." ;
750
+ cs:language "typescript" ;
751
+ cs:code """
695
752
  // [MyComponent]/hooks/types.ts
696
753
  import type { ContextOptions, ProviderProps } from "../types.js";
697
754
 
@@ -700,10 +757,12 @@ export type UseProviderStateProps = Omit<ProviderProps, "children">;
700
757
 
701
758
  // The result of the provider state hook. This should match the context options defined in the main component types file.
702
759
  export type UseProviderStateResult = ContextOptions;
703
- ```
704
-
705
- (Do) Create a provider state hook implementation.
706
- ```tsx
760
+ """
761
+ ] ;
762
+ cs:do [
763
+ cs:description "Create a provider state hook implementation." ;
764
+ cs:language "tsx" ;
765
+ cs:code """
707
766
  // [MyComponent]/hooks/useProviderState.ts
708
767
  import { useContext } from "react";
709
768
  import type { UseProviderStateProps, UseProviderStateResult } from "./types.js";
@@ -716,37 +775,40 @@ const useProviderState = ({
716
775
  }: UseProviderStateProps): UseProviderStateResult => {
717
776
  // centralize the entire provider state here...
718
777
  }
719
- ```
720
- """ ;
721
- cs:donts """
722
- (Don't) Create a separate component file (e.g., `[MyComponent].tsx`) when `Provider.tsx` exists. The provider is the main component.
723
- ```
778
+ """
779
+ ] ;
780
+ cs:dont [
781
+ cs:description "Create a separate component file (e.g., `[MyComponent].tsx`) when `Provider.tsx` exists. The provider is the main component." ;
782
+ cs:code """
724
783
  [MyComponent]/
725
784
  ├── [MyComponent].tsx
726
785
  └── Provider.tsx
727
- ```
728
-
729
- (Don't) Nest context-related files in a `context/` subfolder.
730
- ```
786
+ """
787
+ ] ;
788
+ cs:dont [
789
+ cs:description "Nest context-related files in a `context/` subfolder." ;
790
+ cs:code """
731
791
  [MyComponent]/
732
792
  └── context/ # Unnecessary nesting
733
793
  ├── Context.tsx
734
794
  └── Provider.tsx
735
- ```
736
-
737
- (Don't) Create multiple provider files within the same component folder.
738
- ```
795
+ """
796
+ ] ;
797
+ cs:dont [
798
+ cs:description "Create multiple provider files within the same component folder." ;
799
+ cs:code """
739
800
  [MyComponent]/
740
801
  ├── Provider.tsx
741
802
  └── AnotherProvider.tsx # Only one provider per component
742
- ```
743
-
744
- (Don't) Mix concerns of the Provider and its state.
745
-
746
- ```tsx
803
+ """
804
+ ] ;
805
+ cs:dont [
806
+ cs:description "Mix concerns of the Provider and its state." ;
807
+ cs:language "tsx" ;
808
+ cs:code """
747
809
  exort const Provider = ({ children }: ProviderProps) => {
748
810
  const [state, setState] = useState(...); // Bad: State logic mixed in
749
811
  return <Context.Provider value={{ state, setState }}>{children}</Context.Provider>;
750
812
  };
751
- ```
752
- """ .
813
+ """
814
+ ] .