mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(skin): add error dialogs (#603)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
'use client';
|
||||
|
||||
import type { ForwardedRef } from 'react';
|
||||
import { forwardRef, useEffect, useRef, useState } from 'react';
|
||||
import type { UIComponentProps } from '../../utils/types';
|
||||
import { renderElement } from '../../utils/use-render';
|
||||
|
||||
type ErrorDialogState = { visible: boolean; onDismiss: () => void };
|
||||
|
||||
export interface ErrorDialogProps extends UIComponentProps<'div', ErrorDialogState> {
|
||||
'aria-labelledby': string;
|
||||
'aria-describedby'?: string;
|
||||
dismiss?: () => void;
|
||||
}
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
/**
|
||||
* Displays an error dialog when media playback encounters an error.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <ErrorDialog />
|
||||
*
|
||||
* <ErrorDialog
|
||||
* render={(props, state) => (
|
||||
* <div {...props}>Something went wrong</div>
|
||||
* )}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export const ErrorDialog = forwardRef(function ErrorDialog(
|
||||
componentProps: ErrorDialogProps,
|
||||
forwardedRef: ForwardedRef<HTMLDivElement>
|
||||
) {
|
||||
const { render, className, style, ...elementProps } = componentProps;
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [hasError, setHasError] = useState(false);
|
||||
|
||||
// FIXME: This is just debugging code
|
||||
useEffect(() => {
|
||||
const handle = setTimeout(() => {
|
||||
if (!DEBUG) return;
|
||||
setHasError(true);
|
||||
}, 2000);
|
||||
|
||||
return () => clearTimeout(handle);
|
||||
}, []);
|
||||
|
||||
// Focus the dialog when it becomes visible to ensure it's announced by screen readers.
|
||||
// Wait a frame for the accessibility tree to update with the dialog before focusing.
|
||||
useEffect(() => {
|
||||
if (!hasError) return;
|
||||
requestAnimationFrame(() => {
|
||||
dialogRef.current?.focus();
|
||||
});
|
||||
}, [hasError]);
|
||||
|
||||
return renderElement(
|
||||
'div',
|
||||
{ render, className, style },
|
||||
{
|
||||
state: {
|
||||
visible: hasError,
|
||||
onDismiss: () => setHasError(false),
|
||||
},
|
||||
ref: [forwardedRef, dialogRef],
|
||||
props: [
|
||||
{
|
||||
role: 'alertdialog',
|
||||
tabIndex: -1,
|
||||
},
|
||||
elementProps,
|
||||
],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export namespace ErrorDialog {
|
||||
export type Props = ErrorDialogProps;
|
||||
export type State = ErrorDialogState;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './error-dialog';
|
||||
Reference in New Issue
Block a user