@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.
- package/README.md +43 -0
- package/package.json +24 -0
- package/skills/cratis-application-react-specifications/LICENSE +2 -0
- package/skills/cratis-application-react-specifications/SKILL.md +192 -0
- package/skills/cratis-application-slice-specifications/LICENSE +2 -0
- package/skills/cratis-application-slice-specifications/SKILL.md +222 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/LICENSE +2 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +233 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +140 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +112 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +102 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +85 -0
- package/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +87 -0
- package/skills/cratis-arc-command/LICENSE +2 -0
- package/skills/cratis-arc-command/SKILL.md +286 -0
- package/skills/cratis-arc-command/references/command-result.md +111 -0
- package/skills/cratis-arc-command/references/handler-shapes.md +135 -0
- package/skills/cratis-arc-command/references/proxy-generation.md +87 -0
- package/skills/cratis-arc-command/references/read-model-injection.md +97 -0
- package/skills/cratis-arc-command-execution/LICENSE +2 -0
- package/skills/cratis-arc-command-execution/SKILL.md +148 -0
- package/skills/cratis-arc-command-validation/LICENSE +2 -0
- package/skills/cratis-arc-command-validation/SKILL.md +230 -0
- package/skills/cratis-arc-ef-core-migration/LICENSE +2 -0
- package/skills/cratis-arc-ef-core-migration/SKILL.md +231 -0
- package/skills/cratis-arc-observable-query-http/LICENSE +2 -0
- package/skills/cratis-arc-observable-query-http/SKILL.md +157 -0
- package/skills/cratis-arc-query-paging/LICENSE +2 -0
- package/skills/cratis-arc-query-paging/SKILL.md +173 -0
- package/skills/cratis-arc-react-page/LICENSE +2 -0
- package/skills/cratis-arc-react-page/SKILL.md +291 -0
- package/skills/cratis-arc-react-page/references/data-page.md +125 -0
- package/skills/cratis-arc-react-page/references/data-tables.md +136 -0
- package/skills/cratis-arc-react-page/references/dialogs.md +238 -0
- package/skills/cratis-arc-react-page/references/mvvm.md +150 -0
- package/skills/cratis-arc-react-page/references/queries-and-commands.md +200 -0
- package/skills/cratis-chronicle-cli-operations/LICENSE +2 -0
- package/skills/cratis-chronicle-cli-operations/SKILL.md +199 -0
- package/skills/cratis-chronicle-client-dotnet/LICENSE +2 -0
- package/skills/cratis-chronicle-client-dotnet/SKILL.md +433 -0
- package/skills/cratis-chronicle-client-elixir/LICENSE +2 -0
- package/skills/cratis-chronicle-client-elixir/SKILL.md +429 -0
- package/skills/cratis-chronicle-client-kotlin/LICENSE +2 -0
- package/skills/cratis-chronicle-client-kotlin/SKILL.md +498 -0
- package/skills/cratis-chronicle-client-typescript/LICENSE +2 -0
- package/skills/cratis-chronicle-client-typescript/SKILL.md +396 -0
- package/skills/cratis-chronicle-compliance/LICENSE +2 -0
- package/skills/cratis-chronicle-compliance/SKILL.md +246 -0
- package/skills/cratis-chronicle-event-constraints/LICENSE +2 -0
- package/skills/cratis-chronicle-event-constraints/SKILL.md +227 -0
- package/skills/cratis-chronicle-event-modeling/LICENSE +2 -0
- package/skills/cratis-chronicle-event-modeling/SKILL.md +157 -0
- package/skills/cratis-chronicle-event-specifications/LICENSE +2 -0
- package/skills/cratis-chronicle-event-specifications/SKILL.md +200 -0
- package/skills/cratis-chronicle-event-type-migration/LICENSE +2 -0
- package/skills/cratis-chronicle-event-type-migration/SKILL.md +235 -0
- package/skills/cratis-chronicle-mcp-inspection/LICENSE +2 -0
- package/skills/cratis-chronicle-mcp-inspection/SKILL.md +79 -0
- package/skills/cratis-chronicle-mcp-inspection/references/blocked-tools.md +12 -0
- package/skills/cratis-chronicle-mcp-inspection/references/observational-tools.md +8 -0
- package/skills/cratis-chronicle-multi-tenancy/LICENSE +2 -0
- package/skills/cratis-chronicle-multi-tenancy/SKILL.md +198 -0
- package/skills/cratis-chronicle-projection/LICENSE +2 -0
- package/skills/cratis-chronicle-projection/SKILL.md +162 -0
- package/skills/cratis-chronicle-projection/references/fluent-builder.md +126 -0
- package/skills/cratis-chronicle-projection/references/model-bound-attributes.md +118 -0
- package/skills/cratis-chronicle-reactor/LICENSE +2 -0
- package/skills/cratis-chronicle-reactor/SKILL.md +344 -0
- package/skills/cratis-chronicle-read-model/LICENSE +2 -0
- package/skills/cratis-chronicle-read-model/SKILL.md +193 -0
- package/skills/cratis-chronicle-read-model/references/queries.md +142 -0
- package/skills/cratis-chronicle-read-model-specifications/LICENSE +2 -0
- package/skills/cratis-chronicle-read-model-specifications/SKILL.md +176 -0
- package/skills/cratis-chronicle-reducer/LICENSE +2 -0
- package/skills/cratis-chronicle-reducer/SKILL.md +173 -0
- package/skills/cratis-chronicle-web-workbench/LICENSE +2 -0
- package/skills/cratis-chronicle-web-workbench/SKILL.md +177 -0
- package/skills/cratis-cli-terminal-workbench/LICENSE +2 -0
- package/skills/cratis-cli-terminal-workbench/SKILL.md +156 -0
- package/skills/cratis-code-review/LICENSE +2 -0
- package/skills/cratis-code-review/SKILL.md +177 -0
- package/skills/cratis-components-accessibility/LICENSE +2 -0
- package/skills/cratis-components-accessibility/SKILL.md +176 -0
- package/skills/cratis-components-schema-editor/LICENSE +2 -0
- package/skills/cratis-components-schema-editor/SKILL.md +238 -0
- package/skills/cratis-components-stepper-command-dialog/LICENSE +2 -0
- package/skills/cratis-components-stepper-command-dialog/SKILL.md +209 -0
- package/skills/cratis-components-styling/LICENSE +2 -0
- package/skills/cratis-components-styling/SKILL.md +221 -0
- package/skills/cratis-components-toolbar/LICENSE +2 -0
- package/skills/cratis-components-toolbar/SKILL.md +259 -0
- package/skills/cratis-documentation-writing/LICENSE +2 -0
- package/skills/cratis-documentation-writing/SKILL.md +121 -0
- package/skills/cratis-event-model-diagram/LICENSE +2 -0
- package/skills/cratis-event-model-diagram/SKILL.md +142 -0
- package/skills/cratis-fundamentals-concept/LICENSE +2 -0
- package/skills/cratis-fundamentals-concept/SKILL.md +198 -0
- package/skills/cratis-fundamentals-type-discovery/LICENSE +2 -0
- package/skills/cratis-fundamentals-type-discovery/SKILL.md +152 -0
- package/skills/cratis-governed-release-methodology/LICENSE +2 -0
- package/skills/cratis-governed-release-methodology/SKILL.md +297 -0
- package/skills/cratis-lens-browser-extension/LICENSE +2 -0
- package/skills/cratis-lens-browser-extension/SKILL.md +239 -0
- package/skills/cratis-performance-review/LICENSE +2 -0
- package/skills/cratis-performance-review/SKILL.md +139 -0
- package/skills/cratis-screenplay-model-authoring/LICENSE +2 -0
- package/skills/cratis-screenplay-model-authoring/SKILL.md +231 -0
- package/skills/cratis-security-review/LICENSE +2 -0
- package/skills/cratis-security-review/SKILL.md +141 -0
- package/skills/cratis-specification-by-example/LICENSE +2 -0
- package/skills/cratis-specification-by-example/SKILL.md +188 -0
- package/skills/cratis-specifications-csharp/LICENSE +2 -0
- package/skills/cratis-specifications-csharp/SKILL.md +230 -0
- package/skills/cratis-specifications-csharp/references/application-scenarios.md +191 -0
- package/skills/cratis-specifications-csharp/references/csharp-patterns.md +142 -0
- package/skills/cratis-specifications-csharp/references/integration-specs.md +126 -0
- package/skills/cratis-specifications-typescript/LICENSE +2 -0
- package/skills/cratis-specifications-typescript/SKILL.md +202 -0
- package/skills/cratis-specifications-typescript/references/typescript-patterns.md +168 -0
- package/skills/cratis-stage-rendering-and-sandbox/LICENSE +2 -0
- package/skills/cratis-stage-rendering-and-sandbox/SKILL.md +230 -0
- package/skills/cratis-studio-mcp-safety-guidance/LICENSE +2 -0
- package/skills/cratis-studio-mcp-safety-guidance/SKILL.md +69 -0
- package/skills/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +12 -0
- 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,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,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.
|