@thecb/components 10.12.2-beta.0 → 10.12.3-beta.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/README.md +4 -0
- package/dist/index.cjs.js +1476 -2489
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.esm.js +1476 -2488
- package/dist/index.esm.js.map +1 -1
- package/package.json +25 -13
- package/src/components/atoms/.DS_Store +0 -0
- package/src/components/atoms/alert/Alert.mdx +19 -0
- package/src/components/atoms/alert/Alert.stories.js +148 -26
- package/src/components/atoms/badge/Badge.js +2 -2
- package/src/components/atoms/badge/Badge.mdx +27 -0
- package/src/components/atoms/badge/Badge.stories.js +143 -29
- package/src/components/atoms/breadcrumb/Breadcrumb.mdx +21 -0
- package/src/components/atoms/breadcrumb/Breadcrumb.stories.js +38 -29
- package/src/components/atoms/button-with-action/ButtonWithAction.stories.js +108 -55
- package/src/components/atoms/button-with-link/ButtonWithLink.mdx +21 -0
- package/src/components/atoms/button-with-link/ButtonWithLink.stories.js +160 -31
- package/src/components/atoms/card/Card.js +13 -1
- package/src/components/atoms/card/Card.mdx +41 -0
- package/src/components/atoms/card/Card.stories.js +360 -0
- package/src/components/atoms/card/Card.theme.js +2 -0
- package/src/components/atoms/card/index.d.ts +1 -0
- package/src/components/atoms/checkbox/Checkbox.js +8 -14
- package/src/components/atoms/checkbox/Checkbox.mdx +15 -0
- package/src/components/atoms/checkbox/Checkbox.oldstories.js +30 -0
- package/src/components/atoms/checkbox/Checkbox.stories.js +148 -29
- package/src/components/atoms/country-dropdown/CountryDropdown.mdx +36 -0
- package/src/components/atoms/country-dropdown/CountryDropdown.stories.js +61 -27
- package/src/components/atoms/detail/Detail.js +0 -26
- package/src/components/atoms/detail/Detail.mdx +32 -0
- package/src/components/atoms/detail/Detail.stories.js +156 -0
- package/src/components/atoms/display-box/DisplayBox.mdx +11 -0
- package/src/components/atoms/display-box/DisplayBox.stories.js +65 -21
- package/src/components/atoms/display-card/DisplayCard.mdx +13 -0
- package/src/components/atoms/display-card/DisplayCard.stories.js +163 -22
- package/src/components/atoms/dropdown/Dropdown.mdx +65 -0
- package/src/components/atoms/dropdown/Dropdown.stories.js +91 -10
- package/src/components/atoms/form-layouts/FormInput.mdx +38 -0
- package/src/components/atoms/form-layouts/FormInput.stories.js +212 -26
- package/src/components/atoms/form-select/FormSelect.mdx +42 -0
- package/src/components/atoms/form-select/FormSelect.stories.js +55 -29
- package/src/components/atoms/formatted-address/FormattedAddress.mdx +13 -0
- package/src/components/atoms/formatted-address/FormattedAddress.stories.js +133 -27
- package/src/components/atoms/formatted-bank-account/FormattedBankAccount.mdx +17 -0
- package/src/components/atoms/formatted-bank-account/FormattedBankAccount.stories.js +57 -0
- package/src/components/atoms/formatted-credit-card/FormattedCreditCard.mdx +40 -0
- package/src/components/atoms/formatted-credit-card/FormattedCreditCard.stories.js +74 -0
- package/src/components/atoms/icons/Icons.mdx +40 -0
- package/src/components/atoms/icons/Icons.stories.js +325 -0
- package/src/components/atoms/icons/index.js +1 -5
- package/src/components/atoms/labeled-amount/LabeledAmount.mdx +23 -0
- package/src/components/atoms/labeled-amount/LabeledAmount.stories.js +110 -34
- package/src/components/atoms/line-item/LineItem.mdx +28 -0
- package/src/components/atoms/line-item/LineItem.stories.js +89 -22
- package/src/components/atoms/link/Link.mdx +19 -0
- package/src/components/atoms/link/Link.stories.js +155 -49
- package/src/components/atoms/loading/Loading.mdx +13 -0
- package/src/components/atoms/loading/Loading.stories.js +22 -0
- package/src/components/atoms/loading-line/LoadingLine.js +14 -10
- package/src/components/atoms/loading-line/LoadingLine.mdx +15 -0
- package/src/components/atoms/loading-line/LoadingLine.stories.js +132 -28
- package/src/components/atoms/nav-footer/NavFooter.mdx +15 -0
- package/src/components/atoms/nav-footer/NavFooter.stories.js +235 -22
- package/src/components/atoms/nav-header/NavHeader.mdx +13 -0
- package/src/components/atoms/nav-header/NavHeader.stories.js +122 -21
- package/src/components/atoms/nav-tabs/NavTabs.mdx +30 -0
- package/src/components/atoms/nav-tabs/NavTabs.stories.js +49 -0
- package/src/components/atoms/password-requirements/PasswordRequirements.mdx +39 -0
- package/src/components/atoms/password-requirements/PasswordRequirements.stories.js +108 -44
- package/src/components/atoms/placeholder/Placeholder.mdx +19 -0
- package/src/components/atoms/placeholder/Placeholder.stories.js +164 -36
- package/src/components/atoms/searchable-select/SearchableSelect.mdx +44 -0
- package/src/components/atoms/searchable-select/SearchableSelect.stories.js +103 -28
- package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.mdx +36 -0
- package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.stories.js +65 -40
- package/src/components/atoms/table/Table.mdx +71 -0
- package/src/components/atoms/table/Table.oldstories.js +84 -0
- package/src/components/atoms/table/Table.stories.js +59 -75
- package/src/components/atoms/table/TableRow.js +1 -0
- package/src/components/atoms/title/Title.js +0 -23
- package/src/components/atoms/title/Title.mdx +26 -0
- package/src/components/atoms/title/Title.stories.js +144 -0
- package/src/components/atoms/toggle-switch/ToggleSwitch.mdx +17 -0
- package/src/components/atoms/toggle-switch/ToggleSwitch.stories.js +103 -20
- package/src/components/atoms/toggle-switch/ToggleSwitch.theme.js +8 -5
- package/src/components/atoms/typeahead-input/TypeaheadInput.mdx +13 -0
- package/src/components/atoms/typeahead-input/TypeaheadInput.stories.js +63 -0
- package/src/components/molecules/address-form/AddressForm.mdx +18 -0
- package/src/components/molecules/address-form/AddressForm.stories.js +223 -20
- package/src/components/molecules/banner/Banner.mdx +23 -0
- package/src/components/molecules/banner/Banner.stories.js +122 -26
- package/src/components/molecules/change-password-form/ChangePasswordForm.mdx +15 -0
- package/src/components/molecules/change-password-form/ChangePasswordForm.stories.js +203 -19
- package/src/components/molecules/collapsible-section/CollapsibleSection.mdx +15 -0
- package/src/components/molecules/collapsible-section/CollapsibleSection.stories.js +210 -61
- package/src/components/molecules/edit-name-form/EditNameForm.mdx +13 -0
- package/src/components/molecules/edit-name-form/EditNameForm.stories.js +117 -0
- package/src/components/molecules/idle-modal/IdleModal.js +101 -0
- package/src/components/molecules/idle-modal/IdleModal.mdx +17 -0
- package/src/components/molecules/idle-modal/IdleModal.stories.js +180 -0
- package/src/components/molecules/idle-modal/index.d.ts +16 -0
- package/src/components/molecules/idle-modal/index.js +3 -0
- package/src/components/molecules/index.js +1 -0
- package/src/components/molecules/link-card/LinkCard.mdx +17 -0
- package/src/components/molecules/link-card/LinkCard.stories.js +287 -72
- package/src/components/molecules/login-form/LoginForm.mdx +16 -0
- package/src/components/molecules/login-form/LoginForm.stories.js +117 -21
- package/src/components/molecules/modal/Modal.mdx +17 -0
- package/src/components/molecules/modal/Modal.stories.js +342 -128
- package/src/components/molecules/module/Module.mdx +17 -0
- package/src/components/molecules/module/Module.stories.js +267 -25
- package/src/components/molecules/multiple-select-filter/MultipleSelectFilter.js +309 -77
- package/src/components/molecules/multiple-select-filter/{MultipleSelectFilter.stories.js → MultipleSelectFilter.oldstories.js} +4 -2
- package/src/components/molecules/multiple-select-filter/MultipleSelectFilter.styled.js +6 -6
- package/src/components/molecules/multiple-select-filter/index.d.ts +2 -2
- package/src/components/molecules/obligation/Obligation.mdx +23 -0
- package/src/components/molecules/obligation/Obligation.stories.js +460 -0
- package/src/components/molecules/obligation/icons/PropertyPersonalIcon.js +1 -1
- package/src/components/molecules/pagination/Pagination.mdx +15 -0
- package/src/components/molecules/pagination/Pagination.stories.js +177 -28
- package/src/components/molecules/popover/Popover.mdx +15 -0
- package/src/components/molecules/popover/Popover.stories.js +220 -0
- package/src/components/molecules/tabs/Tabs.mdx +17 -0
- package/src/components/molecules/tabs/Tabs.stories.js +135 -227
- package/src/components/molecules/toast-notification/Toast.mdx +15 -0
- package/src/components/molecules/toast-notification/Toast.stories.js +183 -0
- package/src/hooks/use-outside-click/index.js +5 -4
- package/src/stories/Button.stories.ts +53 -0
- package/src/stories/Button.tsx +48 -0
- package/src/stories/Configure.mdx +364 -0
- package/src/stories/Header.stories.ts +33 -0
- package/src/stories/Header.tsx +56 -0
- package/src/stories/Page.stories.ts +32 -0
- package/src/stories/Page.tsx +73 -0
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +5 -0
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +15 -0
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +3 -0
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +12 -0
- package/src/stories/assets/youtube.svg +4 -0
- package/src/stories/button.css +30 -0
- package/src/stories/header.css +32 -0
- package/src/stories/page.css +69 -0
- package/src/util/idleTimerUtils.js +36 -0
- package/src/util/index.js +3 -1
- package/src/components/atoms/icons/CheckboxCheckmarkIcon.js +0 -45
- package/src/components/atoms/icons/PaymentStatusIcon.d.ts +0 -1
- package/src/components/atoms/icons/PaymentStatusIcon.js +0 -28
- package/src/components/atoms/icons/PersonIcon.d.ts +0 -1
- package/src/components/atoms/icons/PersonIcon.js +0 -28
- package/src/components/atoms/icons/icons.stories.js +0 -120
- package/src/components/molecules/edit-name-form/EdidNameForm.stories.js +0 -24
- package/src/components/molecules/multiple-select-filter/__private__/ActionLinkButton.js +0 -27
- package/src/components/molecules/multiple-select-filter/__private__/FilterButton.js +0 -89
- package/src/components/molecules/multiple-select-filter/__private__/FilterDropdown.js +0 -27
- package/src/components/molecules/multiple-select-filter/__private__/FilterableList.js +0 -146
- package/src/components/molecules/multiple-select-filter/__private__/FilterableListItem.js +0 -79
- package/src/components/molecules/multiple-select-filter/__private__/SearchBox.js +0 -41
- package/src/components/molecules/multiple-select-filter/__private__/useKeyboardNavigation.js +0 -84
- package/src/components/molecules/multiple-select-filter/__private__/util.js +0 -31
- package/src/components/molecules/toast-notification/ToastNotification.stories.js +0 -105
- /package/src/components/atoms/add-obligation/{AddObligation.stories.js → AddObligation.oldstories.js} +0 -0
- /package/src/components/atoms/amount-callout/{AmountCallout.stories.js → AmountCallout.oldstories.js} +0 -0
- /package/src/components/atoms/checkbox-list/{CheckboxList.stories.js → CheckboxList.oldstories.js} +0 -0
- /package/src/components/atoms/form-layouts/{FormLayouts.stories.js → FormLayouts.oldstories.js} +0 -0
- /package/src/components/atoms/hamburger-button/{HamburgerButton.stories.js → HamburgerButton.oldstories.js} +0 -0
- /package/src/components/atoms/heading/{Heading.stories.js → Heading.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/box-example/{BoxExample.stories.js → BoxExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/center-example/{CenterExample.stories.js → CenterExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/cluster-example/{ClusterExample.stories.js → ClusterExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/cover-example/{CoverExample.stories.js → CoverExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/frame-example/{FrameExample.stories.js → FrameExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/grid-example/{GridExample.stories.js → GridExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/imposter-example/{ImposterExample.stories.js → ImposterExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/motion-example/{MotionExample.stories.js → MotionExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/reel-example/{ReelExample.stories.js → ReelExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/sidebar-example/{SidebarExample.stories.js → SidebarExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/stack-example/{StackExample.stories.js → StackExample.oldstories.js} +0 -0
- /package/src/components/atoms/layouts/examples/switcher-example/{SwitcherExample.stories.js → SwitcherExample.oldstories.js} +0 -0
- /package/src/components/atoms/paragraph/{Paragraph.stories.js → Paragraph.oldstories.js} +0 -0
- /package/src/components/atoms/processing-fee/{ProcessingFee.stories.js → ProcessingFee.oldstories.js} +0 -0
- /package/src/components/atoms/search/{Search.stories.js → Search.oldstories.js} +0 -0
- /package/src/components/atoms/solid-divider/{SolidDivider.stories.js → SolidDivider.oldstories.js} +0 -0
- /package/src/components/atoms/sortable-table-heading/{SortableTableHeading.stories.js → SortableTableHeading.oldstories.js} +0 -0
- /package/src/components/atoms/spinner/{Spinner.stories.js → Spinner.oldstories.js} +0 -0
- /package/src/components/atoms/tab/{Tab.stories.js → Tab.oldstories.js} +0 -0
- /package/src/components/atoms/text/{Text.stories.js → Text.oldstories.js} +0 -0
- /package/src/components/atoms/typeahead-input/{TypeaheadIinput.stories.js → TypeaheadIinput.oldstories.js} +0 -0
- /package/src/components/atoms/wallet-name/{WalletName.stories.js → WalletName.oldstories.js} +0 -0
- /package/src/components/molecules/account-and-routing-modal/{AccountAndRoutingModal.stories.js → AccountAndRoutingModal.oldstories.js} +0 -0
- /package/src/components/molecules/editable-list/{EditableList.stories.js → EditableList.oldstories.js} +0 -0
- /package/src/components/molecules/email-form/{EmailForm.stories.js → EmailForm.oldstories.js} +0 -0
- /package/src/components/molecules/forgot-password-form/{ForgotPasswordForm.stories.js → ForgotPasswordForm.oldstories.js} +0 -0
- /package/src/components/molecules/highlight-tab-row/{HighlightTabRow.stories.js → HighlightTabRow.oldstories.js} +0 -0
- /package/src/components/molecules/obligation/modules/{AmountModule.stories.js → AmountModule.oldstories.js} +0 -0
- /package/src/components/molecules/payment-button-bar/{PaymentButtonBar.stories.js → PaymentButtonBar.oldstories.js} +0 -0
- /package/src/components/molecules/payment-details/{PaymentDetails.stories.js → PaymentDetails.oldstories.js} +0 -0
- /package/src/components/molecules/payment-form-ach/{PaymentFormACH.stories.js → PaymentFormACH.oldstories.js} +0 -0
- /package/src/components/molecules/payment-form-card/{PaymentFormCard.stories.js → PaymentFormCard.oldstories.js} +0 -0
- /package/src/components/molecules/periscope-dashboard-iframe/{PeriscopeDashBoardIframe.stories.js → PeriscopeDashBoardIframe.oldstories.js} +0 -0
- /package/src/components/molecules/phone-form/{PhoneForm.stories.js → PhoneForm.oldstories.js} +0 -0
- /package/src/components/molecules/popup-menu/{PopupMenu.stories.js → PopupMenu.oldstories.js} +0 -0
- /package/src/components/molecules/radio-group/{RadioGroup.stories.js → RadioGroup.oldstories.js} +0 -0
- /package/src/components/molecules/radio-section/{RadioSection.stories.js → RadioSection.oldstories.js} +0 -0
- /package/src/components/molecules/registration-form/{RegistrationForm.stories.js → RegistrationForm.oldstories.js} +0 -0
- /package/src/components/molecules/reset-confirmation-form/{ResetConfirmationForm.stories.js → ResetConfirmationForm.oldstories.js} +0 -0
- /package/src/components/molecules/reset-password-form/{ResetPasswordForm.stories.js → ResetPasswordForm.oldstories.js} +0 -0
- /package/src/components/molecules/reset-password-success/{ResetPasswordSuccess.stories.js → ResetPasswordSuccess.oldstories.js} +0 -0
- /package/src/components/molecules/tab-sidebar/{TabSidebar.stories.js → TabSidebar.oldstories.js} +0 -0
- /package/src/components/molecules/terms-and-conditions/{TermsAndConditions.stories.js → TermsAndConditions.oldstories.js} +0 -0
- /package/src/components/molecules/terms-and-conditions-modal/{TermsAndConditionsModal.stories.js → TermsAndConditionsModal.oldstories.js} +0 -0
- /package/src/components/molecules/workflow-tile/{WorkflowTile.stories.js → WorkflowTile.oldstories.js} +0 -0
|
@@ -1,24 +1,152 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from "react";
|
|
1
|
+
import React, { useState, useEffect, useRef, forwardRef } from "react";
|
|
2
2
|
import { fallbackValues } from "./MultipleSelectFilter.theme";
|
|
3
3
|
import { themeComponent } from "../../../util/themeUtils";
|
|
4
|
-
import { Box } from "../../atoms/layouts";
|
|
5
|
-
import {
|
|
4
|
+
import { Box, Center } from "../../atoms/layouts";
|
|
5
|
+
import { FormInput } from "../../atoms/form-layouts";
|
|
6
|
+
import ButtonWithAction from "../../atoms/button-with-action";
|
|
7
|
+
import Checkbox from "../../atoms/checkbox";
|
|
8
|
+
import { GHOST_GREY, WHITE } from "../../../constants/colors";
|
|
9
|
+
import { Text } from "../../atoms";
|
|
10
|
+
import DropdownIconV2 from "../../atoms/dropdown/DropdownIconV2";
|
|
11
|
+
import { FONT_WEIGHT_REGULAR } from "../../../constants/style_constants";
|
|
6
12
|
import { noop } from "../../../util/general";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
import {
|
|
14
|
+
FilterContainer,
|
|
15
|
+
FilterButton,
|
|
16
|
+
FilterDropdown
|
|
17
|
+
} from "./MultipleSelectFilter.styled";
|
|
18
|
+
|
|
19
|
+
const ScrollableOptionsList = ({
|
|
20
|
+
id,
|
|
21
|
+
optionsList,
|
|
22
|
+
selectedOptions,
|
|
23
|
+
themeValues,
|
|
24
|
+
selectOption,
|
|
25
|
+
maxSelections,
|
|
26
|
+
name
|
|
27
|
+
}) => {
|
|
28
|
+
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
29
|
+
const checkboxRefs = useRef([]);
|
|
30
|
+
const isMaxSelectionReached =
|
|
31
|
+
maxSelections && maxSelections === selectedOptions?.length;
|
|
32
|
+
const isChecked = option =>
|
|
33
|
+
selectedOptions?.some(
|
|
34
|
+
selectedOption => selectedOption?.name === option?.name
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (
|
|
39
|
+
focusedIndex !== -1 &&
|
|
40
|
+
checkboxRefs.current &&
|
|
41
|
+
checkboxRefs.current[focusedIndex]
|
|
42
|
+
) {
|
|
43
|
+
checkboxRefs.current[focusedIndex].focus(); // move focus to the active option
|
|
44
|
+
}
|
|
45
|
+
}, [focusedIndex]);
|
|
46
|
+
|
|
47
|
+
const handleKeyDown = event => {
|
|
48
|
+
if (event.key === "ArrowDown") {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
setFocusedIndex(prevIndex =>
|
|
51
|
+
prevIndex < optionsList.length - 1 ? prevIndex + 1 : 0
|
|
52
|
+
);
|
|
53
|
+
} else if (event.key === "ArrowUp") {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
setFocusedIndex(prevIndex =>
|
|
56
|
+
prevIndex > 0 ? prevIndex - 1 : optionsList.length - 1
|
|
57
|
+
);
|
|
58
|
+
} else if (event.key === " ") {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
// Select option on spacebar press if the maximum selection hasn't been reached.
|
|
61
|
+
const validFocusedIndex = focusedIndex < 0 ? 0 : focusedIndex;
|
|
62
|
+
if (
|
|
63
|
+
!isMaxSelectionReached ||
|
|
64
|
+
(focusedIndex !== -1 && isChecked(optionsList[validFocusedIndex]))
|
|
65
|
+
) {
|
|
66
|
+
selectOption(optionsList[validFocusedIndex]);
|
|
67
|
+
}
|
|
68
|
+
} else if (event.key === "Tab") {
|
|
69
|
+
// Reset focus when tabbing out of the list.
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
setFocusedIndex(-1);
|
|
72
|
+
}, 500);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Box
|
|
78
|
+
id={id}
|
|
79
|
+
role="listbox"
|
|
80
|
+
padding="0"
|
|
81
|
+
extraStyles={`
|
|
82
|
+
overflow-y: auto;
|
|
83
|
+
max-height: 250px;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-flow: column;
|
|
86
|
+
`}
|
|
87
|
+
onKeyDown={handleKeyDown}
|
|
88
|
+
>
|
|
89
|
+
{optionsList.map((option, index) => {
|
|
90
|
+
const checked = isChecked(option);
|
|
91
|
+
const isDisabled = isMaxSelectionReached && !checked;
|
|
92
|
+
const tabIndex =
|
|
93
|
+
index === focusedIndex || (index === 0 && focusedIndex === -1)
|
|
94
|
+
? "0"
|
|
95
|
+
: "-1";
|
|
96
|
+
return (
|
|
97
|
+
<Box
|
|
98
|
+
padding="0"
|
|
99
|
+
key={index}
|
|
100
|
+
extraStyles={`
|
|
101
|
+
:hover,
|
|
102
|
+
:active,
|
|
103
|
+
:focus {
|
|
104
|
+
background-color: ${themeValues.primaryColor};
|
|
105
|
+
}
|
|
106
|
+
`}
|
|
107
|
+
>
|
|
108
|
+
<Checkbox
|
|
109
|
+
ref={el => (checkboxRefs.current[index] = el)}
|
|
110
|
+
title={option.name}
|
|
111
|
+
name={option.name}
|
|
112
|
+
checked={checked}
|
|
113
|
+
onChange={() => (isDisabled ? noop : selectOption(option))}
|
|
114
|
+
textExtraStyles={`font-size: 0.875rem; margin: 0;`}
|
|
115
|
+
disabled={isDisabled}
|
|
116
|
+
extraStyles={`
|
|
117
|
+
padding: 0.075rem 0.325rem;
|
|
118
|
+
margin: 0;
|
|
119
|
+
:hover,
|
|
120
|
+
:active,
|
|
121
|
+
:focus {
|
|
122
|
+
background-color: ${themeValues.primaryColor};
|
|
123
|
+
}
|
|
124
|
+
`}
|
|
125
|
+
checkboxMargin="0.3rem"
|
|
126
|
+
role="option"
|
|
127
|
+
checkboxExtraStyles={`
|
|
128
|
+
width: 1.375rem;
|
|
129
|
+
height: 1.375rem;
|
|
130
|
+
${
|
|
131
|
+
checked && !isDisabled
|
|
132
|
+
? `background: ` + themeValues.secondaryColor + `;`
|
|
133
|
+
: ""
|
|
134
|
+
}`}
|
|
135
|
+
tabIndex={tabIndex}
|
|
136
|
+
dataQa={`${name}-option-${index}`}
|
|
137
|
+
/>
|
|
138
|
+
</Box>
|
|
139
|
+
);
|
|
140
|
+
})}
|
|
141
|
+
</Box>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
14
144
|
|
|
15
145
|
const MultipleSelectFilter = ({
|
|
16
146
|
actions,
|
|
17
147
|
autocompleteValue,
|
|
18
148
|
btnContentOverride,
|
|
19
|
-
btnExtraStyles,
|
|
20
149
|
disabled,
|
|
21
|
-
dropdownExtraStyles,
|
|
22
150
|
extraStyles,
|
|
23
151
|
fields,
|
|
24
152
|
filterLabel,
|
|
@@ -31,34 +159,58 @@ const MultipleSelectFilter = ({
|
|
|
31
159
|
options,
|
|
32
160
|
placeholder = "Search",
|
|
33
161
|
searchable = true,
|
|
162
|
+
selectedOptions,
|
|
163
|
+
setSelectedOptions,
|
|
34
164
|
themeValues,
|
|
35
165
|
truncateBtnTextWidth = "15rem"
|
|
36
166
|
}) => {
|
|
167
|
+
const [itemList, setItemList] = useState([]);
|
|
37
168
|
const [opened, setOpened] = useState(false);
|
|
38
|
-
const
|
|
39
|
-
const [appliedOptions, setAppliedOptions] = useState([]);
|
|
40
|
-
const openedRef = useRef(opened);
|
|
41
|
-
|
|
42
|
-
const handleOnClose = () => {
|
|
43
|
-
if (openedRef.current) {
|
|
44
|
-
setOpened(false);
|
|
45
|
-
actions.fields.searchTerm.set("");
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
const containerRef = useOutsideClickHook(() => handleOnClose());
|
|
169
|
+
const containerRef = useRef(null);
|
|
49
170
|
const dropdownRef = useRef(null);
|
|
50
171
|
const filterButtonRef = useRef(null);
|
|
51
172
|
const applyFilterButtonRef = useRef(null);
|
|
52
173
|
const filterDropdownID = `${name}-filter-dropdown`;
|
|
53
|
-
const
|
|
174
|
+
const checkboxListID = `${name}-checkbox-list`;
|
|
175
|
+
|
|
176
|
+
const backgroundColor = opened
|
|
177
|
+
? themeValues.primaryColor
|
|
178
|
+
: selectedOptions?.length
|
|
179
|
+
? themeValues.secondaryColor
|
|
180
|
+
: WHITE;
|
|
181
|
+
const contentColor = !opened && selectedOptions?.length ? WHITE : "#292A33";
|
|
182
|
+
|
|
183
|
+
const completeOptionsList = itemList
|
|
184
|
+
.slice()
|
|
185
|
+
.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
|
|
186
|
+
const selectValues = items => items.map(item => item.value);
|
|
187
|
+
const selectOption = selectedOption => {
|
|
188
|
+
if (selectValues(selectedOptions).includes(selectedOption.value)) {
|
|
189
|
+
const fewerOptions = selectedOptions.filter(
|
|
190
|
+
option => option.value !== selectedOption.value
|
|
191
|
+
);
|
|
192
|
+
setSelectedOptions(fewerOptions);
|
|
193
|
+
} else {
|
|
194
|
+
const moreOptions = selectedOptions.concat(selectedOption);
|
|
195
|
+
setSelectedOptions(moreOptions);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
useEffect(() => setItemList(options), [options]);
|
|
54
200
|
|
|
55
201
|
useEffect(() => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
202
|
+
const filteredItems = options.filter(item =>
|
|
203
|
+
item?.name
|
|
204
|
+
?.toLowerCase()
|
|
205
|
+
.includes(fields?.searchTerm?.rawValue?.toLowerCase())
|
|
206
|
+
);
|
|
207
|
+
// If no items are filtered, display the entire list of options.
|
|
208
|
+
if (filteredItems?.length) {
|
|
209
|
+
setItemList(filteredItems);
|
|
210
|
+
} else {
|
|
211
|
+
setItemList(options);
|
|
60
212
|
}
|
|
61
|
-
}, [
|
|
213
|
+
}, [fields.searchTerm.rawValue]);
|
|
62
214
|
|
|
63
215
|
useEffect(() => {
|
|
64
216
|
const handleKeyDown = event => {
|
|
@@ -81,11 +233,27 @@ const MultipleSelectFilter = ({
|
|
|
81
233
|
filterButtonRef.current &&
|
|
82
234
|
filterButtonRef.current.contains(event.target))
|
|
83
235
|
) {
|
|
84
|
-
|
|
236
|
+
setOpened(false);
|
|
237
|
+
actions.fields.searchTerm.set("");
|
|
238
|
+
onApply(selectedOptions);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const handleClickOutside = event => {
|
|
242
|
+
if (
|
|
243
|
+
containerRef.current &&
|
|
244
|
+
!containerRef.current.contains(event.target) &&
|
|
245
|
+
dropdownRef.current &&
|
|
246
|
+
!dropdownRef.current.contains(event.target)
|
|
247
|
+
) {
|
|
248
|
+
setOpened(false);
|
|
249
|
+
actions.fields.searchTerm.set("");
|
|
250
|
+
onApply(selectedOptions);
|
|
85
251
|
}
|
|
86
252
|
};
|
|
253
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
87
254
|
document.addEventListener("keydown", handleKeyDown);
|
|
88
255
|
return () => {
|
|
256
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
89
257
|
document.removeEventListener("keydown", handleKeyDown);
|
|
90
258
|
};
|
|
91
259
|
}, []);
|
|
@@ -94,56 +262,101 @@ const MultipleSelectFilter = ({
|
|
|
94
262
|
<FilterContainer ref={containerRef} extraStyles={`${extraStyles}`}>
|
|
95
263
|
<FilterButton
|
|
96
264
|
ref={filterButtonRef}
|
|
97
|
-
|
|
265
|
+
variant="tertiary"
|
|
98
266
|
action={() => {
|
|
99
267
|
actions.fields.searchTerm.set("");
|
|
100
268
|
setOpened(!opened);
|
|
101
269
|
}}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
270
|
+
aria-haspopup="listbox"
|
|
271
|
+
aria-expanded={opened}
|
|
272
|
+
aria-controls={filterDropdownID}
|
|
273
|
+
backgroundColor={backgroundColor}
|
|
274
|
+
dataQa={`${name}-filter-button`}
|
|
275
|
+
contentOverride
|
|
276
|
+
>
|
|
277
|
+
{btnContentOverride ? (
|
|
278
|
+
btnContentOverride
|
|
279
|
+
) : (
|
|
280
|
+
<Center
|
|
281
|
+
as="span"
|
|
282
|
+
style={{ display: "flex", flexDirection: "row" }}
|
|
283
|
+
intrinsic
|
|
284
|
+
>
|
|
285
|
+
{hasIcon && <Icon color={contentColor} />}
|
|
286
|
+
<Center
|
|
287
|
+
as="span"
|
|
288
|
+
style={{
|
|
289
|
+
display: "flex",
|
|
290
|
+
flexDirection: "row",
|
|
291
|
+
padding: "0 0.5rem 0 0.25rem"
|
|
292
|
+
}}
|
|
293
|
+
intrinsic
|
|
294
|
+
>
|
|
295
|
+
<Text
|
|
296
|
+
variant="pS"
|
|
297
|
+
color={contentColor}
|
|
298
|
+
extraStyles={`
|
|
299
|
+
white-space: nowrap;
|
|
300
|
+
overflow: hidden;
|
|
301
|
+
text-overflow: ellipsis;
|
|
302
|
+
${truncateBtnTextWidth && `max-width:` + truncateBtnTextWidth}
|
|
303
|
+
`}
|
|
304
|
+
>
|
|
305
|
+
{selectedOptions?.length
|
|
306
|
+
? `${filterLabel ? filterLabel + ": " : ""}${
|
|
307
|
+
selectedOptions[0].name
|
|
308
|
+
}`
|
|
309
|
+
: `${filterLabel ? filterLabel : ""}`}
|
|
310
|
+
</Text>
|
|
311
|
+
<Text color={contentColor} variant="pS">
|
|
312
|
+
{selectedOptions?.length && selectedOptions?.length > 1
|
|
313
|
+
? `, +${selectedOptions?.length - 1} More`
|
|
314
|
+
: ""}
|
|
315
|
+
</Text>
|
|
316
|
+
</Center>
|
|
317
|
+
<DropdownIconV2 color={contentColor} />
|
|
318
|
+
</Center>
|
|
319
|
+
)}
|
|
320
|
+
</FilterButton>
|
|
120
321
|
<FilterDropdown
|
|
121
322
|
id={filterDropdownID}
|
|
122
323
|
ref={dropdownRef}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
324
|
+
hidden={!opened}
|
|
325
|
+
role="combobox"
|
|
326
|
+
aria-expanded={opened}
|
|
327
|
+
aria-haspopup="listbox"
|
|
328
|
+
aria-owns={checkboxListID}
|
|
127
329
|
>
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
330
|
+
<Box padding="0 0 0.5rem">
|
|
331
|
+
{searchable && options?.length > 8 && (
|
|
332
|
+
<FormInput
|
|
333
|
+
autocompleteValue={autocompleteValue}
|
|
334
|
+
showFieldErrorRow={false}
|
|
335
|
+
errorMessages={{}}
|
|
336
|
+
field={fields.searchTerm}
|
|
337
|
+
fieldActions={actions.fields.searchTerm}
|
|
338
|
+
placeholder={placeholder}
|
|
339
|
+
disabled={disabled}
|
|
340
|
+
extraStyles={`
|
|
341
|
+
height: 2.875rem;
|
|
342
|
+
border: 0;
|
|
343
|
+
border-radius: 0;
|
|
344
|
+
padding: 0.45rem;
|
|
345
|
+
font-size: 0.875rem;
|
|
346
|
+
border-bottom: 1px solid ${GHOST_GREY};
|
|
347
|
+
`}
|
|
348
|
+
/>
|
|
349
|
+
)}
|
|
350
|
+
</Box>
|
|
351
|
+
<ScrollableOptionsList
|
|
352
|
+
id={checkboxListID}
|
|
353
|
+
optionsList={completeOptionsList}
|
|
141
354
|
selectedOptions={selectedOptions}
|
|
355
|
+
themeValues={themeValues}
|
|
356
|
+
selectOption={selectOption}
|
|
142
357
|
maxSelections={maxSelections}
|
|
143
358
|
name={name}
|
|
144
|
-
|
|
145
|
-
searchTerm={fields?.searchTerm}
|
|
146
|
-
></FilterableList>
|
|
359
|
+
></ScrollableOptionsList>
|
|
147
360
|
<Box
|
|
148
361
|
padding="0 0.5rem 0.0625rem 0.5rem"
|
|
149
362
|
extraStyles={`
|
|
@@ -154,23 +367,42 @@ const MultipleSelectFilter = ({
|
|
|
154
367
|
border-top: 1px solid ${GHOST_GREY};
|
|
155
368
|
`}
|
|
156
369
|
>
|
|
157
|
-
<
|
|
370
|
+
<ButtonWithAction
|
|
158
371
|
action={() => {
|
|
372
|
+
setOpened(false);
|
|
159
373
|
setSelectedOptions([]);
|
|
160
|
-
|
|
374
|
+
actions.fields.searchTerm.set("");
|
|
161
375
|
onClear();
|
|
162
376
|
}}
|
|
377
|
+
variant="tertiary"
|
|
378
|
+
extraStyles={`
|
|
379
|
+
padding: 0.2rem;
|
|
380
|
+
margin: 0.5rem;
|
|
381
|
+
min-height: auto;
|
|
382
|
+
min-width: auto;
|
|
383
|
+
`}
|
|
384
|
+
textExtraStyles={`font-weight: ${FONT_WEIGHT_REGULAR};`}
|
|
163
385
|
text="Clear"
|
|
164
386
|
dataQa={`${name}-clear-filters`}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<ActionLinkButton
|
|
387
|
+
></ButtonWithAction>
|
|
388
|
+
<ButtonWithAction
|
|
168
389
|
ref={applyFilterButtonRef}
|
|
169
|
-
action={() =>
|
|
390
|
+
action={() => {
|
|
391
|
+
setOpened(false);
|
|
392
|
+
actions.fields.searchTerm.set("");
|
|
393
|
+
onApply(selectedOptions);
|
|
394
|
+
}}
|
|
395
|
+
variant="tertiary"
|
|
396
|
+
extraStyles={`
|
|
397
|
+
padding: 0.2rem;
|
|
398
|
+
margin: 0.5rem;
|
|
399
|
+
min-height: auto;
|
|
400
|
+
min-width: auto;
|
|
401
|
+
`}
|
|
402
|
+
textExtraStyles={`font-weight: ${FONT_WEIGHT_REGULAR};`}
|
|
170
403
|
text="Apply"
|
|
171
404
|
dataQa={`${name}-apply-filters`}
|
|
172
|
-
|
|
173
|
-
></ActionLinkButton>
|
|
405
|
+
></ButtonWithAction>
|
|
174
406
|
</Box>
|
|
175
407
|
</FilterDropdown>
|
|
176
408
|
</FilterContainer>
|
|
@@ -41,6 +41,8 @@ const items = [
|
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
const FormWrapper = props => {
|
|
44
|
+
const [selectedItems, setSelectedItems] = useState(props.selectedItems || []);
|
|
45
|
+
|
|
44
46
|
return (
|
|
45
47
|
<MultipleSelectFilter
|
|
46
48
|
autocompleteValue={props.autocompleteValue}
|
|
@@ -53,8 +55,8 @@ const FormWrapper = props => {
|
|
|
53
55
|
placeholder={"Find an agency"}
|
|
54
56
|
fields={props.fields}
|
|
55
57
|
actions={props.actions}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
selectedOptions={selectedItems}
|
|
59
|
+
setSelectedOptions={setSelectedItems}
|
|
58
60
|
/>
|
|
59
61
|
);
|
|
60
62
|
};
|
|
@@ -5,9 +5,9 @@ import ButtonWithAction from "../../atoms/button-with-action";
|
|
|
5
5
|
|
|
6
6
|
const StyledFilterContainer = styled(Box)`
|
|
7
7
|
position: relative;
|
|
8
|
-
overflow: visible;
|
|
9
8
|
box-sizing: border-box;
|
|
10
9
|
padding: 0;
|
|
10
|
+
${({ extraStyles }) => extraStyles}
|
|
11
11
|
`;
|
|
12
12
|
|
|
13
13
|
export const FilterContainer = forwardRef((props, ref) => (
|
|
@@ -18,7 +18,7 @@ const StyledFilterDropdown = styled(Box)`
|
|
|
18
18
|
position: absolute;
|
|
19
19
|
top: calc(100% + 0.5rem);
|
|
20
20
|
left: 0;
|
|
21
|
-
width:
|
|
21
|
+
width: 100%;
|
|
22
22
|
background-color: white;
|
|
23
23
|
z-index: 1000;
|
|
24
24
|
border-radius: 0.25rem;
|
|
@@ -28,11 +28,11 @@ const StyledFilterDropdown = styled(Box)`
|
|
|
28
28
|
max-width: 18.625rem;
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
|
-
export const
|
|
31
|
+
export const FilterDropdown = forwardRef((props, ref) => (
|
|
32
32
|
<StyledFilterDropdown ref={ref} {...props} />
|
|
33
33
|
));
|
|
34
34
|
|
|
35
|
-
const
|
|
35
|
+
const StyledFilterButton = styled(ButtonWithAction)`
|
|
36
36
|
min-width: auto;
|
|
37
37
|
min-height: 2.3125rem;
|
|
38
38
|
margin: 0;
|
|
@@ -52,6 +52,6 @@ const FilterButton = styled(ButtonWithAction)`
|
|
|
52
52
|
`}
|
|
53
53
|
`;
|
|
54
54
|
|
|
55
|
-
export const
|
|
56
|
-
<
|
|
55
|
+
export const FilterButton = forwardRef((props, ref) => (
|
|
56
|
+
<StyledFilterButton ref={ref} {...props} />
|
|
57
57
|
));
|
|
@@ -10,9 +10,7 @@ export interface MultipleSelectFilterProps {
|
|
|
10
10
|
actions: FieldActions;
|
|
11
11
|
autocompleteValue?: boolean;
|
|
12
12
|
btnContentOverride?: JSX.Element;
|
|
13
|
-
btnExtraStyles?: string;
|
|
14
13
|
disabled: boolean;
|
|
15
|
-
dropdownExtraStyles?: string;
|
|
16
14
|
extraStyles?: string;
|
|
17
15
|
fields: {
|
|
18
16
|
searchTerm: Field;
|
|
@@ -26,6 +24,8 @@ export interface MultipleSelectFilterProps {
|
|
|
26
24
|
options: SearchableSelectOption[];
|
|
27
25
|
placeholder?: string;
|
|
28
26
|
searchable?: boolean;
|
|
27
|
+
selectedOptions: SearchableSelectOption[];
|
|
28
|
+
setSelectedOptions: (options: SearchableSelectOption[]) => void;
|
|
29
29
|
themeValues?: any[];
|
|
30
30
|
truncateBtnTextWidth?: string;
|
|
31
31
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Canvas, Meta, Title, Story, Controls } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import * as ObligationStories from './Obligation.stories.js';
|
|
4
|
+
|
|
5
|
+
<Meta of={ObligationStories} />
|
|
6
|
+
|
|
7
|
+
<Title />
|
|
8
|
+
|
|
9
|
+
The Obligation is a purpose built component to display user accounts on NFE's User Profile. The component consumers configuration provided by FCS to dictate its icon and type. NFE uses this configuration to assemble the description and subDescription from the obligation's custom attributes. A full detail of the structure of the configuration object is beyond the scope of this documentation, but an example can be found in the story code, and further detail is available on Confluence within the implementation guides used by solutions engineers.
|
|
10
|
+
|
|
11
|
+
The component currently has two states. An active obligation uses data from the user lookup and FCS to provide account details and amount due as well as controls to interact with the obligation, such as for viewing account details or enabling/disabling autopay.
|
|
12
|
+
|
|
13
|
+
An inactive obligation is one whose data is not fully returned from lookup (this happens when our systems contain record of the account because of its association with a user, but the source system or source file ingested by FLS no longer provides that information, such as when a debt gets paid off). Inactive obligations look different and take some props to display a small amount of information to the user about what account used to be represented there.
|
|
14
|
+
|
|
15
|
+
If the current user is a customer management admin accessing the profile via the RevM impersonation feature, then most of the interaction controls with the Obligation will be disabled.
|
|
16
|
+
|
|
17
|
+
The Obligation was designed to be extensible to meet product needs in the future. New "modules" can be added to the modules directory that feature different collections of buttons or information display. Some work will need to be done to the main component code to support such additions.
|
|
18
|
+
|
|
19
|
+
<Controls />
|
|
20
|
+
|
|
21
|
+
<div style={{ marginBottom: "2em"}}>
|
|
22
|
+
<Story />
|
|
23
|
+
</div>
|