pasika 0.1.4 → 0.1.6

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.
Files changed (44) hide show
  1. package/dist/eslint/pasika/index.js +3 -0
  2. package/dist/eslint/pasika/rules/filename-case.d.ts +2 -0
  3. package/dist/eslint/pasika/rules/filename-case.js +90 -0
  4. package/docs/agent-conventions.md +6 -0
  5. package/docs/code-organization-guide/code-organization-guide.md +24 -20
  6. package/docs/code-organization-guide/references/application-architecture-reference.md +61 -19
  7. package/docs/code-organization-guide/rules/component-placement-rule.md +9 -25
  8. package/docs/code-organization-guide/rules/configuration-rule.md +9 -9
  9. package/docs/code-organization-guide/rules/constants-rule.md +5 -8
  10. package/docs/code-organization-guide/rules/exports-and-imports-rule.md +10 -7
  11. package/docs/code-organization-guide/rules/folder-nesting-rule.md +1 -2
  12. package/docs/code-organization-guide/rules/hook-extraction-rule.md +4 -5
  13. package/docs/code-organization-guide/rules/interactive-component-rule.md +7 -10
  14. package/docs/code-organization-guide/rules/jsx-hygiene-rule.md +2 -3
  15. package/docs/code-organization-guide/rules/locales-rule.md +2 -4
  16. package/docs/code-organization-guide/rules/no-mixed-concerns-rule.md +0 -1
  17. package/docs/code-organization-guide/rules/repeated-structure-rule.md +1 -1
  18. package/docs/code-organization-guide/rules/smart-vs-dumb-component-rule.md +2 -6
  19. package/docs/code-organization-guide/rules/sole-state-owner-rule.md +1 -2
  20. package/docs/code-organization-guide/rules/types-and-schemas-rule.md +7 -6
  21. package/docs/code-organization-guide/rules/utilities-rule.md +1 -2
  22. package/docs/documentation-guide/_templates/grouped-reference.md +11 -0
  23. package/docs/documentation-guide/_templates/guide.md +1 -1
  24. package/docs/documentation-guide/_templates/single-lookup-reference.md +5 -0
  25. package/docs/documentation-guide/references/documentation-types-reference.md +6 -6
  26. package/docs/documentation-guide/rules/guide-creation-rule.md +1 -0
  27. package/docs/documentation-guide/rules/reference-creation-rule.md +1 -1
  28. package/docs/documentation-guide/rules/template-usage-rule.md +2 -1
  29. package/docs/styling-guide/rules/arbitrary-value-rule.md +31 -0
  30. package/docs/styling-guide/rules/class-composition-rule.md +30 -10
  31. package/docs/styling-guide/rules/component-ui-state-rule.md +53 -0
  32. package/docs/styling-guide/rules/component-variant-rule.md +35 -38
  33. package/docs/styling-guide/rules/global-stylesheet-rule.md +67 -0
  34. package/docs/styling-guide/rules/theme-and-utility-definition-rule.md +39 -82
  35. package/docs/styling-guide/styling-guide.md +8 -11
  36. package/package.json +1 -1
  37. package/docs/code-organization-guide/rules/native-prop-forwarding-rule.md +0 -38
  38. package/docs/documentation-guide/_templates/reference.md +0 -17
  39. package/docs/styling-guide/rules/color-role-naming-rule.md +0 -115
  40. package/docs/styling-guide/rules/component-state-rule.md +0 -26
  41. package/docs/styling-guide/rules/global-style-system-rule.md +0 -63
  42. package/docs/styling-guide/rules/style-placement-rule.md +0 -49
  43. package/docs/styling-guide/rules/tailwind-utility-rule.md +0 -48
  44. package/docs/styling-guide/rules/theme-token-rule.md +0 -32
@@ -3,10 +3,8 @@
3
3
  When locale strings are scattered across components and constants, they are hard to find and keep consistent. This rule keeps them in one central file, puts each feature's strings together, and uses readable keys.
4
4
 
5
5
  - All locales MUST live in the named `locales` object exported from `src/locales/index.ts`.
6
- - A locale consumer is a module that reads the locale.
7
- - A new locale with no consumers MUST use a feature namespace when it is for one feature; otherwise it MUST live at the top level of `locales`.
8
- - Locales read only by modules in one feature folder MUST live in an object with the camelCase form of its feature folder name (for example, `user-settings` becomes `userSettings`).
9
- - Locales read by modules in more than one feature folder or by `src/shared/`, `src/compositions/`, `src/app/`, or root support folders MUST live at the top level of `locales`.
6
+ - Locales read only by files in one feature folder MUST live in an object with the camelCase form of its feature folder name (for example, `user-settings` becomes `userSettings`).
7
+ - Locales read by files in more than one feature folder or by `src/shared/`, `src/compositions/`, `src/app/`, or root support folders MUST live at the top level of `locales`.
10
8
  - A namespaced locale MUST be read through its full dotted path (`locales.stream.watchLiveStream`).
11
9
  - A locale key MUST be camelCase English based on the text, unless a direct translation would be unclear or unwieldy. In that case, it MAY describe the message's purpose instead.
12
10
 
@@ -3,7 +3,6 @@
3
3
  One component per file keeps components easy to find and change independently. This rule applies the same requirement to copied and generated source.
4
4
 
5
5
  - A `.tsx` file that defines a component MUST contain exactly one component.
6
- - A non-component module MUST use `.ts`, except when a framework requires a `.tsx` routing file.
7
6
 
8
7
  ## Incorrect — Two Components in One File
9
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Repeated markup can drift when one copy changes and another does not. This rule makes repeated structure a clear extraction trigger.
4
4
 
5
- - A block of elements MUST be extracted as a named component when the same structural frame and semantic purpose appear in two or more places. Different data or labels do not prevent extraction.
5
+ - A block of elements MUST be extracted as a named component when two or more places use the same arrangement of elements for the same purpose. Different data or labels do not prevent extraction.
6
6
 
7
7
  ## Incorrect — Repeated Structure Kept Inline
8
8
 
@@ -2,12 +2,8 @@
2
2
 
3
3
  Without a file-name convention, a component's smart vs dumb ownership is invisible to reviewers from the tree alone. Without a `data-testid` matching the file's casing, tests hardcode DOM identities that break on rename or restructure.
4
4
 
5
- - Remote or shared application data or state is data from a server, context, store, URL, or server action. A component MUST be smart when it fetches or mutates that data, performs an effect, or defines a callback that changes it, including through a hook or service.
6
- - A component is considered to perform these operations when it calls a custom hook that performs them.
7
- - In this rule, an effect MUST be a subscription, external I/O, DOM manipulation, or resource lifecycle.
8
- - Local UI state and callbacks that only update it MUST NOT make a component smart, including when passed to another component or directly to a native element.
9
- - A dumb component MUST NOT do any of these.
10
- - A component that does none of these MUST be dumb.
5
+ - A smart component MUST fetch data, or define `handle*` callbacks and pass them to children as `on*` props.
6
+ - A dumb component MUST NOT fetch data or define `handle*` callbacks for children.
11
7
  - A smart component file name MUST be `PascalCase.tsx`.
12
8
  - A dumb component file name MUST be `kebab-case.tsx`.
13
9
  - A smart component with one outer DOM element in every rendered result MUST set `data-testid` on that element, and its value MUST match the component name in `PascalCase`.
@@ -2,8 +2,7 @@
2
2
 
3
3
  Some blocks of elements are the only consumers of a state hook. This rule extracts those blocks into components that own the hook.
4
4
 
5
- - A state hook's consumers are the JSX, callbacks, and effects that read its state value or call its updater.
6
- - A proper sub-block of a component's output MUST be extracted when it contains every consumer of one state hook and one clear component name describes it. A consumer declared before `return` belongs to a sub-block only when it is used exclusively by that sub-block; otherwise this rule does not require extraction. The component that owns the state is not itself an extraction trigger.
5
+ - A component MUST extract a named component when one part of its JSX contains every JSX expression, callback, and effect that reads one state hook's value or calls its updater.
7
6
 
8
7
  ## Incorrect — Parent Keeps Child-Only State
9
8
 
@@ -2,14 +2,15 @@
2
2
 
3
3
  Types and schemas are easy to bury in component files or scatter across the project. This rule keeps them close to one component and gives independently used ones a consistent location.
4
4
 
5
- - A type or schema used only to implement one configuration object MUST live in that object's `types/` or `schemas/` folder.
6
- - Except for a type or schema used only to implement one configuration object, a type or schema declared in a component MUST stay in that component file until another file imports it without the component where it is defined. Importing it alongside that component does not trigger extraction.
7
- - Except for a type or schema used only to implement one configuration object, a type or schema declared outside a component MUST stay with its declaring module until another file imports it independently.
5
+ - A type or schema declared in a component MUST stay in that component file until another file imports it without the component where it is defined.
6
+ - Importing a type or schema alongside the component that defines it MUST NOT require extraction.
7
+ - A type or schema declared outside a component MUST stay in its file until another file needs it without using the code in that file.
8
8
  - Extracted types and schemas MUST live in their matching `types/` or `schemas/` folder at the closest common folder (CCF) of their consumers.
9
- - A `types/` or `schemas/` `index.ts` MAY define its exports directly.
10
- - Types and schemas that are used together MAY be grouped in a file with a kebab-case name and named-re-exported from `index.ts`.
11
- - When a `types/` or `schemas/` folder uses grouped files, its `index.ts` MUST only named-re-export those files.
12
9
  - When a type or schema's CCF is `src/features/`, it MUST move to `src/types/` or `src/schemas/`.
10
+ - A `types/` or `schemas/` folder MUST either define its exports directly in `index.ts` or group related types and schemas in kebab-case files that `index.ts` named-re-exports.
11
+ - Consumers MUST import an extracted type or schema through the `index.ts` in that type or schema's `types/` or `schemas/` folder.
12
+ - A type or schema used only to implement one configuration module MUST live in that module's `types/` or `schemas/` folder.
13
+ - A type MAY stay in `src/config/<module>/` when its meaning is derived from the configuration that it parameterizes, even when consumers exist outside the config module.
13
14
 
14
15
  ## Incorrect — Feature and Composition Type Kept in a Feature
15
16
 
@@ -3,13 +3,12 @@
3
3
  Pure functions should not be hidden in component files. This rule extracts them to a predictable `utils/` folder and keeps their imports direct.
4
4
 
5
5
  - A pure function MUST be extracted to `utils/`, even when it has one consumer.
6
- - A pure function returns the same result for the same arguments and does not read or write external mutable state, perform I/O, or manipulate the DOM.
7
- - A utility used only to implement one configuration object MUST live in that object's `utils/` folder.
8
6
  - An extracted utility MUST live in the `utils/` folder at the closest common folder (CCF) of its consumers.
9
7
  - When a utility's CCF is `src/features/`, it MUST move to `src/utils/`.
10
8
  - A utility MUST be imported directly without a barrel.
11
9
  - A utility file that exports one function MUST have a name in that function's kebab-case form.
12
10
  - Utilities that are used together MAY be grouped in a file with a kebab-case name.
11
+ - A utility used only to implement one configuration module MUST live in that module's `utils/` folder.
13
12
 
14
13
  ## Incorrect — Pure Function Left Beside Its Consumer
15
14
 
@@ -0,0 +1,11 @@
1
+ # [Topic] Reference
2
+
3
+ [1-2 short sentences naming exactly what readers can look up here and when they should use this reference.]
4
+
5
+ ## [Lookup Block Name]
6
+
7
+ [1-2 short sentences explaining what this lookup block contains and why it is included.]
8
+
9
+ [Place this lookup block's content here.]
10
+
11
+ [Repeat this section for every remaining lookup block.]
@@ -1,6 +1,6 @@
1
1
  # [Topic] Guide
2
2
 
3
- [1-2 short sentences explaining the underlying idea behind this guide and why it matters.]
3
+ [1-2 short descriptive sentences explaining this guide's scope, underlying idea, and why it matters.]
4
4
 
5
5
  ## How To [Workflow]
6
6
 
@@ -0,0 +1,5 @@
1
+ # [Topic] Reference
2
+
3
+ [1-2 short sentences naming exactly what readers can look up here and when they should use this reference.]
4
+
5
+ [Place the reference's single lookup block here without a heading.]
@@ -1,9 +1,9 @@
1
1
  # Documentation Types Reference
2
2
 
3
- Use this reference to look up the three standard Markdown document kinds in this repository. Their templates are in `docs/documentation-guide/_templates/`.
3
+ Use this reference to look up the three standard Markdown document kinds in this repository.
4
4
 
5
- | Kind | Shape | Template |
6
- | --------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------ |
7
- | Guide | A workflow-oriented document with one or more `## How To [...]` sections. | `guide.md` |
8
- | Rule | An opinionated project rule that states required, forbidden, recommended, or optional behavior. | `rule.md` |
9
- | Reference | Lookup material such as a table, hierarchy, configuration block, glossary, or catalog. | `reference.md` |
5
+ | Kind | Shape | Template |
6
+ | --------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
7
+ | Guide | A workflow-oriented document with one or more `## How To [...]` sections. | `/_templates/guide.md` |
8
+ | Rule | An opinionated project rule that states required, forbidden, recommended, or optional behavior. | `/_templates/rule.md` |
9
+ | Reference | Lookup material. A lookup block is one self-contained set of facts for a reader's question. Use the single template for one lookup block and the grouped template for several blocks organized by topic. | `/_templates/single-lookup-reference.md` or `/_templates/grouped-reference.md` |
@@ -4,6 +4,7 @@ Guides without a consistent creation process invent their own structure. This ru
4
4
 
5
5
  - Each How To step MUST be concise and use one sentence.
6
6
  - A Guide MAY reference Rules, References, and other Guides.
7
+ - A Guide overview MUST contain one or two short descriptive sentences about the guide's scope and purpose, and MUST NOT contain instructions or links to other documentation.
7
8
  - Each How To step MUST link at most one documentation file total, whether that file is a Rule, Reference, or Guide.
8
9
  - When a step links a Rule, Reference, or Guide, the step MUST name the concrete decision or result the reader will have after reading it.
9
10
  - A step that links another Guide MUST link directly to the relevant How To section.
@@ -5,7 +5,7 @@ References without a consistent creation process scatter lookup material. This r
5
5
  - Reference file names MUST match the document title in kebab-case and use the `-reference` suffix (e.g., `foo-reference.md`).
6
6
  - A Reference MUST NOT link to Rules, Guides, or other References.
7
7
  - A Reference MUST NOT use RFC 2119 vocabulary (`MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, `MAY`), because lookup material describes what exists rather than imposing requirements.
8
- - A Reference document overview and each section overview MUST contain one or two short sentences.
8
+ - A Reference overview and the overview of each headed lookup block MUST contain one or two short sentences.
9
9
  - A Reference with a single lookup block MUST NOT add a section heading for it.
10
10
  - A Reference with two or more lookup blocks MUST add a section heading for every block, including the first.
11
11
 
@@ -2,9 +2,10 @@
2
2
 
3
3
  Authoring without a template makes every doc invent its own title, orientation, and section shape. This rule keeps new docs predictable. Templates for each document kind live in `../_templates/`.
4
4
 
5
- - Authors MUST start from the template for the chosen document kind.
5
+ - Authors MUST start from the template that matches the chosen document kind and structure.
6
6
  - Authors MUST replace each bracketed prompt with the final title, explanation, step, or lookup content it asks for.
7
7
  - Authors MUST delete template branches that do not apply to the document being written.
8
+ - Documentation support assets MAY live in folders whose names start with an underscore.
8
9
 
9
10
  ## Incorrect — Template Prompts and Unused Branches Kept
10
11
 
@@ -0,0 +1,31 @@
1
+ # Arbitrary Value Rule
2
+
3
+ Literal arbitrary-value classes hide values used for the project's styling in component code. This rule requires every such value to have a named utility or token.
4
+
5
+ - Components MUST NOT use arbitrary-value classes for project styling. They MUST use an existing Tailwind or project utility, or define a project token or custom utility first.
6
+
7
+ ## Incorrect — Literal Arbitrary Radius
8
+
9
+ ```tsx
10
+ <button className="rounded-[13px]">Save</button>
11
+ ```
12
+
13
+ Why: the design value is hidden in markup and cannot be tracked as part of the project's explicit token set.
14
+
15
+ ## Correct — Named Radius Token
16
+
17
+ ```css
18
+ :root {
19
+ --radius-md: 0.375rem;
20
+ }
21
+
22
+ @theme inline {
23
+ --radius-md: var(--radius-md);
24
+ }
25
+ ```
26
+
27
+ ```tsx
28
+ <button className="rounded-md">Save</button>
29
+ ```
30
+
31
+ Why: the named value makes the radius searchable and exposes the matching Tailwind radius utility.
@@ -1,15 +1,12 @@
1
1
  # Class Composition Rule
2
2
 
3
- Class conditions and caller overrides need one consistent merge point so ordering stays understandable and conflicting Tailwind utilities resolve correctly.
3
+ `cn` is the project's helper for combining conditional classes and resolving conflicting Tailwind utilities. It gives conditional classes and a passed `className` one predictable merge point.
4
4
 
5
- - Components MUST use `cn` or the project's equivalent class-merging helper for conditional classes and a consumer-provided `className`.
5
+ - Components MUST use `cn` or the project's equivalent class-merging helper for conditional classes and a `className` passed to the component.
6
6
  - Components MUST NOT concatenate class strings with template literals or `+` when any part is conditional.
7
- - A consumer-provided `className` MUST contain only outer-layout utilities: margins, width constraints, permitted height constraints, and flex or grid item placement.
8
- - Permitted height constraints MUST be limited to `h-full`, `h-auto`, `min-h-*`, and `max-h-*`; fixed component heights MUST use a typed component API or an external wrapper.
9
- - A consumer-provided `className` MUST NOT change padding, internal gaps, fixed height, colors, typography, borders, radius, shadows, effects, positioning, inset, or z-index.
10
- - A component MUST expose supported internal appearance and fixed-size choices through typed props rather than consumer classes.
11
- - Components SHOULD group long static class lists by concern inside `cn`.
12
- - Components MAY keep a short, fully static `className` string inline.
7
+ - A `className` passed to a component MUST contain only outer-layout utilities: margins, sizing, flex or grid item placement, and `z-index`.
8
+ - A component MUST expose its supported appearance and size variants through typed props, not through a passed `className` or separate class-name props for internal elements.
9
+ - A static class list with more than five class names MUST use `cn` with multiple string literals, each grouped by styling concern and containing no more than five class names.
13
10
 
14
11
  ## Incorrect — Conditional Classes Concatenated Manually
15
12
 
@@ -22,11 +19,34 @@ Why: the condition and merge order are embedded in a string expression, which be
22
19
  ## Correct — Conditional Classes Merged with `cn`
23
20
 
24
21
  ```tsx
25
- export default function Card({ className, ...props }: CardProps): React.JSX.Element {
26
- return <article className={cn("surface-card rounded-lg p-4", className)} {...props} />;
22
+ export function Card({ className, ...props }: CardProps): React.JSX.Element {
23
+ return <article className={cn("card-surface rounded-lg p-4", className)} {...props} />;
27
24
  }
28
25
 
29
26
  <Card className="w-full max-w-lg self-center" />;
30
27
  ```
31
28
 
32
29
  Why: every class source is explicit, and a consumer can add outer layout such as `w-full max-w-lg self-center` without reconstructing the card's internal treatment.
30
+
31
+ ## Incorrect — Long Static Class Literal
32
+
33
+ ```tsx
34
+ <article className="rounded-lg border border-border bg-card px-6 py-4 shadow-sm transition-shadow hover:shadow-md" />
35
+ ```
36
+
37
+ Why: one static literal contains more than five class names, so its styling concerns are difficult to scan.
38
+
39
+ ## Correct — Static Classes Grouped in `cn`
40
+
41
+ ```tsx
42
+ <article
43
+ className={cn(
44
+ "rounded-lg border border-border",
45
+ "bg-card shadow-sm",
46
+ "px-6 py-4",
47
+ "transition-shadow hover:shadow-md",
48
+ )}
49
+ />
50
+ ```
51
+
52
+ Why: each literal contains at most five class names and groups one styling concern.
@@ -0,0 +1,53 @@
1
+ # Component UI State Rule
2
+
3
+ Visual state communicates whether a component can be used and what will happen when it is used. This rule keeps that feedback owned by the component rather than reconstructed by every caller.
4
+
5
+ - A component MUST own a distinguishable appearance for every UI state it supports.
6
+ - A component MUST use Tailwind "state variants" when they can express a supported UI state.
7
+ - Components MUST use native semantic elements and attributes and MUST NOT use custom equivalents.
8
+
9
+ ## Incorrect — State Styled Only with Classes
10
+
11
+ ```tsx
12
+ <Button className={isSaving ? "pointer-events-none opacity-50" : ""}>Save</Button>
13
+ ```
14
+
15
+ Why: every caller has to reconstruct the saving or disabled treatment, and the button does not receive a semantic disabled state.
16
+
17
+ ## Correct — State Exposed Through Component Props
18
+
19
+ ```tsx
20
+ import { cn } from "@/utils/cn";
21
+
22
+ type ButtonProps = {
23
+ children: React.ReactNode;
24
+ disabled?: boolean;
25
+ loading?: boolean;
26
+ };
27
+
28
+ export function Button({ children, disabled = false, loading = false }: ButtonProps): React.JSX.Element {
29
+ const isUnavailable = disabled || loading;
30
+
31
+ return (
32
+ <button
33
+ aria-busy={loading}
34
+ className={cn(
35
+ "rounded px-3",
36
+ "hover:opacity-90 focus-visible:outline-2",
37
+ "disabled:cursor-not-allowed disabled:opacity-50",
38
+ "aria-busy:animate-pulse",
39
+ )}
40
+ disabled={isUnavailable}
41
+ type="button"
42
+ >
43
+ {loading ? "Saving…" : children}
44
+ </button>
45
+ );
46
+ }
47
+
48
+ <Button loading={isSaving}>
49
+ Save
50
+ </Button>
51
+ ```
52
+
53
+ Why: `Button` uses native disabled and ARIA busy attributes with Tailwind state variants, while callers express only loading through its typed API.
@@ -1,14 +1,11 @@
1
1
  # Component Variant Rule
2
2
 
3
- When callers choose between a component's visual appearances, the styling definition and TypeScript API need one source of truth. This rule uses CVA for named choices and reserves `cn` for standalone boolean conditions.
3
+ `cva` is Class Variance Authority, a helper for defining a component's visual options and deriving their TypeScript API. `cn` handles a standalone boolean choice without creating a variant matrix.
4
4
 
5
- - A component that lets callers choose between named visual appearances MUST define those choices with `cva`.
6
- - Component variant prop types MUST be derived with `VariantProps<typeof componentVariants>`.
7
- - Component props MUST NOT manually duplicate a union already defined by the CVA configuration.
8
- - A boolean appearance input MUST use conditional `cn()` when it only adds or removes one standalone class treatment.
9
- - A boolean appearance input MUST use a CVA variant when both boolean values have explicit treatments or when the boolean participates in a compound variant.
10
- - A component MUST NOT expose separate class-name props for internal elements to vary their appearance.
11
- - A component MAY expose structured content slots when callers need to provide content rather than alter internal styling.
5
+ - A component that lets callers choose visual options MUST define them with `cva`.
6
+ - A component's variant prop types MUST be derived from its `cva` definition with `VariantProps` rather than manually duplicated unions.
7
+ - A boolean prop that changes appearance MUST use conditional `cn()` when it only adds or removes one standalone class treatment.
8
+ - A boolean prop that changes appearance MUST use a CVA variant when both boolean values have explicit treatments or when the boolean participates in a compound variant.
12
9
 
13
10
  ## Incorrect — Variant Union Duplicated by Hand
14
11
 
@@ -39,8 +36,8 @@ const buttonVariants = cva("inline-flex items-center", {
39
36
  lg: "h-11 px-5",
40
37
  },
41
38
  tone: {
42
- primary: "surface-primary",
43
- danger: "surface-danger",
39
+ primary: "primary-surface",
40
+ danger: "danger-surface",
44
41
  },
45
42
  },
46
43
  defaultVariants: {
@@ -51,78 +48,78 @@ const buttonVariants = cva("inline-flex items-center", {
51
48
 
52
49
  type ButtonProps = React.ComponentProps<"button"> & VariantProps<typeof buttonVariants>;
53
50
 
54
- export default function Button({ size, tone, className, ...props }: ButtonProps): React.JSX.Element {
51
+ export function Button({ size, tone, className, ...props }: ButtonProps): React.JSX.Element {
55
52
  return <button className={cn(buttonVariants({ size, tone }), className)} {...props} />;
56
53
  }
57
54
  ```
58
55
 
59
56
  Why: the CVA definition owns the accepted values, defaults, and classes, while `VariantProps` derives the public TypeScript API from the same source.
60
57
 
61
- ## Incorrect — Standalone Boolean Added to CVA
58
+ ## Incorrect — Standalone Boolean Variant Added to CVA
62
59
 
63
60
  ```tsx
64
61
  const buttonVariants = cva("inline-flex", {
65
62
  variants: {
66
- loading: {
67
- true: "cursor-wait opacity-70",
63
+ elevated: {
64
+ true: "shadow-md",
68
65
  false: "",
69
66
  },
70
67
  },
71
68
  });
72
69
  ```
73
70
 
74
- Why: one boolean merely adds a standalone treatment and has no compound relationship, so CVA adds configuration without a styling matrix.
71
+ Why: one boolean variant merely adds a standalone treatment and has no compound relationship, so CVA adds configuration without a styling matrix.
75
72
 
76
- ## Correct — Standalone Boolean Uses `cn`
73
+ ## Correct — Standalone Boolean Variant Uses `cn`
77
74
 
78
75
  ```tsx
79
- <button className={cn(buttonVariants({ size, tone }), loading && "cursor-wait opacity-70", className)} />
76
+ <button className={cn(buttonVariants({ size, tone }), elevated && "shadow-md", className)} />
80
77
  ```
81
78
 
82
- Why: the named appearance choices stay in CVA while the independent boolean remains a direct conditional class.
79
+ Why: the named appearance choices stay in CVA while the independent boolean variant remains a direct conditional class.
83
80
 
84
- ## Incorrect — Compound Boolean Styling Split Across Conditions
81
+ ## Incorrect — Compound Boolean Variant Styling Split Across Conditions
85
82
 
86
83
  ```tsx
87
84
  <button
88
85
  className={cn(
89
- buttonVariants({ tone }),
90
- loading && "cursor-wait",
91
- loading && tone === "primary" && "surface-primary-loading",
92
- loading && tone === "danger" && "surface-danger-loading",
86
+ buttonVariants({ size }),
87
+ square && "justify-center",
88
+ square && size === "sm" && "w-8 px-0",
89
+ square && size === "lg" && "w-11 px-0",
93
90
  )}
94
91
  />
95
92
  ```
96
93
 
97
- Why: the boolean changes treatment according to another variant, but the styling matrix is spread across conditional expressions outside CVA.
94
+ Why: the boolean variant changes treatment according to another variant, but the styling matrix is spread across conditional expressions outside CVA.
98
95
 
99
- ## Correct — Boolean with Compound Styling Uses CVA
96
+ ## Correct — Boolean Variant with Compound Styling Uses CVA
100
97
 
101
98
  ```tsx
102
99
  const buttonVariants = cva("inline-flex", {
103
100
  variants: {
104
- tone: {
105
- primary: "surface-primary",
106
- danger: "surface-danger",
101
+ size: {
102
+ sm: "h-8 px-3",
103
+ lg: "h-11 px-5",
107
104
  },
108
- loading: {
109
- true: "cursor-wait",
110
- false: "cursor-default",
105
+ square: {
106
+ true: "justify-center",
107
+ false: "justify-start",
111
108
  },
112
109
  },
113
110
  compoundVariants: [
114
111
  {
115
- tone: "primary",
116
- loading: true,
117
- className: "surface-primary-loading",
112
+ size: "sm",
113
+ square: true,
114
+ className: "w-8 px-0",
118
115
  },
119
116
  {
120
- tone: "danger",
121
- loading: true,
122
- className: "surface-danger-loading",
117
+ size: "lg",
118
+ square: true,
119
+ className: "w-11 px-0",
123
120
  },
124
121
  ],
125
122
  });
126
123
  ```
127
124
 
128
- Why: both boolean values have explicit treatment and loading changes by tone, so CVA owns the complete styling matrix.
125
+ Why: both boolean values have explicit treatment and the square appearance changes by size, so CVA owns the complete styling matrix.
@@ -0,0 +1,67 @@
1
+ # Global Stylesheet Rule
2
+
3
+ Use the global stylesheet to define Tailwind, the shared theme, and base styles. This rule keeps all of the project's global CSS in one entry point and ordered predictably.
4
+
5
+ - A repository MUST have one global stylesheet entry point that registers Tailwind.
6
+ - The project's global CSS MUST live in the global stylesheet entry point and MUST NOT be imported from another file.
7
+ - The global stylesheet MUST reset Tailwind's default theme with `--*: initial`.
8
+ - Every value used for the project's styling MUST be defined as a CSS variable in `:root`, even when no theme selector overrides it. A Tailwind theme variable MUST reference that CSS variable through `@theme inline`.
9
+ - Style declarations added by the project inside global selectors MUST use `@apply`.
10
+ - The global stylesheet MUST order imports, `@custom-variant` definitions, `:root` variables and the selectors that override them, `@theme` definitions, custom utilities, base styles, and keyframes in that order.
11
+ - The global base layer MUST apply `base-canvas` and `base-ink` to the document body as the default page pair.
12
+
13
+ ## Incorrect — Global Styles Split Across Unrelated Files
14
+
15
+ ```css
16
+ /* globals.css */
17
+ @import "tailwindcss";
18
+
19
+ @theme {
20
+ --spacing: 0.25rem;
21
+ }
22
+
23
+ /* editor.css */
24
+ @import "tailwindcss";
25
+
26
+ @theme {
27
+ --font-editor: Georgia, serif;
28
+ }
29
+ ```
30
+
31
+ Why: Tailwind and theme definitions are split across competing global entry points, so neither file clearly owns the system.
32
+
33
+ ## Correct — One Global Stylesheet Owns the System
34
+
35
+ ```css
36
+ @import "tailwindcss";
37
+
38
+ :root {
39
+ --spacing: 0.25rem;
40
+ --base-canvas: #ffffff;
41
+ --base-ink: #111827;
42
+ }
43
+
44
+ @theme {
45
+ --*: initial;
46
+ }
47
+
48
+ @theme inline {
49
+ --spacing: var(--spacing);
50
+ }
51
+
52
+ @utility bg-base-canvas {
53
+ @apply bg-(--base-canvas);
54
+ }
55
+
56
+ @utility text-base-ink {
57
+ @apply text-(--base-ink);
58
+ }
59
+
60
+ @layer base {
61
+ body {
62
+ @apply bg-base-canvas text-base-ink;
63
+ }
64
+ }
65
+ ```
66
+
67
+ Why: one entry point registers Tailwind, defines the shared system, and applies document defaults in a predictable order.