Refresh Soma form import docs

active-uix
dev 5 months ago
parent 96edd41545
commit 959ad3b1f9

@ -17,9 +17,7 @@ Three things make an `AlertDialog` different from a plain `Dialog`:
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title>Delete account?</AlertDialog.Title>
<AlertDialog.Description>
This is permanent and cannot be undone.
</AlertDialog.Description>
<AlertDialog.Description>This is permanent and cannot be undone.</AlertDialog.Description>
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
<AlertDialog.Action onclick={deleteAccount}>Delete</AlertDialog.Action>
</AlertDialog.Content>
@ -32,37 +30,37 @@ By convention, place `Cancel` before `Action` in DOM order: the focus scope land
## Parts
| Part | Element | Origin | Description |
| ------------- | ---------- | ------------ | --------------------------------------------------------------------------- |
| `Provider` | none | AlertDialog | Root context. Forces `variant='alertdialog'` + `modal=true` on Dialog. |
| `Trigger` | `<button>` | Dialog | Opens the dialog on click. |
| `Content` | `<div>` | Dialog | Dialog container. Focus trap, scroll lock, dismissal layers integrated. |
| `Overlay` | `<div>` | Dialog | Backdrop. Click-outside does NOT close (forced by modal=true + alertdialog). |
| `Title` | `<div>` | Dialog | Dialog heading. Linked via `aria-labelledby`. |
| `Description` | `<div>` | Dialog | Supporting text. Linked via `aria-describedby`. |
| `Action` | `<button>` | AlertDialog | Primary / destructive confirmation. Closes the dialog on click. |
| `Cancel` | `<button>` | AlertDialog | Safe escape button. Closes the dialog on click. |
| Part | Element | Origin | Description |
| ------------- | ---------- | ----------- | ---------------------------------------------------------------------------- |
| `Provider` | none | AlertDialog | Root context. Forces `variant='alertdialog'` + `modal=true` on Dialog. |
| `Trigger` | `<button>` | Dialog | Opens the dialog on click. |
| `Content` | `<div>` | Dialog | Dialog container. Focus trap, scroll lock, dismissal layers integrated. |
| `Overlay` | `<div>` | Dialog | Backdrop. Click-outside does NOT close (forced by modal=true + alertdialog). |
| `Title` | `<div>` | Dialog | Dialog heading. Linked via `aria-labelledby`. |
| `Description` | `<div>` | Dialog | Supporting text. Linked via `aria-describedby`. |
| `Action` | `<button>` | AlertDialog | Primary / destructive confirmation. Closes the dialog on click. |
| `Cancel` | `<button>` | AlertDialog | Safe escape button. Closes the dialog on click. |
## Props
### `Provider`
| Prop | Type | Default | Description |
| ---------------------- | ----------------------------- | ------- | ---------------------------------------------------------- |
| `id` | `string` | auto | DOM id for the root. |
| `open` | `boolean` | `false` | Bindable open state. |
| `onOpenChange` | `(v: boolean) => void` | — | Called when open state changes. |
| `onOpenChangeComplete` | `(v: boolean) => void` | — | Called after the open/close animation settles. |
| `disabled` | `boolean` | `false` | Disables the trigger (the dialog stays closed). |
| Prop | Type | Default | Description |
| ---------------------- | ---------------------- | ------- | ----------------------------------------------- |
| `id` | `string` | auto | DOM id for the root. |
| `open` | `boolean` | `false` | Bindable open state. |
| `onOpenChange` | `(v: boolean) => void` | — | Called when open state changes. |
| `onOpenChangeComplete` | `(v: boolean) => void` | — | Called after the open/close animation settles. |
| `disabled` | `boolean` | `false` | Disables the trigger (the dialog stays closed). |
### `Action` / `Cancel`
Both accept every `<button>` attribute plus:
| Prop | Type | Default | Description |
| ------------ | ---------- | ----------------------- | --------------------------------------------------- |
| `id` | `string` | auto | DOM id. |
| `aria-label` | `string` | `"Confirm"` / `"Cancel"` | Accessible name. Overrides the translated default. |
| Prop | Type | Default | Description |
| ------------ | -------- | ------------------------ | -------------------------------------------------- |
| `id` | `string` | auto | DOM id. |
| `aria-label` | `string` | `"Confirm"` / `"Cancel"` | Accessible name. Overrides the translated default. |
`Trigger`, `Content`, `Overlay`, `Title`, `Description` are re-exported from `Dialog` — see [Dialog's props](../dialog/README.md) for the complete list. Of particular interest:
@ -71,49 +69,49 @@ Both accept every `<button>` attribute plus:
## ARIA
| Part | Attribute | Value |
| ------- | ------------------- | ------------------------------------------- |
| Trigger | `aria-haspopup` | `dialog` |
| Trigger | `aria-expanded` | `true` \| `false` |
| Trigger | `aria-controls` | ID of Content |
| Content | `role` | `alertdialog` |
| Content | `aria-modal` | `true` |
| Content | `aria-labelledby` | ID of Title |
| Content | `aria-describedby` | ID of Description |
| Overlay | `aria-hidden` | `true` |
| Title | `role` | `heading` |
| Title | `aria-level` | Number (default `2`) |
| Action | `aria-label` | Translated `'Confirm'` (override via prop) |
| Cancel | `aria-label` | Translated `'Cancel'` (override via prop) |
| Part | Attribute | Value |
| ------- | ------------------ | ------------------------------------------ |
| Trigger | `aria-haspopup` | `dialog` |
| Trigger | `aria-expanded` | `true` \| `false` |
| Trigger | `aria-controls` | ID of Content |
| Content | `role` | `alertdialog` |
| Content | `aria-modal` | `true` |
| Content | `aria-labelledby` | ID of Title |
| Content | `aria-describedby` | ID of Description |
| Overlay | `aria-hidden` | `true` |
| Title | `role` | `heading` |
| Title | `aria-level` | Number (default `2`) |
| Action | `aria-label` | Translated `'Confirm'` (override via prop) |
| Cancel | `aria-label` | Translated `'Cancel'` (override via prop) |
## Data Attributes
| Part | Attribute | Values |
| -------- | ---------------------------- | ------------------------------------------------------ |
| Trigger | `data-dialog-trigger` | Always present |
| Trigger | `data-state` | `open` \| `closed` |
| Content | `data-dialog-content` | Always present |
| Content | `data-state` | `open` \| `closed` |
| Content | `data-nested` | Present when nested |
| Content | `data-nested-open` | Present when a child dialog is open |
| Content | `data-starting-style` | Present during the open animation (one frame) |
| Content | `data-ending-style` | Present during the close animation |
| Overlay | `data-dialog-overlay` | Always present |
| Overlay | `data-state` | `open` \| `closed` |
| Action | `data-alert-dialog-action` | Always present |
| Cancel | `data-alert-dialog-cancel` | Always present |
| Part | Attribute | Values |
| ------- | -------------------------- | --------------------------------------------- |
| Trigger | `data-dialog-trigger` | Always present |
| Trigger | `data-state` | `open` \| `closed` |
| Content | `data-dialog-content` | Always present |
| Content | `data-state` | `open` \| `closed` |
| Content | `data-nested` | Present when nested |
| Content | `data-nested-open` | Present when a child dialog is open |
| Content | `data-starting-style` | Present during the open animation (one frame) |
| Content | `data-ending-style` | Present during the close animation |
| Overlay | `data-dialog-overlay` | Always present |
| Overlay | `data-state` | `open` \| `closed` |
| Action | `data-alert-dialog-action` | Always present |
| Cancel | `data-alert-dialog-cancel` | Always present |
Because `AlertDialog` composes `Dialog`, the Trigger / Content / Overlay / Title / Description emit the `data-dialog-*` attributes inherited from that component. The two AlertDialog-specific parts (`Action`, `Cancel`) emit their own `data-alert-dialog-*` attributes so themes can style the primary vs secondary buttons independently.
## Keyboard
| Key | Action |
| ----------- | -------------------------------------------------------------------------------------- |
| Key | Action |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
| `Escape` | Closes (acts as Cancel). Default `escapeKeydownBehavior='close'`. Pass `'ignore'` to force explicit Action/Cancel. |
| `Tab` | Cycle focus within the dialog (trapped). |
| `Shift+Tab` | Cycle focus backwards. |
| `Enter` | Fires `onclick` on the focused button. |
| `Space` | Fires `onclick` on the focused button. |
| `Tab` | Cycle focus within the dialog (trapped). |
| `Shift+Tab` | Cycle focus backwards. |
| `Enter` | Fires `onclick` on the focused button. |
| `Space` | Fires `onclick` on the focused button. |
Focus lands on the first focusable child when the dialog opens (`Cancel` by DOM order convention). Focus returns to the trigger on close.
@ -121,28 +119,28 @@ Focus lands on the first focusable child when the dialog opens (`Cancel` by DOM
Default button labels resolve through the UIX lang system. The component catalog is owned by `morfo.translations` under `components.alert-dialog`.
| Key | English | Spanish |
| -------- | --------- | ------------ |
| `action` | `Confirm` | `Confirmar` |
| `cancel` | `Cancel` | `Cancelar` |
| Key | English | Spanish |
| -------- | --------- | ----------- |
| `action` | `Confirm` | `Confirmar` |
| `cancel` | `Cancel` | `Cancelar` |
Consumers override per-instance via the `aria-label` prop on `Action` / `Cancel`, or the visible label via `children`.
## Comparison
| Feature | Soma | Radix | Ark UI | bits-ui |
| ---------------------------------------------- | :--: | :---: | :----: | :-----: |
| `role="alertdialog"` emitted | ✅ | ✅ | ✅ | ✅ |
| Always modal | ✅ | ✅ | ✅ | ✅ |
| `Action` + `Cancel` as first-class parts | ✅ | ✅ | ✅ | ✅ |
| Click-outside disabled | ✅ | ✅ | ✅ | ✅ |
| Escape closes by default | ✅ | ✅ | ✅ | ✅ |
| Translated default button labels | ✅ | ❌ | ⚠️² | ❌ |
| Nested alert dialogs | ✅ | ✅ | ✅ | ✅ |
| Portal-agnostic (consumer picks) | ✅ | ✅ | ✅ | ✅ |
| `data-*` attribute contract | ✅ | ✅ | ✅ | ✅ |
| Shared anatomy with plain Dialog | ✅ | ❌ | ✅ | ✅ |
| Built-in Form integration (confirm on submit) | ✅³ | ❌ | ❌ | ❌ |
| Feature | Soma | Radix | Ark UI | bits-ui |
| --------------------------------------------- | :--: | :---: | :----: | :-----: |
| `role="alertdialog"` emitted | ✅ | ✅ | ✅ | ✅ |
| Always modal | ✅ | ✅ | ✅ | ✅ |
| `Action` + `Cancel` as first-class parts | ✅ | ✅ | ✅ | ✅ |
| Click-outside disabled | ✅ | ✅ | ✅ | ✅ |
| Escape closes by default | ✅ | ✅ | ✅ | ✅ |
| Translated default button labels | ✅ | ❌ | ⚠️² | ❌ |
| Nested alert dialogs | ✅ | ✅ | ✅ | ✅ |
| Portal-agnostic (consumer picks) | ✅ | ✅ | ✅ | ✅ |
| `data-*` attribute contract | ✅ | ✅ | ✅ | ✅ |
| Shared anatomy with plain Dialog | ✅ | ❌ | ✅ | ✅ |
| Built-in Form integration (confirm on submit) | ✅³ | ❌ | ❌ | ❌ |
² Ark has a machine-level translator seam but no built-in English/Spanish strings.
³ Demonstrated on the test page: `onValidSubmit` returns a Promise gated on a confirmation dialog.
@ -167,9 +165,7 @@ Consumers override per-instance via the `aria-label` prop on `Action` / `Cancel`
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title>Delete account?</AlertDialog.Title>
<AlertDialog.Description>
All your data will be permanently removed.
</AlertDialog.Description>
<AlertDialog.Description>All your data will be permanently removed.</AlertDialog.Description>
<AlertDialog.Cancel>Keep it</AlertDialog.Cancel>
<AlertDialog.Action onclick={deleteAccount}>Delete</AlertDialog.Action>
</AlertDialog.Content>
@ -179,9 +175,7 @@ Consumers override per-instance via the `aria-label` prop on `Action` / `Cancel`
### Force explicit Action/Cancel (Escape ignored)
```svelte
<AlertDialog.Content escapeKeydownBehavior="ignore">
…
</AlertDialog.Content>
<AlertDialog.Content escapeKeydownBehavior="ignore">…</AlertDialog.Content>
```
### Gating a form submission
@ -189,7 +183,7 @@ Consumers override per-instance via the `aria-label` prop on `Action` / `Cancel`
```svelte
<script lang="ts">
import { AlertDialog, Form, Field } from '$soma/components';
import { createForm } from '$soma/components/form';
import { createForm } from '$libs/forms';
let confirmOpen = $state(false);
let resolve: ((ok: boolean) => void) | null = null;
@ -208,14 +202,17 @@ Consumers override per-instance via the `aria-label` prop on `Action` / `Cancel`
<Form.Provider {form}>…<Form.Submit>Delete</Form.Submit></Form.Provider>
<AlertDialog.Provider bind:open={confirmOpen}
onOpenChange={(v) => !v && resolve?.(false)}
>
<AlertDialog.Provider bind:open={confirmOpen} onOpenChange={(v) => !v && resolve?.(false)}>
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title>Really?</AlertDialog.Title>
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
<AlertDialog.Action onclick={() => { resolve?.(true); confirmOpen = false; }}>
<AlertDialog.Action
onclick={() => {
resolve?.(true);
confirmOpen = false;
}}
>
Confirm
</AlertDialog.Action>
</AlertDialog.Content>

Loading…
Cancel
Save

Powered by TurnKey Linux.