@hellobetterdigitalnz/betterui 0.0.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.
Files changed (230) hide show
  1. package/.editorconfig +17 -0
  2. package/.eslintrc.cjs +14 -0
  3. package/.storybook/main.ts +23 -0
  4. package/.storybook/preview.ts +17 -0
  5. package/README.md +30 -0
  6. package/index.html +13 -0
  7. package/package.json +45 -0
  8. package/public/image/table-image.png +0 -0
  9. package/public/vite.svg +1 -0
  10. package/src/App.tsx +30 -0
  11. package/src/Components/DataDisplay/Accordion/Accordion.stories.tsx +57 -0
  12. package/src/Components/DataDisplay/Accordion/Accordion.tsx +14 -0
  13. package/src/Components/DataDisplay/Accordion/AccordionContext.tsx +11 -0
  14. package/src/Components/DataDisplay/Accordion/AccordionContextInterface.tsx +8 -0
  15. package/src/Components/DataDisplay/Accordion/AccordionItem.tsx +62 -0
  16. package/src/Components/DataDisplay/Accordion/AccordionItemProps.tsx +12 -0
  17. package/src/Components/DataDisplay/Accordion/AccordionProps.tsx +8 -0
  18. package/src/Components/DataDisplay/Accordion/AccordionProvider.tsx +65 -0
  19. package/src/Components/DataDisplay/Accordion/AccordionProviderInterface.tsx +8 -0
  20. package/src/Components/DataDisplay/Accordion/accordion.module.scss +56 -0
  21. package/src/Components/DataDisplay/Badge/Badge.stories.tsx +44 -0
  22. package/src/Components/DataDisplay/Badge/Badge.tsx +32 -0
  23. package/src/Components/DataDisplay/Badge/BadgeProps.tsx +6 -0
  24. package/src/Components/DataDisplay/Badge/badge.module.scss +42 -0
  25. package/src/Components/DataDisplay/Cards/BannerCard/BannerCard.stories.tsx +26 -0
  26. package/src/Components/DataDisplay/Cards/BannerCard/BannerCard.tsx +47 -0
  27. package/src/Components/DataDisplay/Cards/BannerCard/BannerCardInterface.tsx +15 -0
  28. package/src/Components/DataDisplay/Cards/BannerCard/banner-card.scss +54 -0
  29. package/src/Components/DataDisplay/Cards/PathwayCard/PathwayCard.stories.tsx +31 -0
  30. package/src/Components/DataDisplay/Cards/PathwayCard/PathwayCard.tsx +53 -0
  31. package/src/Components/DataDisplay/Cards/PathwayCard/PathwayCardInterface.tsx +17 -0
  32. package/src/Components/DataDisplay/Cards/PathwayCard/pathway-card-stories.scss +3 -0
  33. package/src/Components/DataDisplay/Cards/PathwayCard/pathway-card.scss +62 -0
  34. package/src/Components/DataDisplay/Media/Media.tsx +26 -0
  35. package/src/Components/DataDisplay/Media/MediaProps.tsx +9 -0
  36. package/src/Components/DataDisplay/Media/media.scss +0 -0
  37. package/src/Components/DataDisplay/Modal/Modal.tsx +5 -0
  38. package/src/Components/DataDisplay/Modal/ModalActions.tsx +5 -0
  39. package/src/Components/DataDisplay/Modal/ModalActionsLeft.tsx +5 -0
  40. package/src/Components/DataDisplay/Modal/ModalActionsRight.tsx +5 -0
  41. package/src/Components/DataDisplay/Modal/ModalBody.tsx +5 -0
  42. package/src/Components/DataDisplay/Modal/ModalCurtain.tsx +5 -0
  43. package/src/Components/DataDisplay/Modal/ModalHeader.tsx +5 -0
  44. package/src/Components/DataDisplay/NotificationsBell/NotificationBell.stories.tsx +27 -0
  45. package/src/Components/DataDisplay/NotificationsBell/NotificationsBell.tsx +51 -0
  46. package/src/Components/DataDisplay/NotificationsBell/NotificationsBellProps.tsx +9 -0
  47. package/src/Components/DataDisplay/NotificationsBell/notificationBell.module.scss +48 -0
  48. package/src/Components/DataDisplay/NotificationsPanel/Notification.stories.tsx +128 -0
  49. package/src/Components/DataDisplay/NotificationsPanel/Notification.tsx +59 -0
  50. package/src/Components/DataDisplay/NotificationsPanel/NotificationProps.tsx +11 -0
  51. package/src/Components/DataDisplay/NotificationsPanel/NotificationsGroup.tsx +17 -0
  52. package/src/Components/DataDisplay/NotificationsPanel/NotificationsGroupProps.tsx +8 -0
  53. package/src/Components/DataDisplay/NotificationsPanel/NotificationsGroups.tsx +42 -0
  54. package/src/Components/DataDisplay/NotificationsPanel/NotificationsGroupsProps.tsx +7 -0
  55. package/src/Components/DataDisplay/NotificationsPanel/NotificationsHeader.tsx +27 -0
  56. package/src/Components/DataDisplay/NotificationsPanel/NotificationsHeaderProps.tsx +9 -0
  57. package/src/Components/DataDisplay/NotificationsPanel/NotificationsNone.tsx +11 -0
  58. package/src/Components/DataDisplay/NotificationsPanel/NotificationsPanel.tsx +8 -0
  59. package/src/Components/DataDisplay/NotificationsPanel/NotificationsPanelProps.tsx +7 -0
  60. package/src/Components/DataDisplay/NotificationsPanel/notificationPanel.module.scss +196 -0
  61. package/src/Components/DataDisplay/Tab/Tab.stories.tsx +72 -0
  62. package/src/Components/DataDisplay/Tab/Tab.tsx +20 -0
  63. package/src/Components/DataDisplay/Tab/TabBody.tsx +6 -0
  64. package/src/Components/DataDisplay/Tab/TabBodyContent.tsx +15 -0
  65. package/src/Components/DataDisplay/Tab/TabBodyContentProps.tsx +9 -0
  66. package/src/Components/DataDisplay/Tab/TabBodyProps.tsx +8 -0
  67. package/src/Components/DataDisplay/Tab/TabContext.tsx +9 -0
  68. package/src/Components/DataDisplay/Tab/TabContextProps.tsx +6 -0
  69. package/src/Components/DataDisplay/Tab/TabNav.tsx +6 -0
  70. package/src/Components/DataDisplay/Tab/TabNavItem.tsx +49 -0
  71. package/src/Components/DataDisplay/Tab/TabNavItemProps.tsx +9 -0
  72. package/src/Components/DataDisplay/Tab/TabNavProps.tsx +8 -0
  73. package/src/Components/DataDisplay/Tab/TabProps.tsx +8 -0
  74. package/src/Components/DataDisplay/Tab/tab.module.scss +35 -0
  75. package/src/Components/DataDisplay/Tab/tab.stories.scss +3 -0
  76. package/src/Components/DataDisplay/Table/Table.stories.tsx +64 -0
  77. package/src/Components/DataDisplay/Table/Table.tsx +10 -0
  78. package/src/Components/DataDisplay/Table/TableBody.tsx +13 -0
  79. package/src/Components/DataDisplay/Table/TableBodyProps.tsx +8 -0
  80. package/src/Components/DataDisplay/Table/TableCell.tsx +30 -0
  81. package/src/Components/DataDisplay/Table/TableCellAction.tsx +27 -0
  82. package/src/Components/DataDisplay/Table/TableCellActionProps.tsx +11 -0
  83. package/src/Components/DataDisplay/Table/TableCellProps.tsx +11 -0
  84. package/src/Components/DataDisplay/Table/TableCellWithDesc.tsx +21 -0
  85. package/src/Components/DataDisplay/Table/TableCellWithDescProps.tsx +9 -0
  86. package/src/Components/DataDisplay/Table/TableCellWithImage.tsx +39 -0
  87. package/src/Components/DataDisplay/Table/TableCellWithImageProps.tsx +10 -0
  88. package/src/Components/DataDisplay/Table/TableFooter.tsx +5 -0
  89. package/src/Components/DataDisplay/Table/TableHead.tsx +11 -0
  90. package/src/Components/DataDisplay/Table/TableHeadProps.tsx +8 -0
  91. package/src/Components/DataDisplay/Table/TableHeaderCell.tsx +17 -0
  92. package/src/Components/DataDisplay/Table/TableHeaderCellProps.tsx +10 -0
  93. package/src/Components/DataDisplay/Table/TableProps.tsx +8 -0
  94. package/src/Components/DataDisplay/Table/TableRow.tsx +9 -0
  95. package/src/Components/DataDisplay/Table/TableRowProps.tsx +8 -0
  96. package/src/Components/DataDisplay/Table/table.module.scss +103 -0
  97. package/src/Components/Form/Button/Button.stories.tsx +66 -0
  98. package/src/Components/Form/Button/Button.tsx +64 -0
  99. package/src/Components/Form/Button/ButtonProps.tsx +18 -0
  100. package/src/Components/Form/Button/button.module.scss +142 -0
  101. package/src/Components/Form/Checkbox/Checkbox.stories.tsx +49 -0
  102. package/src/Components/Form/Checkbox/Checkbox.tsx +85 -0
  103. package/src/Components/Form/Checkbox/CheckboxProps.tsx +22 -0
  104. package/src/Components/Form/Checkbox/checkbox.module.scss +63 -0
  105. package/src/Components/Form/CheckboxSelect/CheckboxSelect.tsx +5 -0
  106. package/src/Components/Form/CheckboxSelect/CheckboxSelectItem.tsx +5 -0
  107. package/src/Components/Form/CheckboxSet/CheckboxSet.stories.tsx +93 -0
  108. package/src/Components/Form/CheckboxSet/CheckboxSet.tsx +14 -0
  109. package/src/Components/Form/CheckboxSet/CheckboxSetItem.tsx +88 -0
  110. package/src/Components/Form/CheckboxSet/CheckboxSetProps.tsx +9 -0
  111. package/src/Components/Form/CheckboxSet/checkboxSet.module.scss +13 -0
  112. package/src/Components/Form/CurrencyField/CurrenctField.stories.tsx +22 -0
  113. package/src/Components/Form/CurrencyField/CurrencyField.tsx +59 -0
  114. package/src/Components/Form/CurrencyField/CurrencyFieldProps.tsx +8 -0
  115. package/src/Components/Form/DateField/DateField.stories.tsx +22 -0
  116. package/src/Components/Form/DateField/DateField.tsx +58 -0
  117. package/src/Components/Form/DropdownBadge/DropdownBadge.stories.tsx +49 -0
  118. package/src/Components/Form/DropdownBadge/DropdownBadge.tsx +160 -0
  119. package/src/Components/Form/DropdownBadge/DropdownBadgeItem.tsx +40 -0
  120. package/src/Components/Form/DropdownBadge/DropdownBadgeItemProps.tsx +10 -0
  121. package/src/Components/Form/DropdownBadge/DropdownBadgeProps.tsx +31 -0
  122. package/src/Components/Form/DropdownBadge/DropdownBadgeSelector.tsx +11 -0
  123. package/src/Components/Form/DropdownBadge/DropdownBadgeSelectorProps.tsx +7 -0
  124. package/src/Components/Form/DropdownBadge/dropdownBadge.module.scss +105 -0
  125. package/src/Components/Form/DropdownField/DropdownField.stories.tsx +50 -0
  126. package/src/Components/Form/DropdownField/DropdownField.tsx +118 -0
  127. package/src/Components/Form/DropdownField/DropdownFieldItem.tsx +26 -0
  128. package/src/Components/Form/DropdownField/DropdownFieldItemProps.tsx +9 -0
  129. package/src/Components/Form/DropdownField/DropdownFieldProps.tsx +33 -0
  130. package/src/Components/Form/DropdownField/DropdownFieldSelector.tsx +15 -0
  131. package/src/Components/Form/DropdownField/DropdownFieldSelectorProps.tsx +7 -0
  132. package/src/Components/Form/DropdownField/dropdown.module.scss +79 -0
  133. package/src/Components/Form/EmailField/EmailField.stories.ts +23 -0
  134. package/src/Components/Form/EmailField/EmailField.tsx +51 -0
  135. package/src/Components/Form/ErrorMessage/ErrorMessage.tsx +5 -0
  136. package/src/Components/Form/FormFieldHolder/FormFieldHolder.tsx +5 -0
  137. package/src/Components/Form/IconButton/IconButton.stories.tsx +45 -0
  138. package/src/Components/Form/IconButton/IconButton.tsx +58 -0
  139. package/src/Components/Form/IconButton/IconButtonProps.tsx +15 -0
  140. package/src/Components/Form/IconButton/iconButton.module.scss +111 -0
  141. package/src/Components/Form/InputProps.tsx +25 -0
  142. package/src/Components/Form/MultiSelectField/MultiSelectField.tsx +5 -0
  143. package/src/Components/Form/MultiSelectField/MultiSelectFieldItem.tsx +5 -0
  144. package/src/Components/Form/MultiSelectField/MultiSelectFieldTag.tsx +5 -0
  145. package/src/Components/Form/PasswordField/PasswordField.stories.tsx +22 -0
  146. package/src/Components/Form/PasswordField/PasswordField.tsx +70 -0
  147. package/src/Components/Form/RadioButtons/RadioButton.tsx +70 -0
  148. package/src/Components/Form/RadioButtons/RadioButtonProps.tsx +22 -0
  149. package/src/Components/Form/RadioButtons/RadioButtons.stories.tsx +64 -0
  150. package/src/Components/Form/RadioButtons/RadioButtons.tsx +18 -0
  151. package/src/Components/Form/RadioButtons/RadioButtonsProps.tsx +10 -0
  152. package/src/Components/Form/RadioButtons/radioButton.stories.scss +3 -0
  153. package/src/Components/Form/RadioButtons/radiobutton.module.scss +63 -0
  154. package/src/Components/Form/TextField/TextField.stories.ts +23 -0
  155. package/src/Components/Form/TextField/TextField.tsx +52 -0
  156. package/src/Components/Form/Textarea/Textarea.stories.ts +31 -0
  157. package/src/Components/Form/Textarea/Textarea.tsx +71 -0
  158. package/src/Components/Form/Textarea/TextareaProps.tsx +27 -0
  159. package/src/Components/Form/Textarea/textarea.module.scss +49 -0
  160. package/src/Components/Form/TimeField/TimeField.stories.tsx +22 -0
  161. package/src/Components/Form/TimeField/TimeField.tsx +58 -0
  162. package/src/Components/Form/ToggleSwitch/ToggleSwitch.stories.tsx +49 -0
  163. package/src/Components/Form/ToggleSwitch/ToggleSwitch.tsx +87 -0
  164. package/src/Components/Form/ToggleSwitch/ToggleSwitchProps.tsx +22 -0
  165. package/src/Components/Form/ToggleSwitch/toggleSwitch.module.scss +82 -0
  166. package/src/Components/Form/inputs.module.scss +121 -0
  167. package/src/Components/Icons/Arrows/CaretDown/CaretDown.tsx +49 -0
  168. package/src/Components/Icons/Arrows/CaretUp/CaretUp.tsx +49 -0
  169. package/src/Components/Icons/Commerce/CurrencyDollarSimple/CurrencyDollarSimple.tsx +105 -0
  170. package/src/Components/Icons/Communication/AddressBook/AddressBook.stories.ts +28 -0
  171. package/src/Components/Icons/Communication/AddressBook/AddressBook.tsx +50 -0
  172. package/src/Components/Icons/Communication/Asterick/Asterisk.stories.ts +28 -0
  173. package/src/Components/Icons/Communication/Asterick/Asterisk.tsx +50 -0
  174. package/src/Components/Icons/Communication/AsterickSimple/AsteriskSimple.stories.ts +28 -0
  175. package/src/Components/Icons/Communication/AsterickSimple/AsteriskSimple.tsx +49 -0
  176. package/src/Components/Icons/Communication/At/At.stories.ts +28 -0
  177. package/src/Components/Icons/Communication/At/At.tsx +49 -0
  178. package/src/Components/Icons/Communication/Broadcast/Broadcast.stories.ts +27 -0
  179. package/src/Components/Icons/Communication/Broadcast/Broadcast.tsx +49 -0
  180. package/src/Components/Icons/Communication/Chat/Chat.stories.ts +28 -0
  181. package/src/Components/Icons/Communication/Chat/Chat.tsx +49 -0
  182. package/src/Components/Icons/Design/Eye/Eye.tsx +105 -0
  183. package/src/Components/Icons/Design/EyeSlash/EyeSlash.tsx +105 -0
  184. package/src/Components/Icons/IconProps.tsx +5 -0
  185. package/src/Components/Icons/MathAndFinance/XIcon/XIcon.tsx +107 -0
  186. package/src/Components/Icons/SystemAndDevice/Bell/Bell.tsx +49 -0
  187. package/src/Components/Icons/Time/CalendarBank/CalendarBank.tsx +105 -0
  188. package/src/Components/Icons/Time/Clock/Clock.tsx +105 -0
  189. package/src/Components/Layout/CalloutPopup/CalloutPopup.tsx +5 -0
  190. package/src/Components/Layout/Header/Header.tsx +5 -0
  191. package/src/Components/Layout/Header/HeaderLeft.tsx +5 -0
  192. package/src/Components/Layout/Header/HeaderRight.tsx +5 -0
  193. package/src/Components/Layout/Pagination/Pagination.tsx +5 -0
  194. package/src/Components/Layout/Pagination/PaginationFirst.tsx +5 -0
  195. package/src/Components/Layout/Pagination/PaginationLast.tsx +5 -0
  196. package/src/Components/Layout/Pagination/PaginationNext.tsx +5 -0
  197. package/src/Components/Layout/Pagination/PaginationNumber.tsx +5 -0
  198. package/src/Components/Layout/Pagination/PaginationPrevious.tsx +5 -0
  199. package/src/Components/Layout/ProfileAvatar/ProfileAvatar.tsx +5 -0
  200. package/src/Components/Layout/ProfileAvatar/ProfileAvatarProps.tsx +4 -0
  201. package/src/Components/Layout/ProfileDropdown/ProfileDropdown.tsx +5 -0
  202. package/src/Components/Layout/ProfileDropdown/ProfileHeader.tsx +5 -0
  203. package/src/Components/Layout/ProfileDropdown/ProfileLink.tsx +5 -0
  204. package/src/Components/Layout/ProfileDropdown/ProfileLinks.tsx +5 -0
  205. package/src/Components/Layout/ProfileDropdown/ProfileNavigationItem.tsx +5 -0
  206. package/src/Components/Layout/ProfileDropdown/ProfileSwitchPanel.tsx +5 -0
  207. package/src/Components/Layout/ProfileDropdown/ProfileSwitchUser.tsx +5 -0
  208. package/src/Components/Layout/Sidebar/Sidebar.tsx +5 -0
  209. package/src/Components/Layout/Sidebar/SidebarChevron.tsx +5 -0
  210. package/src/Components/Layout/Sidebar/SidebarNavigation.tsx +5 -0
  211. package/src/Components/Layout/Sidebar/SidebarNavigationItem.tsx +5 -0
  212. package/src/Components/Layout/Sidebar/SidebarSubNavigation.tsx +5 -0
  213. package/src/Notification/Notification.tsx +83 -0
  214. package/src/Notification/NotificationInterface.tsx +9 -0
  215. package/src/Notification/NotificationList.tsx +29 -0
  216. package/src/Notification/NotificationListHolder.tsx +14 -0
  217. package/src/Notification/NotificationListHolderInterface.tsx +8 -0
  218. package/src/Notification/NotificationListInterface.tsx +11 -0
  219. package/src/Notification/notification.scss +225 -0
  220. package/src/global.scss +231 -0
  221. package/src/main.tsx +9 -0
  222. package/src/variables.scss +2 -0
  223. package/src/vite-env.d.ts +1 -0
  224. package/tokens/color/color.mdx +82 -0
  225. package/tokens/shadow/shadow-panel.scss +12 -0
  226. package/tokens/shadow/shadow.mdx +34 -0
  227. package/tokens/typography/typography.mdx +31 -0
  228. package/tsconfig.json +25 -0
  229. package/tsconfig.node.json +10 -0
  230. package/vite.config.ts +7 -0
@@ -0,0 +1,22 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+
3
+ import DataField from "./DateField";
4
+
5
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
6
+ const meta = {
7
+ title: "Form / DataField",
8
+ component: DataField,
9
+ parameters: {
10
+ layout: "centered",
11
+ },
12
+ tags: ["autodocs"],
13
+ } satisfies Meta<typeof DataField>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof DataField>;
17
+
18
+ export const Example: Story = {
19
+ args: {
20
+ placeholder: "Placeholder",
21
+ },
22
+ };
@@ -0,0 +1,58 @@
1
+ import cx from "classnames";
2
+ import InputProps from "../InputProps";
3
+ import styles from "../inputs.module.scss";
4
+ import CalendarBank from "../../Icons/Time/CalendarBank/CalendarBank";
5
+
6
+ const DateField = (props: InputProps) => {
7
+ const {
8
+ name,
9
+ id,
10
+ value,
11
+ placeholder,
12
+ extraClass,
13
+ disabled,
14
+ error,
15
+ ariaLabel,
16
+ required,
17
+ readonly,
18
+ autoComplete,
19
+ ...args
20
+ } = props;
21
+
22
+ const classes = [styles.input];
23
+ if (error) {
24
+ classes.push(styles.error);
25
+ }
26
+ if (extraClass) {
27
+ classes.push(extraClass);
28
+ }
29
+
30
+ return (
31
+ <div className={styles.date}>
32
+ <input
33
+ className={cx(classes)}
34
+ id={id}
35
+ name={name}
36
+ type="date"
37
+ value={value}
38
+ placeholder="YYYY-MM-DD"
39
+ disabled={disabled}
40
+ readOnly={readonly}
41
+ required={required}
42
+ autoComplete={autoComplete ? "on" : "off"}
43
+ aria-label={ariaLabel ? ariaLabel : name}
44
+ aria-required={required ? "true" : "false"}
45
+ aria-invalid={error ? "true" : "false"}
46
+ aria-disabled={disabled ? "true" : "false"}
47
+ aria-readonly={readonly ? "true" : "false"}
48
+ aria-autocomplete={autoComplete ? "list" : "none"}
49
+ {...args}
50
+ />
51
+ <div className={styles.calendarIcon}>
52
+ <CalendarBank type="light" />
53
+ </div>
54
+ </div>
55
+ );
56
+ };
57
+
58
+ export default DateField;
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import DropdownField from "./DropdownBadge";
3
+ import { NameValueInterface } from "./DropdownBadgeProps";
4
+
5
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
6
+ const meta = {
7
+ title: "Form / Dropdown Badge",
8
+ component: DropdownField,
9
+ parameters: {
10
+ layout: "centered",
11
+ },
12
+ tags: ["autodocs"],
13
+ } satisfies Meta<typeof DropdownField>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof DropdownField>;
17
+
18
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
19
+
20
+ export const Default: Story = {
21
+ args: {
22
+ name: "dropdown-badge",
23
+ options: [
24
+ {
25
+ label: "Pending",
26
+ value: 1,
27
+ status: "pending",
28
+ },
29
+
30
+ {
31
+ label: "In Progress",
32
+ value: 2,
33
+ status: "inProgress",
34
+ },
35
+ {
36
+ label: "Complete",
37
+ value: 3,
38
+ status: "complete",
39
+ },
40
+ ] as NameValueInterface[],
41
+ },
42
+ };
43
+
44
+ export const Withoutstatus: Story = {
45
+ args: {
46
+ name: "dropdown-badge",
47
+ options: ["Pending", "In Progress", "Complete"],
48
+ },
49
+ };
@@ -0,0 +1,160 @@
1
+ import cx from "classnames";
2
+ import { useEffect, useState, MouseEvent } from "react";
3
+ import DropdownBadgeProps, { NameValueInterface } from "./DropdownBadgeProps";
4
+ import styles from "./dropdownBadge.module.scss";
5
+ import CaretDown from "../../Icons/Arrows/CaretDown/CaretDown";
6
+ import CaretUp from "../../Icons/Arrows/CaretUp/CaretUp";
7
+ import DropdownBadgeSelector from "./DropdownBadgeSelector";
8
+ import DropdownBadgeItem from "./DropdownBadgeItem";
9
+
10
+ const DropdownBadge = (props: DropdownBadgeProps) => {
11
+ const {
12
+ name,
13
+ id,
14
+ value,
15
+ options,
16
+ extraClass,
17
+ ariaLabel,
18
+ required,
19
+ status,
20
+ // onClick,
21
+ // readonly,
22
+ onChange,
23
+ // ...args
24
+ } = props;
25
+
26
+ const [opened, setOpened] = useState(false);
27
+ const [selected, setSelected] = useState<string | number>();
28
+ const [label, setLabel] = useState("");
29
+ const [statusClass, setStatusClass] = useState("");
30
+
31
+ useEffect(() => {
32
+ setSelected(value);
33
+ }, [value]);
34
+
35
+ const getStatusClass = (
36
+ status: "pending" | "inProgress" | "complete" | undefined
37
+ ) => {
38
+ switch (status) {
39
+ case "pending":
40
+ return styles.circlePending;
41
+ case "inProgress":
42
+ return styles.circleInProgress;
43
+ case "complete":
44
+ return styles.circleComplete;
45
+ default:
46
+ return "";
47
+ }
48
+ };
49
+
50
+ useEffect(() => {
51
+ const defaultOption = options[0];
52
+
53
+ if (defaultOption) {
54
+ setSelected(
55
+ typeof defaultOption === "object" ? defaultOption.value : defaultOption
56
+ );
57
+
58
+ if (typeof defaultOption === "object") {
59
+ setLabel(defaultOption.label || "");
60
+ setStatusClass(
61
+ defaultOption.status ? getStatusClass(defaultOption.status) : ""
62
+ );
63
+ }
64
+ }
65
+ }, [value, options]);
66
+
67
+ useEffect(() => {
68
+ // selected or status has changed, find the right value;
69
+ for (const option of options) {
70
+ let matched = null;
71
+ if (typeof option === "string") {
72
+ matched = option === selected ? option : null;
73
+ } else {
74
+ matched = option.value === selected ? option.label : null;
75
+ }
76
+ if (matched) {
77
+ setLabel(matched);
78
+
79
+ if (typeof option === "object" && option.status) {
80
+ setStatusClass(getStatusClass(option.status));
81
+ } else {
82
+ setStatusClass("");
83
+ }
84
+ break;
85
+ }
86
+ }
87
+ }, [selected, options, status]);
88
+
89
+ const classNames = [styles.dropdown];
90
+ if (extraClass) {
91
+ classNames.push(extraClass);
92
+ }
93
+
94
+ const handleOpenClose = () => {
95
+ setOpened(!opened);
96
+ };
97
+
98
+ const handleSelect = (e: MouseEvent, value: string | number) => {
99
+ setSelected(value);
100
+ setOpened(false);
101
+ if (onChange) {
102
+ onChange(e);
103
+ }
104
+ };
105
+
106
+ return (
107
+ <div className={cx(classNames)}>
108
+ <div className={styles.control} onClick={handleOpenClose}>
109
+ {selected && (
110
+ <div className={styles.labelWrapper}>
111
+ {label && statusClass && (
112
+ <div className={cx(styles.circle, statusClass)}></div>
113
+ )}
114
+ <div className={styles.label} aria-label={ariaLabel}>
115
+ {label}
116
+ {!!selected && <div className={styles.reset}></div>}
117
+ </div>
118
+ </div>
119
+ )}
120
+ <div className={styles.divider}></div>
121
+ <div className={styles.chevron}>
122
+ {!opened && <CaretDown />}
123
+ {!!opened && <CaretUp />}
124
+ </div>
125
+ </div>
126
+
127
+ {!!opened && (
128
+ <DropdownBadgeSelector>
129
+ {options.map((option: string | NameValueInterface, index: number) => (
130
+ <DropdownBadgeItem
131
+ key={index}
132
+ handleSelect={handleSelect}
133
+ status={
134
+ typeof option === "object"
135
+ ? (option.status as
136
+ | "pending"
137
+ | "inProgress"
138
+ | "complete"
139
+ | undefined)
140
+ : undefined
141
+ }
142
+ label={typeof option === "object" ? option.label : option}
143
+ value={typeof option === "object" ? option.value : option}
144
+ />
145
+ ))}
146
+ </DropdownBadgeSelector>
147
+ )}
148
+
149
+ <input
150
+ name={name}
151
+ value={selected}
152
+ id={id}
153
+ type={"hidden"}
154
+ required={required}
155
+ />
156
+ </div>
157
+ );
158
+ };
159
+
160
+ export default DropdownBadge;
@@ -0,0 +1,40 @@
1
+ import cx from "classnames";
2
+ import DropdownBadgeItemProps from "./DropdownBadgeItemProps";
3
+ import styles from "./dropdownBadge.module.scss";
4
+ import { MouseEvent } from "react";
5
+
6
+ const DropdownBadgeItem = (props: DropdownBadgeItemProps) => {
7
+ const { label, value, status, handleSelect } = props;
8
+
9
+ let statusClass;
10
+ if (status === "pending") {
11
+ statusClass = styles.circlePending;
12
+ }
13
+
14
+ if (status === "inProgress") {
15
+ statusClass = styles.circleInProgress;
16
+ }
17
+ if (status === "complete") {
18
+ statusClass = styles.circleComplete;
19
+ }
20
+
21
+ return (
22
+ <div
23
+ className={styles.dropdownItem}
24
+ data-value={value}
25
+ aria-label={label}
26
+ onClick={(e: MouseEvent) => {
27
+ if (handleSelect) {
28
+ handleSelect(e, value);
29
+ }
30
+ }}
31
+ >
32
+ {label && statusClass && (
33
+ <div className={cx(styles.circle, statusClass)}></div>
34
+ )}
35
+ {label}
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default DropdownBadgeItem;
@@ -0,0 +1,10 @@
1
+ import { MouseEvent } from "react";
2
+
3
+ interface DropdownBadgeItemProps {
4
+ label: string;
5
+ value: string | number;
6
+ status?: "pending" | "inProgress" | "complete";
7
+ handleSelect: (e: MouseEvent, value: string | number) => void;
8
+ }
9
+
10
+ export default DropdownBadgeItemProps;
@@ -0,0 +1,31 @@
1
+ import { MouseEvent, FocusEvent } from "react";
2
+
3
+ interface NameValueInterface {
4
+ label: string;
5
+ status?: "pending" | "inProgress" | "complete" | undefined;
6
+ value: string | number;
7
+ }
8
+
9
+ interface DropdownBadgeProps {
10
+ name?: string;
11
+ id?: string;
12
+ value?: string;
13
+ options: (NameValueInterface | string)[];
14
+ status?: "pending" | "inProgress" | "complete" | undefined;
15
+ extraClass?: string;
16
+ disabled?: boolean;
17
+ readonly?: boolean;
18
+ autoComplete?: boolean;
19
+ required?: boolean;
20
+ ariaLabel?: string;
21
+ ariaLabeledby?: string;
22
+ ariaDescribedby?: string;
23
+ onClick?: (e: MouseEvent) => void;
24
+ onChange?: (e: MouseEvent) => void;
25
+ onFocus?: (e: FocusEvent) => void;
26
+ onBlur?: (e: FocusEvent) => void;
27
+ }
28
+
29
+ export type { NameValueInterface };
30
+
31
+ export default DropdownBadgeProps;
@@ -0,0 +1,11 @@
1
+ import cx from "classnames";
2
+ import styles from "./dropdownBadge.module.scss";
3
+ import DropdownBadgeSelectorProps from "./DropdownBadgeSelectorProps";
4
+
5
+ const DropdownBadgeSelector = (props: DropdownBadgeSelectorProps) => {
6
+ const classes = [styles.dropdownSelector];
7
+
8
+ return <div className={cx(classes)}>{props.children}</div>;
9
+ };
10
+
11
+ export default DropdownBadgeSelector;
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from "react";
2
+
3
+ interface DropdownBadgeSelectorProps {
4
+ children: ReactNode;
5
+ }
6
+
7
+ export default DropdownBadgeSelectorProps;
@@ -0,0 +1,105 @@
1
+ .dropdown {
2
+ position: relative;
3
+
4
+ .control {
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: space-between;
8
+ width: 100%;
9
+ height: 24px;
10
+ padding: 0 var(--spacing-1\/2);
11
+ border: 1px solid var(--color-gray-300);
12
+ border-radius: 6px;
13
+ font-family: var(--font);
14
+ font-size: var(--font-size-body-sm);
15
+ line-height: var(--line-height-body-sm);
16
+ font-weight: var(--font-weight-body-sm);
17
+ cursor: pointer;
18
+ }
19
+
20
+ .disabled {
21
+ cursor: not-allowed;
22
+ opacity: 0.3;
23
+ pointer-events: none;
24
+ }
25
+
26
+ .labelWrapper {
27
+ display: flex;
28
+ align-items: center;
29
+ }
30
+
31
+ .label {
32
+ flex-grow: 1;
33
+ white-space: nowrap;
34
+ text-overflow: ellipsis;
35
+ overflow: hidden;
36
+ padding-right: calc(var(--space-unit) * 2);
37
+ }
38
+
39
+ .chevron {
40
+ width: 12px;
41
+ height: 12px;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ flex-shrink: 0;
46
+ margin-left: calc(var(--space-unit) * 2);
47
+
48
+ svg {
49
+ width: 100%;
50
+ height: auto;
51
+ }
52
+ }
53
+ }
54
+
55
+ .dropdownSelector {
56
+ width: 100%;
57
+ display: flex;
58
+ flex-direction: column;
59
+ position: absolute;
60
+ padding: calc(var(--space-unit) * 2) 0;
61
+ border-radius: 4px;
62
+ background-color: var(--color-white);
63
+ box-shadow: var(--drop-shadow-default);
64
+ margin-top: var(--space-unit);
65
+ }
66
+
67
+ .dropdownItem {
68
+ display: flex;
69
+ align-items: center;
70
+ padding: calc(var(--space-unit) * 2);
71
+ cursor: pointer;
72
+
73
+ &.active,
74
+ &:hover {
75
+ background-color: var(--color-gray-50);
76
+ }
77
+ }
78
+
79
+ .circle {
80
+ width: 12px;
81
+ height: 12px;
82
+ border-radius: 100%;
83
+ flex-shrink: 0;
84
+ margin-right: 6px;
85
+
86
+ &Pending {
87
+ background: var(--color-gray-300);
88
+ }
89
+
90
+ &InProgress {
91
+ background: var(--color-inprogress);
92
+ }
93
+
94
+ &Complete {
95
+ background: var(--color-success);
96
+ }
97
+ }
98
+
99
+ .divider {
100
+ display: flex;
101
+ align-items: stretch;
102
+ height: 100%;
103
+ width: 1px;
104
+ background: var(--color-gray-300);
105
+ }
@@ -0,0 +1,50 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import DropdownField from "./DropdownField";
3
+ import {NameValueInterface} from "./DropdownFieldProps";
4
+
5
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
6
+ const meta = {
7
+ title: 'Form / Dropdown Field',
8
+ component: DropdownField,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ tags: ['autodocs'],
13
+ } satisfies Meta<typeof DropdownField>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof DropdownField>;
17
+
18
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
19
+ export const Default: Story = {
20
+ args: {
21
+ name: 'dropdown-field',
22
+ placeholder: 'Super long placeholder text',
23
+ options: [
24
+ 'Lorem ipsum',
25
+ 'Suspendisse sit amet',
26
+ 'In sagittis metus'
27
+ ]
28
+ },
29
+ };
30
+
31
+ export const Props: Story = {
32
+ args: {
33
+ name: 'dropdown-field',
34
+ placeholder: 'Placeholder text',
35
+ options: [
36
+ {
37
+ label: 'Lorem ipsum',
38
+ value: 1
39
+ },
40
+ {
41
+ label: 'In sagittis metus',
42
+ value: 2
43
+ },
44
+ {
45
+ label: 'Suspendisse potenti',
46
+ value: 3
47
+ },
48
+ ] as NameValueInterface[]
49
+ },
50
+ };
@@ -0,0 +1,118 @@
1
+ import cx from "classnames";
2
+ import DropdownFieldProps, { NameValueInterface } from "./DropdownFieldProps";
3
+ import styles from "./dropdown.module.scss";
4
+ import { useEffect, useState, MouseEvent } from "react";
5
+ import CaretDown from "../../Icons/Arrows/CaretDown/CaretDown";
6
+ import CaretUp from "../../Icons/Arrows/CaretUp/CaretUp";
7
+ import DropdownFieldSelector from "./DropdownFieldSelector";
8
+ import DropdownFieldItem from "./DropdownFieldItem";
9
+
10
+ const DropdownField = (props: DropdownFieldProps) => {
11
+ const {
12
+ name,
13
+ id,
14
+ value,
15
+ options,
16
+ placeholder,
17
+ extraClass,
18
+ disabled,
19
+ // error,
20
+ ariaLabel,
21
+ required,
22
+ // onClick,
23
+ // readonly,
24
+ onChange,
25
+ // ...args
26
+ } = props;
27
+
28
+ const [opened, setOpened] = useState(false);
29
+ const [selected, setSelected] = useState<string | number>();
30
+ const [label, setLabel] = useState("");
31
+
32
+ useEffect(() => {
33
+ setSelected(value);
34
+ }, [value]);
35
+
36
+ useEffect(() => {
37
+ // selected has changed, find the right value;
38
+ for (const option of options) {
39
+ let matched = null;
40
+ if (typeof option === "string") {
41
+ matched = option === selected ? option : null;
42
+ } else {
43
+ matched = option.value === selected ? option.label : null;
44
+ }
45
+ if (matched) {
46
+ setLabel(matched);
47
+ break;
48
+ }
49
+ }
50
+ }, [selected]);
51
+
52
+ const classNames = [styles.dropdown];
53
+ if (extraClass) {
54
+ classNames.push(extraClass);
55
+ }
56
+ if (disabled) {
57
+ classNames.push(styles.disabled);
58
+ }
59
+
60
+ const handleOpenClose = () => {
61
+ setOpened(!opened);
62
+ };
63
+
64
+ const handleSelect = (e: MouseEvent, value: string | number) => {
65
+ setSelected(value);
66
+ setOpened(false);
67
+ if (onChange) {
68
+ onChange(e);
69
+ }
70
+ };
71
+
72
+ return (
73
+ <div className={cx(classNames)}>
74
+ <div className={styles.control} onClick={handleOpenClose}>
75
+ {!selected && placeholder && (
76
+ <div className={styles.placeholder} aria-label={ariaLabel}>
77
+ {placeholder}
78
+ </div>
79
+ )}
80
+ {(selected || !placeholder) && (
81
+ <div className={styles.label} aria-label={ariaLabel}>
82
+ {label}
83
+ {!!selected && <div className={styles.reset}></div>}
84
+ </div>
85
+ )}
86
+ <div className={styles.chevron}>
87
+ {!opened && <CaretDown />}
88
+ {!!opened && <CaretUp />}
89
+ </div>
90
+ </div>
91
+
92
+ {!!opened && (
93
+ <DropdownFieldSelector>
94
+ {options.map((option: string | NameValueInterface, index: number) => {
95
+ return (
96
+ <DropdownFieldItem
97
+ key={index}
98
+ handleSelect={handleSelect}
99
+ label={typeof option === "object" ? option.label : option}
100
+ value={typeof option === "object" ? option.value : option}
101
+ />
102
+ );
103
+ })}
104
+ </DropdownFieldSelector>
105
+ )}
106
+
107
+ <input
108
+ name={name}
109
+ value={selected}
110
+ id={id}
111
+ type={"hidden"}
112
+ required={required}
113
+ />
114
+ </div>
115
+ );
116
+ };
117
+
118
+ export default DropdownField;
@@ -0,0 +1,26 @@
1
+ import DropdownFieldItemProps from "./DropdownFieldItemProps";
2
+ import styles from './dropdown.module.scss'
3
+ import {MouseEvent} from "react";
4
+
5
+ const DropdownFieldItem = (props: DropdownFieldItemProps) => {
6
+ const {
7
+ label,
8
+ value,
9
+ handleSelect
10
+ } = props;
11
+
12
+ return <div
13
+ className={styles.dropdownItem}
14
+ data-value={value} aria-label={label}
15
+ onClick={(e: MouseEvent) => {
16
+ if (handleSelect) {
17
+ handleSelect(e, value);
18
+ }
19
+ }}
20
+ >
21
+ {label}
22
+ </div>
23
+
24
+ }
25
+
26
+ export default DropdownFieldItem;