@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/docs/react.md CHANGED
@@ -8,7 +8,7 @@ The index.ts file must be a complete barrel export for the component folder, re-
8
8
 
9
9
  ### Do
10
10
 
11
- (Do) Create an index.ts file that re-exports all public APIs from the component folder.
11
+ Create an index.ts file that re-exports all public APIs from the component folder.
12
12
  ```typescript
13
13
  // index.ts
14
14
  export { default as [MyComponent] } from './[MyComponent].js';
@@ -19,13 +19,13 @@ export { default as SubComponent } from './SubComponent.js';
19
19
 
20
20
  ### Don't
21
21
 
22
- (Don't) Omit the index.ts file or fail to re-export all public APIs.
22
+ Omit the index.ts file or fail to re-export all public APIs.
23
23
  ```typescript
24
24
  // Bad: index.ts only exports default, omits types and named exports
25
25
  export { default } from './[MyComponent].js';
26
26
  ```
27
27
 
28
- (Don't) Use `export * from './types.js'` as it allows value exports, which is not expected for types files.
28
+ Use `export * from './types.js'` as it allows value exports, which is not expected for types files.
29
29
  ```typescript
30
30
  // Bad: Using export * from './types.js' allows value exports, which is not allowed
31
31
  export * from './types.js';
@@ -47,7 +47,7 @@ Component CSS class names must be constructed following a specific pattern:
47
47
 
48
48
  ### Do
49
49
 
50
- (Do) Follow the complete pattern for class name construction.
50
+ Follow the complete pattern for class name construction.
51
51
  ```tsx
52
52
  const componentCssClassName = "ds badge";
53
53
 
@@ -72,19 +72,19 @@ const Badge = ({
72
72
 
73
73
  ### Don't
74
74
 
75
- (Don't) Hardcode the base class name inside the JSX.
75
+ Hardcode the base class name inside the JSX.
76
76
  ```tsx
77
77
  // Bad: Base class "ds badge" is hardcoded.
78
78
  <span className={["ds badge", severity, className].filter(Boolean).join(" ")}>
79
79
  ```
80
80
 
81
- (Don't) Place the consumer `className` prop before other classes.
81
+ Place the consumer `className` prop before other classes.
82
82
  ```tsx
83
83
  // Bad: Consumer class is first
84
84
  <span className={[className, componentCssClassName, severity].filter(Boolean).join(" ")}>
85
85
  ```
86
86
 
87
- (Don't) Use string concatenation or template literals to add class names.
87
+ Use string concatenation or template literals to add class names.
88
88
  ```tsx
89
89
  // Bad: Harder to read and maintain, vulnerable to inconsistent formatting
90
90
  <span className={`${componentCssClassName} ${severity} ${className}`}>
@@ -101,7 +101,7 @@ Component dependencies must follow a strict unidirectional flow:
101
101
 
102
102
  ### Do
103
103
 
104
- (Do) Place subcomponents in a `common/` folder inside the parent component directory.
104
+ Place subcomponents in a `common/` folder inside the parent component directory.
105
105
  ```
106
106
  Card/
107
107
  ├── Card.tsx
@@ -115,7 +115,7 @@ Card/
115
115
  └── index.ts
116
116
  ```
117
117
 
118
- (Do) Allow subcomponents to depend on siblings or shared utilities within the same component scope.
118
+ Allow subcomponents to depend on siblings or shared utilities within the same component scope.
119
119
  ```typescript
120
120
  // Header.tsx can import from utils/
121
121
  import { helper } from '../utils/helpers.js';
@@ -126,13 +126,13 @@ import Header from '../Header.js';
126
126
 
127
127
  ### Don't
128
128
 
129
- (Don't) Create dependencies that flow upwards from a subcomponent to its parent.
129
+ Create dependencies that flow upwards from a subcomponent to its parent.
130
130
  ```typescript
131
131
  // Bad: Header.tsx in Card/common/ should not import from Card.tsx
132
132
  import Card from '../../Card.js';
133
133
  ```
134
134
 
135
- (Don't) Allow external components to depend on the internal structure of another component.
135
+ Allow external components to depend on the internal structure of another component.
136
136
  ```typescript
137
137
  // Bad: AnotherComponent should not import from Card's internal common folder
138
138
  import Header from '../Card/common/Header.js';
@@ -146,7 +146,7 @@ Component folder and file naming is based on scope. Component-specific files (im
146
146
 
147
147
  ### Do
148
148
 
149
- (Do) Prefix component-specific files and use generic names for domain-level files.
149
+ Prefix component-specific files and use generic names for domain-level files.
150
150
  ```
151
151
  [MyComponent]/
152
152
  ├── [MyComponent].tsx # Component-specific
@@ -159,7 +159,7 @@ Component folder and file naming is based on scope. Component-specific files (im
159
159
 
160
160
  ### Don't
161
161
 
162
- (Don't) Add redundant prefixes to domain-level files.
162
+ Add redundant prefixes to domain-level files.
163
163
  ```
164
164
  [MyComponent]/
165
165
  ├── [MyComponent].Context.tsx # Bad: Redundant prefix
@@ -175,14 +175,14 @@ Components must use PascalCase naming and be descriptive of their purpose.
175
175
 
176
176
  ### Do
177
177
 
178
- (Do) Use PascalCase and descriptive names for components:
178
+ Use PascalCase and descriptive names for components:
179
179
  UserProfile
180
180
  NavigationBar
181
181
  SearchResultList
182
182
 
183
183
  ### Don't
184
184
 
185
- (Don't) Use non-PascalCase or unclear names:
185
+ Use non-PascalCase or unclear names:
186
186
  userProfile
187
187
  navigation_bar
188
188
  searchresultlist
@@ -199,7 +199,7 @@ Component props must:
199
199
 
200
200
  ### Do
201
201
 
202
- (Do) Document props with TSDoc comments and use proper destructuring and spreading.
202
+ Document props with TSDoc comments and use proper destructuring and spreading.
203
203
  ```typescript
204
204
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
205
205
  /** The button's text content */
@@ -229,7 +229,7 @@ const Button = ({
229
229
 
230
230
  ### Don't
231
231
 
232
- (Don't) Mix explicit and spread props or destructure props unnecessarily.
232
+ Mix explicit and spread props or destructure props unnecessarily.
233
233
  ```typescript
234
234
  // Bad: Mixing explicit props with spread
235
235
  const Button = (props: ButtonProps) => (
@@ -271,7 +271,7 @@ Components that render HTML markup must extend the base HTML element props inter
271
271
 
272
272
  ### Do
273
273
 
274
- (Do) Extend the appropriate React HTML props interface and add component-specific props.
274
+ Extend the appropriate React HTML props interface and add component-specific props.
275
275
  ```typescript
276
276
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
277
277
  /** The button label */
@@ -281,7 +281,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
281
281
 
282
282
  ### Don't
283
283
 
284
- (Don't) Manually redefine standard HTML attributes that are already available through the base interface.
284
+ Manually redefine standard HTML attributes that are already available through the base interface.
285
285
  ```typescript
286
286
  export interface ButtonProps {
287
287
  /** The button label */
@@ -299,7 +299,7 @@ Wrapper components must use namespaced props for inner components and accept uns
299
299
 
300
300
  ### Do
301
301
 
302
- (Do) Use namespaced props for inner components and unscoped props for the wrapper element.
302
+ Use namespaced props for inner components and unscoped props for the wrapper element.
303
303
  ```tsx
304
304
  interface ThumbnailSectionProps extends SectionProps {
305
305
  /** Props for the thumbnail image */
@@ -321,7 +321,7 @@ const ThumbnailSection = ({
321
321
 
322
322
  ### Don't
323
323
 
324
- (Don't) Mix prop scopes between wrapper and inner components.
324
+ Mix prop scopes between wrapper and inner components.
325
325
  ```tsx
326
326
  interface ThumbnailSectionProps {
327
327
  src: string; // Bad: Unscoped image props
@@ -344,7 +344,7 @@ Context providers must use `Provider.tsx` as the main component file instead of
344
344
 
345
345
  ### Do
346
346
 
347
- (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.`
347
+ 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.`
348
348
  ```
349
349
  [MyComponent]/
350
350
  ├── Context.tsx
@@ -361,8 +361,8 @@ Context providers must use `Provider.tsx` as the main component file instead of
361
361
  ├── types.ts
362
362
  └── useProviderState.ts
363
363
  ```
364
- (Do) Create the context type within `types.ts`.
365
364
 
365
+ Create the context type within `types.ts`.
366
366
  ```typescript
367
367
  // [MyComponent]/types.ts
368
368
  /** The value of the config context */
@@ -374,8 +374,7 @@ export interface ContextOptions {
374
374
  }
375
375
  ```
376
376
 
377
- (Do) create the provider props type within `types.ts`, accepting `children` at a minimum and more props as needed.
378
-
377
+ create the provider props type within `types.ts`, accepting `children` at a minimum and more props as needed.
379
378
  ```typescript
380
379
  // [MyComponent]/types.ts
381
380
 
@@ -386,7 +385,7 @@ export interface ProviderProps {
386
385
  }
387
386
  ```
388
387
 
389
- (Do) Create a `Context.tsx` file for the context definition.
388
+ Create a `Context.tsx` file for the context definition.
390
389
  ```tsx
391
390
  // [MyComponent]/Context.tsx
392
391
  import { createContext } from "react";
@@ -397,8 +396,7 @@ const Context = createContext<ContextOptions | undefined>(undefined);
397
396
  export default Context;
398
397
  ```
399
398
 
400
-
401
- (Do) Use `Provider.tsx` as the main component file. The provider is responsible for wrapping children with the context.
399
+ Use `Provider.tsx` as the main component file. The provider is responsible for wrapping children with the context.
402
400
  ```tsx
403
401
  // [MyComponent]/Provider.tsx
404
402
  import Context from "./Context.js";
@@ -413,7 +411,7 @@ const Provider = ({ children }: ProviderProps) => {
413
411
  export default Provider;
414
412
  ```
415
413
 
416
- (Do) Use `index.ts` to export the `Provider` as a named component that matches the folder name, casting it to the component type.
414
+ Use `index.ts` to export the `Provider` as a named component that matches the folder name, casting it to the component type.
417
415
  ```typescript
418
416
  // [MyComponent]/types.ts
419
417
  import type { ReactElement } from "react";
@@ -430,7 +428,7 @@ export const [MyComponent] = Provider as [MyComponent]Component;
430
428
  export default [MyComponent];
431
429
  ```
432
430
 
433
- (Do) Create provider state hook types in `hooks/types.ts` for context providers.
431
+ Create provider state hook types in `hooks/types.ts` for context providers.
434
432
  ```typescript
435
433
  // [MyComponent]/hooks/types.ts
436
434
  import type { ContextOptions, ProviderProps } from "../types.js";
@@ -442,7 +440,7 @@ export type UseProviderStateProps = Omit<ProviderProps, "children">;
442
440
  export type UseProviderStateResult = ContextOptions;
443
441
  ```
444
442
 
445
- (Do) Create a provider state hook implementation.
443
+ Create a provider state hook implementation.
446
444
  ```tsx
447
445
  // [MyComponent]/hooks/useProviderState.ts
448
446
  import { useContext } from "react";
@@ -460,14 +458,14 @@ const useProviderState = ({
460
458
 
461
459
  ### Don't
462
460
 
463
- (Don't) Create a separate component file (e.g., `[MyComponent].tsx`) when `Provider.tsx` exists. The provider is the main component.
461
+ Create a separate component file (e.g., `[MyComponent].tsx`) when `Provider.tsx` exists. The provider is the main component.
464
462
  ```
465
463
  [MyComponent]/
466
464
  ├── [MyComponent].tsx
467
465
  └── Provider.tsx
468
466
  ```
469
467
 
470
- (Don't) Nest context-related files in a `context/` subfolder.
468
+ Nest context-related files in a `context/` subfolder.
471
469
  ```
472
470
  [MyComponent]/
473
471
  └── context/ # Unnecessary nesting
@@ -475,15 +473,14 @@ const useProviderState = ({
475
473
  └── Provider.tsx
476
474
  ```
477
475
 
478
- (Don't) Create multiple provider files within the same component folder.
476
+ Create multiple provider files within the same component folder.
479
477
  ```
480
478
  [MyComponent]/
481
479
  ├── Provider.tsx
482
480
  └── AnotherProvider.tsx # Only one provider per component
483
481
  ```
484
482
 
485
- (Don't) Mix concerns of the Provider and its state.
486
-
483
+ Mix concerns of the Provider and its state.
487
484
  ```tsx
488
485
  exort const Provider = ({ children }: ProviderProps) => {
489
486
  const [state, setState] = useState(...); // Bad: State logic mixed in
@@ -499,7 +496,7 @@ Each component must reside in its own folder, which contains all related files:
499
496
 
500
497
  ### Do
501
498
 
502
- (Do) Place all component-related files within a single folder named after the component.
499
+ Place all component-related files within a single folder named after the component.
503
500
  ```bash
504
501
  [MyComponent]/
505
502
  ├── [MyComponent].tsx
@@ -512,7 +509,7 @@ Each component must reside in its own folder, which contains all related files:
512
509
 
513
510
  ### Don't
514
511
 
515
- (Don't) Scatter component files across different parts of the application.
512
+ Scatter component files across different parts of the application.
516
513
  ```bash
517
514
  # Bad: Files are not co-located
518
515
  components/
@@ -540,7 +537,7 @@ Private subcomponents must remain internal to the component's implementation and
540
537
 
541
538
  ### Do
542
539
 
543
- (Do) Export public subcomponents by attaching them to the parent component using dot notation:
540
+ Export public subcomponents by attaching them to the parent component using dot notation
544
541
  ```typescript
545
542
  const Item = (props: ItemProps) => { /* ... */ };
546
543
  const Accordion = (props: AccordionProps) => { /* ... */ };
@@ -548,14 +545,14 @@ Accordion.Item = Item;
548
545
  export default Accordion;
549
546
  ```
550
547
 
551
- (Do) Use semantic, self-descriptive names for subcomponents:
548
+ Use semantic, self-descriptive names for subcomponents
552
549
  ```typescript
553
550
  Accordion.Item
554
551
  Card.Header
555
552
  Card.Footer
556
553
  ```
557
554
 
558
- (Do) Keep subcomponent nesting to a single level:
555
+ Keep subcomponent nesting to a single level
559
556
  ```typescript
560
557
  <Card>
561
558
  <Card.Header />
@@ -565,17 +562,17 @@ Card.Footer
565
562
 
566
563
  ### Don't
567
564
 
568
- (Don't) Repeat the parent component name in subcomponent names:
565
+ Repeat the parent component name in subcomponent names
569
566
  ```typescript
570
567
  Card.CardHeader = Header; // Bad: Redundant 'Card' prefix
571
568
  ```
572
569
 
573
- (Don't) Map a subcomponent to a different name (renaming):
570
+ Map a subcomponent to a different name (renaming)
574
571
  ```typescript
575
572
  Card.Top = Header; // Bad: Mapping 'Header' to 'Top' is not allowed
576
573
  ```
577
574
 
578
- (Don't) Use non-semantic or unclear subcomponent names:
575
+ Use non-semantic or unclear subcomponent names
579
576
  ```
580
577
  Card/
581
578
  └── common/
@@ -583,7 +580,7 @@ Card/
583
580
  ├── Element/ # Bad: Too vague, not semantic - what element?
584
581
  ```
585
582
 
586
- (Don't) Nest subcomponents more than one level deep:
583
+ Nest subcomponents more than one level deep
587
584
  ```typescript
588
585
  <Card>
589
586
  <Card.Header>
@@ -592,7 +589,7 @@ Card/
592
589
  </Card>
593
590
  ```
594
591
 
595
- (Don't) Export private subcomponents that are not intended for public use.
592
+ Export private subcomponents that are not intended for public use.
596
593
  ```typescript
597
594
  // Bad: Exporting internal-only subcomponents
598
595
  export { InternalHelper };
@@ -606,7 +603,7 @@ Component TSDoc documentation must use the description from the design system on
606
603
 
607
604
  ### Do
608
605
 
609
- (Do) Use the description from the DSL ontology verbatim.
606
+ Use the description from the DSL ontology verbatim.
610
607
  ```typescript
611
608
  /**
612
609
  * The label component is a compact, non-interactive visual element used to
@@ -625,7 +622,7 @@ const Label = ({ children, criticality, className, ...props }: LabelProps) => (
625
622
 
626
623
  ### Don't
627
624
 
628
- (Don't) Write custom descriptions that deviate from the DSL.
625
+ Write custom descriptions that deviate from the DSL.
629
626
  ```typescript
630
627
  // Bad: Custom title and paraphrased description
631
628
  /**
@@ -635,21 +632,19 @@ const Label = ({ children, criticality, className, ...props }: LabelProps) => (
635
632
  */
636
633
  ```
637
634
 
638
- (Don't) Include @example blocks - stories fulfill this role.
635
+ Include @example blocks - stories fulfill this role.
639
636
  ```typescript
640
637
  // Bad: Examples belong in stories, not TSDoc
641
638
  /**
642
639
  * The label component is a compact...
643
640
  *
644
641
  * @example
645
- * ```tsx
646
642
  * <Label>Default</Label>
647
643
  * <Label criticality="warning">Warning</Label>
648
- * ```
649
644
  */
650
645
  ```
651
646
 
652
- (Don't) Omit the @implements tag that links to the DSL.
647
+ Omit the @implements tag that links to the DSL.
653
648
  ```typescript
654
649
  // Bad: Missing @implements tag
655
650
  /**
@@ -672,7 +667,7 @@ Each hook must define a [HookName]Props and [HookName]Result type in `hooks/type
672
667
 
673
668
  ### Do
674
669
 
675
- (Do) Create a custom hook that focuses on a single concern within the domain.
670
+ Create a custom hook that focuses on a single concern within the domain.
676
671
  ```typescript
677
672
  // [MyComponent]/hooks/useWindowFitment.ts
678
673
  const useWindowFitment = ({
@@ -680,7 +675,8 @@ const useWindowFitment = ({
680
675
  autoFit = false,
681
676
  }: UseWindowFitmentProps): UseWindowFitmentResult => {
682
677
  ```
683
- (Do) Create hook types in `hooks/types.ts`.
678
+
679
+ Create hook types in `hooks/types.ts`.
684
680
  ```typescript
685
681
  // [MyComponent]/hooks/types.ts
686
682
  export interface UseWindowFitmentProps {
@@ -718,7 +714,7 @@ export interface UseWindowFitmentResult {
718
714
 
719
715
  ### Don't
720
716
 
721
- (Don't) Create a custom hook for simple, non-reusable state.
717
+ Create a custom hook for simple, non-reusable state.
722
718
  ```tsx
723
719
  // Bad: Unnecessary abstraction for a simple counter
724
720
  const useCounter = () => {
@@ -727,7 +723,7 @@ const useCounter = () => {
727
723
  };
728
724
  ```
729
725
 
730
- (Don't) Mix multiple concerns in a single hook
726
+ Mix multiple concerns in a single hook
731
727
  ```typescript
732
728
  // Bad: Multiple concerns in one hook
733
729
  const useUserData = () => {
@@ -747,7 +743,7 @@ The hook name must start with 'use' and clearly describe its purpose.
747
743
 
748
744
  ### Do
749
745
 
750
- (Do) Name custom hooks so the hook name starts with 'use' and is descriptive:
746
+ Name custom hooks so the hook name starts with 'use' and is descriptive
751
747
  ```typescript
752
748
  useWindowSize()
753
749
  useAuthentication()
@@ -756,7 +752,7 @@ useFormValidation()
756
752
 
757
753
  ### Don't
758
754
 
759
- (Don't) Name hooks without the 'use' prefix at the start of the hook name:
755
+ Name hooks without the 'use' prefix at the start of the hook name
760
756
  ```typescript
761
757
  windowSize()
762
758
  getAuth()