@ssa-ui-kit/core 1.0.5 → 1.0.7
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/dist/components/Typeahead/Typeahead.context.d.ts +4 -2
- package/dist/components/Typeahead/Typeahead.d.ts +1 -1
- package/dist/components/Typeahead/styles.d.ts +10 -9
- package/dist/components/Typeahead/types.d.ts +4 -2
- package/dist/components/Typeahead/useTypeahead.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CollapsibleNavBar/CollapsibleNavBarBase.ts +3 -3
- package/src/components/NavBar/NavBar.stories.tsx +7 -2
- package/src/components/NavBar/NavBarWrapper.ts +1 -1
- package/src/components/NotificationMenu/NotificationMenu.spec.tsx +1 -1
- package/src/components/NotificationMenu/stories/StoryComponent.tsx +1 -1
- package/src/components/Radio/RadioBase.tsx +1 -1
- package/src/components/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/src/components/Typeahead/Typeahead.context.ts +2 -0
- package/src/components/Typeahead/Typeahead.spec.tsx +6 -3
- package/src/components/Typeahead/Typeahead.stories.tsx +1 -1
- package/src/components/Typeahead/Typeahead.tsx +9 -4
- package/src/components/Typeahead/components/MultipleTrigger.tsx +2 -2
- package/src/components/Typeahead/components/SingleTrigger.tsx +4 -2
- package/src/components/Typeahead/components/TypeaheadItem.ts +1 -1
- package/src/components/Typeahead/styles.ts +4 -2
- package/src/components/Typeahead/types.ts +4 -2
- package/src/components/Typeahead/useTypeahead.tsx +21 -4
- package/src/components/UserProfile/UserProfile.stories.tsx +4 -2
- package/tsbuildcache +1 -1
package/package.json
CHANGED
|
@@ -75,7 +75,7 @@ const CollapsibleNavBarBase = styled(NavBarBase)`
|
|
|
75
75
|
|
|
76
76
|
& ~ div:nth-of-type(2) {
|
|
77
77
|
display: block;
|
|
78
|
-
border-radius:
|
|
78
|
+
border-radius: 0;
|
|
79
79
|
height: calc(100vh - 60px);
|
|
80
80
|
|
|
81
81
|
${({ theme }) => theme.mediaQueries.xlg} {
|
|
@@ -101,8 +101,8 @@ const CollapsibleNavBarBase = styled(NavBarBase)`
|
|
|
101
101
|
|
|
102
102
|
${({ theme }) => theme.mediaQueries.lg} {
|
|
103
103
|
&.opened {
|
|
104
|
-
min-width:
|
|
105
|
-
width:
|
|
104
|
+
min-width: 240px;
|
|
105
|
+
width: 291px;
|
|
106
106
|
|
|
107
107
|
& > div:nth-of-type(2) {
|
|
108
108
|
width: 240px;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fragment } from 'react';
|
|
2
2
|
import { Routes, Route, MemoryRouter } from 'react-router-dom';
|
|
3
3
|
import { Meta } from '@storybook/react';
|
|
4
|
-
import { Title, Description,
|
|
4
|
+
import { Title, Description, Subtitle, Primary } from '@storybook/addon-docs';
|
|
5
5
|
|
|
6
6
|
import { NavBar } from './NavBar';
|
|
7
7
|
import { DecoratorFunction } from '@storybook/types';
|
|
@@ -42,12 +42,17 @@ export default {
|
|
|
42
42
|
viewport: {
|
|
43
43
|
defaultViewport: 'mobile2',
|
|
44
44
|
},
|
|
45
|
+
source: {
|
|
46
|
+
type: 'code',
|
|
47
|
+
},
|
|
45
48
|
docs: {
|
|
49
|
+
inlineStories: false,
|
|
46
50
|
page: () => (
|
|
47
51
|
<Fragment>
|
|
48
52
|
<Title />
|
|
53
|
+
<Subtitle />
|
|
49
54
|
<Description />
|
|
50
|
-
<
|
|
55
|
+
<Primary />
|
|
51
56
|
</Fragment>
|
|
52
57
|
),
|
|
53
58
|
},
|
|
@@ -15,7 +15,7 @@ const NavBarWrapper = styled.div`
|
|
|
15
15
|
${({ theme }) => theme.colors.greyDarker} 100%
|
|
16
16
|
);
|
|
17
17
|
|
|
18
|
-
transform: translateY(-
|
|
18
|
+
transform: translateY(-300vh);
|
|
19
19
|
transition: height 475ms ease, transform 450ms ease, border-radius 450ms ease;
|
|
20
20
|
|
|
21
21
|
${({ theme }) => theme.mediaQueries.md} {
|
|
@@ -71,7 +71,7 @@ export const StoryComponent = () => {
|
|
|
71
71
|
}
|
|
72
72
|
rightButton={
|
|
73
73
|
<Link to={'/'} css={{ gridColumn: 2 }}>
|
|
74
|
-
<Button variant="info" text="View all
|
|
74
|
+
<Button variant="info" text="View all notifications" />
|
|
75
75
|
</Link>
|
|
76
76
|
}
|
|
77
77
|
isLoading={isLoading}>
|
|
@@ -6,6 +6,7 @@ export const RadioBase = styled(Label)`
|
|
|
6
6
|
flex-grow: 0;
|
|
7
7
|
align-items: center;
|
|
8
8
|
cursor: pointer;
|
|
9
|
+
gap: 5px;
|
|
9
10
|
|
|
10
11
|
&:has(input:disabled) {
|
|
11
12
|
cursor: default;
|
|
@@ -29,7 +30,6 @@ export const RadioBase = styled(Label)`
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
span {
|
|
32
|
-
margin-left: 10px;
|
|
33
33
|
font-size: 14px;
|
|
34
34
|
font-weight: 100;
|
|
35
35
|
}
|
|
@@ -47,7 +47,7 @@ export const HorizontalRadioGroupStories: StoryObj<typeof RadioGroup> = (
|
|
|
47
47
|
) => (
|
|
48
48
|
<Fragment>
|
|
49
49
|
<Typography variant="h4">Horizontal Radio Group</Typography>
|
|
50
|
-
<RadioGroup {...args} css={{ marginTop: '10px' }}>
|
|
50
|
+
<RadioGroup {...args} css={{ marginTop: '10px', gap: 10, display: 'flex' }}>
|
|
51
51
|
<Radio id="radio1" value="apple" text="Apple" />
|
|
52
52
|
<Radio id="radio2" value="orange" text="Orange" />
|
|
53
53
|
<Radio id="radio3" value="banana" text="Banana" isDisabled={true} />
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { FieldValues, UseFormReturn } from 'react-hook-form';
|
|
2
3
|
import { UseTypeaheadResult } from './useTypeahead';
|
|
3
4
|
|
|
4
5
|
export const TypeaheadContext = React.createContext<UseTypeaheadResult>({
|
|
@@ -23,6 +24,7 @@ export const TypeaheadContext = React.createContext<UseTypeaheadResult>({
|
|
|
23
24
|
isDisabled: false,
|
|
24
25
|
options: [],
|
|
25
26
|
placeholder: '',
|
|
27
|
+
useFormResult: {} as UseFormReturn<FieldValues>,
|
|
26
28
|
setValue: () => {
|
|
27
29
|
/* no-op */
|
|
28
30
|
},
|
|
@@ -492,15 +492,18 @@ describe('Typeahead', () => {
|
|
|
492
492
|
|
|
493
493
|
it('Error should be displayed', () => {
|
|
494
494
|
const selectedIDs = selectedItems.map((item) => item.id);
|
|
495
|
-
|
|
495
|
+
|
|
496
|
+
const additionalProps = {
|
|
496
497
|
initialSelectedItems: selectedIDs,
|
|
497
498
|
isMultiple: true,
|
|
498
499
|
label: 'Label',
|
|
499
|
-
|
|
500
|
+
error: {
|
|
501
|
+
type: 'required',
|
|
500
502
|
message: 'Error message',
|
|
501
503
|
},
|
|
502
|
-
}
|
|
504
|
+
};
|
|
503
505
|
|
|
506
|
+
const { getByTestId } = setup(additionalProps);
|
|
504
507
|
expect(getByTestId('helper-text')).toBeInTheDocument();
|
|
505
508
|
});
|
|
506
509
|
});
|
|
@@ -189,7 +189,7 @@ export const WithError: StoryObj = (args: TypeaheadProps) => {
|
|
|
189
189
|
validationSchema={{
|
|
190
190
|
required: 'Required',
|
|
191
191
|
}}
|
|
192
|
-
|
|
192
|
+
error={mockError}
|
|
193
193
|
renderOption={({ label, input }) => highlightInputMatch(label, input)}>
|
|
194
194
|
{items.map(({ label, value, id }) => (
|
|
195
195
|
<TypeaheadOption key={id} value={id} label={label || value}>
|
|
@@ -32,7 +32,7 @@ export const Typeahead = ({
|
|
|
32
32
|
className,
|
|
33
33
|
startIcon,
|
|
34
34
|
endIcon,
|
|
35
|
-
|
|
35
|
+
error,
|
|
36
36
|
success,
|
|
37
37
|
helperText,
|
|
38
38
|
validationSchema,
|
|
@@ -40,6 +40,8 @@ export const Typeahead = ({
|
|
|
40
40
|
startIconClassName,
|
|
41
41
|
endIconClassName,
|
|
42
42
|
optionsClassName,
|
|
43
|
+
wrapperClassName,
|
|
44
|
+
width = 300,
|
|
43
45
|
setValue,
|
|
44
46
|
register,
|
|
45
47
|
onChange,
|
|
@@ -58,7 +60,7 @@ export const Typeahead = ({
|
|
|
58
60
|
endIcon,
|
|
59
61
|
startIconClassName,
|
|
60
62
|
endIconClassName,
|
|
61
|
-
|
|
63
|
+
error,
|
|
62
64
|
success,
|
|
63
65
|
validationSchema,
|
|
64
66
|
placeholder,
|
|
@@ -74,7 +76,9 @@ export const Typeahead = ({
|
|
|
74
76
|
css={{
|
|
75
77
|
flexDirection: 'column',
|
|
76
78
|
alignItems: 'flex-start',
|
|
79
|
+
width,
|
|
77
80
|
}}
|
|
81
|
+
className={wrapperClassName}
|
|
78
82
|
data-testid="typeahead">
|
|
79
83
|
{label && (
|
|
80
84
|
<Label
|
|
@@ -94,6 +98,7 @@ export const Typeahead = ({
|
|
|
94
98
|
css={{
|
|
95
99
|
width: hookResult.triggerRef.current?.clientWidth,
|
|
96
100
|
boxShadow: `-4px 4px 14px 0px ${theme.colors.greyDarker14}`,
|
|
101
|
+
zIndex: 100,
|
|
97
102
|
}}
|
|
98
103
|
isFocusManagerDisabled>
|
|
99
104
|
<PopoverDescription css={{ width: '100%' }}>
|
|
@@ -105,13 +110,13 @@ export const Typeahead = ({
|
|
|
105
110
|
</PopoverDescription>
|
|
106
111
|
</PopoverContent>
|
|
107
112
|
</Popover>
|
|
108
|
-
{(
|
|
113
|
+
{(hookResult.status === 'error' || helperText) && (
|
|
109
114
|
<FormHelperText
|
|
110
115
|
role="status"
|
|
111
116
|
status={hookResult.status}
|
|
112
117
|
disabled={isDisabled}
|
|
113
118
|
data-testid="helper-text">
|
|
114
|
-
{
|
|
119
|
+
{error ? error?.message : helperText}
|
|
115
120
|
</FormHelperText>
|
|
116
121
|
)}
|
|
117
122
|
</Wrapper>
|
|
@@ -69,7 +69,7 @@ export const MultipleTrigger = () => {
|
|
|
69
69
|
onChange: context.handleInputChange,
|
|
70
70
|
value: context.inputValue,
|
|
71
71
|
autoComplete: 'off',
|
|
72
|
-
className: ['typeahead-input', S.TypeaheadInput].join(' '),
|
|
72
|
+
className: ['typeahead-input', S.TypeaheadInput(theme)].join(' '),
|
|
73
73
|
}}
|
|
74
74
|
wrapperClassName={S.TypeaheadInputWrapper}
|
|
75
75
|
ref={context.inputRef}
|
|
@@ -84,7 +84,7 @@ export const MultipleTrigger = () => {
|
|
|
84
84
|
disabled={context.isDisabled}
|
|
85
85
|
className={[
|
|
86
86
|
'typeahead-input',
|
|
87
|
-
S.TypeaheadInput,
|
|
87
|
+
S.TypeaheadInput(theme),
|
|
88
88
|
S.TypeaheadInputPlaceholder,
|
|
89
89
|
].join(' ')}
|
|
90
90
|
{...typeaheadInputAdditionalProps}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InputHTMLAttributes } from 'react';
|
|
2
|
+
import { useTheme } from '@emotion/react';
|
|
2
3
|
import Input from '@components/Input';
|
|
3
4
|
import Button from '@components/Button';
|
|
4
5
|
import Icon from '@components/Icon';
|
|
@@ -7,6 +8,7 @@ import * as S from '../styles';
|
|
|
7
8
|
|
|
8
9
|
export const SingleTrigger = () => {
|
|
9
10
|
const context = useTypeaheadContext();
|
|
11
|
+
const theme = useTheme();
|
|
10
12
|
const typeaheadInputAdditionalProps: InputHTMLAttributes<HTMLInputElement> =
|
|
11
13
|
{};
|
|
12
14
|
if (!context.selectedItems.length && !!context.placeholder) {
|
|
@@ -26,7 +28,7 @@ export const SingleTrigger = () => {
|
|
|
26
28
|
onChange: context.handleInputChange,
|
|
27
29
|
value: context.inputValue,
|
|
28
30
|
autoComplete: 'off',
|
|
29
|
-
className: ['typeahead-input', S.TypeaheadInput].join(' '),
|
|
31
|
+
className: ['typeahead-input', S.TypeaheadInput(theme)].join(' '),
|
|
30
32
|
}}
|
|
31
33
|
wrapperClassName={S.TypeaheadInputWrapper}
|
|
32
34
|
ref={context.inputRef}
|
|
@@ -40,7 +42,7 @@ export const SingleTrigger = () => {
|
|
|
40
42
|
value={context.firstSuggestion}
|
|
41
43
|
className={[
|
|
42
44
|
'typeahead-input',
|
|
43
|
-
S.TypeaheadInput,
|
|
45
|
+
S.TypeaheadInput(theme),
|
|
44
46
|
S.TypeaheadInputPlaceholder,
|
|
45
47
|
].join(' ')}
|
|
46
48
|
{...typeaheadInputAdditionalProps}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Theme } from '@emotion/react';
|
|
1
2
|
import { css } from '@emotion/css';
|
|
2
3
|
import styled from '@emotion/styled';
|
|
3
4
|
import Wrapper from '@components/Wrapper';
|
|
@@ -35,8 +36,9 @@ export const TypeaheadOption = styled.li<TypeaheadItemProps>`
|
|
|
35
36
|
}
|
|
36
37
|
`;
|
|
37
38
|
|
|
38
|
-
export const TypeaheadInput = css`
|
|
39
|
+
export const TypeaheadInput = (theme: Theme) => css`
|
|
39
40
|
&.typeahead-input {
|
|
41
|
+
color: ${theme.colors.greyDarker};
|
|
40
42
|
border: none;
|
|
41
43
|
border-radius: 0;
|
|
42
44
|
height: 32px;
|
|
@@ -148,7 +150,7 @@ export const TypeaheadTrigger = styled(PopoverTrigger)<{
|
|
|
148
150
|
background: #fff;
|
|
149
151
|
gap: 8px;
|
|
150
152
|
padding: 5px 28px 5px 8px;
|
|
151
|
-
width:
|
|
153
|
+
width: 100%;
|
|
152
154
|
flex-wrap: wrap;
|
|
153
155
|
border-color: ${({ isOpen, theme, status }) =>
|
|
154
156
|
isOpen &&
|
|
@@ -17,6 +17,8 @@ export interface TypeaheadProps {
|
|
|
17
17
|
children?: React.ReactNode;
|
|
18
18
|
className?: string;
|
|
19
19
|
optionsClassName?: string;
|
|
20
|
+
wrapperClassName?: string;
|
|
21
|
+
width?: string | number;
|
|
20
22
|
isOpen?: boolean;
|
|
21
23
|
startIcon?: React.ReactNode;
|
|
22
24
|
endIcon?: React.ReactNode;
|
|
@@ -25,7 +27,7 @@ export interface TypeaheadProps {
|
|
|
25
27
|
name?: string;
|
|
26
28
|
label?: string;
|
|
27
29
|
helperText?: string;
|
|
28
|
-
|
|
30
|
+
error?: FieldError;
|
|
29
31
|
success?: boolean;
|
|
30
32
|
validationSchema?: Record<string, unknown>;
|
|
31
33
|
placeholder?: string | null;
|
|
@@ -57,7 +59,7 @@ export type UseTypeaheadProps = Pick<
|
|
|
57
59
|
| 'register'
|
|
58
60
|
| 'setValue'
|
|
59
61
|
| 'validationSchema'
|
|
60
|
-
| '
|
|
62
|
+
| 'error'
|
|
61
63
|
| 'success'
|
|
62
64
|
| 'placeholder'
|
|
63
65
|
>;
|
|
@@ -6,6 +6,7 @@ import React, {
|
|
|
6
6
|
useRef,
|
|
7
7
|
useState,
|
|
8
8
|
} from 'react';
|
|
9
|
+
import { useForm } from 'react-hook-form';
|
|
9
10
|
import { propOr } from '@ssa-ui-kit/utils';
|
|
10
11
|
import { TypeaheadOptionProps, UseTypeaheadProps } from './types';
|
|
11
12
|
|
|
@@ -22,7 +23,7 @@ export const useTypeahead = ({
|
|
|
22
23
|
startIconClassName,
|
|
23
24
|
endIconClassName,
|
|
24
25
|
validationSchema,
|
|
25
|
-
|
|
26
|
+
error,
|
|
26
27
|
success,
|
|
27
28
|
placeholder,
|
|
28
29
|
register,
|
|
@@ -41,12 +42,13 @@ export const useTypeahead = ({
|
|
|
41
42
|
const [items, setItems] = useState<Array<React.ReactElement> | undefined>();
|
|
42
43
|
const [inputValue, setInputValue] = useState<string>('');
|
|
43
44
|
const [status, setStatus] = useState<'basic' | 'success' | 'error'>('basic');
|
|
45
|
+
const [firstSuggestion, setFirstSuggestion] = useState('');
|
|
44
46
|
|
|
45
47
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
46
48
|
const typeaheadId = useId();
|
|
47
49
|
const triggerRef: React.MutableRefObject<HTMLDivElement | null> =
|
|
48
50
|
useRef<HTMLDivElement>(null);
|
|
49
|
-
const
|
|
51
|
+
const useFormResult = useForm();
|
|
50
52
|
|
|
51
53
|
useEffect(() => {
|
|
52
54
|
if (!register) {
|
|
@@ -71,9 +73,21 @@ export const useTypeahead = ({
|
|
|
71
73
|
}, [isDisabled]);
|
|
72
74
|
|
|
73
75
|
useEffect(() => {
|
|
74
|
-
const status = success
|
|
76
|
+
const status = success
|
|
77
|
+
? 'success'
|
|
78
|
+
: useFormResult.formState.errors[name]
|
|
79
|
+
? 'error'
|
|
80
|
+
: 'basic';
|
|
75
81
|
setStatus(status);
|
|
76
|
-
}, [errors, success]);
|
|
82
|
+
}, [useFormResult.formState.errors[name], success]);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (error) {
|
|
86
|
+
useFormResult.setError(name, error);
|
|
87
|
+
} else {
|
|
88
|
+
useFormResult.resetField(name);
|
|
89
|
+
}
|
|
90
|
+
}, [error]);
|
|
77
91
|
|
|
78
92
|
useEffect(() => {
|
|
79
93
|
const keyedOptions: Record<
|
|
@@ -201,6 +215,8 @@ export const useTypeahead = ({
|
|
|
201
215
|
setIsOpen(false);
|
|
202
216
|
setFirstSuggestion('');
|
|
203
217
|
inputRef.current?.focus();
|
|
218
|
+
setStatus('basic');
|
|
219
|
+
useFormResult.clearErrors();
|
|
204
220
|
onChange && onChange(changingValue, isNewSelected);
|
|
205
221
|
};
|
|
206
222
|
|
|
@@ -305,6 +321,7 @@ export const useTypeahead = ({
|
|
|
305
321
|
status,
|
|
306
322
|
placeholder,
|
|
307
323
|
options: items,
|
|
324
|
+
useFormResult,
|
|
308
325
|
register,
|
|
309
326
|
setValue,
|
|
310
327
|
handleChange,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
1
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import Avatar from '@components/Avatar';
|
|
3
3
|
import { UserProfile } from './UserProfile';
|
|
4
|
+
import Icon from '@components/Icon';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
title: 'Widgets/UserProfile',
|
|
@@ -8,11 +9,12 @@ export default {
|
|
|
8
9
|
} as Meta<typeof UserProfile>;
|
|
9
10
|
|
|
10
11
|
export const Default: StoryObj<typeof UserProfile> = () => {
|
|
12
|
+
const theme = useTheme();
|
|
11
13
|
return (
|
|
12
14
|
<UserProfile
|
|
13
15
|
name="Josh Li"
|
|
14
16
|
email="Josh@gmail.com"
|
|
15
|
-
trigger={<
|
|
17
|
+
trigger={<Icon size={42} name="user" color={theme.colors.grey} />}
|
|
16
18
|
onClick={() => alert('Clicked!')}
|
|
17
19
|
/>
|
|
18
20
|
);
|