Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
81 lines
3.6 KiB
JavaScript
81 lines
3.6 KiB
JavaScript
import React, {useState, useRef} from 'react';
|
|
import {createRoot} from 'react-dom/client';
|
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
|
|
window.observed = {caught: [], globalErrors: [], requests: [], dialogTransitions: []};
|
|
window.addEventListener('error', e => window.observed.globalErrors.push(e.message));
|
|
class Boundary extends React.Component {
|
|
state = {failed: false};
|
|
static getDerivedStateFromError() { return {failed: true}; }
|
|
componentDidCatch(error) { window.observed.caught.push({boundary: this.props.name, message: error.message}); }
|
|
render() {
|
|
if (this.state.failed) return this.props.brokenFallback
|
|
? <BrokenFallback /> : <p role="alert" data-testid={this.props.name}>Region unavailable</p>;
|
|
return this.props.children;
|
|
}
|
|
}
|
|
function BrokenFallback() { throw new Error('fallback fault'); }
|
|
function Panel() {
|
|
const [broken, setBroken] = useState(false);
|
|
const [request, setRequest] = useState('idle');
|
|
if (broken) throw new Error('render fault');
|
|
return <section data-testid="panel">
|
|
<button onClick={() => setBroken(true)}>Break render</button>
|
|
<button onClick={() => {throw new Error('event fault');}}>Break event</button>
|
|
<button onClick={async () => {
|
|
setRequest('pending');
|
|
try {
|
|
const r = await fetch('/failure');
|
|
window.observed.requests.push(r.status);
|
|
if (!r.ok) throw new Error('request rejected');
|
|
setRequest('accepted');
|
|
} catch {setRequest('request failed');}
|
|
}}>Fail request</button>
|
|
<p role="status">{request}</p>
|
|
</section>;
|
|
}
|
|
function FailureFixture() {
|
|
const [clicks, setClicks] = useState(0);
|
|
const brokenFallback = new URLSearchParams(location.search).has('brokenFallback');
|
|
return <main>
|
|
<button onClick={() => setClicks(clicks + 1)}>Sibling {clicks}</button>
|
|
<Boundary name="outer"><Boundary name="inner" brokenFallback={brokenFallback}>
|
|
<Panel />
|
|
</Boundary></Boundary>
|
|
</main>;
|
|
}
|
|
function Modal({children, title}) {
|
|
return <Dialog.Portal><Dialog.Overlay />
|
|
<Dialog.Content aria-describedby={undefined}>
|
|
<Dialog.Title>{title}</Dialog.Title>{children}
|
|
</Dialog.Content>
|
|
</Dialog.Portal>;
|
|
}
|
|
function FocusFixture() {
|
|
const [open, setOpen] = useState(false);
|
|
const [present, setPresent] = useState(true);
|
|
const next = useRef(null);
|
|
const explicit = new URLSearchParams(location.search).has('explicit');
|
|
return <main>
|
|
<button id="next" ref={next}>Next record</button>
|
|
<Dialog.Root open={open} onOpenChange={value => {window.observed.dialogTransitions.push({dialog: "outer", open: value}); setOpen(value);}}>
|
|
{present && <Dialog.Trigger id="invoker">Open task</Dialog.Trigger>}
|
|
<Dialog.Portal><Dialog.Overlay />
|
|
<Dialog.Content aria-describedby={undefined} onCloseAutoFocus={event => {
|
|
if (explicit && !present) {event.preventDefault(); next.current?.focus();}
|
|
}}>
|
|
<Dialog.Title>Record task</Dialog.Title>
|
|
<button id="remove" onClick={() => {setPresent(false); setOpen(false);}}>Remove invoking record</button>
|
|
<Dialog.Root onOpenChange={value => window.observed.dialogTransitions.push({dialog: "inner", open: value})}>
|
|
<Dialog.Trigger id="nested-invoker">Nested task</Dialog.Trigger>
|
|
<Modal title="Nested task"><Dialog.Close id="nested-close">Close nested</Dialog.Close></Modal>
|
|
</Dialog.Root>
|
|
<Dialog.Close id="close">Close task</Dialog.Close>
|
|
</Dialog.Content>
|
|
</Dialog.Portal>
|
|
</Dialog.Root>
|
|
</main>;
|
|
}
|
|
createRoot(document.getElementById('root')).render(
|
|
new URLSearchParams(location.search).get('mode') === 'focus' ? <FocusFixture /> : <FailureFixture />
|
|
);
|