@nuskin/foundation-ui-components 1.7.0 → 1.8.0-738-v1.1
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/package.json +46 -46
- package/src/common/accordion/NsCollapse.tsx +1 -0
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +37 -82
- package/src/common/autocomplete/NsAutocomplete.styled.tsx +2 -0
- package/src/common/autocomplete/NsAutocomplete.tsx +59 -62
- package/src/common/autocomplete/helper/{ClearButton.tsx → AutoCompleteButton.tsx} +9 -7
- package/src/common/autocomplete/helper/SeeMoreButton.tsx +5 -14
- package/src/common/autocomplete/helper/renderGroupName.tsx +4 -2
- package/src/common/autocomplete/stories/{ACWithoutClose.tsx → NoCloseAutoComplete.tsx} +6 -6
- package/src/common/autocomplete/stories/NsAutocomplete.stories.tsx +3 -3
- package/src/common/autocomplete/stories/RenderAutoComplete.tsx +5 -5
- package/src/common/autocomplete/types.d.ts +21 -8
- package/src/common/button/NsButton.spec.tsx +10 -9
- package/src/common/button/NsButton.styled.tsx +40 -51
- package/src/common/button/NsButton.tsx +3 -2
- package/src/common/card/specs/NsBrandCard.spec.tsx +1 -1
- package/src/common/card/specs/NsHeroCardLevel1.spec.tsx +1 -1
- package/src/common/card/specs/NsHeroCardLevel2.spec.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.stories.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.styled.tsx +3 -2
- package/src/common/email-simple/NsEmailSimple.spec.tsx +72 -102
- package/src/common/icon/icons/RoundedClose.tsx +10 -12
- package/src/common/input/NsInputField.tsx +7 -5
- package/src/common/input/types.d.ts +2 -1
- package/src/common/label/NsLabel.tsx +7 -5
- package/src/common/radiogroup/NsRadioGroup.tsx +5 -6
- package/src/common/validations/regex.ts +1 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/foundation-ui-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0-738-v1.1",
|
|
4
4
|
"description": "It is a foundation library written in react, that provides common components to all UI pages",
|
|
5
5
|
"main": "src/common/index.ts",
|
|
6
6
|
"repository": {
|
|
@@ -42,62 +42,62 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@emotion/react": "^11.11.1",
|
|
44
44
|
"@emotion/styled": "^11.11.0",
|
|
45
|
-
"@mui/icons-material": "^5.
|
|
46
|
-
"@mui/material": "5.
|
|
47
|
-
"@mui/utils": "^5.14.
|
|
48
|
-
"@next/font": "13.
|
|
49
|
-
"@nuskin/foundation-theme": "
|
|
50
|
-
"
|
|
51
|
-
"
|
|
45
|
+
"@mui/icons-material": "^5.14.14",
|
|
46
|
+
"@mui/material": "5.14.14",
|
|
47
|
+
"@mui/utils": "^5.14.14",
|
|
48
|
+
"@next/font": "13.5.6",
|
|
49
|
+
"@nuskin/foundation-theme": "1.2.0",
|
|
50
|
+
"@types/react": "^18.2.30",
|
|
51
|
+
"@types/react-dom": "^18.2.14",
|
|
52
|
+
"cliui": "^8.0.1",
|
|
53
|
+
"framer-motion": "^10.16.4",
|
|
54
|
+
"next": "13.5.6",
|
|
52
55
|
"react": "18.2.0",
|
|
53
|
-
"react-dom": "18.2.0",
|
|
56
|
+
"react-dom": "^18.2.0",
|
|
54
57
|
"react-material-ui-carousel": "^3.4.2",
|
|
55
58
|
"react-slick": "^0.29.0",
|
|
56
59
|
"slick-carousel": "^1.8.1",
|
|
57
|
-
"typescript": "
|
|
60
|
+
"typescript": "^5.2.2"
|
|
58
61
|
},
|
|
59
62
|
"devDependencies": {
|
|
60
|
-
"@babel/core": "^7.
|
|
61
|
-
"@babel/preset-env": "^7.
|
|
62
|
-
"@babel/preset-react": "^7.
|
|
63
|
-
"@babel/preset-typescript": "^7.
|
|
64
|
-
"@emotion/jest": "^11.
|
|
63
|
+
"@babel/core": "^7.23.2",
|
|
64
|
+
"@babel/preset-env": "^7.23.2",
|
|
65
|
+
"@babel/preset-react": "^7.22.15",
|
|
66
|
+
"@babel/preset-typescript": "^7.23.2",
|
|
67
|
+
"@emotion/jest": "^11.11.0",
|
|
65
68
|
"@nuskin/eslint-config": "^1.0.0-setup.1",
|
|
66
|
-
"@storybook/addon-actions": "^7.
|
|
67
|
-
"@storybook/addon-essentials": "^7.
|
|
68
|
-
"@storybook/addon-interactions": "^7.
|
|
69
|
-
"@storybook/addon-links": "^7.
|
|
70
|
-
"@storybook/
|
|
71
|
-
"@storybook/
|
|
72
|
-
"@storybook/
|
|
73
|
-
"@storybook/
|
|
74
|
-
"@storybook/
|
|
75
|
-
"@
|
|
76
|
-
"@testing-library/jest-dom": "^
|
|
69
|
+
"@storybook/addon-actions": "^7.5.1",
|
|
70
|
+
"@storybook/addon-essentials": "^7.5.1",
|
|
71
|
+
"@storybook/addon-interactions": "^7.5.1",
|
|
72
|
+
"@storybook/addon-links": "^7.5.1",
|
|
73
|
+
"@storybook/jest": "^0.2.3",
|
|
74
|
+
"@storybook/nextjs": "^7.5.1",
|
|
75
|
+
"@storybook/react": "^7.5.1",
|
|
76
|
+
"@storybook/test-runner": "^0.13.1-next.1",
|
|
77
|
+
"@storybook/testing-library": "^0.2.2",
|
|
78
|
+
"@testing-library/dom": "^9.3.3",
|
|
79
|
+
"@testing-library/jest-dom": "^6.1.4",
|
|
77
80
|
"@testing-library/react": "^14.0.0",
|
|
78
81
|
"@testing-library/react-hooks": "^8.0.1",
|
|
79
|
-
"@types/jest": "^29.5.
|
|
80
|
-
"@types/lodash": "^4.14.
|
|
81
|
-
"@types/node": "
|
|
82
|
-
"@types/ramda": "^0.29.
|
|
83
|
-
"@types/react": "
|
|
84
|
-
"@types/react-
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"@types/testing-library__jest-dom": "^5.14.5",
|
|
88
|
-
"babel-jest": "^29.5.0",
|
|
89
|
-
"babel-loader": "^9.1.2",
|
|
82
|
+
"@types/jest": "^29.5.6",
|
|
83
|
+
"@types/lodash": "^4.14.200",
|
|
84
|
+
"@types/node": "^20.8.7",
|
|
85
|
+
"@types/ramda": "^0.29.7",
|
|
86
|
+
"@types/react-slick": "^0.23.11",
|
|
87
|
+
"@types/react-test-renderer": "^18.0.5",
|
|
88
|
+
"babel-jest": "^29.7.0",
|
|
89
|
+
"babel-loader": "^9.1.3",
|
|
90
90
|
"babel-plugin-emotion": "^11.0.0",
|
|
91
|
-
"chromatic": "^
|
|
92
|
-
"eslint": "8.
|
|
93
|
-
"eslint-config-next": "13.
|
|
94
|
-
"eslint-config-prettier": "^
|
|
91
|
+
"chromatic": "^7.4.0",
|
|
92
|
+
"eslint": "^8.51.0",
|
|
93
|
+
"eslint-config-next": "^13.5.6",
|
|
94
|
+
"eslint-config-prettier": "^9.0.0",
|
|
95
95
|
"eslint-plugin-json": "^3.1.0",
|
|
96
|
-
"eslint-plugin-prettier": "^
|
|
97
|
-
"eslint-plugin-storybook": "^0.6.
|
|
98
|
-
"jest": "^29.
|
|
99
|
-
"jest-environment-jsdom": "^29.
|
|
100
|
-
"storybook": "^7.
|
|
96
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
97
|
+
"eslint-plugin-storybook": "^0.6.15",
|
|
98
|
+
"jest": "^29.7.0",
|
|
99
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
100
|
+
"storybook": "^7.5.1"
|
|
101
101
|
},
|
|
102
102
|
"files": [
|
|
103
103
|
"src/common"
|
|
@@ -1,62 +1,40 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import { act } from 'react-dom/test-utils';
|
|
4
1
|
import { render, screen, waitFor } from '@/test-utils/index';
|
|
5
|
-
import
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
6
5
|
import { AutocompleteMockList } from './mock/MockData';
|
|
6
|
+
import { OptionUiComponent } from './mock/MockUI';
|
|
7
7
|
import NsAutocomplete from './NsAutocomplete';
|
|
8
8
|
|
|
9
|
+
const commonProps = {
|
|
10
|
+
value: '',
|
|
11
|
+
inputValue: '',
|
|
12
|
+
onInputChange: jest.fn(),
|
|
13
|
+
onChange: jest.fn(),
|
|
14
|
+
options: AutocompleteMockList,
|
|
15
|
+
placeholder: 'autocomplete-input',
|
|
16
|
+
OptionsUI: OptionUiComponent,
|
|
17
|
+
};
|
|
9
18
|
describe('CustomAutocomplete', () => {
|
|
10
19
|
it('1. should render autocomplete component', () => {
|
|
11
|
-
render(
|
|
12
|
-
<NsAutocomplete
|
|
13
|
-
options={AutocompleteMockList}
|
|
14
|
-
placeholder="autocomplete-input"
|
|
15
|
-
OptionsUI={OptionUiComponent}
|
|
16
|
-
inputValue=""
|
|
17
|
-
value=""
|
|
18
|
-
/>
|
|
19
|
-
);
|
|
20
|
+
render(<NsAutocomplete {...commonProps} />);
|
|
20
21
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
21
22
|
expect(autocompleteInput).toBeInTheDocument();
|
|
22
23
|
});
|
|
23
|
-
it('2. check that
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
render(
|
|
27
|
-
<NsAutocomplete
|
|
28
|
-
options={AutocompleteMockList}
|
|
29
|
-
onSelect={onSelectMock}
|
|
30
|
-
onChange={onChangeMock}
|
|
31
|
-
placeholder="autocomplete-input"
|
|
32
|
-
OptionsUI={OptionUiComponent}
|
|
33
|
-
inputValue=""
|
|
34
|
-
value=""
|
|
35
|
-
/>
|
|
36
|
-
);
|
|
24
|
+
it('2. check that onInputChange gets called', async () => {
|
|
25
|
+
const onInputChangeMock = jest.fn();
|
|
26
|
+
render(<NsAutocomplete {...commonProps} onInputChange={onInputChangeMock} />);
|
|
37
27
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
38
28
|
expect(autocompleteInput).toBeInTheDocument();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(onChangeMock).toHaveBeenCalled();
|
|
43
|
-
});
|
|
29
|
+
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
30
|
+
expect(onInputChangeMock).toHaveBeenCalled();
|
|
31
|
+
}, 100000);
|
|
44
32
|
|
|
45
33
|
it('3. displays options when typing in the input', async () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
options={AutocompleteMockList}
|
|
49
|
-
onSelect={() => {}}
|
|
50
|
-
OptionsUI={OptionUiComponent}
|
|
51
|
-
placeholder="autocomplete-input"
|
|
52
|
-
inputValue=""
|
|
53
|
-
value=""
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
34
|
+
const onInputChangeMock = jest.fn();
|
|
35
|
+
render(<NsAutocomplete {...commonProps} onInputChange={onInputChangeMock} />);
|
|
56
36
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
57
|
-
|
|
58
|
-
userEvent.type(autocompleteInput, 'GS Facial');
|
|
59
|
-
});
|
|
37
|
+
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
60
38
|
await waitFor(
|
|
61
39
|
() => {
|
|
62
40
|
const option1 = screen.getByText('GS Facial Gels 2pk Subscription');
|
|
@@ -67,75 +45,52 @@ describe('CustomAutocomplete', () => {
|
|
|
67
45
|
}, 40000);
|
|
68
46
|
|
|
69
47
|
it('4. selects an option when clicking on it', async () => {
|
|
70
|
-
const
|
|
71
|
-
render(
|
|
72
|
-
<NsAutocomplete
|
|
73
|
-
onSelect={onSelectMock}
|
|
74
|
-
options={AutocompleteMockList}
|
|
75
|
-
OptionsUI={OptionUiComponent}
|
|
76
|
-
placeholder="autocomplete-input"
|
|
77
|
-
inputValue=""
|
|
78
|
-
value=""
|
|
79
|
-
/>
|
|
80
|
-
);
|
|
48
|
+
const onChangeMock = jest.fn();
|
|
49
|
+
render(<NsAutocomplete {...commonProps} onChange={onChangeMock} />);
|
|
81
50
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
85
|
-
await waitFor(() => {
|
|
51
|
+
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
52
|
+
await waitFor(async () => {
|
|
86
53
|
const optionLi = screen.getByText('GS Facial Spa');
|
|
87
|
-
userEvent.click(optionLi);
|
|
54
|
+
await userEvent.click(optionLi);
|
|
88
55
|
});
|
|
89
|
-
expect(
|
|
56
|
+
expect(onChangeMock).toHaveBeenCalled();
|
|
90
57
|
}, 40000);
|
|
91
58
|
|
|
92
59
|
it('5. should load more options when clicking load more button', async () => {
|
|
93
60
|
render(
|
|
94
61
|
<NsAutocomplete
|
|
95
|
-
options={AutocompleteMockList}
|
|
96
|
-
OptionsUI={OptionUiComponent}
|
|
97
|
-
placeholder="autocomplete-input"
|
|
98
62
|
seeMore={{
|
|
99
63
|
text: '',
|
|
100
64
|
show: true,
|
|
101
65
|
onSeeMore: () => ({}),
|
|
102
66
|
}}
|
|
103
|
-
|
|
104
|
-
value=""
|
|
67
|
+
{...commonProps}
|
|
105
68
|
/>
|
|
106
69
|
);
|
|
107
70
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
111
|
-
await waitFor(() => {
|
|
71
|
+
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
72
|
+
await waitFor(async () => {
|
|
112
73
|
const loadMoreButton = screen.getByTestId('autocomplete-loadmore-id');
|
|
113
|
-
userEvent.click(loadMoreButton);
|
|
74
|
+
await userEvent.click(loadMoreButton);
|
|
114
75
|
});
|
|
115
76
|
}, 40000);
|
|
116
77
|
|
|
117
78
|
it('6. should clear options when clicking clear button', async () => {
|
|
118
79
|
render(
|
|
119
80
|
<NsAutocomplete
|
|
120
|
-
options={AutocompleteMockList}
|
|
121
|
-
OptionsUI={OptionUiComponent}
|
|
122
|
-
placeholder="autocomplete-input"
|
|
123
81
|
clear={{
|
|
124
82
|
text: '',
|
|
125
83
|
show: true,
|
|
126
84
|
onClear: () => ({}),
|
|
127
85
|
}}
|
|
128
|
-
|
|
129
|
-
value=""
|
|
86
|
+
{...commonProps}
|
|
130
87
|
/>
|
|
131
88
|
);
|
|
132
89
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
await waitFor(() => {
|
|
90
|
+
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
91
|
+
await waitFor(async () => {
|
|
137
92
|
const clearButton = screen.getByTestId('autocomplete-clear-id');
|
|
138
|
-
userEvent.click(clearButton);
|
|
93
|
+
await userEvent.click(clearButton);
|
|
139
94
|
});
|
|
140
95
|
}, 40000);
|
|
141
96
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
|
|
2
3
|
import { NsInputField } from '../input';
|
|
3
4
|
|
|
4
5
|
// TODO: why is .muiautocomplete-popupindicator added?
|
|
6
|
+
// TODO: ${({ theme }) => getGenomeColor(theme, 'N100')}; use forceMode light
|
|
5
7
|
export const StyledTextField = styled(NsInputField)`
|
|
6
8
|
.MuiAutocomplete-inputRoot {
|
|
7
9
|
padding-right: 10px !important;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Autocomplete, AutocompleteRenderInputParams
|
|
2
|
-
import React, {
|
|
1
|
+
import { Autocomplete, AutocompleteRenderInputParams } from '@mui/material';
|
|
2
|
+
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { AutoCompleteButton } from './helper/AutoCompleteButton';
|
|
5
5
|
import { renderGroupBy, renderGroupName, renderOptionLabel } from './helper/renderGroupName';
|
|
6
6
|
import { SeeMoreButton } from './helper/SeeMoreButton';
|
|
7
7
|
import { StyledTextField } from './NsAutocomplete.styled';
|
|
8
8
|
import { ComponentBoxProps, NsAutocompleteProps, OptionsProps } from './types.d';
|
|
9
|
-
|
|
9
|
+
const noop = () => {};
|
|
10
10
|
const NsAutocomplete = ({
|
|
11
11
|
id = 'custom_autocomplete_dropdown',
|
|
12
12
|
options,
|
|
13
13
|
OptionsUI,
|
|
14
14
|
loading,
|
|
15
15
|
noOptionsText,
|
|
16
|
-
|
|
16
|
+
onInputChange,
|
|
17
17
|
onChange,
|
|
18
18
|
clear,
|
|
19
19
|
seeMore,
|
|
@@ -34,24 +34,6 @@ const NsAutocomplete = ({
|
|
|
34
34
|
}
|
|
35
35
|
}, [options, scrollTopPosition]);
|
|
36
36
|
|
|
37
|
-
const handleSelect = useCallback(
|
|
38
|
-
(event: React.SyntheticEvent, value: string | OptionsProps | null) => {
|
|
39
|
-
if (typeof onSelect === 'function') {
|
|
40
|
-
onSelect(value);
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
[onSelect]
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const onInputChange = useCallback(
|
|
47
|
-
(event: React.SyntheticEvent, newInputValue: string) => {
|
|
48
|
-
if (typeof onChange === 'function') {
|
|
49
|
-
onChange(newInputValue);
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
[onChange]
|
|
53
|
-
);
|
|
54
|
-
|
|
55
37
|
const renderInput = (params: AutocompleteRenderInputParams) => (
|
|
56
38
|
<StyledTextField
|
|
57
39
|
{...params}
|
|
@@ -71,47 +53,62 @@ const NsAutocomplete = ({
|
|
|
71
53
|
</li>
|
|
72
54
|
);
|
|
73
55
|
|
|
74
|
-
const renderListBoxComponent = ({ children, ...
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
56
|
+
const renderListBoxComponent = ({ children, ...rest }: ComponentBoxProps) => {
|
|
57
|
+
return (
|
|
58
|
+
<ul
|
|
59
|
+
aria-labelledby={rest['aria-labelledby']}
|
|
60
|
+
onMouseDown={rest.onMouseDown}
|
|
61
|
+
role={rest.role}
|
|
62
|
+
id={rest.id}
|
|
63
|
+
className={rest.className}
|
|
64
|
+
ref={listboxRef}
|
|
65
|
+
>
|
|
66
|
+
<AutoCompleteButton
|
|
67
|
+
show={clear?.show ?? false}
|
|
68
|
+
text={clear?.text ?? 'Clear All'}
|
|
69
|
+
onClick={clear?.onClear ?? noop}
|
|
70
|
+
testId="autocomplete-clear-id"
|
|
71
|
+
/>
|
|
72
|
+
{children}
|
|
73
|
+
<SeeMoreButton
|
|
74
|
+
onSeeMore={seeMore?.onSeeMore}
|
|
75
|
+
show={seeMore?.show}
|
|
76
|
+
text={seeMore?.text}
|
|
77
|
+
options={options}
|
|
78
|
+
setScrollTopPosition={setScrollTopPosition}
|
|
79
|
+
listboxRef={listboxRef}
|
|
80
|
+
/>
|
|
81
|
+
</ul>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
88
84
|
|
|
89
85
|
return (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
86
|
+
<>
|
|
87
|
+
<Autocomplete
|
|
88
|
+
id={id}
|
|
89
|
+
disablePortal
|
|
90
|
+
className={className}
|
|
91
|
+
options={options}
|
|
92
|
+
loading={loading}
|
|
93
|
+
noOptionsText={noOptionsText}
|
|
94
|
+
groupBy={renderGroupBy}
|
|
95
|
+
getOptionLabel={renderOptionLabel}
|
|
96
|
+
renderOption={renderOption}
|
|
97
|
+
renderInput={renderInput}
|
|
98
|
+
ListboxComponent={renderListBoxComponent}
|
|
99
|
+
renderGroup={renderGroupName}
|
|
100
|
+
onChange={onChange}
|
|
101
|
+
onInputChange={onInputChange}
|
|
102
|
+
value={value}
|
|
103
|
+
inputValue={inputValue}
|
|
104
|
+
filterOptions={
|
|
105
|
+
isFilterEnabled
|
|
106
|
+
? undefined // Use default filtering behavior
|
|
107
|
+
: (options) => options
|
|
108
|
+
}
|
|
109
|
+
freeSolo
|
|
110
|
+
/>
|
|
111
|
+
</>
|
|
115
112
|
);
|
|
116
113
|
};
|
|
117
114
|
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { NsButton, NsTypography } from '../..';
|
|
2
2
|
|
|
3
|
-
type
|
|
4
|
-
text
|
|
5
|
-
show
|
|
6
|
-
|
|
3
|
+
type AutoCompleteButtonProps = {
|
|
4
|
+
text: string;
|
|
5
|
+
show: boolean;
|
|
6
|
+
onClick(): void;
|
|
7
|
+
testId?: string;
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
export const AutoCompleteButton = (props: AutoCompleteButtonProps) => {
|
|
11
|
+
const { show, onClick, text, testId } = props;
|
|
10
12
|
if (!show) {
|
|
11
13
|
return null;
|
|
12
14
|
}
|
|
13
15
|
return (
|
|
14
16
|
<li className="text-right p-3">
|
|
15
|
-
<NsButton onClick={
|
|
17
|
+
<NsButton onClick={onClick} data-testid={testId}>
|
|
16
18
|
<NsTypography variant="p-xs" weight="bold">
|
|
17
19
|
{text}
|
|
18
20
|
</NsTypography>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Dispatch, MutableRefObject, SetStateAction, useCallback } from 'react';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import { OptionsProps } from '../..';
|
|
4
|
+
import { AutoCompleteButton } from './AutoCompleteButton';
|
|
3
5
|
|
|
4
6
|
type SeeMoreButtonProps = {
|
|
5
7
|
text?: string;
|
|
6
8
|
show?: boolean;
|
|
7
9
|
onSeeMore?(): void;
|
|
8
|
-
options:
|
|
10
|
+
options: OptionsProps[];
|
|
9
11
|
setScrollTopPosition: Dispatch<SetStateAction<number>>;
|
|
10
12
|
listboxRef: MutableRefObject<HTMLUListElement | null>;
|
|
11
13
|
};
|
|
@@ -32,16 +34,5 @@ export const SeeMoreButton = (props: SeeMoreButtonProps) => {
|
|
|
32
34
|
onSeeMore();
|
|
33
35
|
}
|
|
34
36
|
}, [listboxRef, onSeeMore, options?.length, setScrollTopPosition]);
|
|
35
|
-
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
return (
|
|
39
|
-
<li className="text-center p-3">
|
|
40
|
-
<NsButton onClick={handleSeeMore} data-testid="autocomplete-loadmore-id">
|
|
41
|
-
<NsTypography variant="p-xs" weight="bold">
|
|
42
|
-
{text}
|
|
43
|
-
</NsTypography>
|
|
44
|
-
</NsButton>
|
|
45
|
-
</li>
|
|
46
|
-
);
|
|
37
|
+
return <AutoCompleteButton show={show} text={text} onClick={handleSeeMore} testId="autocomplete-loadmore-id" />;
|
|
47
38
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AutocompleteRenderGroupParams } from '@mui/material';
|
|
2
|
+
|
|
2
3
|
import { NsTypography, OptionsProps } from '../..';
|
|
3
4
|
|
|
4
5
|
export const renderGroupName = ({ key, group, children }: AutocompleteRenderGroupParams) => (
|
|
@@ -12,6 +13,7 @@ export const renderGroupName = ({ key, group, children }: AutocompleteRenderGrou
|
|
|
12
13
|
</li>
|
|
13
14
|
);
|
|
14
15
|
|
|
15
|
-
export const renderOptionLabel = (option: OptionsProps) =>
|
|
16
|
+
export const renderOptionLabel = (option: string | OptionsProps) =>
|
|
17
|
+
typeof option === 'string' ? option : option?.value ?? '';
|
|
16
18
|
|
|
17
|
-
export const renderGroupBy = (option: OptionsProps) => option
|
|
19
|
+
export const renderGroupBy = (option: OptionsProps) => (option?.group ?? '') as string;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { NsAutocompleteProps, OptionsProps } from '../types';
|
|
2
|
-
import React, { useState } from 'react';
|
|
2
|
+
import React, { useState, SyntheticEvent } from 'react';
|
|
3
3
|
|
|
4
4
|
import { NsAutocomplete } from '..';
|
|
5
5
|
import { OptionUiComponent } from '../mock/MockUI';
|
|
6
6
|
|
|
7
7
|
const PAGE_SIZE = 6;
|
|
8
8
|
|
|
9
|
-
export const
|
|
9
|
+
export const NoCloseAutoComplete = (args: NsAutocompleteProps) => {
|
|
10
10
|
const [selectedOption, setSelectedOption] = useState<string | OptionsProps | null>(null);
|
|
11
11
|
const [searchTerms, setSearchTerms] = useState<string>('');
|
|
12
12
|
const [pageNo, setPageNo] = useState(PAGE_SIZE);
|
|
@@ -23,12 +23,12 @@ export const ACWithoutClose = (args: NsAutocompleteProps) => {
|
|
|
23
23
|
},
|
|
24
24
|
} as NsAutocompleteProps;
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const onChange = (event: SyntheticEvent<Element, Event>, value: string | OptionsProps | null) => {
|
|
27
27
|
setSelectedOption(value);
|
|
28
28
|
setSearchTerms((value = ''));
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const onInputChange = (event: SyntheticEvent<Element, Event>, newValue: string) => {
|
|
32
32
|
setSearchTerms(newValue);
|
|
33
33
|
};
|
|
34
34
|
|
|
@@ -37,8 +37,8 @@ export const ACWithoutClose = (args: NsAutocompleteProps) => {
|
|
|
37
37
|
<NsAutocomplete
|
|
38
38
|
{...AutoCompleteProps}
|
|
39
39
|
options={args.options.slice(0, pageNo)}
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
onInputChange={onInputChange}
|
|
41
|
+
onChange={onChange}
|
|
42
42
|
OptionsUI={OptionUiComponent}
|
|
43
43
|
value={selectedOption}
|
|
44
44
|
inputValue={searchTerms}
|
|
@@ -7,7 +7,7 @@ import { NsAutocomplete } from '..';
|
|
|
7
7
|
import { AutocompleteMockList } from '../mock/MockData';
|
|
8
8
|
import { NsIcon } from '../../icon';
|
|
9
9
|
import { RenderAutoComplete } from './RenderAutoComplete';
|
|
10
|
-
import {
|
|
10
|
+
import { NoCloseAutoComplete } from './NoCloseAutoComplete';
|
|
11
11
|
|
|
12
12
|
type ComponentType = typeof NsAutocomplete;
|
|
13
13
|
type Story = StoryObj<ComponentType>;
|
|
@@ -63,7 +63,7 @@ export default {
|
|
|
63
63
|
},
|
|
64
64
|
iconStart: <NsIcon name="search" />,
|
|
65
65
|
iconEnd: <NsIcon name="roundedClose" size="small" colorOverride="#F5F5F5" />,
|
|
66
|
-
placeholder: '
|
|
66
|
+
placeholder: 'Search',
|
|
67
67
|
},
|
|
68
68
|
} as MetaStory;
|
|
69
69
|
|
|
@@ -72,5 +72,5 @@ export const Autocomplete: Story = {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
export const WithoutClose: Story = {
|
|
75
|
-
render:
|
|
75
|
+
render: NoCloseAutoComplete,
|
|
76
76
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NsAutocompleteProps, OptionsProps } from '../types';
|
|
2
2
|
import { IconButton } from '@mui/material';
|
|
3
|
-
import React, { useState } from 'react';
|
|
3
|
+
import React, { useState, SyntheticEvent } from 'react';
|
|
4
4
|
|
|
5
5
|
import { NsAutocomplete } from '..';
|
|
6
6
|
import { NsIcon } from '../../icon';
|
|
@@ -25,12 +25,12 @@ export const RenderAutoComplete = (args: NsAutocompleteProps) => {
|
|
|
25
25
|
},
|
|
26
26
|
} as NsAutocompleteProps;
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const onChange = (event: SyntheticEvent<Element, Event>, value: string | OptionsProps | null) => {
|
|
29
29
|
setSelectedOption(value);
|
|
30
30
|
setSearchTerms((value = ''));
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const onInputChange = (event: SyntheticEvent<Element, Event>, newValue: string) => {
|
|
34
34
|
setSearchTerms(newValue);
|
|
35
35
|
};
|
|
36
36
|
|
|
@@ -44,8 +44,8 @@ export const RenderAutoComplete = (args: NsAutocompleteProps) => {
|
|
|
44
44
|
<NsAutocomplete
|
|
45
45
|
{...AutoCompleteProps}
|
|
46
46
|
options={args.options.slice(0, pageNo)}
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
onInputChange={onInputChange}
|
|
48
|
+
onChange={onChange}
|
|
49
49
|
OptionsUI={OptionUiComponent}
|
|
50
50
|
iconEnd={
|
|
51
51
|
<IconButton onClick={onInputClear}>
|