Skip to content

Commit a8a6b18

Browse files
Add checkboxes stories to show controlled checked change via state
1 parent 00ff629 commit a8a6b18

1 file changed

Lines changed: 154 additions & 1 deletion

File tree

‎stories/Form Elements/Checkboxes.stories.tsx‎

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type Meta, type StoryObj } from '@storybook/react-vite';
2-
import { type ChangeEvent, useEffect, useRef, useState } from 'react';
2+
import { type ChangeEvent, Fragment, type RefObject, useEffect, useRef, useState } from 'react';
33

44
import { SummaryList } from '#components/content-presentation/summary-list/index.js';
55
import { Checkboxes } from '#components/form-elements/checkboxes/index.js';
@@ -235,6 +235,55 @@ export const WithValues: Story = {
235235
),
236236
};
237237

238+
export const WithValueStateControlled: Story = {
239+
name: 'Checkboxes with pre-checked values state, controlled',
240+
parameters: {
241+
chromatic: {
242+
disableSnapshot: true,
243+
},
244+
},
245+
render: function WithValueStateControlledRender(args) {
246+
const [values, setValues] = useState<Set<string>>(new Set(['email', 'text']));
247+
248+
const handleChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
249+
const updated = new Set(values);
250+
251+
if (target.checked) {
252+
updated.add(target.value);
253+
} else {
254+
updated.delete(target.value);
255+
}
256+
257+
setValues(updated);
258+
};
259+
260+
return (
261+
<>
262+
<Checkboxes {...args}>
263+
<Checkboxes.Item value="email" checked={values?.has('email')} onChange={handleChange}>
264+
Email
265+
</Checkboxes.Item>
266+
<Checkboxes.Item value="phone" checked={values?.has('phone')} onChange={handleChange}>
267+
Phone
268+
</Checkboxes.Item>
269+
<Checkboxes.Item value="text" checked={values?.has('text')} onChange={handleChange}>
270+
Text message
271+
</Checkboxes.Item>
272+
</Checkboxes>
273+
274+
<SummaryList>
275+
<SummaryList.Row>
276+
<SummaryList.Key>Values</SummaryList.Key>
277+
<SummaryList.Value>
278+
<samp>{values.size ? [...values].join(', ') : 'None'}</samp>
279+
</SummaryList.Value>
280+
</SummaryList.Row>
281+
</SummaryList>
282+
</>
283+
);
284+
},
285+
};
286+
238287
export const WithConditionalContent: Story = {
239288
name: 'Checkboxes with conditional content',
240289
args: {
@@ -284,6 +333,110 @@ export const WithConditionalContentValues: Story = {
284333
),
285334
};
286335

336+
export const WithConditionalContentValuesStateControlled: Story = {
337+
name: 'Checkboxes with conditional content and pre-checked values state, controlled',
338+
args: {
339+
name: 'with-conditional-content-values-state-controlled',
340+
},
341+
parameters: {
342+
chromatic: {
343+
disableSnapshot: true,
344+
},
345+
},
346+
render: function WithConditionalContentValuesStateControlledRender(args) {
347+
const [values, setValues] = useState<Set<string>>(new Set(['email', 'text']));
348+
const [inputs, setInputs] = useState<Map<string, string>>(
349+
new Map([
350+
['contact-by-email', 'karen.francis@example.com'],
351+
['contact-by-text', '07700 900362'],
352+
]),
353+
);
354+
355+
const handleChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
356+
const updated = new Set(values);
357+
358+
if (target.checked) {
359+
updated.add(target.value);
360+
} else {
361+
updated.delete(target.value);
362+
}
363+
364+
setValues(updated);
365+
};
366+
367+
const handleInput = ({ target }: ChangeEvent<HTMLInputElement>) => {
368+
const updated = new Map(inputs);
369+
370+
updated.set(target.name, target.value);
371+
setInputs(updated);
372+
};
373+
374+
return (
375+
<>
376+
<Checkboxes {...args}>
377+
<Checkboxes.Item
378+
value="email"
379+
conditional={
380+
<ExampleEmail value={inputs?.get('contact-by-email')} onChange={handleInput} />
381+
}
382+
checked={values?.has('email')}
383+
onChange={handleChange}
384+
>
385+
Email
386+
</Checkboxes.Item>
387+
<Checkboxes.Item
388+
value="phone"
389+
conditional={
390+
<ExamplePhoneNumber value={inputs?.get('contact-by-phone')} onChange={handleInput} />
391+
}
392+
checked={values?.has('phone')}
393+
onChange={handleChange}
394+
>
395+
Phone
396+
</Checkboxes.Item>
397+
<Checkboxes.Item
398+
value="text"
399+
conditional={
400+
<ExampleMobilePhoneNumber
401+
value={inputs?.get('contact-by-text')}
402+
onChange={handleInput}
403+
/>
404+
}
405+
checked={values?.has('text')}
406+
onChange={handleChange}
407+
>
408+
Text message
409+
</Checkboxes.Item>
410+
</Checkboxes>
411+
412+
<SummaryList>
413+
<SummaryList.Row>
414+
<SummaryList.Key>Values</SummaryList.Key>
415+
<SummaryList.Value>
416+
<samp>{values.size ? [...values].join(', ') : 'None'}</samp>
417+
</SummaryList.Value>
418+
</SummaryList.Row>
419+
<SummaryList.Row>
420+
<SummaryList.Key>Inputs</SummaryList.Key>
421+
<SummaryList.Value>
422+
{inputs.size ? (
423+
[...inputs.entries()].map(([key, value]) => (
424+
<Fragment key={key}>
425+
<samp>{value}</samp>
426+
<br />
427+
</Fragment>
428+
))
429+
) : (
430+
<samp>None</samp>
431+
)}
432+
</SummaryList.Value>
433+
</SummaryList.Row>
434+
</SummaryList>
435+
</>
436+
);
437+
},
438+
};
439+
287440
export const WithConditionalContentError: Story = {
288441
name: 'Checkboxes with conditional content, error message',
289442
args: {

0 commit comments

Comments
 (0)