@cratis/pi 0.0.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.
Files changed (125) hide show
  1. package/README.md +43 -0
  2. package/package.json +24 -0
  3. package/skills/cratis-application-react-specifications/LICENSE +2 -0
  4. package/skills/cratis-application-react-specifications/SKILL.md +192 -0
  5. package/skills/cratis-application-slice-specifications/LICENSE +2 -0
  6. package/skills/cratis-application-slice-specifications/SKILL.md +222 -0
  7. package/skills/cratis-arc-authentication-authorization-and-identity/LICENSE +2 -0
  8. package/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +233 -0
  9. package/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +140 -0
  10. package/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +112 -0
  11. package/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +102 -0
  12. package/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +85 -0
  13. package/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +87 -0
  14. package/skills/cratis-arc-command/LICENSE +2 -0
  15. package/skills/cratis-arc-command/SKILL.md +286 -0
  16. package/skills/cratis-arc-command/references/command-result.md +111 -0
  17. package/skills/cratis-arc-command/references/handler-shapes.md +135 -0
  18. package/skills/cratis-arc-command/references/proxy-generation.md +87 -0
  19. package/skills/cratis-arc-command/references/read-model-injection.md +97 -0
  20. package/skills/cratis-arc-command-execution/LICENSE +2 -0
  21. package/skills/cratis-arc-command-execution/SKILL.md +148 -0
  22. package/skills/cratis-arc-command-validation/LICENSE +2 -0
  23. package/skills/cratis-arc-command-validation/SKILL.md +230 -0
  24. package/skills/cratis-arc-ef-core-migration/LICENSE +2 -0
  25. package/skills/cratis-arc-ef-core-migration/SKILL.md +231 -0
  26. package/skills/cratis-arc-observable-query-http/LICENSE +2 -0
  27. package/skills/cratis-arc-observable-query-http/SKILL.md +157 -0
  28. package/skills/cratis-arc-query-paging/LICENSE +2 -0
  29. package/skills/cratis-arc-query-paging/SKILL.md +173 -0
  30. package/skills/cratis-arc-react-page/LICENSE +2 -0
  31. package/skills/cratis-arc-react-page/SKILL.md +291 -0
  32. package/skills/cratis-arc-react-page/references/data-page.md +125 -0
  33. package/skills/cratis-arc-react-page/references/data-tables.md +136 -0
  34. package/skills/cratis-arc-react-page/references/dialogs.md +238 -0
  35. package/skills/cratis-arc-react-page/references/mvvm.md +150 -0
  36. package/skills/cratis-arc-react-page/references/queries-and-commands.md +200 -0
  37. package/skills/cratis-chronicle-cli-operations/LICENSE +2 -0
  38. package/skills/cratis-chronicle-cli-operations/SKILL.md +199 -0
  39. package/skills/cratis-chronicle-client-dotnet/LICENSE +2 -0
  40. package/skills/cratis-chronicle-client-dotnet/SKILL.md +433 -0
  41. package/skills/cratis-chronicle-client-elixir/LICENSE +2 -0
  42. package/skills/cratis-chronicle-client-elixir/SKILL.md +429 -0
  43. package/skills/cratis-chronicle-client-kotlin/LICENSE +2 -0
  44. package/skills/cratis-chronicle-client-kotlin/SKILL.md +498 -0
  45. package/skills/cratis-chronicle-client-typescript/LICENSE +2 -0
  46. package/skills/cratis-chronicle-client-typescript/SKILL.md +396 -0
  47. package/skills/cratis-chronicle-compliance/LICENSE +2 -0
  48. package/skills/cratis-chronicle-compliance/SKILL.md +246 -0
  49. package/skills/cratis-chronicle-event-constraints/LICENSE +2 -0
  50. package/skills/cratis-chronicle-event-constraints/SKILL.md +227 -0
  51. package/skills/cratis-chronicle-event-modeling/LICENSE +2 -0
  52. package/skills/cratis-chronicle-event-modeling/SKILL.md +157 -0
  53. package/skills/cratis-chronicle-event-specifications/LICENSE +2 -0
  54. package/skills/cratis-chronicle-event-specifications/SKILL.md +200 -0
  55. package/skills/cratis-chronicle-event-type-migration/LICENSE +2 -0
  56. package/skills/cratis-chronicle-event-type-migration/SKILL.md +235 -0
  57. package/skills/cratis-chronicle-mcp-inspection/LICENSE +2 -0
  58. package/skills/cratis-chronicle-mcp-inspection/SKILL.md +79 -0
  59. package/skills/cratis-chronicle-mcp-inspection/references/blocked-tools.md +12 -0
  60. package/skills/cratis-chronicle-mcp-inspection/references/observational-tools.md +8 -0
  61. package/skills/cratis-chronicle-multi-tenancy/LICENSE +2 -0
  62. package/skills/cratis-chronicle-multi-tenancy/SKILL.md +198 -0
  63. package/skills/cratis-chronicle-projection/LICENSE +2 -0
  64. package/skills/cratis-chronicle-projection/SKILL.md +162 -0
  65. package/skills/cratis-chronicle-projection/references/fluent-builder.md +126 -0
  66. package/skills/cratis-chronicle-projection/references/model-bound-attributes.md +118 -0
  67. package/skills/cratis-chronicle-reactor/LICENSE +2 -0
  68. package/skills/cratis-chronicle-reactor/SKILL.md +344 -0
  69. package/skills/cratis-chronicle-read-model/LICENSE +2 -0
  70. package/skills/cratis-chronicle-read-model/SKILL.md +193 -0
  71. package/skills/cratis-chronicle-read-model/references/queries.md +142 -0
  72. package/skills/cratis-chronicle-read-model-specifications/LICENSE +2 -0
  73. package/skills/cratis-chronicle-read-model-specifications/SKILL.md +176 -0
  74. package/skills/cratis-chronicle-reducer/LICENSE +2 -0
  75. package/skills/cratis-chronicle-reducer/SKILL.md +173 -0
  76. package/skills/cratis-chronicle-web-workbench/LICENSE +2 -0
  77. package/skills/cratis-chronicle-web-workbench/SKILL.md +177 -0
  78. package/skills/cratis-cli-terminal-workbench/LICENSE +2 -0
  79. package/skills/cratis-cli-terminal-workbench/SKILL.md +156 -0
  80. package/skills/cratis-code-review/LICENSE +2 -0
  81. package/skills/cratis-code-review/SKILL.md +177 -0
  82. package/skills/cratis-components-accessibility/LICENSE +2 -0
  83. package/skills/cratis-components-accessibility/SKILL.md +176 -0
  84. package/skills/cratis-components-schema-editor/LICENSE +2 -0
  85. package/skills/cratis-components-schema-editor/SKILL.md +238 -0
  86. package/skills/cratis-components-stepper-command-dialog/LICENSE +2 -0
  87. package/skills/cratis-components-stepper-command-dialog/SKILL.md +209 -0
  88. package/skills/cratis-components-styling/LICENSE +2 -0
  89. package/skills/cratis-components-styling/SKILL.md +221 -0
  90. package/skills/cratis-components-toolbar/LICENSE +2 -0
  91. package/skills/cratis-components-toolbar/SKILL.md +259 -0
  92. package/skills/cratis-documentation-writing/LICENSE +2 -0
  93. package/skills/cratis-documentation-writing/SKILL.md +121 -0
  94. package/skills/cratis-event-model-diagram/LICENSE +2 -0
  95. package/skills/cratis-event-model-diagram/SKILL.md +142 -0
  96. package/skills/cratis-fundamentals-concept/LICENSE +2 -0
  97. package/skills/cratis-fundamentals-concept/SKILL.md +198 -0
  98. package/skills/cratis-fundamentals-type-discovery/LICENSE +2 -0
  99. package/skills/cratis-fundamentals-type-discovery/SKILL.md +152 -0
  100. package/skills/cratis-governed-release-methodology/LICENSE +2 -0
  101. package/skills/cratis-governed-release-methodology/SKILL.md +297 -0
  102. package/skills/cratis-lens-browser-extension/LICENSE +2 -0
  103. package/skills/cratis-lens-browser-extension/SKILL.md +239 -0
  104. package/skills/cratis-performance-review/LICENSE +2 -0
  105. package/skills/cratis-performance-review/SKILL.md +139 -0
  106. package/skills/cratis-screenplay-model-authoring/LICENSE +2 -0
  107. package/skills/cratis-screenplay-model-authoring/SKILL.md +231 -0
  108. package/skills/cratis-security-review/LICENSE +2 -0
  109. package/skills/cratis-security-review/SKILL.md +141 -0
  110. package/skills/cratis-specification-by-example/LICENSE +2 -0
  111. package/skills/cratis-specification-by-example/SKILL.md +188 -0
  112. package/skills/cratis-specifications-csharp/LICENSE +2 -0
  113. package/skills/cratis-specifications-csharp/SKILL.md +230 -0
  114. package/skills/cratis-specifications-csharp/references/application-scenarios.md +191 -0
  115. package/skills/cratis-specifications-csharp/references/csharp-patterns.md +142 -0
  116. package/skills/cratis-specifications-csharp/references/integration-specs.md +126 -0
  117. package/skills/cratis-specifications-typescript/LICENSE +2 -0
  118. package/skills/cratis-specifications-typescript/SKILL.md +202 -0
  119. package/skills/cratis-specifications-typescript/references/typescript-patterns.md +168 -0
  120. package/skills/cratis-stage-rendering-and-sandbox/LICENSE +2 -0
  121. package/skills/cratis-stage-rendering-and-sandbox/SKILL.md +230 -0
  122. package/skills/cratis-studio-mcp-safety-guidance/LICENSE +2 -0
  123. package/skills/cratis-studio-mcp-safety-guidance/SKILL.md +69 -0
  124. package/skills/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +12 -0
  125. package/skills/cratis-studio-mcp-safety-guidance/references/observational-tools.md +8 -0
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: cratis-components-schema-editor
3
+ description: Use the Cratis Components schema editors — SchemaEditor for editing a JSON schema's property structure, and ObjectContentEditor for viewing and editing an object instance against a schema. Covers the exact props, the narrow JSON-schema subset they consume, how edits come back out, the type-format vocabulary, property-name validation, and the real editing limits. Use when building a UI that lets a user shape an event or payload schema, or inspect and edit a stored object. Do not use for a command form bound to a generated Arc command.
4
+ license: MIT
5
+ ---
6
+
7
+ # Cratis Components schema editors
8
+
9
+ Two components edit schema-shaped data. They are **not** interchangeable:
10
+
11
+ | Component | Edits | Subpath |
12
+ | --- | --- | --- |
13
+ | `SchemaEditor` | the **schema** — property names, types, and formats | `@cratis/components/SchemaEditor` |
14
+ | `ObjectContentEditor` | an **object instance**, interpreted through a schema | `@cratis/components/ObjectContentEditor` |
15
+
16
+ For a form bound to a generated Arc command, use `CommandForm` and its fields
17
+ instead — see the **cratis-arc-react-page** skill. These editors are for the
18
+ case where the shape itself is data.
19
+
20
+ ## Verified product sources
21
+
22
+ | Package | Version | Verified from |
23
+ | --- | --- | --- |
24
+ | `@cratis/components` | `3.0.0` | its package manifest and the `SchemaEditor` / `ObjectContentEditor` sources |
25
+ | `primereact` | `^11.0.0` | peer of `@cratis/components@3.0.0` |
26
+ | `react` | `^19.0.0` | peer of `@cratis/components@3.0.0` |
27
+
28
+ ## The schema type these editors consume
29
+
30
+ This is a deliberately narrow, hand-rolled subset — **not** a JSON Schema draft
31
+ type. Import it from either editor's subpath.
32
+
33
+ ```ts
34
+ interface JsonSchema {
35
+ title?: string; name?: string; $id?: string; $ref?: string;
36
+ type?: string; format?: string; description?: string;
37
+ properties?: Record<string, JsonSchemaProperty>;
38
+ items?: JsonSchema;
39
+ required?: string[];
40
+ definitions?: Record<string, JsonSchema>;
41
+ }
42
+
43
+ interface JsonSchemaProperty {
44
+ id?: string; name?: string; type?: string; format?: string; description?: string;
45
+ items?: JsonSchema; properties?: Record<string, JsonSchemaProperty>;
46
+ required?: boolean; $ref?: string;
47
+ }
48
+
49
+ type Json = string | number | boolean | null | Json[] | { [key: string]: Json };
50
+ ```
51
+
52
+ Three limits to design around:
53
+
54
+ - **`$ref` and `definitions` are declared but never resolved.** Nested
55
+ navigation walks `properties` and `items` literally. A schema that relies on
56
+ references will not render its referenced shapes.
57
+ - **`type` is a plain string**, not a union — there is no exhaustiveness check.
58
+ - **`required` is read but never rendered or edited** by `SchemaEditor`. Its
59
+ table has two columns, Property and Type. Do not promise a required toggle.
60
+
61
+ ## `SchemaEditor`
62
+
63
+ ```tsx
64
+ import { SchemaEditor } from '@cratis/components/SchemaEditor';
65
+ import type { JsonSchema, TypeFormat } from '@cratis/components/SchemaEditor';
66
+ ```
67
+
68
+ The editor is internally stateful and pushes the **whole new schema** out on
69
+ every structural change.
70
+
71
+ ```tsx
72
+ const [schema, setSchema] = useState<JsonSchema>(initialSchema);
73
+
74
+ <SchemaEditor
75
+ schema={schema}
76
+ eventTypeName='User'
77
+ canEdit
78
+ onChange={setSchema}
79
+ onSave={() => persist(schema)}
80
+ onCancel={() => reload()} />
81
+ ```
82
+
83
+ ### Props
84
+
85
+ | Prop | Type | Default |
86
+ | --- | --- | --- |
87
+ | `schema` | `JsonSchema` | **required** |
88
+ | `eventTypeName` | `string` | `''` — the breadcrumb root label |
89
+ | `canEdit` | `boolean` | `true` |
90
+ | `canNotEditReason` | `string` | shown when `canEdit` is false |
91
+ | `onChange` | `(schema: JsonSchema) => void` | receives the complete new schema |
92
+ | `onSave` | `() => void` | takes **no arguments** |
93
+ | `onCancel` | `() => void` | |
94
+ | `editMode` | `boolean` | initial edit state only — see below |
95
+ | `saveDisabled` | `boolean` | `false` |
96
+ | `cancelDisabled` | `boolean` | `false` |
97
+ | `typeFormats` | `TypeFormat[]` | the default vocabulary |
98
+ | `className` | `string` | |
99
+ | `labels` | `Partial<SchemaEditorLabels>` | override every visible and accessible string |
100
+
101
+ ### Two behaviors that decide how you wire it
102
+
103
+ - **`editMode` is initial state, not a controlled prop.** It seeds the internal
104
+ flag once; changing it later has no effect. Drive edit mode from inside the
105
+ editor, or remount it with a `key` when you must force a mode.
106
+ - **`schema` *is* re-synced.** A new `schema` identity resets both the working
107
+ copy and the cancel baseline. Cancel restores that baseline and calls
108
+ `onChange` with the restored clone, so a controlled parent stays consistent.
109
+
110
+ `onSave` receives nothing — accumulate state from `onChange` and persist what
111
+ you already hold. `onSave` also returns the editor to read mode.
112
+
113
+ ### Type and format vocabulary
114
+
115
+ The type dropdown is built from `typeFormats`, a flat list of
116
+ `{ jsonType, format }` pairs; the option label is the format when there is one,
117
+ otherwise the JSON type. The container types `array` and `object` are always
118
+ appended.
119
+
120
+ The default vocabulary covers `string` (plain, `guid`, `date-time`, `date`,
121
+ `time`), `integer` (plain, `int16`, `int32`, `int64`), `number` (plain, `float`,
122
+ `double`), and `boolean`. Supply your own `typeFormats` to narrow or extend it.
123
+
124
+ **`typeFormats` is the only extension point.** There is no registry mapping a
125
+ schema type to a custom editor component — the cell renderers are a fixed
126
+ branch on `array` / `object` / everything else. You can change the vocabulary,
127
+ not the widget.
128
+
129
+ Changing a property's type has side effects worth knowing: switching to `array`
130
+ seeds `items` as a string and clears `format`; switching to `object` seeds an
131
+ empty `properties` and clears `format` and `items`; switching to anything else
132
+ clears both `items` and `properties`.
133
+
134
+ ### Nested navigation
135
+
136
+ Drilling into an object property or an array's item definition pushes a
137
+ breadcrumb segment. Array item definitions use the reserved path segment
138
+ `$items`, rendered in the breadcrumb as `[items]`. Nested navigation is
139
+ **click-driven only** — the breadcrumbs and rows are not keyboard-operable, so
140
+ do not document a keyboard path that does not exist.
141
+
142
+ ### Property-name validation
143
+
144
+ A property name must be non-empty, must match an identifier pattern (a letter
145
+ or underscore followed by letters, digits, or underscores), and must be unique
146
+ among its siblings. Save is disabled while any name is invalid.
147
+
148
+ ### Localization
149
+
150
+ `SchemaEditorLabels` has ten fields, five of them accessible names:
151
+ `edit`, `save`, `cancel`, `addProperty`, `actions`, `navigateBack`,
152
+ `emptyMessage`, `navigateToItemDefinition`, `navigateToProperties`,
153
+ `deleteProperty`. Pass `labels` with the ones you want to change — they merge
154
+ over the English defaults. Never rely on the built-in English strings in a
155
+ localized application.
156
+
157
+ ## `ObjectContentEditor`
158
+
159
+ ```tsx
160
+ import { ObjectContentEditor } from '@cratis/components/ObjectContentEditor';
161
+ ```
162
+
163
+ Renders an object's values against a schema, read-only by default.
164
+
165
+ ```tsx
166
+ const [value, setValue] = useState<Json>(storedObject);
167
+ const [hasErrors, setHasErrors] = useState(false);
168
+
169
+ <ObjectContentEditor
170
+ object={value}
171
+ schema={schema}
172
+ timestamp={occurred}
173
+ editMode
174
+ onChange={setValue}
175
+ onValidationChange={setHasErrors} />
176
+ ```
177
+
178
+ ### Props
179
+
180
+ | Prop | Type | Default |
181
+ | --- | --- | --- |
182
+ | `object` | `Json` | **required** |
183
+ | `schema` | `JsonSchema` | **required** |
184
+ | `timestamp` | `Date` | optional, displayed with the content |
185
+ | `editMode` | `boolean` | `false` |
186
+ | `onChange` | `(object: Json) => void` | receives the whole updated object |
187
+ | `onValidationChange` | `(hasErrors: boolean) => void` | fires only in edit mode |
188
+ | `className` | `string` | |
189
+
190
+ ### Editing limits — design around these
191
+
192
+ - **Only root-level properties are editable.** Array and object values render
193
+ "not yet supported" text in edit mode, and any nested navigation view is
194
+ read-only by construction.
195
+ - **In edit mode every field is treated as required**, regardless of the
196
+ schema's `required` list. The schema's `required` is consulted only in read
197
+ mode. If your object legitimately has optional values, either stay read-only
198
+ or gate saving on your own rules rather than on `onValidationChange`.
199
+ - `onValidationChange` never fires outside edit mode, so a read-only view will
200
+ never report errors.
201
+
202
+ ### Field rendering
203
+
204
+ The editor branches on the property's `type` and `format`: booleans render a
205
+ checkbox, numbers an integer-friendly numeric input, `string` with `date-time`
206
+ or `date` a date picker (emitting an ISO string, date-only for `date`), a long
207
+ string a multi-line text area, and everything else a text input.
208
+
209
+ Built-in format validation covers `email` and `uri`, plus numeric parseability.
210
+ Anything richer belongs in the caller.
211
+
212
+ ## Breadcrumb
213
+
214
+ `ObjectNavigationalBar` (`@cratis/components/ObjectNavigationalBar`) is the
215
+ shared breadcrumb both editors use. Standalone, it takes `navigationPath`,
216
+ `onNavigate`, and `backLabel` (which is both the tooltip and the accessible
217
+ name — localize it). It is click-only, like the editors' own breadcrumbs.
218
+
219
+ ## Styling
220
+
221
+ Both editors expose `className` only. Restyle their internals through a global
222
+ PrimeReact pass-through preset on the provider rather than per instance — see
223
+ the **cratis-components-styling** skill.
224
+
225
+ ## Verify
226
+
227
+ - Imports use the component subpath, not the root barrel.
228
+ - The schema passed in is the narrow subset — no `$ref` or `definitions` is
229
+ relied on for rendering.
230
+ - The parent holds the schema or object state and updates it from `onChange`;
231
+ `onSave` is treated as a signal, not a carrier of data.
232
+ - `editMode` on `SchemaEditor` is treated as initial state, not a controlled
233
+ prop.
234
+ - Nothing in the UI or the documentation promises a required-flag toggle,
235
+ nested object editing, or keyboard navigation in these editors.
236
+ - Every visible and accessible string is supplied through `labels` /
237
+ `backLabel` in a localized application.
238
+ - Lint and the TypeScript build pass.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: cratis-components-stepper-command-dialog
3
+ description: Build a multi-step wizard dialog for a single Cratis Arc command with StepperCommandDialog and StepperPanel from Cratis Components — named steps, per-step validation, linear navigation, vertical or horizontal orientation, and pre-populated edit wizards. Use when one command gathers information across several stages or a form has too many fields to show at once. Do not use for an ordinary single-page command dialog or for a page shell.
4
+ license: MIT
5
+ ---
6
+
7
+ # Cratis Components stepper command dialogs
8
+
9
+ `StepperCommandDialog` splits **one** command's form across named steps. The
10
+ user moves with Previous and Next; Submit appears on the last step once every
11
+ field across every step is valid.
12
+
13
+ ## Verified product sources
14
+
15
+ | Package | Version | Verified from |
16
+ | --- | --- | --- |
17
+ | `@cratis/components` | `3.0.0` | its package manifest and `CommandDialog` sources |
18
+ | `@cratis/arc.react` | `>=20.3.1 <23` | peer range declared by `@cratis/components@3.0.0` |
19
+ | `primereact` | `^11.0.0` | peer of `@cratis/components@3.0.0` |
20
+
21
+ ## Choose it over `CommandDialog` when
22
+
23
+ - the form has too many fields to show at once;
24
+ - the fields group into logical stages ("Contact → Details → Budget");
25
+ - guided linear input with per-step feedback is what the task deserves.
26
+
27
+ A four-field form is usually still an ordinary `CommandDialog`.
28
+
29
+ ## Step 1 — One command for the whole wizard
30
+
31
+ Every step contributes properties to the same command instance. Define the
32
+ command on the backend and run a Debug build so the TypeScript proxy exists
33
+ before importing it.
34
+
35
+ ## Step 2 — Build the dialog
36
+
37
+ ```tsx
38
+ import { StepperCommandDialog, StepperPanel } from '@cratis/components/CommandDialog';
39
+ import { InputTextField, NumberField, TextAreaField } from '@cratis/components/CommandForm';
40
+ import { DialogResult, useDialogContext } from '@cratis/arc.react/dialogs';
41
+ import { CreateProject } from '../api/Projects/CreateProject';
42
+
43
+ export const CreateProjectDialog = () => {
44
+ const { closeDialog } = useDialogContext();
45
+
46
+ return (
47
+ <StepperCommandDialog<CreateProject>
48
+ command={CreateProject}
49
+ title='Create new project'
50
+ okLabel='Create'
51
+ onSuccess={() => closeDialog(DialogResult.Ok)}
52
+ onCancel={() => closeDialog(DialogResult.Cancelled)}>
53
+ <StepperPanel header='Contact info'>
54
+ <InputTextField<CreateProject> value={c => c.email} title='Contact email' type='email' />
55
+ </StepperPanel>
56
+ <StepperPanel header='Project details'>
57
+ <InputTextField<CreateProject> value={c => c.name} title='Project name' />
58
+ <TextAreaField<CreateProject> value={c => c.description} title='Description' rows={4} />
59
+ </StepperPanel>
60
+ <StepperPanel header='Budget'>
61
+ <NumberField<CreateProject> value={c => c.budget} title='Budget' />
62
+ </StepperPanel>
63
+ </StepperCommandDialog>
64
+ );
65
+ };
66
+ ```
67
+
68
+ Rules:
69
+
70
+ - Every `StepperPanel` needs a `header` — it is the step label.
71
+ - All `CommandForm` fields inside any panel bind to the **same** command
72
+ instance through their `value` accessor.
73
+ - Each command property belongs on exactly one step.
74
+ - Next is disabled while the current step has validation errors.
75
+ - Submit appears on the last step only when every field across every step is
76
+ valid.
77
+ - `StepperCommandDialog` reads the dialog context when it is hosted by
78
+ `useDialog`, and works standalone when it is not.
79
+
80
+ ## Step 3 — Open it from the page
81
+
82
+ ```tsx
83
+ import { useDialog } from '@cratis/arc.react/dialogs';
84
+
85
+ const [CreateProjectWrapper, showCreateProject] = useDialog(CreateProjectDialog);
86
+
87
+ <MenuItem label='New project' icon={() => <i className='pi pi-plus' />} command={() => showCreateProject()} />
88
+ <CreateProjectWrapper />
89
+ ```
90
+
91
+ ## Validation timing
92
+
93
+ Pass `validateOnInit` to run validation on mount so a wizard opened with
94
+ pre-populated invalid values shows its errors immediately instead of after the
95
+ first keystroke. `validateOn` (`'blur' | 'change' | 'both'`) chooses when
96
+ subsequent validation runs.
97
+
98
+ ## Pre-populating an edit wizard
99
+
100
+ `initialValues` is the synchronous baseline and also the change-tracking
101
+ baseline — use it for values that must be present but are not user-entered.
102
+ `currentValues` is the reactive overlay for values that arrive late, such as
103
+ from a query.
104
+
105
+ ```tsx
106
+ <StepperCommandDialog
107
+ command={UpdateProject}
108
+ title='Update project'
109
+ initialValues={{ projectId: project.id }}
110
+ currentValues={{ name: project.name, description: project.description }}>
111
+ ```
112
+
113
+ Never seed a value required for validity in `onBeforeExecute` — validation runs
114
+ against the pre-transform values, so the Submit button would stay permanently
115
+ disabled.
116
+
117
+ ## Orientation and labels
118
+
119
+ ```tsx
120
+ <StepperCommandDialog
121
+ command={RegisterEmployee}
122
+ title='Register employee'
123
+ orientation='vertical'
124
+ okLabel='Register'
125
+ nextLabel='Continue'
126
+ previousLabel='Back'>
127
+ ```
128
+
129
+ ## Props
130
+
131
+ Dialog-level props:
132
+
133
+ | Prop | Type | Default |
134
+ | --- | --- | --- |
135
+ | `command` | the generated command class | **required** |
136
+ | `title` | `string` | **required** |
137
+ | `children` | `StepperPanel` elements | — |
138
+ | `visible` | `boolean` | `true` |
139
+ | `width` | `string` | `'600px'` |
140
+ | `okLabel` | `string` | `'Submit'` |
141
+ | `nextLabel` | `string` | `'Next'` |
142
+ | `previousLabel` | `string` | `'Previous'` |
143
+ | `showCancel` | `boolean` | `false` |
144
+ | `cancelLabel` | `string` | `'Cancel'` |
145
+ | `isValid` | `boolean` | extra validity gate on top of form validity |
146
+ | `onConfirm` / `onCancel` / `onClose` | close gates | — |
147
+ | `onBeforeExecute` | `(values) => values` | transformer; must return the values |
148
+ | `style` / `contentStyle` | `CSSProperties` | — |
149
+ | `resizable` | `boolean` | `false` — accepted but has no effect |
150
+
151
+ Stepper-level props (inherited from the stepper customization surface):
152
+
153
+ | Prop | Type | Default |
154
+ | --- | --- | --- |
155
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` |
156
+ | `headerPosition` | `'top' \| 'bottom'` | `'top'` |
157
+ | `linear` | `boolean` | `true` |
158
+ | `showNavigation` | `boolean` | `true` |
159
+ | `showSubmit` | `boolean` | `true` |
160
+ | `start` / `end` | `React.ReactNode` | extra content beside the step headers |
161
+ | `onChangeStep` | `(event: { index: number }) => void` | — |
162
+
163
+ Command-form props (`initialValues`, `currentValues`, `validateOn`,
164
+ `validateOnInit`, `onSuccess`, `onValidationFailure`, `onFailed`,
165
+ `autoServerValidate`, …) all apply as well.
166
+
167
+ ### Two pass-through targets
168
+
169
+ The inherited `pt`, `ptOptions`, and `unstyled` target the **inner stepper**.
170
+ Use `dialogPt`, `dialogPtOptions`, `dialogUnstyled`, and `dialogClassName` to
171
+ reach the **outer dialog**. Getting these the wrong way round is the usual cause
172
+ of a pass-through that appears to do nothing.
173
+
174
+ ## Dismissal while the command runs
175
+
176
+ The dialog withdraws its close control, Escape, and backdrop dismissal while the
177
+ command is executing, so a half-submitted wizard cannot be abandoned mid-flight.
178
+ Do not add your own Cancel button to the footer — set `showCancel` if the wizard
179
+ needs one.
180
+
181
+ ## Related components
182
+
183
+ `CommandStepper` (same subpath) is the stepper without the dialog chrome, for
184
+ embedding a wizard directly in a page. It takes the same `StepperPanel`
185
+ children.
186
+
187
+ ## Common mistakes
188
+
189
+ | Mistake | Fix |
190
+ | --- | --- |
191
+ | A hand-rolled Cancel button in the footer | Set `showCancel`, or rely on the header close control |
192
+ | One step per field | Group related fields; aim for two to five per step |
193
+ | The same property bound on two steps | Each property appears on exactly one step |
194
+ | A `StepperPanel` without `header` | `header` is the navigation label |
195
+ | Several panels wrapped in one fragment | A fragment counts as **one** step — give each step its own `StepperPanel` child |
196
+ | A raw PrimeReact control for a command value | Use a `CommandForm` field, or validation never re-runs |
197
+ | Seeding a required value in `onBeforeExecute` | Use `initialValues` |
198
+ | `pt` applied expecting it to reach the dialog | `pt` targets the stepper; use `dialogPt` |
199
+
200
+ ## Verify
201
+
202
+ - Imports come from `@cratis/components/CommandDialog` and
203
+ `@cratis/components/CommandForm`, not the root barrel.
204
+ - Every `StepperPanel` has a `header` and is a direct child.
205
+ - Every command property appears on exactly one step.
206
+ - Required values come from `initialValues`.
207
+ - `onBeforeExecute`, if present, returns the values.
208
+ - Pass-through props target the intended element.
209
+ - Lint and the TypeScript build pass.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -0,0 +1,221 @@
1
+ ---
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.
4
+ license: MIT
5
+ ---
6
+
7
+ # Styling Cratis Components
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
12
+ components rendering completely unstyled, which is the single most common
13
+ first-run problem.
14
+
15
+ ## Verified product sources
16
+
17
+ | Package | Version | Verified from |
18
+ | --- | --- | --- |
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` |
24
+
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.
29
+
30
+ ## Step 1 — What an app must do
31
+
32
+ Two things, or the components render unstyled:
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:
39
+
40
+ ```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
44
+ ```
45
+
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.
49
+
50
+ ## Step 2 — Pick one of four setups
51
+
52
+ | Setup | What you do | When |
53
+ | --- | --- | --- |
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>
85
+ ```
86
+
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
95
+
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.
99
+
100
+ ## Step 3 — Colors: use the token layer
101
+
102
+ 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:
112
+
113
+ | Group | Tokens |
114
+ | --- | --- |
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` |
122
+
123
+ Only hard-code a color that is intentionally theme-independent — a brand accent
124
+ dot, a traffic-light indicator.
125
+
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
+ ## Step 4 — Writing styles
133
+
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.
144
+ - 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.
194
+
195
+ ## Where Tailwind fits
196
+
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.
205
+
206
+ ## Verify
207
+
208
+ - PrimeReact and its `@primereact/*` peers are installed in the application, at
209
+ one version each.
210
+ - `CratisComponentsProvider` wraps the tree.
211
+ - `@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.
215
+ - 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.
218
+ - 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.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the project root for full license information.