src/dialog/dialog.stories.tsx (279 lines of code) (raw):

import {Component} from 'react'; import {useState} from 'storybook/preview-api'; import {Header, Content} from '../island/island'; import Button from '../button/button'; import Input from '../input/input'; import Group from '../group/group'; import Toggle from '../toggle/toggle'; import Panel from '../panel/panel'; import Popup from '../popup/popup'; import Dialog from './dialog'; import type {StoryFn} from '@storybook/react-webpack5'; export default { title: 'Components/Dialog', tags: ['!autodocs'], parameters: { notes: 'The Dialog component is a simple way to present content above an enclosing view.', screenshots: {captureSelector: '*[data-test~=ring-dialog]'}, a11y: {context: '#storybook-root,*[data-test~=ring-dialog]'}, }, }; interface Args { onAction(action: string): void; } export const basic: StoryFn<Args> = ({onAction}) => { class DialogDemo extends Component { state = { show: true, text: '', autoFocusEnabled: true, }; doAction = () => { onAction(`${this.state.text} performed`); this.setState({show: false}); }; cancelDialog = () => { this.setState({show: false}); }; render() { const {show, text, autoFocusEnabled} = this.state; return ( <div className='long-page'> <Group> <Button onClick={() => this.setState({show: true})}>Show dialog</Button> <Toggle checked={this.state.autoFocusEnabled} onChange={() => this.setState({autoFocusEnabled: !autoFocusEnabled})} > Autofocus </Toggle> </Group> <Dialog label='Dialog' show={show} onCloseAttempt={this.cancelDialog} trapFocus autoFocusFirst={autoFocusEnabled} showCloseButton > <Header>Dialog title</Header> <Content> <Input label='Enter action name' value={text} onChange={e => this.setState({text: e.target.value})} /> </Content> <Panel> <Button primary onClick={this.doAction}> OK </Button> <Button onClick={this.cancelDialog}>Cancel</Button> </Panel> </Dialog> </div> ); } } return <DialogDemo />; }; basic.storyName = 'basic'; basic.argTypes = {onAction: {}}; basic.parameters = { storyStyles: ` <style> .long-page { height: 200vh; } </style>`, }; export const withCloseButtonInside: StoryFn<Args> = ({onAction}) => { class DialogDemo extends Component { state = { show: true, text: '', }; doAction = () => { onAction(`${this.state.text} performed`); this.setState({show: false}); }; cancelDialog = () => { this.setState({show: false}); }; render() { const {show, text} = this.state; return ( <Dialog label='Dialog' show={show} onCloseAttempt={this.cancelDialog} trapFocus showCloseButton closeButtonInside > <Header>Dialog title</Header> <Content> <Input label='Enter action name' value={text} onChange={e => this.setState({text: e.target.value})} /> </Content> <Panel> <Button primary onClick={this.doAction}> OK </Button> <Button onClick={this.cancelDialog}>Cancel</Button> </Panel> </Dialog> ); } } return <DialogDemo />; }; withCloseButtonInside.storyName = 'with close button inside'; withCloseButtonInside.argTypes = {onAction: {}}; withCloseButtonInside.parameters = { screenshots: {skip: true}, }; export const native: StoryFn<Args> = ({onAction}) => { class DialogDemo extends Component { state = { show: true, text: '', modal: true, }; doAction = () => { onAction(`${this.state.text} performed`); this.setState({show: false}); }; cancelDialog = () => { this.setState({show: false}); }; render() { const {show, text, modal} = this.state; return ( <div className='long-page'> <Group> <Button onClick={() => this.setState({show: true})}>Show dialog</Button> <Toggle checked={modal} onChange={() => this.setState({modal: !modal})}> Modal </Toggle> </Group> <Dialog label='Dialog' show={show} onCloseAttempt={this.cancelDialog} native modal={modal} showCloseButton> <Header>Dialog title</Header> <Content> <Input label='Enter action name' value={text} onChange={e => this.setState({text: e.target.value})} /> </Content> <Panel> <Button primary onClick={this.doAction}> OK </Button> <Button onClick={this.cancelDialog}>Cancel</Button> </Panel> </Dialog> </div> ); } } return <DialogDemo />; }; native.storyName = 'native'; native.argTypes = {onAction: {}}; native.parameters = { storyStyles: ` <style> .long-page { height: 200vh; } </style>`, }; export const dense: StoryFn = () => ( <Dialog show dense> <Header>Dialog title</Header> <Content> <Input label='Enter action name' /> </Content> <Panel> <Button primary>OK</Button> <Button>Cancel</Button> </Panel> </Dialog> ); const lorem = `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.`; export const withScroll: StoryFn<Args> = ({onAction}) => { class DialogDemo extends Component { state = { show: true, }; doAction = () => { onAction('action performed'); this.setState({show: false}); }; cancelDialog = () => { this.setState({show: false}); }; render() { return ( <div> <div> <Button onClick={() => this.setState({show: true})}>Show dialog</Button> </div> <Dialog label='Dialog' show={this.state.show} onCloseAttempt={this.cancelDialog} trapFocus showCloseButton> <Header>Dialog title</Header> <Content tabIndex={0}> <div> <p>Dialog content (scrollable)</p> <p>{lorem}</p> <p>{lorem}</p> <p>{lorem}</p> <p>{lorem}</p> <p>{lorem}</p> <p>{lorem}</p> <p>{lorem}</p> </div> </Content> <Panel> <Button primary onClick={this.doAction}> OK </Button> <Button onClick={this.cancelDialog}>Cancel</Button> </Panel> </Dialog> </div> ); } } return <DialogDemo />; }; withScroll.storyName = 'with scroll'; withScroll.argTypes = {onAction: {}}; export const WithOverflowScrollOnHtml = () => { const [open, setOpen] = useState(false); return ( <div className='container'> <div>Scroll down</div> <Button className='button' onClick={() => setOpen(true)}> Show dialog </Button> <Dialog label='Dialog' show={open} onCloseAttempt={() => setOpen(false)}> <Header>Dialog title</Header> </Dialog> </div> ); }; WithOverflowScrollOnHtml.parameters = { storyStyles: ` <style> html { overflow-y: scroll; } html, body { height: 100%; } body { margin: 0 !important; } .container { height: 200vh; } .button { margin-top: 100vh; } </style> `, screenshots: { actions: [ {type: 'click', selector: '.button'}, {type: 'capture', selector: '*[data-test~=ring-dialog-container]'}, ], }, }; export const DialogInPopup: StoryFn = () => { const [showPopup, setShowPopup] = useState(true); const [showDialog, setShowDialog] = useState(false); return ( <Popup hidden={!showPopup} onCloseAttempt={() => setShowPopup(false)}> <Button onClick={() => setShowDialog(true)}>Show dialog</Button> <Dialog show={showDialog} onCloseAttempt={() => setShowDialog(false)}> <Header>Dialog title</Header> <Content> <Input label='Enter action name' /> </Content> <Panel> <Button primary>OK</Button> <Button>Cancel</Button> </Panel> </Dialog> </Popup> ); }; DialogInPopup.parameters = { screenshots: {skip: true}, }; export const NativeDialogInPopup: StoryFn = () => { const [showPopup, setShowPopup] = useState(true); const [showDialog, setShowDialog] = useState(false); return ( <Popup hidden={!showPopup} onCloseAttempt={() => setShowPopup(false)}> <Button onClick={() => setShowDialog(true)}>Show dialog</Button> <Dialog native show={showDialog} onCloseAttempt={() => setShowDialog(false)}> <Header>Dialog title</Header> <Content> <Input label='Enter action name' /> </Content> <Panel> <Button primary>OK</Button> <Button>Cancel</Button> </Panel> </Dialog> </Popup> ); }; NativeDialogInPopup.parameters = { screenshots: {skip: true}, };