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
82dc343
initlal version
ciampo Mar 26, 2026
cb2132a
ConfirmDialog: Fix Dialog API incompatibilities
ciampo Mar 26, 2026
fcc57a6
ConfirmDialog: Adapt to @wordpress/ui package conventions
ciampo Mar 26, 2026
c6518dd
ConfirmDialog: Add CHANGELOG entry
ciampo Mar 26, 2026
111b91e
Dialog: Remove ConfirmDialog story now covered by dedicated component
ciampo Mar 26, 2026
22a8d5e
ConfirmDialog: Tighten irreversible intent behavior
ciampo Mar 26, 2026
d799050
ConfirmDialog: Add `loading` prop for async confirm flows
ciampo Mar 26, 2026
7d35ea0
ConfirmDialog: Add CHANGELOG entries for enhancements
ciampo Mar 26, 2026
da122c4
ConfirmDialog: Move title prop from Root to Popup
ciampo Mar 26, 2026
5b01278
format css
ciampo Mar 26, 2026
db422a1
ConfirmDialog: Restore backdrop click dismissal for default intent
ciampo Mar 26, 2026
bfd4163
Dialog: Fix Action disabled/loading forwarding to Button
ciampo Mar 26, 2026
a9d9d3f
ConfirmDialog: Remove disabled workaround on confirm action
ciampo Mar 26, 2026
6f6dee4
Remove superflous CHANGELOG entries
ciampo Mar 26, 2026
65f9df7
Update CHANGELOG PR reference
ciampo Mar 26, 2026
e5f0c41
Allow Escape key to dismiss the irreversible variant, cleanup getInte…
ciampo Mar 27, 2026
803c7a6
Remove hardcoded domain from Storybook docs URL
ciampo Mar 27, 2026
4e628d9
CHANGELOG
ciampo Mar 27, 2026
ee3aae5
Try to fix async confirm workflow
ciampo Mar 27, 2026
5f8f0df
Better approach to async confirm work
ciampo Mar 27, 2026
d3f19bb
Add async flow unit test
ciampo Mar 27, 2026
2d5026b
ConfirmDialog: Clarify loading prop manual-close contract
ciampo Mar 27, 2026
700a817
Log "onConfirm" action
ciampo Mar 27, 2026
2d37d04
Refactor to use base ui's AlertDialog, rename to AlertDialog
ciampo Mar 27, 2026
3256925
format
ciampo Mar 27, 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
5 changes: 5 additions & 0 deletions packages/ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New Features

- Add `AlertDialog` primitive ([#76847](https://github.com/WordPress/gutenberg/pull/76847)).
- Add `InputControl` component ([#76653](https://github.com/WordPress/gutenberg/pull/76653)).
- `Dialog`: Expose `initialFocus` and `finalFocus` props on `Dialog.Popup` for custom focus management ([#76860](https://github.com/WordPress/gutenberg/pull/76860)).

Expand All @@ -12,6 +13,10 @@
- `Card`: Add `overflow: clip` to `Card.Root` to prevent child content from overflowing rounded corners ([#76678](https://github.com/WordPress/gutenberg/pull/76678)).
- `CollapsibleCard`: do not animate the focus ring when expanding/collapsing the card ([#76459](https://github.com/WordPress/gutenberg/pull/76459)).

### Enhancements

- `Dialog.Root`: expose `disablePointerDismissal` prop ([#76847](https://github.com/WordPress/gutenberg/pull/76847)).

### Internal

- `Tabs`: Add development-mode validation for Tab/Panel count matching ([#75170](https://github.com/WordPress/gutenberg/pull/75170)).
Expand Down
14 changes: 14 additions & 0 deletions packages/ui/src/alert-dialog/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext } from '@wordpress/element';
import type { RootProps } from './types';

type Intent = NonNullable< RootProps[ 'intent' ] >;

interface AlertDialogContextValue {
intent: Intent;
}

const AlertDialogContext = createContext< AlertDialogContextValue >( {
intent: 'default',
} );

export { AlertDialogContext };
3 changes: 3 additions & 0 deletions packages/ui/src/alert-dialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Root } from './root';
export { Trigger } from './trigger';
export { Popup } from './popup';
58 changes: 58 additions & 0 deletions packages/ui/src/alert-dialog/popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { forwardRef, useContext } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button } from '../button';
import * as Dialog from '../dialog';
import { AlertDialogContext } from './context';
import styles from './style.module.css';
import type { PopupProps } from './types';

const Popup = forwardRef< HTMLDivElement, PopupProps >(
function AlertDialogPopup(
{
title,
children,
onConfirm,
confirmButtonText = __( 'OK' ),
cancelButtonText = __( 'Cancel' ),
loading,
},
ref
) {
const { intent } = useContext( AlertDialogContext );

// When `loading` is provided, the consumer controls when the dialog
// closes (async flow). Use a plain Button so clicking confirm doesn't
// auto-close — the consumer sets `open={false}` after their operation.
const ConfirmButton = loading !== undefined ? Button : Dialog.Action;

return (
<Dialog.Popup ref={ ref }>
<Dialog.Header>
<Dialog.Title>{ title }</Dialog.Title>
</Dialog.Header>
{ children }
<Dialog.Footer>
<Dialog.Action
variant="minimal"
disabled={ loading || undefined }
>
{ cancelButtonText }
</Dialog.Action>
<ConfirmButton
className={
intent === 'irreversible'
? styles[ 'irreversible-action' ]
: undefined
}
onClick={ onConfirm }
loading={ loading }
>
{ confirmButtonText }
</ConfirmButton>
</Dialog.Footer>
</Dialog.Popup>
);
}
);

export { Popup };
48 changes: 48 additions & 0 deletions packages/ui/src/alert-dialog/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AlertDialog as _AlertDialog } from '@base-ui/react/alert-dialog';
import { useMemo } from '@wordpress/element';
import { AlertDialogContext } from './context';
import type { RootProps } from './types';

/**
* A dialog that requires a user response to proceed.
*
* Use `AlertDialog.Trigger` to render a button that opens the dialog.
* Use `AlertDialog.Popup` to render the dialog content.
* The `AlertDialog.Trigger` is optional — the dialog can also be controlled
* via `open` / `onOpenChange` props.
*
* ## Use cases
*
* - **Default intent**: Standard confirmation dialog for reversible actions.
* - **Irreversible intent**: Confirmation dialog for irreversible actions that
* cannot be undone. The confirm button uses error/danger coloring.
*
* For use cases outside the standard confirm/cancel pattern, use the lower-level
* `Dialog` component directly.
*
* See the [Destructive Actions guidelines](?path=/docs/design-system-patterns-destructive-actions--docs)
* for more details on when to use each pattern.
*/
function Root( {
intent = 'default',
children,
open,
onOpenChange,
defaultOpen,
}: RootProps ) {
const contextValue = useMemo( () => ( { intent } ), [ intent ] );

return (
<_AlertDialog.Root
open={ open }
onOpenChange={ onOpenChange }
defaultOpen={ defaultOpen }
>
<AlertDialogContext.Provider value={ contextValue }>
{ children }
</AlertDialogContext.Provider>
</_AlertDialog.Root>
);
}

export { Root };
Loading
Loading