Skip to content

Commit d481def

Browse files
authored
Merge pull request #17 from marklearst/pr/17-layout
feat(layout): refresh shell components
2 parents 9aeba25 + ba56a84 commit d481def

58 files changed

Lines changed: 1136 additions & 858 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 147 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,153 @@
1-
import type { Meta, StoryObj } from "@storybook/react";
1+
import type { ComponentProps } from 'react'
2+
import { useState } from 'react'
3+
import type { Meta, StoryObj } from '@storybook/react-vite'
24

3-
import React, { useState } from "react";
4-
import { getStoryDescription, hiddenArgControl } from "../../util/storybook-utils";
5-
import { Dialog } from "./dialog";
6-
import { Button } from "../button/button";
7-
import { TickIcon } from "../../icons";
8-
import { FormField } from "../form-field/form-field";
9-
import { Toggle } from "../toggle";
10-
import { Alert } from "../alert/alert";
5+
import {
6+
getStoryDescription,
7+
hiddenArgControl,
8+
} from '../../util/storybook-utils'
9+
import { Dialog } from './dialog'
10+
import { Button } from '../button/button'
11+
import { TickIcon } from '../../icons'
12+
import { FormField } from '../form-field/form-field'
13+
import { Toggle } from '../toggle'
14+
import { Alert } from '../alert/alert'
1115

12-
const noop = () => undefined;
16+
const noop = () => undefined
1317

14-
const SpanFooter = () => <span>test footer 🍭</span>;
15-
const IconFooters = ({ onClose }: Pick<React.ComponentProps<typeof Dialog>, "onClose">) => (
16-
<>
17-
<Button variant="secondary" onClick={() => onClose?.(false)}>
18-
Cancel
19-
</Button>
18+
const SpanFooter = () => <span>test footer 🍭</span>
19+
const IconFooters = ({
20+
onClose,
21+
}: Pick<ComponentProps<typeof Dialog>, 'onClose'>) => (
22+
<>
23+
<Button variant='secondary' onClick={() => onClose?.(false)}>
24+
Cancel
25+
</Button>
2026

21-
<Button variant="primary" LeftIcon={TickIcon} onClick={() => onClose?.(true)}>
22-
Confirm
23-
</Button>
24-
</>
25-
);
26-
const footerOptions = { undefined, SpanFooter: <SpanFooter />, buttons: <IconFooters /> };
27+
<Button
28+
variant='primary'
29+
LeftIcon={TickIcon}
30+
onClick={() => onClose?.(true)}
31+
>
32+
Confirm
33+
</Button>
34+
</>
35+
)
36+
const footerOptions = {
37+
undefined,
38+
SpanFooter: <SpanFooter />,
39+
buttons: <IconFooters />,
40+
}
2741
const footerArgs = {
28-
options: Object.keys(footerOptions),
29-
mapping: footerOptions,
30-
};
42+
options: Object.keys(footerOptions),
43+
mapping: footerOptions,
44+
}
3145

3246
const meta: Meta<typeof Dialog> = {
33-
title: "Dialog",
34-
component: Dialog,
35-
parameters: {
36-
...getStoryDescription("Modal showing on top of the screen"),
37-
inlineStories: false, // keep controls interactive
38-
},
39-
args: {
40-
title: "Dialog Title",
41-
children: "Dialog Description",
42-
isShown: false,
43-
footer: undefined,
44-
},
45-
argTypes: {
46-
isShown: hiddenArgControl,
47-
onClose: hiddenArgControl,
48-
footer: footerArgs,
49-
},
50-
render: ({ children, ...args }) => {
51-
// eslint-disable-next-line react-hooks/rules-of-hooks
52-
const [isShown, setIsShown] = useState(false);
53-
const toggleBtn = () => setIsShown((val) => !val);
47+
title: 'Dialog',
48+
component: Dialog,
49+
parameters: {
50+
...getStoryDescription('Modal showing on top of the screen'),
51+
inlineStories: false, // keep controls interactive
52+
},
53+
args: {
54+
title: 'Dialog Title',
55+
children: 'Dialog Description',
56+
isShown: false,
57+
footer: undefined,
58+
},
59+
argTypes: {
60+
isShown: hiddenArgControl,
61+
onClose: hiddenArgControl,
62+
footer: footerArgs,
63+
},
64+
render: ({ children, ...args }) => {
65+
// eslint-disable-next-line react-hooks/rules-of-hooks
66+
const [isShown, setIsShown] = useState(false)
67+
const toggleBtn = () => setIsShown((val) => !val)
5468

55-
return (
56-
<div className="body-font">
57-
<button
58-
type="button"
59-
onClick={toggleBtn}
60-
className="bg-neutral-100 px-4 py-2 shadow-sm"
61-
>
62-
show Modal
63-
</button>
69+
return (
70+
<div className='body-font'>
71+
<button
72+
type='button'
73+
onClick={toggleBtn}
74+
className='bg-neutral-100 px-4 py-2 shadow-sm'
75+
>
76+
show Modal
77+
</button>
6478

65-
<Dialog {...args} isShown={isShown} onClose={toggleBtn}>
66-
{children}
67-
</Dialog>
68-
</div>
69-
);
70-
},
71-
};
79+
<Dialog {...args} isShown={isShown} onClose={toggleBtn}>
80+
{children}
81+
</Dialog>
82+
</div>
83+
)
84+
},
85+
}
7286

73-
export default meta;
74-
type Story = StoryObj<typeof Dialog>;
87+
export default meta
88+
type Story = StoryObj<typeof Dialog>
7589

76-
export const Default: Story = {};
90+
export const Default: Story = {}
7791

7892
export const WithFooterButtons: Story = {
79-
argTypes: {
80-
footer: hiddenArgControl,
81-
},
82-
render: ({ children, ...args }) => {
83-
// eslint-disable-next-line react-hooks/rules-of-hooks
84-
const [isShown, setIsShown] = useState(false);
85-
const toggleBtn = () => setIsShown((val) => !val);
93+
argTypes: {
94+
footer: hiddenArgControl,
95+
},
96+
render: ({ children, ...args }) => {
97+
// eslint-disable-next-line react-hooks/rules-of-hooks
98+
const [isShown, setIsShown] = useState(false)
99+
const toggleBtn = () => setIsShown((val) => !val)
86100

87-
return (
88-
<div className="body-font">
89-
<button
90-
type="button"
91-
onClick={toggleBtn}
92-
className="bg-neutral-100 px-4 py-2 shadow-sm"
93-
>
94-
show Modal
95-
</button>
101+
return (
102+
<div className='body-font'>
103+
<button
104+
type='button'
105+
onClick={toggleBtn}
106+
className='bg-neutral-100 px-4 py-2 shadow-sm'
107+
>
108+
show Modal
109+
</button>
96110

97-
<Dialog
98-
{...args}
99-
footer={<IconFooters onClose={() => setIsShown(false)} />}
100-
isShown={isShown}
101-
onClose={toggleBtn}
102-
>
103-
{children}
104-
</Dialog>
105-
</div>
106-
);
107-
},
108-
};
111+
<Dialog
112+
{...args}
113+
footer={<IconFooters onClose={() => setIsShown(false)} />}
114+
isShown={isShown}
115+
onClose={toggleBtn}
116+
>
117+
{children}
118+
</Dialog>
119+
</div>
120+
)
121+
},
122+
}
109123

110124
export const WithLongContent: Story = {
111-
args: {
112-
children: (
113-
<>
114-
<Toggle.Switch checked ariaLabel="test" onChange={noop} />
115-
<p className="py-10">Paragraph Content</p>
116-
<FormField>
117-
<FormField.LabelGroup>
118-
<FormField.Label htmlFor="value">Label</FormField.Label>
119-
<FormField.Description id="value-description">
120-
Description
121-
</FormField.Description>
122-
</FormField.LabelGroup>
123-
<FormField.RadioInput id="value" value="value_1" onChange={noop}>
124-
<FormField.RadioInput.Option value="value_1">
125-
Value 1
126-
</FormField.RadioInput.Option>
127-
<FormField.RadioInput.Option value="value_2">
128-
Value 2
129-
</FormField.RadioInput.Option>
130-
<FormField.RadioInput.Option value="value_3" disabled>
131-
Value 3
132-
</FormField.RadioInput.Option>
133-
</FormField.RadioInput>
134-
</FormField>
135-
<p className="py-5">
136-
{`
125+
args: {
126+
children: (
127+
<>
128+
<Toggle.Switch checked ariaLabel='test' onChange={noop} />
129+
<p className='py-10'>Paragraph Content</p>
130+
<FormField>
131+
<FormField.LabelGroup>
132+
<FormField.Label htmlFor='value'>Label</FormField.Label>
133+
<FormField.Description id='value-description'>
134+
Description
135+
</FormField.Description>
136+
</FormField.LabelGroup>
137+
<FormField.RadioInput id='value' value='value_1' onChange={noop}>
138+
<FormField.RadioInput.Option value='value_1'>
139+
Value 1
140+
</FormField.RadioInput.Option>
141+
<FormField.RadioInput.Option value='value_2'>
142+
Value 2
143+
</FormField.RadioInput.Option>
144+
<FormField.RadioInput.Option value='value_3' disabled>
145+
Value 3
146+
</FormField.RadioInput.Option>
147+
</FormField.RadioInput>
148+
</FormField>
149+
<p className='py-5'>
150+
{`
137151
"Oh, hush, hush, my child!" said Van Helsing. "God does not purchase souls in
138152
this wise; and the Devil, though he may purchase, does not keep faith. But God
139153
is merciful and just, and knows your pain and your devotion to that dear Madam
@@ -145,10 +159,10 @@ export const WithLongContent: Story = {
145159
before he can hither come, be he never so quick. What we must hope for is that
146160
my Lord Arthur and Quincey arrive first."
147161
`}
148-
</p>
162+
</p>
149163

150-
<p className="py-10">
151-
{`
164+
<p className='py-10'>
165+
{`
152166
"He will be here before long now," said Van Helsing, who had been consulting his
153167
pocket-book. "Nota bene, in Madam's telegram he went south from Carfax, that
154168
means he went to cross the river, and he could only do so at slack of tide,
@@ -163,14 +177,14 @@ export const WithLongContent: Story = {
163177
hand as he spoke, for we all could hear a key softly inserted in the lock of the
164178
hall door.
165179
`}
166-
</p>
167-
<span>litipsum.com</span>
168-
<Alert title="Some important information" intent="info" />
169-
<Toggle.Switch checked={false} ariaLabel="test" onChange={noop} />
170-
</>
171-
),
172-
},
173-
argTypes: {
174-
children: hiddenArgControl,
175-
},
176-
};
180+
</p>
181+
<span>litipsum.com</span>
182+
<Alert title='Some important information' intent='info' />
183+
<Toggle.Switch checked={false} ariaLabel='test' onChange={noop} />
184+
</>
185+
),
186+
},
187+
argTypes: {
188+
children: hiddenArgControl,
189+
},
190+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import { fireEvent, render, screen } from '@testing-library/react'
3+
import { Dialog } from './dialog'
4+
5+
describe('Dialog', () => {
6+
it('renders content and triggers onClose from the close button', async () => {
7+
const onClose = vi.fn()
8+
const { container } = render(
9+
<Dialog isShown title='Confirm action' onClose={onClose}>
10+
Dialog content
11+
</Dialog>,
12+
)
13+
14+
expect(await screen.findByText('Confirm action')).toBeInTheDocument()
15+
expect(screen.getByText('Dialog content')).toBeInTheDocument()
16+
17+
const closeButton = await screen.findByRole('button')
18+
fireEvent.click(closeButton)
19+
20+
expect(onClose).toHaveBeenCalledWith(false)
21+
})
22+
})

0 commit comments

Comments
 (0)