@ceed/ads 1.38.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,6 +4,12 @@ export interface DialogFrameProps {
|
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
actions: React.ReactNode;
|
|
6
6
|
fullscreen?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* When provided, the dialog root renders as a `<form>` and this handler runs on submit.
|
|
9
|
+
* This enables native submit-on-Enter and lets a `type="submit"` button in `actions`
|
|
10
|
+
* submit the fields in the content area. When omitted, the root stays a `<div>`.
|
|
11
|
+
*/
|
|
12
|
+
onSubmit?: React.FormEventHandler<HTMLFormElement>;
|
|
7
13
|
}
|
|
8
14
|
declare const DialogFrame: React.ForwardRefExoticComponent<Omit<Omit<Pick<{
|
|
9
15
|
children?: React.ReactNode;
|
|
@@ -18,5 +24,5 @@ declare const DialogFrame: React.ForwardRefExoticComponent<Omit<Omit<Pick<{
|
|
|
18
24
|
variant?: import("@mui/types").OverridableStringUnion<import("@mui/joy").VariantProp, import("@mui/joy").ModalDialogPropsVariantOverrides> | undefined;
|
|
19
25
|
} & import("@mui/joy").ModalDialogSlotsAndSlotProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
20
26
|
ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject<HTMLDivElement> | null | undefined;
|
|
21
|
-
}, "children" | "layout" | "color" | "maxWidth" | "minWidth" | "variant" | "sx" | "size" | "invertedColors" | "orientation" | keyof import("@mui/joy").ModalDialogSlotsAndSlotProps> & import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme>, "style" | "title" | "children" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "layout" | "color" | "content" | "maxWidth" | "minWidth" | "translate" | "ref" | "slot" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "variant" | "size" | "invertedColors" | "orientation" | keyof import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme> | keyof import("@mui/joy").ModalDialogSlotsAndSlotProps> & import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme>, "title" | "children"> & DialogFrameProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
27
|
+
}, "children" | "layout" | "color" | "maxWidth" | "minWidth" | "variant" | "sx" | "size" | "invertedColors" | "orientation" | keyof import("@mui/joy").ModalDialogSlotsAndSlotProps> & import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme>, "style" | "title" | "children" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "layout" | "color" | "content" | "maxWidth" | "minWidth" | "translate" | "ref" | "slot" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "variant" | "size" | "invertedColors" | "orientation" | keyof import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme> | keyof import("@mui/joy").ModalDialogSlotsAndSlotProps> & import("@mui/system").MUIStyledCommonProps<import("@mui/joy").Theme>, "title" | "children" | "onSubmit"> & DialogFrameProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
22
28
|
export { DialogFrame };
|
|
@@ -204,41 +204,45 @@ function DeleteConfirmation({ itemName, open, onClose, onDelete }) {
|
|
|
204
204
|
|
|
205
205
|
## Form Dialog
|
|
206
206
|
|
|
207
|
+
> ✅ **Best Practice** ✅
|
|
208
|
+
>
|
|
209
|
+
> For any dialog that collects input and submits, **always pass `onSubmit`** to DialogFrame — never wire the confirm button with `onClick` alone. When `onSubmit` is provided, DialogFrame renders its root as a `<form>`, so the fields in the content area and the `type="submit"` button in `actions` belong to the same form. This is what enables **submit-on-Enter** (pressing Enter inside an input submits) plus native constraint validation (`required`, `type="email"`, etc.).
|
|
210
|
+
>
|
|
211
|
+
> An `onClick` handler on the action button cannot do this: the button lives in `actions`, a sibling of the content area, so without a wrapping `<form>` there is no implicit submit and Enter does nothing.
|
|
212
|
+
|
|
207
213
|
```tsx
|
|
208
214
|
function QuickAddDialog({ open, onClose, onSubmit }) {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
onSubmit({ name, email });
|
|
214
|
-
setName('');
|
|
215
|
-
setEmail('');
|
|
215
|
+
const handleSubmit = (event) => {
|
|
216
|
+
event.preventDefault();
|
|
217
|
+
const formData = new FormData(event.currentTarget);
|
|
218
|
+
onSubmit({ name: formData.get('name'), email: formData.get('email') });
|
|
216
219
|
onClose();
|
|
217
220
|
};
|
|
218
221
|
|
|
219
222
|
return (
|
|
220
223
|
<Modal open={open} onClose={onClose}>
|
|
224
|
+
{/* onSubmit makes the root a <form>; Enter in any field submits */}
|
|
221
225
|
<DialogFrame
|
|
222
226
|
title="Add New User"
|
|
227
|
+
onSubmit={handleSubmit}
|
|
223
228
|
actions={
|
|
224
229
|
<>
|
|
225
230
|
<Button variant="plain" color="neutral" onClick={onClose}>
|
|
226
231
|
Cancel
|
|
227
232
|
</Button>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
</Button>
|
|
233
|
+
{/* type="submit" ties this button to the DialogFrame form */}
|
|
234
|
+
<Button type="submit">Add User</Button>
|
|
231
235
|
</>
|
|
232
236
|
}
|
|
233
237
|
>
|
|
234
238
|
<Stack gap={2}>
|
|
235
239
|
<FormControl>
|
|
236
240
|
<FormLabel>Name</FormLabel>
|
|
237
|
-
<Input
|
|
241
|
+
<Input name="name" placeholder="Enter name" autoFocus required />
|
|
238
242
|
</FormControl>
|
|
239
243
|
<FormControl>
|
|
240
244
|
<FormLabel>Email</FormLabel>
|
|
241
|
-
<Input type="email"
|
|
245
|
+
<Input type="email" name="email" placeholder="Enter email" required />
|
|
242
246
|
</FormControl>
|
|
243
247
|
</Stack>
|
|
244
248
|
</DialogFrame>
|
|
@@ -398,13 +402,14 @@ function SelectOptionDialog({ open, onClose, options, onSelect }) {
|
|
|
398
402
|
|
|
399
403
|
### Key Props
|
|
400
404
|
|
|
401
|
-
| Prop | Type
|
|
402
|
-
| ------------ |
|
|
403
|
-
| `title` | `string`
|
|
404
|
-
| `children` | `ReactNode`
|
|
405
|
-
| `actions` | `ReactNode`
|
|
406
|
-
| `fullscreen` | `boolean`
|
|
407
|
-
| `
|
|
405
|
+
| Prop | Type | Default | Description |
|
|
406
|
+
| ------------ | --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
407
|
+
| `title` | `string` | - | Dialog title displayed in the header |
|
|
408
|
+
| `children` | `ReactNode` | - | Dialog body content |
|
|
409
|
+
| `actions` | `ReactNode` | - | Action buttons displayed in the footer |
|
|
410
|
+
| `fullscreen` | `boolean` | `false` | Enable fullscreen mode |
|
|
411
|
+
| `onSubmit` | `(event: FormEvent<HTMLFormElement>) => void` | - | When provided, the dialog root renders as a `<form>`, enabling submit-on-Enter and a `type="submit"` action button. Omit it and the root stays a `<div>` |
|
|
412
|
+
| `onKeyDown` | `(event: KeyboardEvent) => void` | - | Keyboard event handler |
|
|
408
413
|
|
|
409
414
|
### Structure
|
|
410
415
|
|
|
@@ -572,6 +577,25 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
572
577
|
/>
|
|
573
578
|
```
|
|
574
579
|
|
|
580
|
+
5. **Use `onSubmit` for input dialogs**: For any dialog that collects values and submits, pass `onSubmit` and mark the confirm button `type="submit"`. This renders the root as a `<form>`, giving you submit-on-Enter and native validation for free.
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
// ✅ Good: onSubmit + type="submit" — Enter submits, `required` is enforced
|
|
584
|
+
<DialogFrame
|
|
585
|
+
onSubmit={handleSubmit}
|
|
586
|
+
actions={
|
|
587
|
+
<>
|
|
588
|
+
<Button variant="plain" color="neutral" onClick={onClose}>
|
|
589
|
+
Cancel
|
|
590
|
+
</Button>
|
|
591
|
+
<Button type="submit">Save</Button>
|
|
592
|
+
</>
|
|
593
|
+
}
|
|
594
|
+
>
|
|
595
|
+
<Input name="email" required />
|
|
596
|
+
</DialogFrame>
|
|
597
|
+
```
|
|
598
|
+
|
|
575
599
|
### ❌ Don't
|
|
576
600
|
|
|
577
601
|
1. **Don't use for notifications**: Use Toast instead
|
|
@@ -607,6 +631,20 @@ showToast({ message: 'Item saved!' });
|
|
|
607
631
|
|
|
608
632
|
4. **Don't block critical workflows**: Important features should be accessible
|
|
609
633
|
|
|
634
|
+
5. **Don't submit input dialogs with `onClick` only**: Pressing Enter in a field won't submit, because the button in `actions` sits outside any form.
|
|
635
|
+
|
|
636
|
+
```tsx
|
|
637
|
+
// ❌ Bad: onClick-only — Enter in the input does nothing
|
|
638
|
+
<DialogFrame actions={<Button onClick={handleSubmit}>Save</Button>}>
|
|
639
|
+
<Input value={value} onChange={...} />
|
|
640
|
+
</DialogFrame>
|
|
641
|
+
|
|
642
|
+
// ✅ Good: onSubmit + type="submit" — Enter submits
|
|
643
|
+
<DialogFrame onSubmit={handleSubmit} actions={<Button type="submit">Save</Button>}>
|
|
644
|
+
<Input name="value" />
|
|
645
|
+
</DialogFrame>
|
|
646
|
+
```
|
|
647
|
+
|
|
610
648
|
## Performance Considerations
|
|
611
649
|
|
|
612
650
|
### Lazy Load Dialog Content
|