@nuskin/foundation-ui-components 1.0.0-develop.3 → 1.0.0-develop.4
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 +1 -1
- package/src/common/accordion/NsAccordion.tsx +77 -0
- package/src/common/accordion/NsAccordionHeader.tsx +56 -0
- package/src/common/accordion/NsAccordionItem.tsx +39 -0
- package/src/common/accordion/NsCollapse.tsx +56 -0
- package/src/common/accordion/NsToggleSection.tsx +30 -0
- package/src/common/accordion/ToggleSection.styled.tsx +28 -0
- package/src/common/accordion/index.ts +6 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +91 -0
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +47 -0
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +38 -0
- package/src/common/accordion/specs/NsCollapse.spec.tsx +37 -0
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +33 -0
- package/src/common/accordion/stories/NsAccordion.stories.tsx +47 -0
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +40 -0
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +40 -0
- package/src/common/accordion/stories/NsCollapse.stories.tsx +35 -0
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +23 -0
- package/src/common/accordion/stories/data.tsx +22 -0
- package/src/common/accordion/types.d.ts +73 -0
- package/src/common/alert/types.d.ts +22 -22
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +20 -8
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +3 -0
- package/src/common/autocomplete/NsAutocomplete.styled.tsx +12 -0
- package/src/common/autocomplete/NsAutocomplete.tsx +36 -18
- package/src/common/autocomplete/types.d.ts +7 -1
- package/src/common/button/NsButton.spec.tsx +10 -11
- package/src/common/checkbox/NsCheckbox.styled.tsx +2 -2
- package/src/common/common.types.d.ts +1 -0
- package/src/common/email-simple/NsEmailSimple.spec.tsx +145 -0
- package/src/common/email-simple/NsEmailSimple.stories.tsx +61 -0
- package/src/common/email-simple/NsEmailSimple.tsx +71 -0
- package/src/common/email-simple/index.ts +2 -0
- package/src/common/email-simple/types.d.ts +14 -0
- package/src/common/flag/NsFlag.spec.tsx +4 -25
- package/src/common/flag/NsFlag.tsx +0 -2
- package/src/common/image/types.d.ts +1 -0
- package/src/common/index.ts +3 -0
- package/src/common/input/NsInputField.stories.tsx +11 -9
- package/src/common/input/NsInputField.tsx +12 -5
- package/src/common/input/getAdornmentProps.tsx +4 -0
- package/src/common/input/types.d.ts +3 -1
- package/src/common/label/NsLabel.stories.tsx +3 -0
- package/src/common/label/NsLabel.tsx +14 -17
- package/src/common/label/types.d.ts +2 -1
- package/src/common/nav-tab/NsNavTab.spec.tsx +0 -5
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +63 -0
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +101 -0
- package/src/common/radiogroup/NsRadioGroup.styled.tsx +56 -0
- package/src/common/radiogroup/NsRadioGroup.tsx +46 -0
- package/src/common/radiogroup/index.ts +2 -0
- package/src/common/radiogroup/types.d.ts +19 -0
- package/src/common/select/NsSelect.spec.tsx +200 -0
- package/src/common/select/NsSelect.styled.tsx +89 -0
- package/src/common/select/NsSelect.tsx +117 -0
- package/src/common/select/NsSelectOption.tsx +30 -0
- package/src/common/select/index.ts +3 -0
- package/src/common/select/stories/NsSelect.stories.tsx +134 -0
- package/src/common/select/types.d.ts +34 -0
- package/src/common/table/NsExpandableRow.tsx +68 -0
- package/src/common/table/NsTable.spec.tsx +69 -41
- package/src/common/table/NsTable.stories.tsx +45 -7
- package/src/common/table/NsTable.styled.ts +95 -4
- package/src/common/table/NsTable.tsx +78 -89
- package/src/common/table/NsTableHeader.tsx +52 -38
- package/src/common/table/NsTablePagination.tsx +21 -13
- package/src/common/table/types.d.ts +21 -8
- package/src/common/validations/regex.ts +3 -0
- /package/src/common/card/{tests → specs}/BrandLogo.spec.tsx +0 -0
- /package/src/common/card/{tests → specs}/NsBgCard.spec.tsx +0 -0
- /package/src/common/card/{tests → specs}/NsBrandProductCard.spec.tsx +0 -0
- /package/src/common/card/{tests → specs}/NsFfgCard.spec.tsx +0 -0
- /package/src/common/carousal/{tests → specs}/Chevron.spec.tsx +0 -0
- /package/src/common/carousal/{tests → specs}/NsCarousal.spec.tsx +0 -0
- /package/src/common/carousal/{tests → specs}/NsScrollingCarousal.spec.tsx +0 -0
- /package/src/common/carousal/{tests → specs}/RenderBrand.spec.tsx +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
3
|
+
import { NsAccordionItem } from '@/common/index';
|
|
4
|
+
|
|
5
|
+
type ComponentType = typeof NsAccordionItem;
|
|
6
|
+
type Story = StoryObj<ComponentType>;
|
|
7
|
+
type MetaStory = Meta<ComponentType>;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/Accordion/NsAccordionItem',
|
|
11
|
+
component: NsAccordionItem,
|
|
12
|
+
decorators: [withCenterDecorator],
|
|
13
|
+
argTypes: {
|
|
14
|
+
isOpen: {
|
|
15
|
+
control: 'boolean',
|
|
16
|
+
description: 'if true renders NsAccordionItem in open state, and close state otherwise',
|
|
17
|
+
},
|
|
18
|
+
content: {},
|
|
19
|
+
title: {
|
|
20
|
+
control: 'string',
|
|
21
|
+
description: 'text used for header of section',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
} as MetaStory;
|
|
25
|
+
|
|
26
|
+
export const OpenSection: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
isOpen: true,
|
|
29
|
+
content: 'Nuskin Description',
|
|
30
|
+
title: 'Nuskin',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const ClosedSection: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
isOpen: false,
|
|
37
|
+
content: 'Nuskin Description',
|
|
38
|
+
title: 'Nuskin',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
3
|
+
import { NsCollapse } from '../';
|
|
4
|
+
|
|
5
|
+
type ComponentType = typeof NsCollapse;
|
|
6
|
+
type Story = StoryObj<ComponentType>;
|
|
7
|
+
type MetaStory = Meta<ComponentType>;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/Accordion/NsCollapse',
|
|
11
|
+
component: NsCollapse,
|
|
12
|
+
decorators: [withCenterDecorator],
|
|
13
|
+
argTypes: {
|
|
14
|
+
isOpen: {
|
|
15
|
+
control: 'boolean',
|
|
16
|
+
description: 'if true renders NsCollapse in open state, and close state otherwise',
|
|
17
|
+
},
|
|
18
|
+
children: {
|
|
19
|
+
control: 'React Node',
|
|
20
|
+
description: 'Content for NsCollapse',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
} as MetaStory;
|
|
24
|
+
export const Closed: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
isOpen: false,
|
|
27
|
+
children: 'Nuskin Description',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export const Open: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
isOpen: true,
|
|
33
|
+
children: 'Nuskin Description',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
3
|
+
import { NsToggleSection } from '../..';
|
|
4
|
+
|
|
5
|
+
type ComponentType = typeof NsToggleSection;
|
|
6
|
+
type Story = StoryObj<ComponentType>;
|
|
7
|
+
type MetaStory = Meta<ComponentType>;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/Accordion/NsToggleSection',
|
|
11
|
+
component: NsToggleSection,
|
|
12
|
+
decorators: [withCenterDecorator],
|
|
13
|
+
argTypes: {
|
|
14
|
+
title: { control: 'string' },
|
|
15
|
+
},
|
|
16
|
+
args: {
|
|
17
|
+
title: 'Nuskin',
|
|
18
|
+
children: 'Nuskin Details',
|
|
19
|
+
|
|
20
|
+
},
|
|
21
|
+
} as MetaStory;
|
|
22
|
+
|
|
23
|
+
export const DefaultAccordion: Story = {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NsAccordionProps } from '../types';
|
|
2
|
+
|
|
3
|
+
export const contentArray: NsAccordionProps['contentArray'] = [
|
|
4
|
+
{
|
|
5
|
+
title: 'Nuskin',
|
|
6
|
+
body: <div>Nuskin Details</div>,
|
|
7
|
+
isDefaultOpen: true,
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
title: 'Nuskin',
|
|
11
|
+
body: <div>Nuskin Details</div>,
|
|
12
|
+
isDefaultOpen: true,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
title: 'Nuskin',
|
|
16
|
+
body: <div>Nuskin Details</div>,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
title: 'Nuskin',
|
|
20
|
+
body: <div>Nuskin Details</div>,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { PropsWithChildren, ReactNode } from 'react';
|
|
2
|
+
import { AdditionalProps } from '../common.types';
|
|
3
|
+
import { NsIconNameType } from '../icon';
|
|
4
|
+
import { Variants } from '../typography';
|
|
5
|
+
|
|
6
|
+
export type NsAccordionHeaderProps = AdditionalProps & {
|
|
7
|
+
title: string | ReactNode;
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
onClick: (...args: any[]) => void;
|
|
10
|
+
/** a flag for the header, based on which header can change properties */
|
|
11
|
+
isOpen?: boolean;
|
|
12
|
+
/** NsIcon's icon name to be shown in opened state */
|
|
13
|
+
openedIconName?: NsIconNameType;
|
|
14
|
+
/** NsIcon's icon name to be shown in closed state */
|
|
15
|
+
closedIconName?: NsIconNameType;
|
|
16
|
+
variant: AccordionVariant;
|
|
17
|
+
headerTypographyVariant?: Variants;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type NsCollapseProps = AdditionalProps &
|
|
21
|
+
PropsWithChildren<{
|
|
22
|
+
isOpen: boolean;
|
|
23
|
+
variant: AccordionVariant;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export type NsFramerCollapseProps = NsCollapseProps & {
|
|
27
|
+
transitionDetails?: {
|
|
28
|
+
duration?: number;
|
|
29
|
+
ease?: number[];
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type NsToggleSectionProps = AdditionalProps &
|
|
34
|
+
PropsWithChildren<{
|
|
35
|
+
title: string | ReactNode;
|
|
36
|
+
/** if true, NsToggle is rendered in open state, that collapsible section is visible */
|
|
37
|
+
defaultOpen?: boolean;
|
|
38
|
+
variant: AccordionVariant;
|
|
39
|
+
}>;
|
|
40
|
+
|
|
41
|
+
export type NsAccordionItemProps = AdditionalProps & {
|
|
42
|
+
isOpen: boolean;
|
|
43
|
+
// eslint-disable-next-line no-unused-vars
|
|
44
|
+
toggleOpen(index: number, isOpen: boolean): void;
|
|
45
|
+
title: string | ReactNode;
|
|
46
|
+
content: ReactNode;
|
|
47
|
+
variant: AccordionVariant;
|
|
48
|
+
headerTypographyVariant?: Variants;
|
|
49
|
+
/** NsIcon's icon name to be shown in opened state */
|
|
50
|
+
openedIconName?: NsIconNameType;
|
|
51
|
+
/** NsIcon's icon name to be shown in closed state */
|
|
52
|
+
closedIconName?: NsIconNameType;
|
|
53
|
+
};
|
|
54
|
+
export type NsAccordionProps = AdditionalProps & {
|
|
55
|
+
allowMultipleExpanded: boolean;
|
|
56
|
+
contentArray: {
|
|
57
|
+
title: string | ReactNode;
|
|
58
|
+
body: ReactNode;
|
|
59
|
+
isDefaultOpen?: boolean;
|
|
60
|
+
}[];
|
|
61
|
+
variant: AccordionVariant;
|
|
62
|
+
headerTypographyVariant?: Variants;
|
|
63
|
+
/** NsIcon's icon name to be shown in opened state */
|
|
64
|
+
openedIconName?: NsIconNameType;
|
|
65
|
+
/** NsIcon's icon name to be shown in closed state */
|
|
66
|
+
closedIconName?: NsIconNameType;
|
|
67
|
+
};
|
|
68
|
+
export enum AccordionVariant {
|
|
69
|
+
// eslint-disable-next-line no-unused-vars
|
|
70
|
+
Basic = 'basic', // basic is as per figma
|
|
71
|
+
// eslint-disable-next-line no-unused-vars
|
|
72
|
+
Compact = 'compact', // compact is as per test.nuskin.com
|
|
73
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { ReactNode, CSSProperties } from 'react';
|
|
2
2
|
|
|
3
3
|
export interface NsAlertProps {
|
|
4
|
-
context?: string
|
|
5
|
-
title?: string
|
|
6
|
-
threshhold?: number,
|
|
7
|
-
type?: string
|
|
8
|
-
visible?: boolean
|
|
9
|
-
head?: ReactNode
|
|
10
|
-
body?: ReactNode
|
|
11
|
-
onDismiss?: () => void
|
|
12
|
-
foot?: ReactNode
|
|
4
|
+
context?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
threshhold?: number; // TODO: update to threshold, i.e. remove extra h
|
|
7
|
+
type?: string;
|
|
8
|
+
visible?: boolean;
|
|
9
|
+
head?: ReactNode;
|
|
10
|
+
body?: ReactNode;
|
|
11
|
+
onDismiss?: () => void;
|
|
12
|
+
foot?: ReactNode;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface HeaderProps {
|
|
@@ -18,28 +18,28 @@ export interface HeaderProps {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export type AlertContainerParams = {
|
|
21
|
-
visible: boolean
|
|
21
|
+
visible: boolean;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export type ContextType = 'error' | 'info' | 'notice'| 'success' | 'warning';
|
|
24
|
+
export type ContextType = 'error' | 'info' | 'notice' | 'success' | 'warning';
|
|
25
25
|
export type AlertType = 'auto' | 'banner' | 'card';
|
|
26
26
|
|
|
27
27
|
export type AlertParams = {
|
|
28
|
-
context: ContextType
|
|
29
|
-
type: AlertType
|
|
30
|
-
}
|
|
28
|
+
context: ContextType;
|
|
29
|
+
type: AlertType;
|
|
30
|
+
};
|
|
31
31
|
|
|
32
32
|
export type CustomCSSProperties = CSSProperties & {
|
|
33
33
|
'min-height'?: string;
|
|
34
|
-
'content-column-start'
|
|
35
|
-
'content-column-end'
|
|
36
|
-
'bar-position'
|
|
37
|
-
'foot-visibility'
|
|
38
|
-
'foot-display'
|
|
34
|
+
'content-column-start'?: string;
|
|
35
|
+
'content-column-end'?: string;
|
|
36
|
+
'bar-position'?: string;
|
|
37
|
+
'foot-visibility'?: string;
|
|
38
|
+
'foot-display'?: string;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
export interface TypeMapCSS {
|
|
42
|
-
banner: CustomCSSProperties
|
|
43
|
-
card: CustomCSSProperties
|
|
44
|
-
auto?: CustomCSSProperties
|
|
42
|
+
banner: CustomCSSProperties;
|
|
43
|
+
card: CustomCSSProperties;
|
|
44
|
+
auto?: CustomCSSProperties;
|
|
45
45
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, waitFor } from '
|
|
2
|
+
import { render, screen, waitFor } from '@/test-utils/index';
|
|
3
3
|
import { NsAutocomplete } from '@/common/index';
|
|
4
4
|
import { OptionUiComponent } from './mock/MockUI';
|
|
5
5
|
import { AutocompleteMockList } from './mock/MockData';
|
|
6
6
|
import userEvent from '@testing-library/user-event';
|
|
7
|
+
import { act } from 'react-dom/test-utils';
|
|
7
8
|
|
|
8
9
|
describe('CustomAutocomplete', () => {
|
|
9
10
|
test('should render autocomplete component', () => {
|
|
@@ -29,11 +30,16 @@ describe('CustomAutocomplete', () => {
|
|
|
29
30
|
/>
|
|
30
31
|
);
|
|
31
32
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const option1 = screen.getByText('GS Facial Gels 2pk Subscription');
|
|
35
|
-
expect(option1).toBeInTheDocument();
|
|
33
|
+
act(() => {
|
|
34
|
+
userEvent.type(autocompleteInput, 'GS Facial');
|
|
36
35
|
});
|
|
36
|
+
await waitFor(
|
|
37
|
+
() => {
|
|
38
|
+
const option1 = screen.getByText('GS Facial Gels 2pk Subscription');
|
|
39
|
+
expect(option1).toBeInTheDocument();
|
|
40
|
+
},
|
|
41
|
+
{ timeout: 5000 }
|
|
42
|
+
);
|
|
37
43
|
}, 40000);
|
|
38
44
|
|
|
39
45
|
test('selects an option when clicking on it', async () => {
|
|
@@ -45,7 +51,9 @@ describe('CustomAutocomplete', () => {
|
|
|
45
51
|
/>
|
|
46
52
|
);
|
|
47
53
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
48
|
-
|
|
54
|
+
act(() => {
|
|
55
|
+
userEvent.type(autocompleteInput, 'GS Facial');
|
|
56
|
+
});
|
|
49
57
|
await waitFor(() => {
|
|
50
58
|
const optionLi = screen.getByText('GS Facial Spa');
|
|
51
59
|
userEvent.click(optionLi);
|
|
@@ -66,7 +74,9 @@ describe('CustomAutocomplete', () => {
|
|
|
66
74
|
/>
|
|
67
75
|
);
|
|
68
76
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
69
|
-
|
|
77
|
+
act(() => {
|
|
78
|
+
userEvent.type(autocompleteInput, 'GS Facial');
|
|
79
|
+
});
|
|
70
80
|
await waitFor(() => {
|
|
71
81
|
const loadMoreButton = screen.getByTestId('autocomplete-loadmore-id');
|
|
72
82
|
userEvent.click(loadMoreButton);
|
|
@@ -87,7 +97,9 @@ describe('CustomAutocomplete', () => {
|
|
|
87
97
|
/>
|
|
88
98
|
);
|
|
89
99
|
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
90
|
-
|
|
100
|
+
act(() => {
|
|
101
|
+
userEvent.type(autocompleteInput, 'GS Facial');
|
|
102
|
+
});
|
|
91
103
|
await waitFor(() => {
|
|
92
104
|
const clearButton = screen.getByTestId('autocomplete-clear-id');
|
|
93
105
|
userEvent.click(clearButton);
|
|
@@ -12,6 +12,7 @@ import { NsAutocomplete } from './';
|
|
|
12
12
|
import { AutocompleteMockList } from './mock/MockData';
|
|
13
13
|
import { OptionUiComponent } from './mock/MockUI';
|
|
14
14
|
import { NsAutocompleteProps } from './types.d';
|
|
15
|
+
import { NsIcon } from '../icon';
|
|
15
16
|
|
|
16
17
|
type ComponentType = typeof NsAutocomplete;
|
|
17
18
|
type Story = StoryObj<ComponentType>;
|
|
@@ -42,6 +43,8 @@ export default {
|
|
|
42
43
|
throw new Error('Function not implemented.');
|
|
43
44
|
},
|
|
44
45
|
},
|
|
46
|
+
iconStart: <NsIcon name="search" />,
|
|
47
|
+
iconEnd: <NsIcon name="close" size='small'/>,
|
|
45
48
|
placeholder: 'search',
|
|
46
49
|
},
|
|
47
50
|
} as MetaStory;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
|
|
3
|
+
import { NsInputField } from '../input';
|
|
4
|
+
|
|
5
|
+
export const StyledTextField = styled(NsInputField)`
|
|
6
|
+
.MuiAutocomplete-inputRoot {
|
|
7
|
+
padding-right: 10px !important;
|
|
8
|
+
}
|
|
9
|
+
.muiautocomplete-popupindicator {
|
|
10
|
+
display: none;
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { NsInputField } from '../input';
|
|
1
|
+
import React, { useState, PropsWithChildren, useRef } from 'react';
|
|
3
2
|
import { Autocomplete, AutocompleteRenderGroupParams, List, AutocompleteRenderInputParams } from '@mui/material';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { NsButton } from '../button';
|
|
3
|
+
import { NsTypography, NsButton } from '../';
|
|
4
|
+
import { NsAutocompleteProps, OptionsProps, ComponentBoxProps } from './types.d';
|
|
5
|
+
import { StyledTextField } from './NsAutocomplete.styled';
|
|
8
6
|
|
|
9
7
|
const NsAutocomplete = ({
|
|
10
8
|
id = 'custom_autocomplete_dropdown',
|
|
11
9
|
options = [],
|
|
12
10
|
renderOptions,
|
|
11
|
+
loading,
|
|
12
|
+
noOptionsText,
|
|
13
13
|
onSelect,
|
|
14
|
+
onChange,
|
|
14
15
|
clear,
|
|
15
16
|
seeMore,
|
|
16
17
|
placeholder,
|
|
17
18
|
className,
|
|
19
|
+
iconStart,
|
|
20
|
+
iconEnd,
|
|
18
21
|
}: PropsWithChildren<NsAutocompleteProps>) => {
|
|
19
22
|
const inputRef = useRef(null);
|
|
20
23
|
|
|
@@ -27,10 +30,21 @@ const NsAutocomplete = ({
|
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
const renderInput = (params: AutocompleteRenderInputParams) => (
|
|
30
|
-
<
|
|
33
|
+
<StyledTextField
|
|
34
|
+
{...params}
|
|
35
|
+
onChange={onChange}
|
|
36
|
+
placeholder={placeholder}
|
|
37
|
+
inputRef={inputRef}
|
|
38
|
+
InputProps={{
|
|
39
|
+
...params.InputProps,
|
|
40
|
+
startAdornment: iconStart,
|
|
41
|
+
endAdornment: iconEnd,
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
31
44
|
);
|
|
32
45
|
|
|
33
|
-
|
|
46
|
+
// TODO: @vijayprathap need to check if we can remove object spread of ...props and ...params in renderInput
|
|
47
|
+
const renderOption = (props: ComponentBoxProps, option: OptionsProps) => (
|
|
34
48
|
<li {...props}>
|
|
35
49
|
<OptionUI {...props} option={option} />
|
|
36
50
|
</li>
|
|
@@ -43,7 +57,7 @@ const NsAutocomplete = ({
|
|
|
43
57
|
const renderGroupName = ({ key, group, children }: AutocompleteRenderGroupParams) => (
|
|
44
58
|
<li key={key}>
|
|
45
59
|
{group ? (
|
|
46
|
-
<NsTypography variant="p-
|
|
60
|
+
<NsTypography variant="p-m" weight="bold" className="p-3">
|
|
47
61
|
{group}
|
|
48
62
|
</NsTypography>
|
|
49
63
|
) : null}
|
|
@@ -59,7 +73,9 @@ const NsAutocomplete = ({
|
|
|
59
73
|
return (
|
|
60
74
|
<div className="text-right p-3">
|
|
61
75
|
<NsButton onClick={onClear} data-testid="autocomplete-clear-id">
|
|
62
|
-
<NsTypography variant={'p-xs'}>
|
|
76
|
+
<NsTypography variant={'p-xs'} weight="bold">
|
|
77
|
+
{text}
|
|
78
|
+
</NsTypography>
|
|
63
79
|
</NsButton>
|
|
64
80
|
</div>
|
|
65
81
|
);
|
|
@@ -73,20 +89,20 @@ const NsAutocomplete = ({
|
|
|
73
89
|
return (
|
|
74
90
|
<div className="text-center p-3">
|
|
75
91
|
<NsButton onClick={onSeeMore} data-testid="autocomplete-loadmore-id">
|
|
76
|
-
<NsTypography variant="p-xs">
|
|
92
|
+
<NsTypography variant="p-xs" weight="bold">
|
|
93
|
+
{text}
|
|
94
|
+
</NsTypography>
|
|
77
95
|
</NsButton>
|
|
78
96
|
</div>
|
|
79
97
|
);
|
|
80
98
|
};
|
|
81
99
|
|
|
82
|
-
const renderListBoxComponent = ({ children, ...otherProps }:
|
|
83
|
-
|
|
100
|
+
const renderListBoxComponent = ({ children, ...otherProps }: ComponentBoxProps) => (
|
|
101
|
+
<List {...otherProps}>
|
|
84
102
|
{renderClearButton()}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</List>
|
|
89
|
-
</>
|
|
103
|
+
{children}
|
|
104
|
+
{renderSeeMoreButton()}
|
|
105
|
+
</List>
|
|
90
106
|
);
|
|
91
107
|
|
|
92
108
|
return (
|
|
@@ -95,6 +111,8 @@ const NsAutocomplete = ({
|
|
|
95
111
|
disablePortal
|
|
96
112
|
className={className}
|
|
97
113
|
options={options}
|
|
114
|
+
loading={loading}
|
|
115
|
+
noOptionsText={noOptionsText}
|
|
98
116
|
groupBy={renderGroupBy}
|
|
99
117
|
getOptionLabel={renderOptionLabel}
|
|
100
118
|
renderOption={renderOption}
|
|
@@ -6,9 +6,13 @@ import { ComponentsProps } from '@mui/material';
|
|
|
6
6
|
export type NsAutocompleteProps = {
|
|
7
7
|
id?: string;
|
|
8
8
|
options: OptionsProps[];
|
|
9
|
+
loading?:boolean;
|
|
9
10
|
renderOptions: React.ComponentType<any>;
|
|
11
|
+
noOptionsText ?:string;
|
|
10
12
|
// eslint-disable-next-line no-unused-vars
|
|
11
13
|
onSelect?: (params: OptionsProps | null) => void;
|
|
14
|
+
// eslint-disable-next-line no-unused-vars
|
|
15
|
+
onChange?: (params) => void;
|
|
12
16
|
clear?: {
|
|
13
17
|
text: string;
|
|
14
18
|
show?: boolean; //default to false
|
|
@@ -21,6 +25,8 @@ export type NsAutocompleteProps = {
|
|
|
21
25
|
};
|
|
22
26
|
placeholder?: string;
|
|
23
27
|
className?: string;
|
|
28
|
+
iconStart?: string | React.ReactNode;
|
|
29
|
+
iconEnd?: string | React.ReactNode;
|
|
24
30
|
} & AdditionalProps;
|
|
25
31
|
|
|
26
32
|
export type ListUiProps = {
|
|
@@ -36,4 +42,4 @@ export type OptionsProps = {
|
|
|
36
42
|
groupBgColor?: string;
|
|
37
43
|
};
|
|
38
44
|
|
|
39
|
-
export type
|
|
45
|
+
export type ComponentBoxProps = ComponentsProps & HTMLAttributes<HTMLElement>;
|
|
@@ -8,28 +8,29 @@ const { palette } = nuskinTheme;
|
|
|
8
8
|
describe('<Button />', () => {
|
|
9
9
|
describe(' button primary', () => {
|
|
10
10
|
test('should render default button styles', () => {
|
|
11
|
+
const text = 'Click Me';
|
|
11
12
|
render(
|
|
12
13
|
<Button color="primary" variant="contained">
|
|
13
|
-
|
|
14
|
+
{text}
|
|
14
15
|
</Button>
|
|
15
16
|
);
|
|
16
17
|
|
|
17
|
-
const button = screen.getByText(
|
|
18
|
-
|
|
18
|
+
const button = screen.getByText(text);
|
|
19
19
|
expect(button).toBeInTheDocument();
|
|
20
|
-
expect(button).toHaveStyle(`color: ${palette
|
|
21
|
-
expect(button).toHaveStyle(`background-color: ${palette
|
|
20
|
+
expect(button).toHaveStyle(`color: ${palette?.primary?.contrastText ?? ''}`);
|
|
21
|
+
expect(button).toHaveStyle(`background-color: ${palette?.primary?.main ?? ''}`);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
24
|
describe('button secondary', () => {
|
|
25
25
|
test('should render default button styles', () => {
|
|
26
|
+
const text = 'Click Me';
|
|
26
27
|
render(
|
|
27
28
|
<Button color="success" variant="contained" size="large">
|
|
28
|
-
|
|
29
|
+
{text}
|
|
29
30
|
</Button>
|
|
30
31
|
);
|
|
31
32
|
|
|
32
|
-
const button = screen.getByText(
|
|
33
|
+
const button = screen.getByText(text);
|
|
33
34
|
|
|
34
35
|
expect(button).toBeInTheDocument();
|
|
35
36
|
expect(button).toHaveStyle(`color: ${palette.success.contrastText}`);
|
|
@@ -37,7 +38,7 @@ describe('<Button />', () => {
|
|
|
37
38
|
});
|
|
38
39
|
});
|
|
39
40
|
describe('button outline success', () => {
|
|
40
|
-
test('should render outlined
|
|
41
|
+
test('should render outlined success button', () => {
|
|
41
42
|
render(
|
|
42
43
|
<Button color="success" variant="outlined" size="large">
|
|
43
44
|
Click Me
|
|
@@ -48,11 +49,10 @@ describe('<Button />', () => {
|
|
|
48
49
|
|
|
49
50
|
expect(button).toBeInTheDocument();
|
|
50
51
|
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
51
|
-
expect(button).toHaveStyle(`border-color: ${palette.success.main}`);
|
|
52
52
|
});
|
|
53
53
|
});
|
|
54
54
|
describe('button outline accentColorA', () => {
|
|
55
|
-
test('should render outlined
|
|
55
|
+
test('should render outlined success button', () => {
|
|
56
56
|
render(
|
|
57
57
|
<Button color="accentColorA" variant="outlined" size="large">
|
|
58
58
|
Click Me
|
|
@@ -63,7 +63,6 @@ describe('<Button />', () => {
|
|
|
63
63
|
|
|
64
64
|
expect(button).toBeInTheDocument();
|
|
65
65
|
expect(button).toHaveStyle(`color: ${palette?.accentColorA?.main}`);
|
|
66
|
-
expect(button).toHaveStyle(`border-color: ${palette?.accentColorA?.main}`);
|
|
67
66
|
});
|
|
68
67
|
});
|
|
69
68
|
});
|
|
@@ -38,8 +38,8 @@ export const BpCheckedIcon = styled(BpIcon)(({ theme: { palette } }) => ({
|
|
|
38
38
|
path: {
|
|
39
39
|
display: 'block',
|
|
40
40
|
},
|
|
41
|
-
background: palette
|
|
42
|
-
color: palette
|
|
41
|
+
background: palette?.primary?.main ?? '#fff',
|
|
42
|
+
color: palette?.primary?.contrastText ?? '#000',
|
|
43
43
|
}));
|
|
44
44
|
|
|
45
45
|
export const StyledLabel = styled('span')<{ $hasDisabled: boolean }>`
|