@thecb/components 10.12.1 → 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 +1413 -2314
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.esm.js +1413 -2315
- 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.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/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 +295 -61
- package/src/components/molecules/multiple-select-filter/{MultipleSelectFilter.stories.js → MultipleSelectFilter.oldstories.js} +1 -1
- package/src/components/molecules/multiple-select-filter/MultipleSelectFilter.styled.js +4 -4
- 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/icons.stories.js +0 -116
- package/src/components/molecules/edit-name-form/EdidNameForm.stories.js +0 -24
- package/src/components/molecules/multiple-select-filter/__private__/ActionLinkButton.js +0 -24
- package/src/components/molecules/multiple-select-filter/__private__/FilterButton.js +0 -85
- package/src/components/molecules/multiple-select-filter/__private__/FilterDropdown.js +0 -23
- package/src/components/molecules/multiple-select-filter/__private__/FilterableList.js +0 -144
- package/src/components/molecules/multiple-select-filter/__private__/FilterableListItem.js +0 -67
- package/src/components/molecules/multiple-select-filter/__private__/SearchBox.js +0 -38
- 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,16 +1,146 @@
|
|
|
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,
|
|
@@ -34,27 +164,53 @@ const MultipleSelectFilter = ({
|
|
|
34
164
|
themeValues,
|
|
35
165
|
truncateBtnTextWidth = "15rem"
|
|
36
166
|
}) => {
|
|
167
|
+
const [itemList, setItemList] = useState([]);
|
|
37
168
|
const [opened, setOpened] = useState(false);
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const handleClickOutsideContainer = () => {
|
|
41
|
-
setOpened(false);
|
|
42
|
-
actions.fields.searchTerm.set("");
|
|
43
|
-
onApply(selectedOptions);
|
|
44
|
-
};
|
|
45
|
-
const containerRef = useOutsideClickHook(() => handleClickOutsideContainer());
|
|
169
|
+
const containerRef = useRef(null);
|
|
46
170
|
const dropdownRef = useRef(null);
|
|
47
171
|
const filterButtonRef = useRef(null);
|
|
48
172
|
const applyFilterButtonRef = useRef(null);
|
|
49
173
|
const filterDropdownID = `${name}-filter-dropdown`;
|
|
50
174
|
const checkboxListID = `${name}-checkbox-list`;
|
|
51
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]);
|
|
200
|
+
|
|
52
201
|
useEffect(() => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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);
|
|
56
212
|
}
|
|
57
|
-
}, [
|
|
213
|
+
}, [fields.searchTerm.rawValue]);
|
|
58
214
|
|
|
59
215
|
useEffect(() => {
|
|
60
216
|
const handleKeyDown = event => {
|
|
@@ -82,8 +238,22 @@ const MultipleSelectFilter = ({
|
|
|
82
238
|
onApply(selectedOptions);
|
|
83
239
|
}
|
|
84
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);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
85
254
|
document.addEventListener("keydown", handleKeyDown);
|
|
86
255
|
return () => {
|
|
256
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
87
257
|
document.removeEventListener("keydown", handleKeyDown);
|
|
88
258
|
};
|
|
89
259
|
}, []);
|
|
@@ -92,53 +262,101 @@ const MultipleSelectFilter = ({
|
|
|
92
262
|
<FilterContainer ref={containerRef} extraStyles={`${extraStyles}`}>
|
|
93
263
|
<FilterButton
|
|
94
264
|
ref={filterButtonRef}
|
|
95
|
-
|
|
265
|
+
variant="tertiary"
|
|
96
266
|
action={() => {
|
|
97
267
|
actions.fields.searchTerm.set("");
|
|
98
268
|
setOpened(!opened);
|
|
99
269
|
}}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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>
|
|
117
321
|
<FilterDropdown
|
|
118
322
|
id={filterDropdownID}
|
|
119
323
|
ref={dropdownRef}
|
|
120
|
-
|
|
121
|
-
|
|
324
|
+
hidden={!opened}
|
|
325
|
+
role="combobox"
|
|
326
|
+
aria-expanded={opened}
|
|
327
|
+
aria-haspopup="listbox"
|
|
328
|
+
aria-owns={checkboxListID}
|
|
122
329
|
>
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
|
132
352
|
id={checkboxListID}
|
|
133
|
-
|
|
134
|
-
appliedOptions={appliedOptions}
|
|
135
|
-
themeValues={themeValues}
|
|
353
|
+
optionsList={completeOptionsList}
|
|
136
354
|
selectedOptions={selectedOptions}
|
|
355
|
+
themeValues={themeValues}
|
|
356
|
+
selectOption={selectOption}
|
|
137
357
|
maxSelections={maxSelections}
|
|
138
358
|
name={name}
|
|
139
|
-
|
|
140
|
-
searchTerm={fields?.searchTerm}
|
|
141
|
-
></FilterableList>
|
|
359
|
+
></ScrollableOptionsList>
|
|
142
360
|
<Box
|
|
143
361
|
padding="0 0.5rem 0.0625rem 0.5rem"
|
|
144
362
|
extraStyles={`
|
|
@@ -149,26 +367,42 @@ const MultipleSelectFilter = ({
|
|
|
149
367
|
border-top: 1px solid ${GHOST_GREY};
|
|
150
368
|
`}
|
|
151
369
|
>
|
|
152
|
-
<
|
|
370
|
+
<ButtonWithAction
|
|
153
371
|
action={() => {
|
|
154
372
|
setOpened(false);
|
|
155
373
|
setSelectedOptions([]);
|
|
156
374
|
actions.fields.searchTerm.set("");
|
|
157
375
|
onClear();
|
|
158
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};`}
|
|
159
385
|
text="Clear"
|
|
160
386
|
dataQa={`${name}-clear-filters`}
|
|
161
|
-
></
|
|
162
|
-
<
|
|
387
|
+
></ButtonWithAction>
|
|
388
|
+
<ButtonWithAction
|
|
163
389
|
ref={applyFilterButtonRef}
|
|
164
390
|
action={() => {
|
|
165
391
|
setOpened(false);
|
|
166
392
|
actions.fields.searchTerm.set("");
|
|
167
393
|
onApply(selectedOptions);
|
|
168
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};`}
|
|
169
403
|
text="Apply"
|
|
170
404
|
dataQa={`${name}-apply-filters`}
|
|
171
|
-
></
|
|
405
|
+
></ButtonWithAction>
|
|
172
406
|
</Box>
|
|
173
407
|
</FilterDropdown>
|
|
174
408
|
</FilterContainer>
|
|
@@ -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
|
));
|
|
@@ -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>
|