@arbor-education/design-system.components 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gather/skills/write-stories/SKILL.md +207 -271
- package/.storybook/preview.ts +5 -0
- package/CHANGELOG.md +17 -0
- package/README.md +8 -0
- package/component-library.md +144 -13
- package/dist/components/articleCard/ArticleCard.stories.d.ts +137 -11
- package/dist/components/articleCard/ArticleCard.stories.d.ts.map +1 -1
- package/dist/components/articleCard/ArticleCard.stories.js +358 -91
- package/dist/components/articleCard/ArticleCard.stories.js.map +1 -1
- package/dist/components/avatar/Avatar.stories.d.ts +6 -6
- package/dist/components/avatar/Avatar.stories.d.ts.map +1 -1
- package/dist/components/avatar/Avatar.stories.js +393 -49
- package/dist/components/avatar/Avatar.stories.js.map +1 -1
- package/dist/components/avatarGroup/AvatarGroup.stories.d.ts +9 -7
- package/dist/components/avatarGroup/AvatarGroup.stories.d.ts.map +1 -1
- package/dist/components/avatarGroup/AvatarGroup.stories.js +688 -65
- package/dist/components/avatarGroup/AvatarGroup.stories.js.map +1 -1
- package/dist/components/banner/Banner.stories.d.ts.map +1 -1
- package/dist/components/banner/Banner.stories.js +7 -3
- package/dist/components/banner/Banner.stories.js.map +1 -1
- package/dist/components/card/Card.stories.d.ts +105 -4
- package/dist/components/card/Card.stories.d.ts.map +1 -1
- package/dist/components/card/Card.stories.js +336 -18
- package/dist/components/card/Card.stories.js.map +1 -1
- package/dist/components/combobox/Combobox.stories.d.ts +134 -21
- package/dist/components/combobox/Combobox.stories.d.ts.map +1 -1
- package/dist/components/combobox/Combobox.stories.js +676 -175
- package/dist/components/combobox/Combobox.stories.js.map +1 -1
- package/dist/components/datePicker/DatePicker.stories.d.ts +119 -27
- package/dist/components/datePicker/DatePicker.stories.d.ts.map +1 -1
- package/dist/components/datePicker/DatePicker.stories.js +575 -47
- package/dist/components/datePicker/DatePicker.stories.js.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +155 -39
- package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts.map +1 -1
- package/dist/components/dateTimePicker/DateTimePicker.stories.js +674 -103
- package/dist/components/dateTimePicker/DateTimePicker.stories.js.map +1 -1
- package/dist/components/editableText/EditableText.stories.d.ts +53 -12
- package/dist/components/editableText/EditableText.stories.d.ts.map +1 -1
- package/dist/components/editableText/EditableText.stories.js +401 -64
- package/dist/components/editableText/EditableText.stories.js.map +1 -1
- package/dist/components/formField/FormField.d.ts +4 -0
- package/dist/components/formField/FormField.d.ts.map +1 -1
- package/dist/components/formField/FormField.js +2 -1
- package/dist/components/formField/FormField.js.map +1 -1
- package/dist/components/formField/FormField.test.js +5 -0
- package/dist/components/formField/FormField.test.js.map +1 -1
- package/dist/components/formField/fieldset/Fieldset.stories.d.ts +56 -4
- package/dist/components/formField/fieldset/Fieldset.stories.d.ts.map +1 -1
- package/dist/components/formField/fieldset/Fieldset.stories.js +534 -28
- package/dist/components/formField/fieldset/Fieldset.stories.js.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +3 -1
- package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.js +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.js.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts +95 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js +386 -9
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +6 -2
- package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonGroup.js.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +61 -49
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts +188 -166
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js +821 -160
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js.map +1 -1
- package/dist/components/formField/inputs/time/TimeInput.stories.d.ts +176 -22
- package/dist/components/formField/inputs/time/TimeInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/time/TimeInput.stories.js +851 -92
- package/dist/components/formField/inputs/time/TimeInput.stories.js.map +1 -1
- package/dist/components/formField/label/Label.stories.d.ts +54 -5
- package/dist/components/formField/label/Label.stories.d.ts.map +1 -1
- package/dist/components/formField/label/Label.stories.js +238 -4
- package/dist/components/formField/label/Label.stories.js.map +1 -1
- package/dist/components/icoText/IcoText.stories.d.ts +32 -6
- package/dist/components/icoText/IcoText.stories.d.ts.map +1 -1
- package/dist/components/icoText/IcoText.stories.js +309 -14
- package/dist/components/icoText/IcoText.stories.js.map +1 -1
- package/dist/components/kpiCard/KPICard.stories.d.ts +100 -2
- package/dist/components/kpiCard/KPICard.stories.d.ts.map +1 -1
- package/dist/components/kpiCard/KPICard.stories.js +354 -10
- package/dist/components/kpiCard/KPICard.stories.js.map +1 -1
- package/dist/components/kvpList/KVPList.stories.d.ts +57 -4
- package/dist/components/kvpList/KVPList.stories.d.ts.map +1 -1
- package/dist/components/kvpList/KVPList.stories.js +403 -10
- package/dist/components/kvpList/KVPList.stories.js.map +1 -1
- package/dist/components/modal/Modal.stories.d.ts +113 -9
- package/dist/components/modal/Modal.stories.d.ts.map +1 -1
- package/dist/components/modal/Modal.stories.js +633 -13
- package/dist/components/modal/Modal.stories.js.map +1 -1
- package/dist/components/modal/modalManager/ModalManager.stories.d.ts +34 -10
- package/dist/components/modal/modalManager/ModalManager.stories.d.ts.map +1 -1
- package/dist/components/modal/modalManager/ModalManager.stories.js +463 -85
- package/dist/components/modal/modalManager/ModalManager.stories.js.map +1 -1
- package/dist/components/pill/Pill.d.ts.map +1 -1
- package/dist/components/pill/Pill.js +1 -1
- package/dist/components/pill/Pill.js.map +1 -1
- package/dist/components/pill/Pill.stories.d.ts.map +1 -1
- package/dist/components/pill/Pill.stories.js +11 -13
- package/dist/components/pill/Pill.stories.js.map +1 -1
- package/dist/components/row/Row.stories.d.ts +1 -2
- package/dist/components/row/Row.stories.d.ts.map +1 -1
- package/dist/components/row/Row.stories.js +360 -50
- package/dist/components/row/Row.stories.js.map +1 -1
- package/dist/components/searchBar/SearchBar.stories.d.ts +52 -4
- package/dist/components/searchBar/SearchBar.stories.d.ts.map +1 -1
- package/dist/components/searchBar/SearchBar.stories.js +428 -36
- package/dist/components/searchBar/SearchBar.stories.js.map +1 -1
- package/dist/components/section/Section.stories.d.ts +11 -41
- package/dist/components/section/Section.stories.d.ts.map +1 -1
- package/dist/components/section/Section.stories.js +494 -56
- package/dist/components/section/Section.stories.js.map +1 -1
- package/dist/components/singleUser/SingleUser.stories.d.ts +5 -4
- package/dist/components/singleUser/SingleUser.stories.d.ts.map +1 -1
- package/dist/components/singleUser/SingleUser.stories.js +303 -31
- package/dist/components/singleUser/SingleUser.stories.js.map +1 -1
- package/dist/components/slideoverManager/SlideoverManager.stories.d.ts +32 -11
- package/dist/components/slideoverManager/SlideoverManager.stories.d.ts.map +1 -1
- package/dist/components/slideoverManager/SlideoverManager.stories.js +380 -84
- package/dist/components/slideoverManager/SlideoverManager.stories.js.map +1 -1
- package/dist/components/table/DSDefaultColDef.d.ts.map +1 -1
- package/dist/components/table/DSDefaultColDef.js +4 -3
- package/dist/components/table/DSDefaultColDef.js.map +1 -1
- package/dist/components/table/Table.d.ts +6 -1
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +8 -3
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +2 -0
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +357 -3
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/TableFooter.stories.d.ts +49 -0
- package/dist/components/table/TableFooter.stories.d.ts.map +1 -0
- package/dist/components/table/TableFooter.stories.js +137 -0
- package/dist/components/table/TableFooter.stories.js.map +1 -0
- package/dist/components/table/TableHeader.stories.d.ts +93 -0
- package/dist/components/table/TableHeader.stories.d.ts.map +1 -0
- package/dist/components/table/TableHeader.stories.js +176 -0
- package/dist/components/table/TableHeader.stories.js.map +1 -0
- package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts +44 -0
- package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts.map +1 -0
- package/dist/components/table/cellEditors/DateCellEditor.stories.js +186 -0
- package/dist/components/table/cellEditors/DateCellEditor.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts +40 -0
- package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js +209 -0
- package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts +48 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js +244 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.d.ts.map +1 -1
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.js +3 -1
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.js.map +1 -1
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts +64 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js +241 -0
- package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts +55 -0
- package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js +245 -0
- package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts +67 -0
- package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js +221 -0
- package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js.map +1 -0
- package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts +75 -0
- package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js +270 -0
- package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js.map +1 -0
- package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts +57 -0
- package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts.map +1 -0
- package/dist/components/table/columnFilters/BooleanFilter.stories.js +198 -0
- package/dist/components/table/columnFilters/BooleanFilter.stories.js.map +1 -0
- package/dist/components/table/columnFilters/TimeFilter.stories.d.ts +58 -0
- package/dist/components/table/columnFilters/TimeFilter.stories.d.ts.map +1 -0
- package/dist/components/table/columnFilters/TimeFilter.stories.js +207 -0
- package/dist/components/table/columnFilters/TimeFilter.stories.js.map +1 -0
- package/dist/components/table/pagination/PaginationPanel.stories.d.ts +113 -0
- package/dist/components/table/pagination/PaginationPanel.stories.d.ts.map +1 -0
- package/dist/components/table/pagination/PaginationPanel.stories.js +272 -0
- package/dist/components/table/pagination/PaginationPanel.stories.js.map +1 -0
- package/dist/components/table/tableControls/TableControls.stories.d.ts +151 -0
- package/dist/components/table/tableControls/TableControls.stories.d.ts.map +1 -0
- package/dist/components/table/tableControls/TableControls.stories.js +356 -0
- package/dist/components/table/tableControls/TableControls.stories.js.map +1 -0
- package/dist/components/table/tableControls/TableSettingsDropdown.d.ts +27 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.js +53 -26
- package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -1
- package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts +2 -0
- package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts.map +1 -0
- package/dist/components/table/tableControls/TableSettingsDropdown.test.js +178 -0
- package/dist/components/table/tableControls/TableSettingsDropdown.test.js.map +1 -0
- package/dist/components/tabs/Tabs.stories.d.ts +22 -4
- package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.stories.js +398 -22
- package/dist/components/tabs/Tabs.stories.js.map +1 -1
- package/dist/components/tabs/TabsItem.stories.d.ts +54 -1
- package/dist/components/tabs/TabsItem.stories.d.ts.map +1 -1
- package/dist/components/tabs/TabsItem.stories.js +61 -9
- package/dist/components/tabs/TabsItem.stories.js.map +1 -1
- package/dist/components/toast/Toast.stories.d.ts +103 -10
- package/dist/components/toast/Toast.stories.d.ts.map +1 -1
- package/dist/components/toast/Toast.stories.js +409 -47
- package/dist/components/toast/Toast.stories.js.map +1 -1
- package/dist/components/toggle/Toggle.stories.d.ts +61 -46
- package/dist/components/toggle/Toggle.stories.d.ts.map +1 -1
- package/dist/components/toggle/Toggle.stories.js +311 -122
- package/dist/components/toggle/Toggle.stories.js.map +1 -1
- package/dist/components/tooltip/Tooltip.stories.d.ts +78 -6
- package/dist/components/tooltip/Tooltip.stories.d.ts.map +1 -1
- package/dist/components/tooltip/Tooltip.stories.js +413 -7
- package/dist/components/tooltip/Tooltip.stories.js.map +1 -1
- package/dist/components/tooltip/TooltipWrapper.stories.d.ts +71 -7
- package/dist/components/tooltip/TooltipWrapper.stories.d.ts.map +1 -1
- package/dist/components/tooltip/TooltipWrapper.stories.js +238 -10
- package/dist/components/tooltip/TooltipWrapper.stories.js.map +1 -1
- package/dist/index.css +8 -0
- package/dist/index.css.map +1 -1
- package/dist/utils/PopupParentContext.stories.d.ts +17 -0
- package/dist/utils/PopupParentContext.stories.d.ts.map +1 -0
- package/dist/utils/PopupParentContext.stories.js +266 -0
- package/dist/utils/PopupParentContext.stories.js.map +1 -0
- package/dist/utils/getDefaultPopupParent.d.ts.map +1 -1
- package/dist/utils/getDefaultPopupParent.js +6 -0
- package/dist/utils/getDefaultPopupParent.js.map +1 -1
- package/package.json +1 -1
- package/src/components/articleCard/ArticleCard.stories.tsx +524 -111
- package/src/components/avatar/Avatar.stories.tsx +504 -59
- package/src/components/avatarGroup/AvatarGroup.stories.tsx +977 -175
- package/src/components/banner/Banner.stories.tsx +7 -3
- package/src/components/card/Card.stories.tsx +466 -36
- package/src/components/combobox/Combobox.stories.tsx +867 -260
- package/src/components/datePicker/DatePicker.stories.tsx +777 -60
- package/src/components/dateTimePicker/DateTimePicker.stories.tsx +910 -132
- package/src/components/editableText/EditableText.stories.tsx +567 -91
- package/src/components/formField/FormField.test.tsx +6 -0
- package/src/components/formField/FormField.tsx +5 -0
- package/src/components/formField/fieldset/Fieldset.stories.tsx +761 -51
- package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +1 -1
- package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +1 -1
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.tsx +504 -11
- package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +17 -4
- package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +71 -59
- package/src/components/formField/inputs/selectDropdown/SelectDropdown.stories.tsx +1079 -168
- package/src/components/formField/inputs/time/TimeInput.stories.tsx +1140 -104
- package/src/components/formField/label/Label.stories.tsx +317 -8
- package/src/components/icoText/IcoText.stories.tsx +442 -31
- package/src/components/kpiCard/KPICard.stories.tsx +475 -30
- package/src/components/kvpList/KVPList.stories.tsx +593 -26
- package/src/components/modal/Modal.stories.tsx +963 -26
- package/src/components/modal/modalManager/ModalManager.stories.tsx +612 -454
- package/src/components/pill/Pill.stories.tsx +11 -13
- package/src/components/pill/Pill.tsx +1 -0
- package/src/components/row/Row.stories.tsx +474 -58
- package/src/components/searchBar/SearchBar.stories.tsx +570 -38
- package/src/components/section/Section.stories.tsx +723 -70
- package/src/components/singleUser/SingleUser.stories.tsx +393 -34
- package/src/components/slideoverManager/SlideoverManager.stories.tsx +572 -342
- package/src/components/table/DSDefaultColDef.ts +25 -5
- package/src/components/table/Table.stories.tsx +411 -3
- package/src/components/table/Table.tsx +9 -2
- package/src/components/table/TableFooter.stories.tsx +196 -0
- package/src/components/table/TableHeader.stories.tsx +251 -0
- package/src/components/table/cellEditors/DateCellEditor.stories.tsx +245 -0
- package/src/components/table/cellRenderers/BooleanCellRenderer.stories.tsx +278 -0
- package/src/components/table/cellRenderers/ButtonCellRenderer.stories.tsx +333 -0
- package/src/components/table/cellRenderers/CheckboxCellRenderer.stories.tsx +337 -0
- package/src/components/table/cellRenderers/CheckboxCellRenderer.tsx +5 -1
- package/src/components/table/cellRenderers/DefaultCellRenderer.stories.tsx +342 -0
- package/src/components/table/cellRenderers/InlineTextCellRenderer.stories.tsx +292 -0
- package/src/components/table/cellRenderers/SelectDropdownCellRenderer.stories.tsx +369 -0
- package/src/components/table/columnFilters/BooleanFilter.stories.tsx +268 -0
- package/src/components/table/columnFilters/TimeFilter.stories.tsx +281 -0
- package/src/components/table/pagination/PaginationPanel.stories.tsx +327 -0
- package/src/components/table/tableControls/TableControls.stories.tsx +415 -0
- package/src/components/table/tableControls/TableSettingsDropdown.test.tsx +207 -0
- package/src/components/table/tableControls/TableSettingsDropdown.tsx +103 -39
- package/src/components/tabs/Tabs.stories.tsx +540 -60
- package/src/components/tabs/TabsItem.stories.tsx +82 -8
- package/src/components/toast/Toast.stories.tsx +539 -77
- package/src/components/toggle/Toggle.stories.tsx +371 -135
- package/src/components/tooltip/Tooltip.stories.tsx +606 -15
- package/src/components/tooltip/TooltipWrapper.stories.tsx +348 -12
- package/src/docs/Contributing.mdx +241 -0
- package/src/docs/UsingComponents.mdx +93 -0
- package/src/docs/Welcome.mdx +68 -0
- package/src/global.scss +7 -0
- package/src/utils/PopupParentContext.stories.tsx +367 -0
- package/src/utils/getDefaultPopupParent.ts +6 -0
- package/.ralph/storybook-upgrade/knowledge.md +0 -308
- package/.ralph/storybook-upgrade/prd.json +0 -777
- package/.ralph/storybook-upgrade/progress.md +0 -342
- package/src/components/table/TableWIP.mdx +0 -3
|
@@ -1,185 +1,846 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Controls, Heading as DocHeading, Markdown, Primary as DocPrimary, Stories, Subtitle, Title, } from '@storybook/addon-docs/blocks';
|
|
4
|
+
import { FormField } from '../../../formField/FormField';
|
|
1
5
|
import { SelectDropdown } from './SelectDropdown';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Docs page content
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const DESCRIPTION_INTRO = [
|
|
10
|
+
'SelectDropdown is a stylised dropdown select input that matches the Arbor design language.',
|
|
11
|
+
'It supports single-select and multi-select, option grouping, icons, two-line item layouts,',
|
|
12
|
+
'and both controlled and uncontrolled state management.',
|
|
13
|
+
'',
|
|
14
|
+
'> **Built on [Radix UI DropdownMenu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu).**',
|
|
15
|
+
'> The dropdown panel renders via a portal — do **not** place SelectDropdown inside a container',
|
|
16
|
+
'> with `overflow: hidden`, or the panel will be clipped.',
|
|
17
|
+
].join('\n');
|
|
18
|
+
const USAGE_GUIDANCE = [
|
|
19
|
+
'### When to use',
|
|
20
|
+
'',
|
|
21
|
+
'- Replacing a native `<select>` when you need the Arbor visual style',
|
|
22
|
+
'- Offering a list of options for single or multi-selection within a form',
|
|
23
|
+
'- Displaying options with icons, section headers, or group separators',
|
|
24
|
+
'- When built-in form serialisation is useful (a hidden `<input type="hidden">` is always rendered)',
|
|
25
|
+
'',
|
|
26
|
+
'---',
|
|
27
|
+
'',
|
|
28
|
+
'### When NOT to use',
|
|
29
|
+
'',
|
|
30
|
+
'| Situation | Use instead |',
|
|
31
|
+
'|---|---|',
|
|
32
|
+
'| Need native browser select for mobile or performance | Plain `<select>` inside a FormField |',
|
|
33
|
+
'| Need async search or type-to-filter | Combobox |',
|
|
34
|
+
'| Need individual options to be disabled | Custom `Dropdown` composition |',
|
|
35
|
+
'| Thousands of options | No virtualisation — consider a search-first pattern |',
|
|
36
|
+
].join('\n');
|
|
37
|
+
const DEVELOPER_NOTES = [
|
|
38
|
+
'### Critical usage patterns',
|
|
39
|
+
'',
|
|
40
|
+
'**`errorText` does not exist on SelectDropdown.** Error text belongs on `FormField`. Pass `errorText`',
|
|
41
|
+
'to `FormField` and use `inputType="selectDropdown"` — it automatically wires `hasError`,',
|
|
42
|
+
'`aria-invalid`, and `aria-describedby` for you.',
|
|
43
|
+
'',
|
|
44
|
+
'**`hasError` is visual-only.** It applies error styling to the trigger button but tells screen readers',
|
|
45
|
+
'nothing. Always pair it with `aria-invalid={true}`.',
|
|
46
|
+
'',
|
|
47
|
+
'**`id` is dual-purpose.** It is set as both the `name` on the hidden form input and the `id` on the',
|
|
48
|
+
'trigger button. Set this when using inside a `<form>` or when you need a `<label htmlFor>` to target the trigger.',
|
|
49
|
+
'',
|
|
50
|
+
'**Multi-select count display.** With `multiple` and no `placeholder` prop, the trigger shows',
|
|
51
|
+
'`"Select (2)"` when two items are selected. Setting a `placeholder` suppresses the count — the',
|
|
52
|
+
'trigger shows your placeholder string instead. Choose deliberately.',
|
|
53
|
+
'',
|
|
54
|
+
'**Controlled vs uncontrolled.** Providing `selectedValues` activates controlled mode — the component',
|
|
55
|
+
'stops managing its own state. You must update `selectedValues` via `onSelectionChange` or the',
|
|
56
|
+
'dropdown will appear frozen. Do not mix `initialSelectedValues` with `selectedValues`.',
|
|
57
|
+
'',
|
|
58
|
+
'**Groups are automatic.** Add `group: "Year 7"` to options and the component clusters them under',
|
|
59
|
+
'`<h3>` section headers. Headers only appear when two or more distinct `group` values exist.',
|
|
60
|
+
'',
|
|
61
|
+
'---',
|
|
62
|
+
'',
|
|
63
|
+
'### Accessibility',
|
|
64
|
+
'',
|
|
65
|
+
'- Always pair `hasError` with `aria-invalid={true}` — `hasError` is visual-only',
|
|
66
|
+
'- Use `aria-describedBy` to link to your error/hint message element',
|
|
67
|
+
'- When used standalone (outside FormField), set `id` and associate a `<label htmlFor={id}>`',
|
|
68
|
+
'- When used inside `FormField`, label association and ARIA wiring are automatic — prefer that pattern',
|
|
69
|
+
'- Keyboard navigation is built in via Radix UI: `↑ ↓` to move through options, `Enter` to select, `Esc` to close',
|
|
70
|
+
'',
|
|
71
|
+
'---',
|
|
72
|
+
'',
|
|
73
|
+
'### TypeScript types',
|
|
74
|
+
'',
|
|
75
|
+
'```ts',
|
|
76
|
+
"import { SelectDropdown } from '@arbor-education/design-system.components';",
|
|
77
|
+
'',
|
|
78
|
+
'function MySelect(props: SelectDropdown.Props) { ... }',
|
|
79
|
+
'```',
|
|
80
|
+
'',
|
|
81
|
+
'| Type | Description |',
|
|
82
|
+
'|---|---|',
|
|
83
|
+
'| `SelectDropdown.Props` | Full props interface (`SelectDropdownInputProps`) |',
|
|
84
|
+
].join('\n');
|
|
85
|
+
const RELATED_COMPONENTS = [
|
|
86
|
+
'## Related components',
|
|
87
|
+
'',
|
|
88
|
+
'[FormField](?path=/docs/components-formfield--docs) · [Dropdown](?path=/docs/components-dropdown--docs) · [ColourPickerDropdown](?path=/docs/components-formfield-inputs-colourpickerdropdown--docs)',
|
|
89
|
+
].join('\n');
|
|
90
|
+
const PROPS_INTRO = 'The preview below is wired to the **Controls** panel — tweak any prop to see the story update in real time.';
|
|
91
|
+
function SelectDropdownDocsPage() {
|
|
92
|
+
return (_jsxs(_Fragment, { children: [_jsx(Title, {}), _jsx(Subtitle, {}), _jsx(Markdown, { children: DESCRIPTION_INTRO }), _jsx(DocHeading, { children: "Interactive example" }), _jsx(Markdown, { children: PROPS_INTRO }), _jsx(DocPrimary, {}), _jsx(Controls, {}), _jsx(DocHeading, { children: "Usage guidance" }), _jsx(Markdown, { children: USAGE_GUIDANCE }), _jsx(DocHeading, { children: "Developer notes" }), _jsx(Markdown, { children: DEVELOPER_NOTES }), _jsx(DocHeading, { children: "Examples" }), _jsx(Stories, { title: "" }), _jsx(Markdown, { children: RELATED_COMPONENTS })] }));
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Option fixtures
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
const yearGroupOptions = [
|
|
98
|
+
{ label: 'Year 7', value: 'year7' },
|
|
99
|
+
{ label: 'Year 8', value: 'year8' },
|
|
100
|
+
{ label: 'Year 9', value: 'year9' },
|
|
101
|
+
{ label: 'Year 10', value: 'year10' },
|
|
102
|
+
{ label: 'Year 11', value: 'year11' },
|
|
103
|
+
];
|
|
104
|
+
const subjectOptions = [
|
|
105
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
106
|
+
{ label: 'English', value: 'english' },
|
|
107
|
+
{ label: 'Science', value: 'science' },
|
|
108
|
+
{ label: 'History', value: 'history' },
|
|
109
|
+
{ label: 'Geography', value: 'geography' },
|
|
110
|
+
{ label: 'Art', value: 'art' },
|
|
111
|
+
];
|
|
112
|
+
const subjectOptionsWithIcons = [
|
|
113
|
+
{ label: 'Mathematics', value: 'maths', icon: 'chart-column-increasing' },
|
|
114
|
+
{ label: 'English', value: 'english', icon: 'book-open' },
|
|
115
|
+
{ label: 'Science', value: 'science', icon: 'circle-check' },
|
|
116
|
+
{ label: 'History', value: 'history', icon: 'clock-3' },
|
|
117
|
+
{ label: 'Geography', value: 'geography', icon: 'flag' },
|
|
118
|
+
];
|
|
119
|
+
const attendanceReasonOptions = [
|
|
120
|
+
{ label: 'Authorised absence', value: 'authorised', header: 'Planned' },
|
|
121
|
+
{ label: 'Holiday', value: 'holiday', header: 'Planned' },
|
|
122
|
+
{ label: 'Medical appointment', value: 'medical', header: 'Health' },
|
|
123
|
+
{ label: 'Illness', value: 'illness', header: 'Health' },
|
|
124
|
+
{ label: 'Unauthorised absence', value: 'unauthorised', header: 'Unplanned' },
|
|
125
|
+
{ label: 'Late arrival', value: 'late', header: 'Unplanned' },
|
|
126
|
+
];
|
|
127
|
+
const groupedYearOptions = [
|
|
128
|
+
{ label: 'Year 7', value: 'year7', group: 'Lower school' },
|
|
129
|
+
{ label: 'Year 8', value: 'year8', group: 'Lower school' },
|
|
130
|
+
{ label: 'Year 9', value: 'year9', group: 'Lower school' },
|
|
131
|
+
{ label: 'Year 10', value: 'year10', group: 'Upper school' },
|
|
132
|
+
{ label: 'Year 11', value: 'year11', group: 'Upper school' },
|
|
133
|
+
{ label: 'Year 12', value: 'year12', group: 'Sixth form' },
|
|
134
|
+
{ label: 'Year 13', value: 'year13', group: 'Sixth form' },
|
|
135
|
+
];
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Meta
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
2
139
|
const meta = {
|
|
3
140
|
title: 'Components/FormField/Inputs/SelectDropdown',
|
|
4
141
|
component: SelectDropdown,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{ label: 'Option 2', value: 'option2' },
|
|
12
|
-
{ label: 'Option 3', value: 'option3' },
|
|
13
|
-
],
|
|
14
|
-
multiple: false,
|
|
15
|
-
onSelectionChange: (value) => { console.log(value); },
|
|
142
|
+
tags: ['autodocs'],
|
|
143
|
+
parameters: {
|
|
144
|
+
layout: 'padded',
|
|
145
|
+
docs: {
|
|
146
|
+
page: SelectDropdownDocsPage,
|
|
147
|
+
},
|
|
16
148
|
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
149
|
+
argTypes: {
|
|
150
|
+
'options': {
|
|
151
|
+
description: [
|
|
152
|
+
'Array of option items to display in the dropdown.',
|
|
153
|
+
'Each item must have a `value` string.',
|
|
154
|
+
'`label`, `icon`, `header`, and `group` are optional.',
|
|
155
|
+
].join(' '),
|
|
156
|
+
control: false,
|
|
157
|
+
table: {
|
|
158
|
+
type: { summary: 'SelectDropdownItemProps[]' },
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
'placeholder': {
|
|
162
|
+
description: [
|
|
163
|
+
'Text shown in the trigger when nothing is selected.',
|
|
164
|
+
'In multi-select mode, also shown when 2+ items are selected (suppressing the count display).',
|
|
165
|
+
'Defaults to `"Select"`.',
|
|
166
|
+
].join(' '),
|
|
167
|
+
control: 'text',
|
|
168
|
+
table: {
|
|
169
|
+
type: { summary: 'string' },
|
|
170
|
+
defaultValue: { summary: "'Select'" },
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
'multiple': {
|
|
174
|
+
description: [
|
|
175
|
+
'Enables multi-select mode.',
|
|
176
|
+
'The dropdown stays open after each selection and items toggle on/off.',
|
|
177
|
+
].join(' '),
|
|
178
|
+
control: 'boolean',
|
|
179
|
+
table: {
|
|
180
|
+
type: { summary: 'boolean' },
|
|
181
|
+
defaultValue: { summary: 'false' },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
'disabled': {
|
|
185
|
+
description: 'Disables the trigger button, preventing the dropdown from opening.',
|
|
186
|
+
control: 'boolean',
|
|
187
|
+
table: {
|
|
188
|
+
type: { summary: 'boolean' },
|
|
189
|
+
defaultValue: { summary: 'false' },
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
'hasError': {
|
|
193
|
+
description: [
|
|
194
|
+
'**Visual only.** Applies error styling to the trigger button.',
|
|
195
|
+
'Must be paired with `aria-invalid={true}` for screen reader support.',
|
|
196
|
+
'Do not pass `errorText` here — that prop does not exist. Use `FormField` with `errorText` instead.',
|
|
197
|
+
].join(' '),
|
|
198
|
+
control: 'boolean',
|
|
199
|
+
table: {
|
|
200
|
+
type: { summary: 'boolean' },
|
|
201
|
+
defaultValue: { summary: 'false' },
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
'aria-invalid': {
|
|
205
|
+
description: [
|
|
206
|
+
'Communicates an invalid state to screen readers via the trigger button.',
|
|
207
|
+
'Always pair with `hasError`.',
|
|
208
|
+
].join(' '),
|
|
209
|
+
control: 'boolean',
|
|
210
|
+
table: {
|
|
211
|
+
type: { summary: 'boolean' },
|
|
212
|
+
defaultValue: { summary: 'undefined' },
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
'aria-describedBy': {
|
|
216
|
+
description: [
|
|
217
|
+
'ID of the element that describes this field (e.g. an error message or hint).',
|
|
218
|
+
'Passed through to the trigger button.',
|
|
219
|
+
].join(' '),
|
|
220
|
+
control: 'text',
|
|
221
|
+
table: {
|
|
222
|
+
type: { summary: 'string' },
|
|
223
|
+
defaultValue: { summary: 'undefined' },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
'id': {
|
|
227
|
+
description: [
|
|
228
|
+
'**Dual-purpose.** Set as `name` on the hidden form input AND as `id` on the trigger button.',
|
|
229
|
+
'Required for label association (`<label htmlFor={id}>`) and form submission.',
|
|
230
|
+
].join(' '),
|
|
231
|
+
control: 'text',
|
|
232
|
+
table: {
|
|
233
|
+
type: { summary: 'string' },
|
|
234
|
+
defaultValue: { summary: 'undefined' },
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
'alwaysShowPlaceholder': {
|
|
238
|
+
description: [
|
|
239
|
+
'When `true`, the trigger always displays the placeholder regardless of what is selected.',
|
|
240
|
+
'Use for action-style dropdowns (e.g. "Add filter") where the label must not change.',
|
|
241
|
+
].join(' '),
|
|
242
|
+
control: 'boolean',
|
|
243
|
+
table: {
|
|
244
|
+
type: { summary: 'boolean' },
|
|
245
|
+
defaultValue: { summary: 'false' },
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
'initialSelectedValues': {
|
|
249
|
+
description: [
|
|
250
|
+
'Uncontrolled mode only — sets the initial selection on mount.',
|
|
251
|
+
'Ignored if `selectedValues` is provided.',
|
|
252
|
+
].join(' '),
|
|
253
|
+
control: false,
|
|
254
|
+
table: {
|
|
255
|
+
type: { summary: 'string[]' },
|
|
256
|
+
defaultValue: { summary: '[]' },
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
'selectedValues': {
|
|
260
|
+
description: [
|
|
261
|
+
'Activates fully controlled mode.',
|
|
262
|
+
'You must update this via `onSelectionChange` — the component stops managing its own state.',
|
|
263
|
+
'Do not mix with `initialSelectedValues`.',
|
|
264
|
+
].join(' '),
|
|
265
|
+
control: false,
|
|
266
|
+
table: {
|
|
267
|
+
type: { summary: 'string[]' },
|
|
268
|
+
defaultValue: { summary: 'undefined' },
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
'onSelectionChange': {
|
|
272
|
+
description: 'Fires after every selection change with the full updated array of selected values.',
|
|
273
|
+
action: 'onSelectionChange',
|
|
274
|
+
control: false,
|
|
275
|
+
table: {
|
|
276
|
+
type: { summary: '(value: string[]) => void' },
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
'open': {
|
|
280
|
+
description: 'Controls the open/closed state of the dropdown externally.',
|
|
281
|
+
control: 'boolean',
|
|
282
|
+
table: {
|
|
283
|
+
type: { summary: 'boolean' },
|
|
284
|
+
defaultValue: { summary: 'undefined' },
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
'onOpenChange': {
|
|
288
|
+
description: 'Fires when the dropdown attempts to open or close. Required when `open` is controlled.',
|
|
289
|
+
action: 'onOpenChange',
|
|
290
|
+
control: false,
|
|
291
|
+
table: {
|
|
292
|
+
type: { summary: '(open: boolean) => void' },
|
|
293
|
+
},
|
|
294
|
+
},
|
|
28
295
|
},
|
|
29
296
|
};
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
],
|
|
45
|
-
onSelectionChange: (value) => { console.log(value); },
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
export const DefaultMultiSelect = {
|
|
49
|
-
args: {
|
|
50
|
-
title: 'titleValue',
|
|
51
|
-
options: [
|
|
52
|
-
{ label: 'Option 1', value: 'option1' },
|
|
53
|
-
{ label: 'Option 2', value: 'option2' },
|
|
54
|
-
{ label: 'Option 3', value: 'option3' },
|
|
55
|
-
],
|
|
56
|
-
multiple: true,
|
|
57
|
-
onSelectionChange: (value) => { console.log(value); },
|
|
297
|
+
export default meta;
|
|
298
|
+
// ---------------------------------------------------------------------------
|
|
299
|
+
// Helper: attach a per-story description to docs
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
const withDescription = (story, description) => ({
|
|
302
|
+
...story,
|
|
303
|
+
parameters: {
|
|
304
|
+
...story.parameters,
|
|
305
|
+
docs: {
|
|
306
|
+
...story.parameters?.docs,
|
|
307
|
+
description: {
|
|
308
|
+
story: description,
|
|
309
|
+
},
|
|
310
|
+
},
|
|
58
311
|
},
|
|
312
|
+
});
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
// Template components for stateful and composite stories
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
const WithInitialSelectionTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select a year group", initialSelectedValues: ['year9'], options: yearGroupOptions, onSelectionChange: values => console.log(values) }) }));
|
|
317
|
+
const MultiSelectTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select subjects", multiple: true, options: subjectOptions, onSelectionChange: values => console.log(values) }) }));
|
|
318
|
+
const MultiSelectWithCountTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { multiple: true, initialSelectedValues: ['maths', 'english', 'science'], options: subjectOptions, onSelectionChange: values => console.log(values) }) }));
|
|
319
|
+
const DisabledTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select a year group", disabled: true, options: yearGroupOptions, onSelectionChange: values => console.log(values) }) }));
|
|
320
|
+
const WithErrorTemplate = () => (_jsxs("div", { style: { maxWidth: '320px', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-xsmall)' }, children: [_jsx(SelectDropdown, { placeholder: "Select a year group", hasError: true, "aria-invalid": true, "aria-describedBy": "year-group-error", options: yearGroupOptions, onSelectionChange: values => console.log(values) }), _jsx("span", { id: "year-group-error", style: { fontSize: '0.875rem', color: 'var(--color-feedback-danger-600)' }, children: "Please select a year group" })] }));
|
|
321
|
+
const WithIconsTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select a subject", options: subjectOptionsWithIcons, onSelectionChange: values => console.log(values) }) }));
|
|
322
|
+
const WithItemHeadersTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select absence reason", options: attendanceReasonOptions, onSelectionChange: values => console.log(values) }) }));
|
|
323
|
+
const WithGroupsTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select a year group", options: groupedYearOptions, onSelectionChange: values => console.log(values) }) }));
|
|
324
|
+
const WithGroupsMultiSelectTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Select year groups", multiple: true, options: groupedYearOptions, onSelectionChange: values => console.log(values) }) }));
|
|
325
|
+
const AlwaysShowPlaceholderTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { placeholder: "Add filter", alwaysShowPlaceholder: true, multiple: true, options: subjectOptions, onSelectionChange: values => console.log(values) }) }));
|
|
326
|
+
const ControlledSingleSelectTemplate = () => {
|
|
327
|
+
const [selected, setSelected] = useState([]);
|
|
328
|
+
return (_jsxs("div", { style: { maxWidth: '320px', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-small)' }, children: [_jsx(SelectDropdown, { placeholder: "Select a subject", selectedValues: selected, onSelectionChange: setSelected, options: subjectOptions }), _jsxs("span", { style: { fontSize: '0.875rem', color: 'var(--color-grey-600)' }, children: ["Selected:", ' ', selected.length > 0 ? selected.join(', ') : 'nothing yet'] })] }));
|
|
59
329
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{ label: 'Option 2', value: 'option2' },
|
|
67
|
-
{ label: 'Option 3', value: 'option3' },
|
|
68
|
-
],
|
|
69
|
-
onSelectionChange: (value) => { console.log(value); },
|
|
70
|
-
},
|
|
330
|
+
const ControlledOpenTemplate = () => {
|
|
331
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
332
|
+
return (_jsxs("div", { style: { maxWidth: '320px', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-small)' }, children: [_jsx("button", { type: "button", onClick: () => setIsOpen(true), children: "Open dropdown externally" }), _jsx(SelectDropdown, { placeholder: "Select a subject", open: isOpen, onOpenChange: setIsOpen, options: subjectOptions, onSelectionChange: (values) => {
|
|
333
|
+
console.log(values);
|
|
334
|
+
setIsOpen(false);
|
|
335
|
+
} })] }));
|
|
71
336
|
};
|
|
72
|
-
|
|
337
|
+
const InsideFormFieldTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(FormField, { label: "Year group", id: "year-group-field", inputType: "selectDropdown", inputProps: {
|
|
338
|
+
placeholder: 'Select a year group',
|
|
339
|
+
options: yearGroupOptions,
|
|
340
|
+
onSelectionChange: values => console.log(values),
|
|
341
|
+
} }) }));
|
|
342
|
+
const InsideFormFieldWithErrorTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(FormField, { label: "Year group", id: "year-group-error-field", inputType: "selectDropdown", errorText: "Please select a year group", inputProps: {
|
|
343
|
+
placeholder: 'Select a year group',
|
|
344
|
+
options: yearGroupOptions,
|
|
345
|
+
onSelectionChange: values => console.log(values),
|
|
346
|
+
} }) }));
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
// Stories
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
export const Default = withDescription({
|
|
73
351
|
args: {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{ label: 'Option 2', value: 'option2' },
|
|
78
|
-
{ label: 'Option 3', value: 'option3' },
|
|
79
|
-
],
|
|
352
|
+
options: yearGroupOptions,
|
|
353
|
+
placeholder: 'Select a year group',
|
|
354
|
+
multiple: false,
|
|
80
355
|
disabled: false,
|
|
81
|
-
onSelectionChange: (value) => { console.log(value); },
|
|
82
356
|
},
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
357
|
+
render: args => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(SelectDropdown, { ...args }) })),
|
|
358
|
+
}, 'The interactive canvas — every prop is wired to the Controls panel above. Use `options`, `placeholder`, `multiple`, and `disabled` to explore the full range of configurations.');
|
|
359
|
+
export const WithInitialSelection = withDescription({
|
|
360
|
+
render: WithInitialSelectionTemplate,
|
|
361
|
+
parameters: {
|
|
362
|
+
controls: { disable: true },
|
|
363
|
+
docs: {
|
|
364
|
+
source: {
|
|
365
|
+
language: 'tsx',
|
|
366
|
+
code: `
|
|
367
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
368
|
+
|
|
369
|
+
function WithInitialSelectionExample() {
|
|
370
|
+
return (
|
|
371
|
+
<SelectDropdown
|
|
372
|
+
placeholder="Select a year group"
|
|
373
|
+
initialSelectedValues={['year9']}
|
|
374
|
+
options={[
|
|
375
|
+
{ label: 'Year 7', value: 'year7' },
|
|
376
|
+
{ label: 'Year 8', value: 'year8' },
|
|
377
|
+
{ label: 'Year 9', value: 'year9' },
|
|
378
|
+
{ label: 'Year 10', value: 'year10' },
|
|
379
|
+
{ label: 'Year 11', value: 'year11' },
|
|
380
|
+
]}
|
|
381
|
+
onSelectionChange={(values) => console.log(values)}
|
|
382
|
+
/>
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
export default WithInitialSelectionExample;
|
|
386
|
+
`.trim(),
|
|
387
|
+
},
|
|
388
|
+
},
|
|
95
389
|
},
|
|
96
|
-
};
|
|
97
|
-
export const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
390
|
+
}, 'Uncontrolled mode with a pre-selected value via `initialSelectedValues`. The component manages its own state after mount — no `selectedValues` prop is needed. Use this when you only need to set a default and let the user take over.');
|
|
391
|
+
export const MultiSelect = withDescription({
|
|
392
|
+
render: MultiSelectTemplate,
|
|
393
|
+
parameters: {
|
|
394
|
+
controls: { disable: true },
|
|
395
|
+
docs: {
|
|
396
|
+
source: {
|
|
397
|
+
language: 'tsx',
|
|
398
|
+
code: `
|
|
399
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
400
|
+
|
|
401
|
+
function MultiSelectExample() {
|
|
402
|
+
return (
|
|
403
|
+
<SelectDropdown
|
|
404
|
+
placeholder="Select subjects"
|
|
405
|
+
multiple
|
|
406
|
+
options={[
|
|
407
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
408
|
+
{ label: 'English', value: 'english' },
|
|
409
|
+
{ label: 'Science', value: 'science' },
|
|
410
|
+
{ label: 'History', value: 'history' },
|
|
411
|
+
{ label: 'Geography', value: 'geography' },
|
|
412
|
+
]}
|
|
413
|
+
onSelectionChange={(values) => console.log(values)}
|
|
414
|
+
/>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
export default MultiSelectExample;
|
|
418
|
+
`.trim(),
|
|
419
|
+
},
|
|
420
|
+
},
|
|
107
421
|
},
|
|
108
|
-
};
|
|
109
|
-
export const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
422
|
+
}, '`multiple={true}` allows selecting more than one item. The dropdown stays open after each selection so users can make multiple choices without re-opening. Items toggle on and off.');
|
|
423
|
+
export const MultiSelectWithCount = withDescription({
|
|
424
|
+
render: MultiSelectWithCountTemplate,
|
|
425
|
+
parameters: {
|
|
426
|
+
controls: { disable: true },
|
|
427
|
+
docs: {
|
|
428
|
+
source: {
|
|
429
|
+
language: 'tsx',
|
|
430
|
+
code: `
|
|
431
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
432
|
+
|
|
433
|
+
function MultiSelectWithCountExample() {
|
|
434
|
+
return (
|
|
435
|
+
// No placeholder prop — the trigger shows "Select (3)" when items are selected.
|
|
436
|
+
// Setting a placeholder would suppress this count display.
|
|
437
|
+
<SelectDropdown
|
|
438
|
+
multiple
|
|
439
|
+
initialSelectedValues={['maths', 'english', 'science']}
|
|
440
|
+
options={[
|
|
441
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
442
|
+
{ label: 'English', value: 'english' },
|
|
443
|
+
{ label: 'Science', value: 'science' },
|
|
444
|
+
{ label: 'History', value: 'history' },
|
|
445
|
+
]}
|
|
446
|
+
onSelectionChange={(values) => console.log(values)}
|
|
447
|
+
/>
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
export default MultiSelectWithCountExample;
|
|
451
|
+
`.trim(),
|
|
452
|
+
},
|
|
453
|
+
},
|
|
122
454
|
},
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
455
|
+
}, [
|
|
456
|
+
'When `multiple` is true and **no `placeholder` prop is set**, the trigger shows `"Select (3)"` when three items are selected.',
|
|
457
|
+
'Setting a `placeholder` suppresses this count — the trigger shows your placeholder text instead.',
|
|
458
|
+
'Choose deliberately based on whether you want users to see how many items are selected.',
|
|
459
|
+
].join(' '));
|
|
460
|
+
export const Disabled = withDescription({
|
|
461
|
+
render: DisabledTemplate,
|
|
462
|
+
parameters: {
|
|
463
|
+
controls: { disable: true },
|
|
464
|
+
docs: {
|
|
465
|
+
source: {
|
|
466
|
+
language: 'tsx',
|
|
467
|
+
code: `
|
|
468
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
469
|
+
|
|
470
|
+
function DisabledExample() {
|
|
471
|
+
return (
|
|
472
|
+
<SelectDropdown
|
|
473
|
+
placeholder="Select a year group"
|
|
474
|
+
disabled
|
|
475
|
+
options={[
|
|
476
|
+
{ label: 'Year 7', value: 'year7' },
|
|
477
|
+
{ label: 'Year 8', value: 'year8' },
|
|
478
|
+
{ label: 'Year 9', value: 'year9' },
|
|
479
|
+
]}
|
|
480
|
+
onSelectionChange={(values) => console.log(values)}
|
|
481
|
+
/>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
export default DisabledExample;
|
|
485
|
+
`.trim(),
|
|
486
|
+
},
|
|
487
|
+
},
|
|
134
488
|
},
|
|
135
|
-
};
|
|
136
|
-
export const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
489
|
+
}, 'The `disabled` prop prevents the trigger from opening. Use when the field is not applicable in the current context — for example, a dependent field that requires another field to be filled first.');
|
|
490
|
+
export const WithError = withDescription({
|
|
491
|
+
render: WithErrorTemplate,
|
|
492
|
+
parameters: {
|
|
493
|
+
controls: { disable: true },
|
|
494
|
+
docs: {
|
|
495
|
+
source: {
|
|
496
|
+
language: 'tsx',
|
|
497
|
+
code: `
|
|
498
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
499
|
+
|
|
500
|
+
function WithErrorExample() {
|
|
501
|
+
return (
|
|
502
|
+
<div>
|
|
503
|
+
<SelectDropdown
|
|
504
|
+
placeholder="Select a year group"
|
|
505
|
+
hasError
|
|
506
|
+
aria-invalid
|
|
507
|
+
aria-describedBy="year-group-error"
|
|
508
|
+
options={[
|
|
509
|
+
{ label: 'Year 7', value: 'year7' },
|
|
510
|
+
{ label: 'Year 8', value: 'year8' },
|
|
511
|
+
{ label: 'Year 9', value: 'year9' },
|
|
512
|
+
]}
|
|
513
|
+
onSelectionChange={(values) => console.log(values)}
|
|
514
|
+
/>
|
|
515
|
+
<span id="year-group-error">Please select a year group</span>
|
|
516
|
+
</div>
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
export default WithErrorExample;
|
|
520
|
+
`.trim(),
|
|
521
|
+
},
|
|
522
|
+
},
|
|
151
523
|
},
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
524
|
+
}, [
|
|
525
|
+
'`hasError` applies error styling to the trigger. `aria-invalid` tells screen readers the field is invalid.',
|
|
526
|
+
'`aria-describedBy` links to the error message element by ID.',
|
|
527
|
+
'**All three should be used together for an accessible error state.**',
|
|
528
|
+
'When using `FormField`, these are wired automatically via `errorText` — prefer the `InsideFormFieldWithError` pattern.',
|
|
529
|
+
].join(' '));
|
|
530
|
+
export const WithIcons = withDescription({
|
|
531
|
+
render: WithIconsTemplate,
|
|
532
|
+
parameters: {
|
|
533
|
+
controls: { disable: true },
|
|
534
|
+
docs: {
|
|
535
|
+
source: {
|
|
536
|
+
language: 'tsx',
|
|
537
|
+
code: `
|
|
538
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
539
|
+
|
|
540
|
+
function WithIconsExample() {
|
|
541
|
+
return (
|
|
542
|
+
<SelectDropdown
|
|
543
|
+
placeholder="Select a subject"
|
|
544
|
+
options={[
|
|
545
|
+
{ label: 'Mathematics', value: 'maths', icon: 'chart-column-increasing' },
|
|
546
|
+
{ label: 'English', value: 'english', icon: 'book-open' },
|
|
547
|
+
{ label: 'Science', value: 'science', icon: 'circle-check' },
|
|
548
|
+
{ label: 'History', value: 'history', icon: 'clock-3' },
|
|
549
|
+
{ label: 'Geography', value: 'geography', icon: 'flag' },
|
|
550
|
+
]}
|
|
551
|
+
onSelectionChange={(values) => console.log(values)}
|
|
552
|
+
/>
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
export default WithIconsExample;
|
|
556
|
+
`.trim(),
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
}, 'Options can include an `icon` prop to display an icon to the left of the label. Use icon names from the Arbor Icon component.');
|
|
561
|
+
export const WithItemHeaders = withDescription({
|
|
562
|
+
render: WithItemHeadersTemplate,
|
|
563
|
+
parameters: {
|
|
564
|
+
controls: { disable: true },
|
|
565
|
+
docs: {
|
|
566
|
+
source: {
|
|
567
|
+
language: 'tsx',
|
|
568
|
+
code: `
|
|
569
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
570
|
+
|
|
571
|
+
function WithItemHeadersExample() {
|
|
572
|
+
return (
|
|
573
|
+
<SelectDropdown
|
|
574
|
+
placeholder="Select absence reason"
|
|
575
|
+
options={[
|
|
576
|
+
{ label: 'Authorised absence', value: 'authorised', header: 'Planned' },
|
|
577
|
+
{ label: 'Holiday', value: 'holiday', header: 'Planned' },
|
|
578
|
+
{ label: 'Medical appointment', value: 'medical', header: 'Health' },
|
|
579
|
+
{ label: 'Illness', value: 'illness', header: 'Health' },
|
|
580
|
+
{ label: 'Unauthorised absence', value: 'unauthorised', header: 'Unplanned' },
|
|
581
|
+
]}
|
|
582
|
+
onSelectionChange={(values) => console.log(values)}
|
|
583
|
+
/>
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
export default WithItemHeadersExample;
|
|
587
|
+
`.trim(),
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
}, 'The `header` prop on an option renders a small label above the option text, creating a two-line item layout. Use this to add context to complex options — for example, showing the category of an absence type alongside its name.');
|
|
592
|
+
export const WithGroups = withDescription({
|
|
593
|
+
render: WithGroupsTemplate,
|
|
594
|
+
parameters: {
|
|
595
|
+
controls: { disable: true },
|
|
596
|
+
docs: {
|
|
597
|
+
source: {
|
|
598
|
+
language: 'tsx',
|
|
599
|
+
code: `
|
|
600
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
601
|
+
|
|
602
|
+
function WithGroupsExample() {
|
|
603
|
+
return (
|
|
604
|
+
<SelectDropdown
|
|
605
|
+
placeholder="Select a year group"
|
|
606
|
+
options={[
|
|
607
|
+
{ label: 'Year 7', value: 'year7', group: 'Lower school' },
|
|
608
|
+
{ label: 'Year 8', value: 'year8', group: 'Lower school' },
|
|
609
|
+
{ label: 'Year 9', value: 'year9', group: 'Lower school' },
|
|
610
|
+
{ label: 'Year 10', value: 'year10', group: 'Upper school' },
|
|
611
|
+
{ label: 'Year 11', value: 'year11', group: 'Upper school' },
|
|
612
|
+
{ label: 'Year 12', value: 'year12', group: 'Sixth form' },
|
|
613
|
+
{ label: 'Year 13', value: 'year13', group: 'Sixth form' },
|
|
614
|
+
]}
|
|
615
|
+
onSelectionChange={(values) => console.log(values)}
|
|
616
|
+
/>
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
export default WithGroupsExample;
|
|
620
|
+
`.trim(),
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
}, 'Adding a `group` string to options automatically clusters them under section headings. Group headers are only rendered when two or more distinct group values exist. Items without a `group` are rendered ungrouped.');
|
|
625
|
+
export const WithGroupsMultiSelect = withDescription({
|
|
626
|
+
render: WithGroupsMultiSelectTemplate,
|
|
627
|
+
parameters: {
|
|
628
|
+
controls: { disable: true },
|
|
629
|
+
docs: {
|
|
630
|
+
source: {
|
|
631
|
+
language: 'tsx',
|
|
632
|
+
code: `
|
|
633
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
634
|
+
|
|
635
|
+
function WithGroupsMultiSelectExample() {
|
|
636
|
+
return (
|
|
637
|
+
<SelectDropdown
|
|
638
|
+
placeholder="Select year groups"
|
|
639
|
+
multiple
|
|
640
|
+
options={[
|
|
641
|
+
{ label: 'Year 7', value: 'year7', group: 'Lower school' },
|
|
642
|
+
{ label: 'Year 8', value: 'year8', group: 'Lower school' },
|
|
643
|
+
{ label: 'Year 9', value: 'year9', group: 'Lower school' },
|
|
644
|
+
{ label: 'Year 10', value: 'year10', group: 'Upper school' },
|
|
645
|
+
{ label: 'Year 11', value: 'year11', group: 'Upper school' },
|
|
646
|
+
]}
|
|
647
|
+
onSelectionChange={(values) => console.log(values)}
|
|
648
|
+
/>
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
export default WithGroupsMultiSelectExample;
|
|
652
|
+
`.trim(),
|
|
653
|
+
},
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
}, 'Grouped options combined with multi-select. The dropdown stays open while users make multiple selections across groups.');
|
|
657
|
+
export const AlwaysShowPlaceholder = withDescription({
|
|
658
|
+
render: AlwaysShowPlaceholderTemplate,
|
|
659
|
+
parameters: {
|
|
660
|
+
controls: { disable: true },
|
|
661
|
+
docs: {
|
|
662
|
+
source: {
|
|
663
|
+
language: 'tsx',
|
|
664
|
+
code: `
|
|
665
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
666
|
+
|
|
667
|
+
function AlwaysShowPlaceholderExample() {
|
|
668
|
+
return (
|
|
669
|
+
<SelectDropdown
|
|
670
|
+
placeholder="Add filter"
|
|
671
|
+
alwaysShowPlaceholder
|
|
672
|
+
multiple
|
|
673
|
+
options={[
|
|
674
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
675
|
+
{ label: 'English', value: 'english' },
|
|
676
|
+
{ label: 'Science', value: 'science' },
|
|
677
|
+
]}
|
|
678
|
+
onSelectionChange={(values) => console.log(values)}
|
|
679
|
+
/>
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
export default AlwaysShowPlaceholderExample;
|
|
683
|
+
`.trim(),
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
}, '`alwaysShowPlaceholder` keeps the trigger label fixed regardless of selection state. Use for action-style dropdowns (e.g. "Add filter") where the trigger label should not change to reflect the selected value.');
|
|
688
|
+
export const ControlledSingleSelect = withDescription({
|
|
689
|
+
render: ControlledSingleSelectTemplate,
|
|
690
|
+
parameters: {
|
|
691
|
+
controls: { disable: true },
|
|
692
|
+
docs: {
|
|
693
|
+
source: {
|
|
694
|
+
language: 'tsx',
|
|
695
|
+
code: `
|
|
696
|
+
import { useState } from 'react';
|
|
697
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
698
|
+
|
|
699
|
+
function ControlledSingleSelectExample() {
|
|
700
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
701
|
+
|
|
702
|
+
return (
|
|
703
|
+
<SelectDropdown
|
|
704
|
+
placeholder="Select a subject"
|
|
705
|
+
selectedValues={selected}
|
|
706
|
+
onSelectionChange={setSelected}
|
|
707
|
+
options={[
|
|
708
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
709
|
+
{ label: 'English', value: 'english' },
|
|
710
|
+
{ label: 'Science', value: 'science' },
|
|
711
|
+
{ label: 'History', value: 'history' },
|
|
712
|
+
]}
|
|
713
|
+
/>
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
export default ControlledSingleSelectExample;
|
|
717
|
+
`.trim(),
|
|
718
|
+
},
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
}, [
|
|
722
|
+
'Fully controlled single-select. Providing `selectedValues` activates controlled mode — the component stops managing its own state.',
|
|
723
|
+
'You **must** update `selectedValues` in response to `onSelectionChange`, otherwise the dropdown will appear frozen.',
|
|
724
|
+
'Use this pattern when the selected value needs to be derived from, or synchronised with, external state.',
|
|
725
|
+
].join(' '));
|
|
726
|
+
export const ControlledOpen = withDescription({
|
|
727
|
+
render: ControlledOpenTemplate,
|
|
728
|
+
parameters: {
|
|
729
|
+
controls: { disable: true },
|
|
730
|
+
docs: {
|
|
731
|
+
source: {
|
|
732
|
+
language: 'tsx',
|
|
733
|
+
code: `
|
|
734
|
+
import { useState } from 'react';
|
|
735
|
+
import { SelectDropdown } from '@arbor-education/design-system.components';
|
|
736
|
+
|
|
737
|
+
function ControlledOpenExample() {
|
|
738
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
739
|
+
|
|
740
|
+
return (
|
|
741
|
+
<div>
|
|
742
|
+
<button type="button" onClick={() => setIsOpen(true)}>Open dropdown externally</button>
|
|
743
|
+
<SelectDropdown
|
|
744
|
+
placeholder="Select a subject"
|
|
745
|
+
open={isOpen}
|
|
746
|
+
onOpenChange={setIsOpen}
|
|
747
|
+
options={[
|
|
748
|
+
{ label: 'Mathematics', value: 'maths' },
|
|
749
|
+
{ label: 'English', value: 'english' },
|
|
750
|
+
{ label: 'Science', value: 'science' },
|
|
751
|
+
]}
|
|
752
|
+
onSelectionChange={(values) => {
|
|
753
|
+
console.log(values);
|
|
754
|
+
setIsOpen(false);
|
|
755
|
+
}}
|
|
756
|
+
/>
|
|
757
|
+
</div>
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
export default ControlledOpenExample;
|
|
761
|
+
`.trim(),
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
}, '`open` and `onOpenChange` let you control the dropdown visibility externally. Use when you need to open the dropdown programmatically — from a toolbar button, a keyboard shortcut, or after completing a validation step.');
|
|
766
|
+
export const InsideFormField = withDescription({
|
|
767
|
+
render: InsideFormFieldTemplate,
|
|
768
|
+
parameters: {
|
|
769
|
+
controls: { disable: true },
|
|
770
|
+
docs: {
|
|
771
|
+
source: {
|
|
772
|
+
language: 'tsx',
|
|
773
|
+
code: `
|
|
774
|
+
import { FormField } from '@arbor-education/design-system.components';
|
|
775
|
+
|
|
776
|
+
function InsideFormFieldExample() {
|
|
777
|
+
return (
|
|
778
|
+
<FormField
|
|
779
|
+
label="Year group"
|
|
780
|
+
id="year-group-field"
|
|
781
|
+
inputType="selectDropdown"
|
|
782
|
+
inputProps={{
|
|
783
|
+
placeholder: 'Select a year group',
|
|
157
784
|
options: [
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{ label: 'Option 2', value: 'option2', header: 'header2' },
|
|
164
|
-
{ label: 'Option 3', value: 'option3', header: 'header3' },
|
|
165
|
-
{ label: 'Option 4', value: 'option4', header: 'header4' },
|
|
166
|
-
{ label: 'Option 9', value: 'option9', header: 'header9' },
|
|
785
|
+
{ label: 'Year 7', value: 'year7' },
|
|
786
|
+
{ label: 'Year 8', value: 'year8' },
|
|
787
|
+
{ label: 'Year 9', value: 'year9' },
|
|
788
|
+
{ label: 'Year 10', value: 'year10' },
|
|
789
|
+
{ label: 'Year 11', value: 'year11' },
|
|
167
790
|
],
|
|
168
|
-
onSelectionChange: (
|
|
791
|
+
onSelectionChange: (values) => console.log(values),
|
|
792
|
+
}}
|
|
793
|
+
/>
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
export default InsideFormFieldExample;
|
|
797
|
+
`.trim(),
|
|
798
|
+
},
|
|
799
|
+
},
|
|
169
800
|
},
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
801
|
+
}, [
|
|
802
|
+
'The recommended way to use SelectDropdown in forms.',
|
|
803
|
+
'`FormField` with `inputType="selectDropdown"` provides an accessible `<label>` linked to the trigger,',
|
|
804
|
+
'and automatically wires `aria-invalid` and `aria-describedby` when `errorText` is set.',
|
|
805
|
+
'Pass SelectDropdown props via `inputProps`.',
|
|
806
|
+
].join(' '));
|
|
807
|
+
export const InsideFormFieldWithError = withDescription({
|
|
808
|
+
render: InsideFormFieldWithErrorTemplate,
|
|
809
|
+
parameters: {
|
|
810
|
+
controls: { disable: true },
|
|
811
|
+
docs: {
|
|
812
|
+
source: {
|
|
813
|
+
language: 'tsx',
|
|
814
|
+
code: `
|
|
815
|
+
import { FormField } from '@arbor-education/design-system.components';
|
|
816
|
+
|
|
817
|
+
function InsideFormFieldWithErrorExample() {
|
|
818
|
+
return (
|
|
819
|
+
<FormField
|
|
820
|
+
label="Year group"
|
|
821
|
+
id="year-group-error-field"
|
|
822
|
+
inputType="selectDropdown"
|
|
823
|
+
errorText="Please select a year group"
|
|
824
|
+
inputProps={{
|
|
825
|
+
placeholder: 'Select a year group',
|
|
174
826
|
options: [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
827
|
+
{ label: 'Year 7', value: 'year7' },
|
|
828
|
+
{ label: 'Year 8', value: 'year8' },
|
|
829
|
+
{ label: 'Year 9', value: 'year9' },
|
|
178
830
|
],
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
831
|
+
onSelectionChange: (values) => console.log(values),
|
|
832
|
+
}}
|
|
833
|
+
/>
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
export default InsideFormFieldWithErrorExample;
|
|
837
|
+
`.trim(),
|
|
838
|
+
},
|
|
839
|
+
},
|
|
182
840
|
},
|
|
183
|
-
}
|
|
184
|
-
|
|
841
|
+
}, [
|
|
842
|
+
'Error state via `FormField`. Setting `errorText` on `FormField` automatically passes `hasError`,',
|
|
843
|
+
'`aria-invalid`, and `aria-describedby` to the SelectDropdown, and renders the error message below the field.',
|
|
844
|
+
'This is the correct and recommended pattern for accessible form validation.',
|
|
845
|
+
].join(' '));
|
|
185
846
|
//# sourceMappingURL=SelectDropdown.stories.js.map
|