@cratis/pi 2.21.3 → 2.23.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.
Files changed (102) hide show
  1. package/package/corpus/agents/backend-developer.md +6 -5
  2. package/package/corpus/agents/code-reviewer.md +7 -7
  3. package/package/corpus/agents/coordinator.md +5 -4
  4. package/package/corpus/agents/frontend-developer.md +34 -40
  5. package/package/corpus/agents/orchestrator.md +5 -4
  6. package/package/corpus/agents/performance-reviewer.md +5 -4
  7. package/package/corpus/agents/planner.md +5 -4
  8. package/package/corpus/agents/repository-investigation-reviewer.md +2 -1
  9. package/package/corpus/agents/repository-investigator.md +2 -1
  10. package/package/corpus/agents/security-reviewer.md +5 -4
  11. package/package/corpus/agents/slice-implementer.md +8 -2
  12. package/package/corpus/agents/spec-writer.md +6 -4
  13. package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +52 -7
  14. package/package/corpus/harnesses/pi/extensions/subagent/index.ts +14 -0
  15. package/package/corpus/hooks/README.md +29 -27
  16. package/package/corpus/hooks/agent-stop.md +1 -5
  17. package/package/corpus/hooks/scripts/cratis-patterns.json +1 -1
  18. package/package/corpus/hooks/scripts/validate-package-subpaths.sh +1 -2
  19. package/package/corpus/prompts/verify-ai-setup.prompt.md +17 -7
  20. package/package/corpus/rules/ai-distribution.md +58 -0
  21. package/package/corpus/rules/components.md +77 -44
  22. package/package/corpus/rules/dialogs.md +24 -20
  23. package/package/corpus/rules/efcore.md +35 -187
  24. package/package/corpus/rules/framework.md +1 -1
  25. package/package/corpus/rules/frontend-quality.md +1 -1
  26. package/package/corpus/rules/frontend-testing.md +4 -4
  27. package/package/corpus/rules/general.md +29 -105
  28. package/package/corpus/rules/new-repository-intake.md +34 -0
  29. package/package/corpus/rules/orleans.md +13 -27
  30. package/package/corpus/rules/react.md +12 -12
  31. package/package/corpus/rules/reactors.md +28 -5
  32. package/package/corpus/rules/specs.scenarios.csharp.md +18 -3
  33. package/package/corpus/rules/specs.typescript.md +1 -1
  34. package/package/corpus/rules/storybook.md +2 -2
  35. package/package/corpus/rules/typescript.md +1 -0
  36. package/package/corpus/rules/vertical-slices.md +20 -15
  37. package/package/corpus/rules/writing-correct-examples.md +1 -0
  38. package/package/corpus/skills/cratis-application-react-specifications/SKILL.md +4 -4
  39. package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +16 -8
  40. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +6 -4
  41. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +1 -1
  42. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +1 -1
  43. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +1 -1
  44. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +1 -1
  45. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +7 -4
  46. package/package/corpus/skills/cratis-arc-command/SKILL.md +9 -7
  47. package/package/corpus/skills/cratis-arc-command/references/command-result.md +1 -1
  48. package/package/corpus/skills/cratis-arc-command/references/handler-shapes.md +2 -2
  49. package/package/corpus/skills/cratis-arc-command/references/proxy-generation.md +6 -3
  50. package/package/corpus/skills/cratis-arc-command/references/read-model-injection.md +1 -1
  51. package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +12 -2
  52. package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +5 -3
  53. package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +7 -4
  54. package/package/corpus/skills/cratis-arc-observable-query-http/SKILL.md +10 -3
  55. package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +13 -8
  56. package/package/corpus/skills/cratis-arc-react-page/SKILL.md +27 -24
  57. package/package/corpus/skills/cratis-arc-react-page/references/data-page.md +15 -11
  58. package/package/corpus/skills/cratis-arc-react-page/references/data-tables.md +9 -2
  59. package/package/corpus/skills/cratis-arc-react-page/references/dialogs.md +11 -9
  60. package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +26 -2
  61. package/package/corpus/skills/cratis-chronicle-cli-operations/SKILL.md +19 -13
  62. package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +17 -15
  63. package/package/corpus/skills/cratis-chronicle-client-elixir/SKILL.md +24 -20
  64. package/package/corpus/skills/cratis-chronicle-client-kotlin/SKILL.md +26 -15
  65. package/package/corpus/skills/cratis-chronicle-client-typescript/SKILL.md +15 -11
  66. package/package/corpus/skills/cratis-chronicle-compliance/SKILL.md +14 -3
  67. package/package/corpus/skills/cratis-chronicle-event-constraints/SKILL.md +13 -6
  68. package/package/corpus/skills/cratis-chronicle-event-modeling/SKILL.md +2 -2
  69. package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +11 -5
  70. package/package/corpus/skills/cratis-chronicle-event-type-migration/SKILL.md +2 -2
  71. package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +2 -2
  72. package/package/corpus/skills/cratis-chronicle-projection/SKILL.md +23 -4
  73. package/package/corpus/skills/cratis-chronicle-projection/references/fluent-builder.md +1 -1
  74. package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +2 -2
  75. package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +22 -8
  76. package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +1 -1
  77. package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +1 -1
  78. package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +3 -1
  79. package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +1 -1
  80. package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +19 -11
  81. package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +11 -6
  82. package/package/corpus/skills/cratis-code-review/SKILL.md +8 -6
  83. package/package/corpus/skills/cratis-components-accessibility/SKILL.md +112 -82
  84. package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +12 -10
  85. package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +11 -12
  86. package/package/corpus/skills/cratis-components-styling/SKILL.md +204 -170
  87. package/package/corpus/skills/cratis-components-toolbar/SKILL.md +32 -26
  88. package/package/corpus/skills/cratis-event-model-diagram/SKILL.md +1 -1
  89. package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +2 -2
  90. package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +2 -2
  91. package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +4 -2
  92. package/package/corpus/skills/cratis-performance-review/SKILL.md +4 -2
  93. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +15 -5
  94. package/package/corpus/skills/cratis-security-review/SKILL.md +20 -3
  95. package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +3 -3
  96. package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +12 -8
  97. package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +1 -1
  98. package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +7 -3
  99. package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +6 -3
  100. package/package/corpus/skills/cratis-specifications-typescript/references/typescript-patterns.md +21 -4
  101. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +29 -17
  102. package/package.json +1 -1
@@ -1,221 +1,255 @@
1
1
  ---
2
2
  name: cratis-components-styling
3
- description: Style and theme an application built on Cratis Components — the stylesheet imports an app must make, the --cratis-* design-token layer and the PrimeReact token chain behind it, choosing between the baseline theme, a styled preset, a custom palette, and fully unstyled, dark mode, the PrimeReact pass-through prop, and where Tailwind actually fits. Use when setting up a new Cratis frontend, changing colors or theming, fixing components that render unstyled, or reaching into a component's internal DOM. Do not use for component API or page composition questions.
3
+ description: Style and theme an application built on Cratis Components 4 — the three stylesheet entries an app must import, the --cratis-* design-token seam, choosing between the baseline theme, a product theme and fully owned styling, dark mode, the typed pt parts and data-cratis-part selectors, the optional renderer adapters, and where Tailwind actually fits. Use when setting up a new Cratis frontend, changing colors or theming, fixing components that render unstyled, or styling one part of a component. Do not use for component API or page composition questions.
4
4
  license: MIT
5
5
  ---
6
6
 
7
7
  # Styling Cratis Components
8
8
 
9
- Cratis Components builds on PrimeReact 11, which is **unstyled-first**: it ships
10
- no CSS and renders no class names of its own. Everything a Cratis application
11
- looks like comes from the layers below. Getting the setup wrong shows up as
9
+ Cratis Components 4 owns its markup and its styling contract. There is no
10
+ third-party theme engine, preset or provider underneath it: what a Cratis
11
+ application looks like is decided by three Cratis-owned stylesheet entries and
12
+ the `--cratis-*` custom properties they read. Getting the setup wrong shows up as
12
13
  components rendering completely unstyled, which is the single most common
13
- first-run problem.
14
+ first-run problem — and it is fixed with two `import` lines.
14
15
 
15
16
  ## Verified product sources
16
17
 
17
18
  | Package | Version | Verified from |
18
19
  | --- | --- | --- |
19
- | `@cratis/components` | `3.0.0` | its package manifest, `Styled/`, and the CSS sources |
20
- | `primereact` | `^11.0.0` | peer of `@cratis/components@3.0.0` |
21
- | `@primereact/core`, `@primereact/headless`, `@primereact/hooks` | `^11.0.0` | peers of `@cratis/components@3.0.0` |
22
- | `@primereact/styles`, `@primereact/types`, `@primeuix/themes` | optional peers | `@primereact/styles`/`types` `^11.0.0`, `@primeuix/themes` `^3.0.0` |
23
- | `primeicons` | `^8.0.0` | peer of `@cratis/components@3.0.0` |
20
+ | `@cratis/components` | `4.6.0` | its package manifest (`exports`, no vendor UI dependency or peer), `Source/tokens.css`, `Source/MIGRATION.md`, `Documentation/Styling/*`, `Documentation/Common/cratis-components-provider.md`, `Documentation/renderers/*` |
24
21
 
25
- PrimeReact is a **peer dependency** — install it in the application yourself.
26
- Two copies mean two provider contexts, which breaks overlays and pass-through
27
- silently. Remove any `resolutions` or `overrides` pin that used to work around
28
- this.
22
+ Components declares **no** PrimeReact, PrimeIcons or PrimeUI dependency or peer.
23
+ React Aria supplies focus, overlay, collection and date behavior *internally* —
24
+ you never import it, never style its class names, and it never appears in an
25
+ application's manifest. Remove any leftover Prime packages that only Components
26
+ used to need (`Source/MIGRATION.md` lists them); keep one only if the application
27
+ itself still imports it directly, and then that island's provider, theme and
28
+ license are the application's.
29
29
 
30
30
  ## Step 1 — What an app must do
31
31
 
32
32
  Two things, or the components render unstyled:
33
33
 
34
- 1. **Mount `CratisComponentsProvider`** (from `@cratis/components/Common`)
35
- above every Cratis component. It wraps the PrimeReact provider and merges
36
- your configuration over the Cratis defaults, so anything you pass wins.
37
- 2. **Import the stylesheets explicitly**, in this order — components no longer
38
- import their own CSS:
34
+ 1. **Import the stylesheets, in this order**, once, at the entry point:
39
35
 
40
36
  ```ts
41
- import '@cratis/components/tokens'; // the --cratis-* layer every component reads
42
- import '@cratis/components/styles'; // every component stylesheet, in one file
43
- import '@cratis/components/theme'; // optional: the license-free baseline look
37
+ import '@cratis/components/tokens'; // the semantic --cratis-* seam, with conservative light defaults on :root
38
+ import '@cratis/components/styles'; // structural rules for every component, in low-priority Cratis layers
39
+ import '@cratis/components/theme'; // optional: the maintained baseline look, dark mode, forced colors
44
40
  ```
45
41
 
46
- Order matters: both `styles` and `theme` consume the tokens. The `styles` entry
47
- also vendors the split-pane CSS the `DataPage` details pane needs, so importing
48
- it is not optional even in a fully custom-styled app.
42
+ `tokens` first — `styles` and `theme` both read it. `styles` also carries the
43
+ split-pane CSS the `DataPage` details pane needs, so it is not optional even
44
+ in a fully custom-styled app. `styles` contains **no** Tailwind Preflight, no
45
+ global reset and no copy of the token values.
46
+
47
+ 2. **Mount `CratisComponentsProvider`** (from the package root,
48
+ `@cratis/components`) above every Cratis component. It carries `locale` and
49
+ the Components-owned `messages`, and mounts the toast region with `toaster`;
50
+ it carries **no** styling. The Components 3 renderer keys — `license`, `theme`,
51
+ `defaults`, global `pt`, `ptOptions`, `ripple`, `unstyled`, z-index — are a
52
+ type error on purpose, so a migrated app cannot compile a provider whose
53
+ visual configuration silently does nothing.
54
+
55
+ ```tsx
56
+ import { CratisComponentsProvider } from '@cratis/components';
57
+
58
+ <CratisComponentsProvider value={{ locale: 'en-US' }} toaster>
59
+ <App />
60
+ </CratisComponentsProvider>
61
+ ```
49
62
 
50
- ## Step 2 — Pick one of four setups
63
+ ## Step 2 — Pick one of three setups
51
64
 
52
- | Setup | What you do | When |
65
+ | Setup | Imports | You own |
53
66
  | --- | --- | --- |
54
- | **Baseline theme** | import `tokens` + `styles` + `theme`, add the theme class to a root element | you want a working look with no license and little effort |
55
- | **Styled mode** | import `tokens` + `styles`, pass the Cratis styled-mode configuration to the provider | you want a full PrimeReact-preset look |
56
- | **Custom palette** | styled mode with your own preset | you have brand colors |
57
- | **Fully unstyled** | import `tokens` + `styles`, supply your own pass-through or CSS | you have your own design system |
58
-
59
- A preset **alone** is not one of these. Passing `theme: { preset }` to the
60
- provider emits the PrimeReact token variables but styles nothing that Cratis
61
- Components renders, because those are PrimeReact *primitives* — they render
62
- data attributes rather than class names, so a preset has nothing to attach to.
63
- That is exactly what the styled-mode helper fixes.
64
-
65
- ### Styled mode
66
-
67
- `@cratis/components/styled` exports the pieces:
68
-
69
- - `CratisPreset` — a PrimeReact preset derived from Lara with the Cratis blue
70
- primary ramp and a deliberate one-step surface shift so dark mode matches the
71
- previous Cratis look.
72
- - `primeReactStyles` — the component-defaults map that glues the PrimeReact
73
- primitive styles onto the primitives Cratis Components renders. This is the
74
- part a bare preset is missing.
75
- - `styledMode(options?)` — returns `{ theme, defaults }` ready to hand to the
76
- provider.
77
-
78
- ```tsx
79
- import { CratisComponentsProvider } from '@cratis/components/Common';
80
- import { styledMode } from '@cratis/components/styled';
81
-
82
- <CratisComponentsProvider value={styledMode()}>
83
- <App />
84
- </CratisComponentsProvider>
67
+ | **Baseline theme** | `tokens` + `styles` + `theme` | choosing `cratis-dark` / `cratis-light` / system preference; overriding only the brand values you mean to |
68
+ | **Product theme** | `tokens` + `styles` + *your* CSS, imported after them | mapping your complete palette onto `--cratis-*`; typography, spacing, motion, contrast; component treatment through parts |
69
+ | **Fully owned** | `tokens` + `styles` + your CSS | the same, plus every `--cratis-*` value — omit `theme` entirely |
70
+
71
+ A theme is **CSS**. No JavaScript preset, provider option or wrapper class is
72
+ required for the normal whole-application setup. The product's CSS is written
73
+ *outside* a cascade layer, so it wins over all three Components layers
74
+ (`cratis-theme`, `cratis-components`, `cratis-utilities`) without specificity
75
+ tricks; if the product uses its own layers, declare their order explicitly after
76
+ the Components imports.
77
+
78
+ ### Baseline theme and dark mode
79
+
80
+ `theme` adds document foreground/background, system dark-mode values, the
81
+ explicit scheme classes, forced-colors tuning and `.cratis-theme` subtree
82
+ defaults. It stays visually familiar to Components 2/3 — Lara-adjacent blue
83
+ actions, neutral surfaces, 6px radii — implemented entirely with Cratis tokens.
84
+
85
+ ```ts
86
+ document.documentElement.classList.toggle('cratis-dark', darkMode);
85
87
  ```
86
88
 
87
- `styledMode` accepts `preset` (yours instead of `CratisPreset`),
88
- `darkModeSelector`, and `cssLayer`. Its defaults are the dark-mode selector
89
- `.cratis-dark` and a CSS layer named `primereact` ordered
90
- `theme, base, primereact, components, utilities`. That order is deliberate: the
91
- theme sits above Tailwind's `base` so preflight cannot strip table and input
92
- padding, and below `components` and `utilities` so a utility class still wins.
93
-
94
- ### Dark mode
89
+ - Without a class, the baseline follows `prefers-color-scheme`.
90
+ - `cratis-light` keeps light values when the OS prefers dark; an explicit light
91
+ wins over an ambient root `cratis-dark`.
92
+ - An independently themed island puts `cratis-theme` on the subtree and adds
93
+ `cratis-dark` or `cratis-light` there (on the same element, or on an ancestor).
94
+ - Override any `--cratis-*` variable *after* the theme import to adapt it.
95
+
96
+ ### Product theme
97
+
98
+ ```css
99
+ :root {
100
+ --cratis-primary-color: var(--brand-accent-700);
101
+ --cratis-primary-color-text: var(--brand-text-inverse);
102
+ --cratis-action-background: var(--brand-action);
103
+ --cratis-action-background-hover: var(--brand-action-hover);
104
+ --cratis-action-background-active: var(--brand-action-active);
105
+ --cratis-action-text: var(--brand-on-action);
106
+ --cratis-surface-ground: var(--brand-canvas);
107
+ --cratis-surface-card: var(--brand-surface);
108
+ --cratis-surface-overlay: var(--brand-surface);
109
+ --cratis-surface-border: var(--brand-border);
110
+ --cratis-control-background: var(--brand-control);
111
+ --cratis-control-border: var(--brand-control-border);
112
+ --cratis-text-color: var(--brand-text-primary);
113
+ --cratis-text-color-secondary: var(--brand-text-secondary);
114
+ --cratis-focus-ring: var(--brand-focus-ring);
115
+ }
116
+
117
+ [data-theme='dark'] {
118
+ --brand-canvas: #171717; /* switch schemes by redefining the *product* values under the product's own selector */
119
+ }
120
+ ```
95
121
 
96
- Toggle the `cratis-dark` class on the root element. The baseline theme scopes
97
- its dark palette to that class, and styled mode uses it as the preset's dark
98
- selector by default.
122
+ Nothing sits between the product tokens and the rendered component — no
123
+ renderer preset, no internal selector, no commercial theme package.
99
124
 
100
- ## Step 3 — Colors: use the token layer
125
+ ## Step 3 — Colors: use the token seam
101
126
 
102
127
  Never hard-code a hex or `rgb()` value for UI chrome — it breaks the moment the
103
- theme changes. Read a `--cratis-*` custom property instead.
104
-
105
- The chain is: **preset (JavaScript) → `--p-*` (runtime) → `--cratis-*` (the
106
- tokens stylesheet) → component CSS.** Each `--cratis-*` token resolves a
107
- PrimeReact 11 token with a PrimeReact 10 name as fallback, so both eras work.
108
- The tokens are intentionally fallback-free at the end of the chain: if nothing
109
- resolves, the rule no-ops rather than painting a wrong color.
110
-
111
- The full vocabulary:
128
+ theme changes. Read a `--cratis-*` custom property instead. The full vocabulary
129
+ (from `tokens.css`):
112
130
 
113
131
  | Group | Tokens |
114
132
  | --- | --- |
115
- | Surfaces | `--cratis-surface-0`, `--cratis-surface-100`, `--cratis-surface-ground`, `--cratis-surface-section`, `--cratis-surface-card`, `--cratis-surface-overlay`, `--cratis-surface-hover`, `--cratis-surface-border` |
116
- | Text | `--cratis-text-color`, `--cratis-text-color-secondary` |
117
- | Primary | `--cratis-primary-color`, `--cratis-primary-color-text`, `--cratis-primary-300`, `--cratis-primary-400`, `--cratis-primary-500`, `--cratis-primary-600` |
118
- | Highlight | `--cratis-highlight-bg`, `--cratis-highlight-text-color` |
119
- | Semantic | `--cratis-green-500`, `--cratis-orange-500`, `--cratis-red-500` |
120
- | Geometry | `--cratis-border-radius` |
121
- | Effects | `--cratis-focus-ring`, `--cratis-maskbg` |
133
+ | Accent | `--cratis-primary-color`, `--cratis-primary-color-text`, `--cratis-primary-300` … `-600`, `--cratis-primary-600-text` |
134
+ | Primary action | `--cratis-action-background` / `-hover` / `-active`, `--cratis-action-text` |
135
+ | Status pairs | `--cratis-info-background` / `-text`, `--cratis-success-*`, `--cratis-warning-*`, `--cratis-danger-*`; single indicators `--cratis-green-500`, `--cratis-orange-500`, `--cratis-red-500` |
136
+ | Surfaces | `--cratis-surface-ground` (page), `-section`, `-card`, `-overlay` (dialogs, popovers, toasts), `-hover`, `-border`, `-0`, `-100` |
137
+ | Controls | `--cratis-control-background`, `--cratis-control-border`, `--cratis-control-height` / `-small` / `-large` |
138
+ | Text & highlight | `--cratis-text-color`, `--cratis-text-color-secondary`, `--cratis-highlight-bg`, `--cratis-highlight-text-color` |
139
+ | Effects | `--cratis-focus-ring`, `--cratis-maskbg`, `--cratis-border-radius`, `--cratis-disabled-opacity`, `--cratis-shadow-subtle` / `-overlay` / `-dialog` / `-toast` |
140
+ | Layering | `--cratis-z-index-dialog` (1100), `-overlay` (1200), `-filter` (1250), `-tooltip` (1300), `-toast` (1400) |
122
141
 
123
142
  Only hard-code a color that is intentionally theme-independent — a brand accent
124
143
  dot, a traffic-light indicator.
125
144
 
126
- A back-compatibility stylesheet
127
- (`@cratis/components/primereact-v10-palette`) republishes the PrimeReact 10
128
- names (`--surface-ground`, `--text-color`, `--primary-color`, and the numbered
129
- ramps) for code that has not migrated. Import it to keep an old application
130
- running; **write nothing new against those names.**
131
-
132
145
  ## Step 4 — Writing styles
133
146
 
134
- - Put static styles in a **co-located `.css` file** and reference it from the
135
- application's stylesheet manifest. Never write `import './Foo.css'` inside a
136
- `.tsx` — a CSS file in the JavaScript module graph is what made the published
137
- Cratis Components package unloadable in Node, and the library's own build now
138
- fails if a component stylesheet is only reachable that way.
139
- - One CSS file per component. A composition root's CSS carries layout and
140
- positioning for its children, not the children's own styling.
141
- - Use inline `style` **only** for runtime-dynamic values such as computed
142
- pixel positions. A `style` object full of static token names bypasses theming
143
- and review — move it to a class.
147
+ - Put static styles in a **co-located `.css` file**, one per component. A
148
+ composition root's CSS carries layout and positioning for its children, not the
149
+ children's own styling.
150
+ - Use inline `style` **only** for runtime-dynamic values such as computed pixel
151
+ positions. A `style` object full of static token names bypasses theming and
152
+ review — move it to a class.
144
153
  - Name classes with a prefix matching the component.
145
-
146
- ## Step 5 — Pass-through: reaching a component's internals
147
-
148
- PrimeReact's pass-through (`pt`) prop targets the internal parts of a rendered
149
- component; `ptOptions` controls how your values merge with existing ones, and
150
- `unstyled` opts a component out of the theme entirely. Cratis Components
151
- forwards all three, typed against the underlying primitive, on roughly thirty
152
- components — every command-form field, the buttons, dialogs, dropdowns, data
153
- tables, the toaster, and more.
154
-
155
- Three shapes to expect:
156
-
157
- 1. **A single `pt`** on most components.
158
- 2. **Named pass-throughs** where a component wraps two primitives —
159
- `DataPage` takes `tablePt` / `tablePtOptions` / `tableUnstyled` and
160
- `menubarPt` / `menubarPtOptions` / `menubarUnstyled`;
161
- `StepperCommandDialog` uses plain `pt` for the inner stepper and `dialogPt`
162
- for the outer dialog. Applying `pt` and expecting it to reach the other
163
- element is the usual cause of a pass-through that seems to do nothing.
164
- 3. **Composite pass-throughs**, such as the toaster's `{ region, toast }`.
165
-
166
- There is **no global Cratis pass-through preset shipped** — the library's
167
- defaults are deliberately empty so an application's configuration always wins.
168
- Supply your own through the provider's value when you want an app-wide preset:
169
-
170
- ```tsx
171
- <CratisComponentsProvider value={{ pt: myAppPreset }}>
172
- ```
173
-
174
- A few components expose `className` only and have no pass-through of their own —
175
- `SchemaEditor`, `ObjectContentEditor`, and `ObjectNavigationalBar`. Restyle
176
- those through the global preset. `BusyIndicatorDialog` is also global-preset
177
- only, because its request type is owned by the Arc React package.
178
-
179
- ### Pass-through as attribute removal
180
-
181
- Setting a pass-through value to `undefined` **removes** that attribute. Cratis
182
- Components uses this deliberately to strip invalid ARIA that PrimeReact 11 emits
183
- — for example clearing `role` and `aria-controls` off stepper headers whose
184
- target ids are never rendered. It is a legitimate tool when you need to delete
185
- an attribute rather than add one.
186
-
187
- ### The compatibility contract
188
-
189
- `@cratis/components/compatibility` exports a machine-checkable description of
190
- which pass-through keys and slots this major version supports against which
191
- PrimeReact major, plus an assertion helper. Use it in a specification when your
192
- application depends on reaching a specific internal part, so a PrimeReact
193
- upgrade that moves the part fails loudly instead of silently.
154
+ - Import product CSS *after* the Components entries so it wins the cascade.
155
+
156
+ ## Step 5 — Parts: reaching inside a component
157
+
158
+ Every meaningful element a component renders carries **`data-cratis-part`**, and
159
+ most components accept a **`pt`** prop typed by their own `*Parts` type. They
160
+ are documented separately because they are not always the same names: for most
161
+ components the typed `pt` key is the camelCase spelling of the kebab-case DOM
162
+ value (`headerRow` ↔ `header-row`), but the Toolbar family prefixes its DOM
163
+ values (`ToolbarButtonParts.root` ↔ `data-cratis-part='button'`,
164
+ `ToolbarFolderParts.root` ↔ `'toolbar-folder'`, `ToolbarFanOutParts.trigger` ↔
165
+ `'fanout-trigger'`). Read the DOM value off the rendered element (or the parts
166
+ manifest in `@cratis/components/types`) before writing a selector. Both spellings
167
+ are stable across internal foundation changes; React Aria class names and
168
+ undocumented DOM structure are not.
169
+
170
+ - **One instance:** `pt` — plain HTML attributes per part.
171
+
172
+ ```tsx
173
+ <Dropdown aria-label='Role' options={roles}
174
+ pt={{ trigger: { className: 'product-select-trigger' }, popover: { className: 'product-select-popover' }, option: { className: 'product-select-option' } }} />
175
+ ```
176
+
177
+ - **Product-wide:** a CSS rule on the part and its state attributes.
178
+
179
+ ```css
180
+ [data-cratis-part='header-cell'] { text-transform: uppercase; }
181
+ [data-cratis-part='row'][data-selected='true'] { background: var(--product-selected-row); }
182
+ .product-dialog[data-cratis-part='root'] { border-radius: 1rem; }
183
+ ```
184
+
185
+ The typed part families: `ButtonParts`/`IconButtonParts` (`root`, `icon`,
186
+ `label`, `spinner`); `DialogParts` (`backdrop`, `positioner`, `root`, `header`,
187
+ `title`, `close`, `content`, `footer`, `confirm`, `cancel`); `DropdownParts`
188
+ (`root`, `trigger`, `value`, `clear`, `indicator`, `popover`, `listbox`, `option`,
189
+ `filter`, `multiple`); `DataTableParts` (`root`, `search`, `searchInput`,
190
+ `tableContainer`, `table`, `head`, `headerRow`, `headerCell`, `body`, `row`,
191
+ `cell`, `emptyRow`, `emptyCell`); `TablePaginatorParts` (`root`, `range`, `info`,
192
+ `first`, `previous`, `next`, `last`); `StepperParts` (`root`, `list`, `step`,
193
+ `header`, `number`, `title`, `separator`, `panels`, `panel`);
194
+ `ToasterPassThrough` (`region`, `toast`, `icon`, `content`, `title`,
195
+ `description`, `action`, `close`); the `Toolbar*Parts` family; and per-field
196
+ parts for every CommandForm field. The Components `Styling/pass-through`
197
+ reference is the exhaustive table.
198
+
199
+ **Named parts where a component wraps two surfaces** — the usual cause of a
200
+ `pt` that "does nothing" is applying it to the wrong one:
201
+
202
+ - `DataPage`: `tablePt: DataTableParts`, `paginatorPt: TablePaginatorParts`, `menubarPt: ButtonParts`.
203
+ - `StepperCommandDialog`: `pt` is the inner **stepper**, `dialogPt` the outer **dialog**.
204
+ - `Column`: `filterPt: ColumnFilterMenuParts` for the filter popup.
205
+
206
+ **State attributes** are component-specific: `data-active`, `data-selected`,
207
+ `data-invalid`, `data-disabled`, `data-readonly`, `data-loading`, `data-position`,
208
+ `data-orientation`, `data-size`, `data-severity`. Do not assume one exists on
209
+ every component — read the component's parts reference.
210
+
211
+ `ptOptions` and `unstyled` are accepted for Components 3 source compatibility and
212
+ do **nothing**: part attributes always merge, and styling is always CSS-owned.
213
+ There is no global provider `pt`.
214
+
215
+ ## Renderer adapters — when a vendor look is wanted
216
+
217
+ The default renderer is built in; omit `library` on the provider. Three optional
218
+ adapter packages exist — `@cratis/components.mui` (MUI 9),
219
+ `@cratis/components.primereact` (PrimeReact 11), `@cratis/components.primereact10`
220
+ — and each adapts exactly **nine primitive slots**: button, icon-button, text
221
+ input, text area, checkbox, radio, switch, progress bar, surface. Pass the
222
+ adapter's manifest to the provider's `library` prop. Dialogs, dropdowns, tables,
223
+ date pickers, tooltips, paginators, toasts and steppers stay Components-owned
224
+ regardless; an adapter never restores a vendor's public API, and the vendor's
225
+ own provider, theme and license remain the application's, outside Components.
226
+ Reach for an adapter only when the product genuinely wants that vendor's look on
227
+ those nine controls — mapping tokens is almost always the smaller change.
194
228
 
195
229
  ## Where Tailwind fits
196
230
 
197
- Tailwind is **one supported path, not the Cratis default.** Cratis Components
198
- compiles Tailwind utilities with **preflight deliberately excluded**, so
199
- Tailwind's base resets never strip the component styling. If your application
200
- enables preflight, keep the CSS layer order from styled mode so the theme still
201
- sits above `base`.
202
-
203
- Do not reach for Tailwind utilities as the primary styling mechanism for Cratis
204
- components; reach for the token layer and pass-through first.
231
+ Tailwind is **one supported way to write the CSS above, not the Cratis default.**
232
+ It is a fine tool for authoring the token mapping and part rules; it is not a
233
+ substitute for them. Components' own internal utilities are prefixed (`cratis:*`)
234
+ and are not public styling hooks. `styles` ships no Preflight and no reset of its
235
+ own; if the application uses Tailwind's Preflight or its own cascade layers,
236
+ declare the layer order explicitly after the Components imports (Components says
237
+ nothing more specific than that — verify the result in the running app).
205
238
 
206
239
  ## Verify
207
240
 
208
- - PrimeReact and its `@primereact/*` peers are installed in the application, at
209
- one version each.
210
- - `CratisComponentsProvider` wraps the tree.
241
+ - No PrimeReact / PrimeIcons / PrimeUI package remains in the manifest unless the
242
+ application itself imports it directly — and then it has its own provider.
243
+ - `CratisComponentsProvider` (root import) wraps the tree and carries only
244
+ `locale`, `messages` and `toaster`.
211
245
  - `@cratis/components/tokens` and `@cratis/components/styles` are imported once
212
- at the entry point, tokens first.
213
- - Exactly one of the four setups is chosen — a bare preset with no styled-mode
214
- defaults is not one of them.
246
+ at the entry point, tokens first; `theme` is imported or deliberately omitted;
247
+ product CSS comes after.
215
248
  - No hex or `rgb()` value is hard-coded for UI chrome; colors read `--cratis-*`.
216
- - No new code is written against the PrimeReact 10 palette names.
217
- - No `.tsx` imports a `.css` file.
249
+ - No CSS targets a React Aria class name or undocumented DOM; parts are reached
250
+ through `pt` or `[data-cratis-part=…]`.
218
251
  - Inline `style` carries only runtime-dynamic values.
219
- - Pass-through props target the intended element, especially on `DataPage` and
220
- `StepperCommandDialog`.
221
- - Dark mode is toggled with the `cratis-dark` class on the root element.
252
+ - Named parts land on the intended surface (`tablePt` vs `menubarPt`; `pt` vs
253
+ `dialogPt`).
254
+ - Dark mode is toggled with `cratis-dark` / `cratis-light` on the root element
255
+ (or a `cratis-theme` subtree), not through a provider option.
@@ -15,9 +15,9 @@ over a list, use `DataPage.MenuItems` instead (see the
15
15
 
16
16
  | Package | Version | Verified from |
17
17
  | --- | --- | --- |
18
- | `@cratis/components` | `3.0.0` | its package manifest and `Toolbar` component sources |
19
- | `primeicons` | `^8.0.0` | peer of `@cratis/components@3.0.0` |
20
- | `react` | `^19.0.0` | peer of `@cratis/components@3.0.0` |
18
+ | `@cratis/components` | `4.6.0` | its package manifest, `Source/Toolbar/*` (exports and props), `Documentation/Toolbar/*`, `Documentation/Common/icon.md` |
19
+ | `react-icons` | `5.7.0` | dependency of `@cratis/components@4.6.0` — the icon source the examples use |
20
+ | `react` | `^19.0.0` | peer of `@cratis/components@4.6.0` |
21
21
 
22
22
  ## Import from the subpath
23
23
 
@@ -53,19 +53,25 @@ Buttons default to a vertical layout. **`title` is the required prop and it is
53
53
  what appears in the tooltip** — there is no `tooltip` prop on `ToolbarButton`.
54
54
 
55
55
  ```tsx
56
+ import { FaArrowPointer, FaPencil, FaVectorSquare } from 'react-icons/fa6';
56
57
  import { Toolbar, ToolbarButton } from '@cratis/components/Toolbar';
57
58
 
58
59
  export const DrawingToolbar = () => (
59
60
  <Toolbar>
60
- <ToolbarButton icon='pi pi-arrow-up-left' title='Select' />
61
- <ToolbarButton icon='pi pi-pencil' title='Draw' />
62
- <ToolbarButton icon='pi pi-stop' title='Rectangle' />
61
+ <ToolbarButton icon={<FaArrowPointer />} title='Select' />
62
+ <ToolbarButton icon={<FaPencil />} title='Draw' />
63
+ <ToolbarButton icon={<FaVectorSquare />} title='Rectangle' />
63
64
  </Toolbar>
64
65
  );
65
66
  ```
66
67
 
67
- `icon` accepts either a PrimeIcons class string or a React node, so a custom SVG
68
- component works directly: `<ToolbarButton icon={<CircleIcon />} title='Circle' />`.
68
+ `icon` is the Components `Icon` type: a **React node** (preferred — the examples
69
+ below take theirs from `react-icons/fa6`, which Components itself depends on, and
70
+ omit the import line after this first one) or a complete, consumer-owned
71
+ icon-font class string. Components installs **no icon font**: a string is rendered
72
+ on an `<i>` unchanged, so the product must load that stylesheet and pass every
73
+ class the font needs. A custom SVG component works directly:
74
+ `<ToolbarButton icon={<CircleIcon />} title='Circle' />`.
69
75
 
70
76
  ## Step 2 — Active state
71
77
 
@@ -73,9 +79,9 @@ component works directly: `<ToolbarButton icon={<CircleIcon />} title='Circle' /
73
79
  const [activeTool, setActiveTool] = useState('select');
74
80
 
75
81
  <Toolbar>
76
- <ToolbarButton icon='pi pi-pencil' title='Draw'
82
+ <ToolbarButton icon={<FaPencil />} title='Draw'
77
83
  active={activeTool === 'draw'} onClick={() => setActiveTool('draw')} />
78
- <ToolbarButton icon='pi pi-stop' title='Rectangle'
84
+ <ToolbarButton icon={<FaVectorSquare />} title='Rectangle'
79
85
  active={activeTool === 'rect'} onClick={() => setActiveTool('rect')} />
80
86
  </Toolbar>
81
87
  ```
@@ -87,11 +93,11 @@ tooltips out of the bar's way on a horizontal toolbar:
87
93
 
88
94
  ```tsx
89
95
  <Toolbar orientation='horizontal'>
90
- <ToolbarButton icon='pi pi-minus' title='Zoom out' tooltipPosition='bottom' onClick={() => setZoom(z => z - 10)} />
96
+ <ToolbarButton icon={<FaMinus />} title='Zoom out' tooltipPosition='bottom' onClick={() => setZoom(z => z - 10)} />
91
97
  <ToolbarButton text={`${zoom}%`} title='Reset zoom' tooltipPosition='bottom' onClick={() => setZoom(100)} />
92
- <ToolbarButton icon='pi pi-plus' title='Zoom in' tooltipPosition='bottom' onClick={() => setZoom(z => z + 10)} />
98
+ <ToolbarButton icon={<FaPlus />} title='Zoom in' tooltipPosition='bottom' onClick={() => setZoom(z => z + 10)} />
93
99
  <ToolbarSeparator orientation='horizontal' />
94
- <ToolbarButton icon='pi pi-question-circle' title='Help' tooltipPosition='bottom' />
100
+ <ToolbarButton icon={<FaCircleQuestion />} title='Help' tooltipPosition='bottom' />
95
101
  </Toolbar>
96
102
  ```
97
103
 
@@ -108,18 +114,18 @@ unaffected.
108
114
  const [mode, setMode] = useState<'drawing' | 'text'>('drawing');
109
115
 
110
116
  <Toolbar>
111
- <ToolbarButton icon='pi pi-arrow-up-left' title='Select' />
117
+ <ToolbarButton icon={<FaArrowPointer />} title='Select' />
112
118
  <ToolbarSection activeContext={mode}>
113
119
  <ToolbarContext name='drawing'>
114
- <ToolbarButton icon='pi pi-pencil' title='Draw' />
115
- <ToolbarButton icon='pi pi-stop' title='Rectangle' />
120
+ <ToolbarButton icon={<FaPencil />} title='Draw' />
121
+ <ToolbarButton icon={<FaVectorSquare />} title='Rectangle' />
116
122
  </ToolbarContext>
117
123
  <ToolbarContext name='text'>
118
- <ToolbarButton icon='pi pi-align-left' title='Align left' />
119
- <ToolbarButton icon='pi pi-align-center' title='Align center' />
124
+ <ToolbarButton icon={<FaAlignLeft />} title='Align left' />
125
+ <ToolbarButton icon={<FaAlignCenter />} title='Align center' />
120
126
  </ToolbarContext>
121
127
  </ToolbarSection>
122
- <ToolbarButton icon='pi pi-undo' title='Undo' />
128
+ <ToolbarButton icon={<FaRotateLeft />} title='Undo' />
123
129
  </Toolbar>
124
130
  ```
125
131
 
@@ -130,9 +136,9 @@ the one component whose label prop **is** called `tooltip`, and both `icon` and
130
136
  `tooltip` are required.
131
137
 
132
138
  ```tsx
133
- <ToolbarFanOutItem icon='pi pi-th-large' tooltip='Shapes' fanOutDirection='left'>
134
- <ToolbarButton icon='pi pi-stop' title='Rectangle' />
135
- <ToolbarButton icon='pi pi-circle' title='Circle' />
139
+ <ToolbarFanOutItem icon={<FaShapes />} tooltip='Shapes' fanOutDirection='left'>
140
+ <ToolbarButton icon={<FaVectorSquare />} title='Rectangle' />
141
+ <ToolbarButton icon={<FaCircle />} title='Circle' />
136
142
  </ToolbarFanOutItem>
137
143
  ```
138
144
 
@@ -142,9 +148,9 @@ away from the screen edge the toolbar sits against.
142
148
  `ToolbarFolder` opens a larger panel of buttons as a grid or a list:
143
149
 
144
150
  ```tsx
145
- <ToolbarFolder icon='pi pi-th-large' title='Tools' mode='list'>
146
- <ToolbarButton icon='pi pi-pencil' title='Draw' />
147
- <ToolbarButton icon='pi pi-eraser' title='Erase' />
151
+ <ToolbarFolder icon={<FaShapes />} title='Tools' mode='list'>
152
+ <ToolbarButton icon={<FaPencil />} title='Draw' />
153
+ <ToolbarButton icon={<FaEraser />} title='Erase' />
148
154
  </ToolbarFolder>
149
155
  ```
150
156
 
@@ -163,7 +169,7 @@ by rendering a named `ToolbarLayout`.
163
169
  {mode === 'draw' && <ToolbarSlot slotName='tool-options' order={10}>{drawTools}</ToolbarSlot>}
164
170
  <Toolbar>
165
171
  <ToolbarGroup>
166
- <ToolbarButton icon='pi pi-arrow-up-left' title='Select' />
172
+ <ToolbarButton icon={<FaArrowPointer />} title='Select' />
167
173
  </ToolbarGroup>
168
174
  <ToolbarGroup slotName='tool-options' />
169
175
  </Toolbar>
@@ -20,7 +20,7 @@ file and Mermaid disagree. Confirm the Mermaid version available to the renderer
20
20
  before relying on a construct.
21
21
 
22
22
  The Cratis artifacts a diagram refers to are verified against `Cratis.Chronicle`
23
- `16.45.2` and the Arc query and command surface it is used with.
23
+ `18.3.0` and the Arc query and command surface it is used with.
24
24
 
25
25
  ## What an event model is
26
26
 
@@ -15,8 +15,8 @@ This skill is verified against these exact public releases:
15
15
 
16
16
  | Package | Version | Purpose |
17
17
  | --- | --- | --- |
18
- | `Cratis.Fundamentals` | `7.18.1` | `Cratis.Concepts.ConceptAs<T>` |
19
- | `Cratis.Chronicle` | `16.38.1` | `Cratis.Chronicle.Events.EventSourceId` and `EventSourceId<T>` |
18
+ | `Cratis.Fundamentals` | `7.19.2` | `Cratis.Concepts.ConceptAs<T>` |
19
+ | `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Events.EventSourceId` and `EventSourceId<T>` |
20
20
 
21
21
  Reverify product sources before claiming support for another version.
22
22
 
@@ -18,7 +18,7 @@ removing one becomes a single-file change.
18
18
 
19
19
  | Package | Version | Purpose |
20
20
  | --- | --- | --- |
21
- | `Cratis.Fundamentals` | `7.18.2` | `IInstancesOf<T>`, `IImplementationsOf<T>`, `[Singleton]`, `[Scoped]`, `[IgnoreConvention]`, the convention bindings |
21
+ | `Cratis.Fundamentals` | `7.19.2` | `IInstancesOf<T>`, `IImplementationsOf<T>`, `[Singleton]`, `[Scoped]`, `[IgnoreConvention]`, the convention bindings |
22
22
 
23
23
  Reverify against the Cratis Fundamentals repository before claiming support for
24
24
  another version.
@@ -50,7 +50,7 @@ registered implementation:
50
50
  `IInstancesOf<T>` finds types by convention across the loaded assemblies. The
51
51
  requirements are only:
52
52
 
53
- - Each implementation is a non-abstract `public class`.
53
+ - Each implementation is a non-abstract, non-interface class. Discovery reads each assembly's `DefinedTypes` and filters only on `!IsInterface && !IsAbstract`, so an `internal` class is discovered too; `public` is a convention for a type meant to be reached from another assembly, not a discovery requirement. Instances are resolved from the service provider (`GetService(type)`), so each implementation must be registered as itself — `AddSelfBindings()` does that for every concrete, non-static, non-`Exception` class whose constructor is resolvable (visibility is not a criterion), honoring `[Singleton]`/`[Scoped]`/`[IgnoreConvention]`.
54
54
  - It implements the interface directly, not through a layer that hides it.
55
55
  - `T` is an interface or abstract class — the interface is declared
56
56
  `where T : class`.