Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
789c3b0
Add --cratis-* CSS variable token layer
woksin May 28, 2026
48131fe
Migrate internal styles from PrimeReact theme vars to --cratis-* tokens
woksin May 28, 2026
d028ffc
Add CratisComponentsProvider with merge contract and spec
woksin May 28, 2026
0fa9245
Replace hard-coded PrimeReact / PrimeFlex class hooks and accept clas…
woksin May 28, 2026
197769a
Forward pt / ptOptions / unstyled / className on Dialog wrappers
woksin May 28, 2026
48b7ec4
Forward pt / ptOptions / unstyled / className on DataPage and DataTables
woksin May 28, 2026
082e7cf
Forward pt / ptOptions / unstyled / className on every CommandForm field
woksin May 28, 2026
e1e2f93
Add PrimeReact-style JSDoc on remaining public components
woksin May 28, 2026
d54261a
Restructure package.json and re-export Provider from the root entry
woksin May 28, 2026
aaa2dda
Rewrite README into a comprehensive styling guide with three paths
woksin May 28, 2026
69d0440
Add multi-path styling toolbar to Storybook
woksin May 28, 2026
17d7de6
Clean up workspace dependencies
woksin May 28, 2026
8d0d155
Correct Path B framing: PrimeReact theme + palette override, not toke…
woksin May 28, 2026
8323ae7
Add Styling section to the DocFX documentation
woksin May 28, 2026
a16adda
Add migration guide for upgrading from earlier @cratis/components rel…
woksin May 28, 2026
53ff5fe
Expand component-level JSDoc with Arc integration and unique-feature …
woksin May 29, 2026
47d1413
Enhance documentation and improve component styling for better clarit…
woksin May 29, 2026
0891e18
Merge remote-tracking branch 'origin/main' into fix/unstyled-improvem…
Copilot May 29, 2026
68d5f87
Refine documentation for styling options and improve clarity across m…
woksin May 29, 2026
c3b18ec
Merge branch 'fix/unstyled-improvements' of github.com:Cratis/Compone…
woksin May 29, 2026
dd4a17f
Type DataPage pass-through props with row type instead of any
woksin May 29, 2026
0673490
Reattach Dialog JSDoc to its declaration
woksin May 29, 2026
bf3a5db
Extract repeated field error style in ObjectContentEditor
woksin May 29, 2026
99db7e3
Resolve --cratis-* tokens v11-first with v10 fallback
woksin May 29, 2026
e736989
Document PrimeReact 10/11 token compatibility in styling guides
woksin May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions Documentation/Common/cratis-components-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# CratisComponentsProvider

Single setup point for Cratis Components. Wraps PrimeReact's `PrimeReactProvider` so the package can layer Cratis-wide defaults on top of PrimeReact's pass-through and unstyled mechanisms while still letting the consumer take complete control.

## Purpose

- Hosts the PrimeReact `pt` / `unstyled` / `ptOptions` / `inputStyle` / `ripple` / `appendTo` / `zIndex` / `locale` configuration for every Cratis wrapper below it in the tree.
- Deep-merges Cratis-wide defaults with the consumer's value, so future Cratis defaults can land without breaking consumer overrides.
- Re-exported from the package root so the recommended setup is one import:

```ts
import { CratisComponentsProvider } from '@cratis/components';
```

## Basic usage

Mount once at the root of your tree:

```tsx
import '@cratis/components/styles';
import { CratisComponentsProvider } from '@cratis/components';

export const App = () => (
<CratisComponentsProvider>
<YourApp />
</CratisComponentsProvider>
);
```

## Configuring `pt` / `unstyled` globally

The `value` prop accepts the full PrimeReact `APIOptions` shape. The most commonly used members are `unstyled`, `pt`, `ptOptions`, `inputStyle`, `ripple`, and `appendTo`:

```tsx
import { CratisComponentsProvider } from '@cratis/components';
import { globalPt } from './pt-preset';

export const App = () => (
<CratisComponentsProvider value={{ unstyled: true, pt: globalPt }}>
<YourApp />
</CratisComponentsProvider>
);
```

The `value` is deep-merged with the Cratis defaults (currently empty) so consumer settings always win. Pass a stable reference (a module-level constant or a `useMemo` result) to avoid unnecessary re-renders.

## Props

### `value`

`Partial<APIOptions>` — Cratis-wide and PrimeReact pass-through configuration. Merged on top of the library's defaults and made available to every Cratis component below in the tree.

The most useful members:

| Member | Purpose |
|---|---|
| `unstyled` | When `true`, disables every PrimeReact base style. Combine with `pt` (or per-component CSS / Tailwind) to fully restyle. |
| `pt` | Per-component pass-through configuration. Keys are PrimeReact component names (`button`, `dialog`, `inputtext`, …); values are slot configuration objects. |
| `ptOptions` | Controls merge vs. replace behavior for `pt`. Default is `{ mergeSections: true }` which merges per-instance `pt` with the global preset. |
| `inputStyle` | `'outlined'` or `'filled'` — switches the default input rendering across the whole app. |
| `ripple` | Enables PrimeReact's ripple animation on supported components. |
| `appendTo` | Where overlays mount (`document.body`, `'self'`, or a DOM ref). The Cratis `Dropdown` defaults to `document.body` independently of this setting. |
| `zIndex` | Per-overlay-type z-index baseline (`{ modal: 1100, overlay: 1000, … }`). |
| `locale` | PrimeReact locale string. |

The full type is re-exported as `CratisComponentsConfig`.

### `children`

`React.ReactNode` — your application tree.

## Using `PrimeReactProvider` directly

`CratisComponentsProvider` is optional. If you'd rather mount PrimeReact's own provider directly, that works too — every Cratis wrapper reads the same context:

```tsx
import { PrimeReactProvider } from 'primereact/api';

export const App = () => (
<PrimeReactProvider value={{ unstyled: true, pt: globalPt }}>
<YourApp />
</PrimeReactProvider>
);
```

The Cratis provider exists to give Cratis one place to layer in defaults later without breaking consumers, and to keep the setup discoverable from a single import path.

## Pure helpers (testing / library extension)

The merge logic is exported so the contract can be verified without rendering React:

```ts
import { mergeCratisComponentsConfig, cratisDefaults } from '@cratis/components';

const merged = mergeCratisComponentsConfig({ unstyled: true, pt: myPt });
// → { ...cratisDefaults, unstyled: true, pt: myPt }
```

| Export | Description |
|---|---|
| `CratisComponentsProvider` | The React component. |
| `CratisComponentsProviderProps` | Props type. |
| `CratisComponentsConfig` | Alias for `Partial<APIOptions>`. |
| `cratisDefaults` | The Cratis-wide defaults that ship today (currently `{}`). |
| `mergeCratisComponentsConfig` | Pure deep-merge helper used inside the provider. |

## See also

- [Styling Overview](../Styling/index.md) — the supported styling options and where the provider fits
- [Pass-through cheat sheet](../Styling/pass-through.md) — what `pt` reaches in each Cratis wrapper
- [Use fully unstyled mode](../Styling/unstyled.md) — full `pt` preset walk-through
198 changes: 82 additions & 116 deletions Documentation/Common/form-element.md
Original file line number Diff line number Diff line change
@@ -1,165 +1,131 @@
# FormElement

Wrapper component for form inputs with label and validation display.
Lightweight wrapper that places an icon addon to the left of a form input, styled with the `--cratis-*` token layer. Use it to give input fields a leading icon without pulling in PrimeReact's `InputGroup` chrome.

## Purpose

FormElement provides consistent styling and structure for form input fields with labels and validation messages.
FormElement is a structural primitive — it lays out an icon addon and a child input side by side, with rounded-on-the-left chrome around the addon. It does **not** render labels, required indicators, or validation messages — those concerns live on the underlying input itself or on the surrounding command form.

## Key Features

- Label positioning
- Validation error display
- Required field indication
- Consistent spacing
- Integration with form validation
- Icon addon styled from `--cratis-*` tokens (background, border, radius).
- Independent of PrimeReact's `p-inputgroup` / `p-inputgroup-addon` classes — works the same with or without a PrimeReact theme loaded.
- Accepts any React node as the icon (PrimeIcons class, `<svg>`, third-party icon component, …).

## Props

| Prop | Type | Description |
|---|---|---|
| `icon` | `React.ReactNode` | Icon node displayed inside the leading addon. Can be any React node — a PrimeIcons `<i className="pi pi-…" />`, an `<svg>`, or a `react-icons` component. |
| `children` | `React.ReactNode` | The form input rendered to the right of the icon addon (typically an `InputText`, `Dropdown`, etc.). |

## Basic Usage

```typescript
```tsx
import { FormElement } from '@cratis/components';
import { InputText } from 'primereact/inputtext';

function MyForm() {
return (
<FormElement label="Name" required={true} error="Name is required">
<FormElement icon={<i className="pi pi-user" />}>
<InputText value={name} onChange={(e) => setName(e.target.value)} />
</FormElement>
);
}
```

## Props

- `label`: Label text for the field
- `required`: Show required indicator (default: false)
- `error`: Validation error message to display
- `children`: The form input component

## Examples

### Text Input
### Email field with envelope icon

```typescript
<FormElement label="Email" required>
<InputText
```tsx
<FormElement icon={<i className="pi pi-envelope" />}>
<InputText
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
</FormElement>
```

### With Validation Error

```typescript
<FormElement
label="Password"
required
error={passwordError}
>
<InputText
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</FormElement>
```
### Search field with react-icons

### Dropdown
```tsx
import { FaMagnifyingGlass } from 'react-icons/fa6';

```typescript
<FormElement label="Country" required>
<Dropdown
value={country}
options={countries}
onChange={(e) => setCountry(e.value)}
<FormElement icon={<FaMagnifyingGlass />}>
<InputText
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search…"
/>
</FormElement>
```

### Checkbox
### Dropdown with category icon

```typescript
<FormElement label="Agree to Terms">
<Checkbox
checked={agreed}
onChange={(e) => setAgreed(e.checked)}
```tsx
import { FaLayerGroup } from 'react-icons/fa6';

<FormElement icon={<FaLayerGroup />}>
<Dropdown
value={category}
options={categories}
onChange={(e) => setCategory(e.value)}
optionLabel="name"
optionValue="id"
/>
</FormElement>
```

### Text Area
## Styling

```typescript
<FormElement label="Description">
<InputTextarea
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={5}
/>
</FormElement>
```
The addon's background, border, and radius are driven by the [`--cratis-*` token layer](../Styling/cratis-tokens.md):

## Complete Form Example
| Token | Surface |
|---|---|
| `--cratis-surface-100` | Addon background. |
| `--cratis-surface-border` | Addon border. |
| `--cratis-text-color-secondary` | Icon color. |
| `--cratis-border-radius` | Rounded-on-the-left corner radius. |

```typescript
function UserForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
role: null
});
const [errors, setErrors] = useState({});
Override the tokens to retint the addon without forking the component:

return (
<form onSubmit={handleSubmit}>
<FormElement
label="Full Name"
required
error={errors.name}
>
<InputText
value={formData.name}
onChange={(e) => handleChange('name', e.target.value)}
/>
</FormElement>

<FormElement
label="Email Address"
required
error={errors.email}
>
<InputText
type="email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
/>
</FormElement>

<FormElement
label="Role"
required
error={errors.role}
>
<Dropdown
value={formData.role}
options={roleOptions}
onChange={(e) => handleChange('role', e.value)}
/>
</FormElement>

<Button type="submit" label="Save" />
</form>
);
```css
:root {
--cratis-surface-100: #1e293b;
--cratis-surface-border: #334155;
--cratis-border-radius: 10px;
}
```

For per-instance restyling, wrap the FormElement with your own class and target it in CSS:

```css
.brand-form-element .cratis-form-element__addon {
background: var(--brand-accent);
color: var(--brand-on-accent);
}
```

## Best Practices
```tsx
<div className="brand-form-element">
<FormElement icon={<i className="pi pi-shield" />}>
<InputText … />
</FormElement>
</div>
```

For full styling control under `unstyled` mode, the addon classes are stable: `cratis-form-element` on the row and `cratis-form-element__addon` on the leading slot.

## When to use FormElement vs CommandForm fields

- Use **`FormElement`** for ad-hoc forms outside of a `CommandForm`, when you want the icon-addon visual on top of any input you control.
- Use **CommandForm fields** (`InputTextField`, `NumberField`, `DropdownField`, …) inside a `CommandForm` or `CommandDialog` — they bind to a command property, surface validation state, and render the appropriate input type.

## See Also

1. Always use FormElement for consistent form layouts
2. Show required indicators on mandatory fields
3. Display validation errors clearly
4. Keep labels concise
5. Group related fields together
6. Use appropriate input types for data
- [Styling Overview](../Styling/index.md) — the supported styling options and where FormElement fits
- [Cratis token reference](../Styling/cratis-tokens.md) — every token and the surfaces it tints
- [CommandForm Field Types](../CommandForm/index.md) — command-bound field wrappers
15 changes: 9 additions & 6 deletions Documentation/Common/index.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# Common Components

The Common module provides reusable UI components that serve as building blocks for applications.
The Common module provides reusable UI components and the styling setup primitive that serve as building blocks for applications.

## Components

- **Icon / IconDisplay**: Unified icon type that accepts a PrimeIcons CSS class string or any React node
- **Page**: Layout component for consistent page structures
- **FormElement**: Wrapper for form inputs with labels and validation
- **ErrorBoundary**: Error handling for React component trees
- **CratisComponentsProvider**: Single setup point for Cratis Components — wraps PrimeReact's `PrimeReactProvider` and hosts the `pt`, `unstyled`, locale, and other global configuration.
- **Icon / IconDisplay**: Unified icon type that accepts a PrimeIcons CSS class string or any React node.
- **Page**: Layout primitive for consistent page structures.
- **FormElement**: Lightweight wrapper that places an icon addon to the left of a form input.
- **ErrorBoundary**: Error handling for React component trees.

## See Also

- [CratisComponentsProvider](cratis-components-provider.md) — global setup, `pt` / `unstyled` configuration
- [Icon](icon.md) - Icon type and IconDisplay component
- [Page](page.md) - Page layout component
- [FormElement](form-element.md) - Form field wrapper
- [FormElement](form-element.md) - Form field icon-addon wrapper
- [ErrorBoundary](error-boundary.md) - Error boundary component
- [Styling Overview](../Styling/index.md) — the supported styling options and how Common fits in
2 changes: 2 additions & 0 deletions Documentation/Common/toc.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
- name: Overview
href: index.md
- name: CratisComponentsProvider
href: cratis-components-provider.md
- name: Icon
href: icon.md
- name: Page
Expand Down
Loading
Loading