@takaro/lib-components 0.0.13 → 0.0.15
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/Dockerfile.dev +1 -1
- package/package.json +21 -20
- package/src/components/actions/ToggleButton/ToggleButton.stories.tsx +1 -0
- package/src/components/actions/ToggleButton/ToggleButton.tsx +3 -1
- package/src/components/actions/ToggleButton/ToggleButtonGroup.tsx +16 -2
- package/src/components/charts/AreaChart/AreaChart.stories.tsx +15 -20
- package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +24 -18
- package/src/components/charts/GeoMercator/index.tsx +160 -58
- package/src/components/charts/GeoMercator/iso3166-alpha2-to-alpha3.ts +250 -0
- package/src/components/charts/GeoMercator/world.json +333 -0
- package/src/components/charts/ZoomControls.tsx +47 -0
- package/src/components/charts/index.tsx +3 -0
- package/src/components/data/Drawer/Drawer.stories.tsx +19 -10
- package/src/components/data/Drawer/DrawerContent.tsx +56 -1
- package/src/components/data/Drawer/useDrawer.tsx +16 -2
- package/src/components/data/Table/index.tsx +94 -33
- package/src/components/data/Table/style.ts +21 -0
- package/src/components/data/Table/subcomponents/Pagination/PageSizeSelect.tsx +1 -0
- package/src/components/dialogs/Dialog/DialogContent.tsx +1 -5
- package/src/components/feedback/Alert/Alert.stories.tsx +1 -10
- package/src/components/feedback/Alert/index.tsx +11 -15
- package/src/components/feedback/Alert/style.ts +9 -11
- package/src/components/feedback/ErrorPage/index.tsx +2 -2
- package/src/components/feedback/snacks/Drawer/Drawer.stories.tsx +1 -1
- package/src/components/feedback/snacks/Drawer/index.tsx +4 -0
- package/src/components/inputs/Date/DatePicker/Controlled.tsx +2 -0
- package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +1 -1
- package/src/components/inputs/Date/DatePicker/Generic.tsx +20 -4
- package/src/components/inputs/Date/DatePicker/style.ts +3 -4
- package/src/components/inputs/index.ts +7 -0
- package/src/components/inputs/selects/SelectQueryField/Controlled.tsx +10 -0
- package/src/components/inputs/selects/SelectQueryField/Generic/index.tsx +39 -16
- package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +20 -0
- package/src/components/inputs/selects/SubComponents/OptionGroup.tsx +4 -2
- package/src/components/other/CollapseList/index.tsx +26 -31
- package/src/components/visual/Card/Card.stories.tsx +4 -1
- package/src/components/visual/Card/CardBody.tsx +11 -0
- package/src/components/visual/Card/CardTitle.tsx +23 -0
- package/src/components/visual/Card/index.tsx +21 -14
|
@@ -18,10 +18,9 @@ export const ResultContainer = styled.div<{ readOnly: boolean; hasError: boolean
|
|
|
18
18
|
z-index: ${({ theme }) => theme.zIndex.dropdown};
|
|
19
19
|
cursor: ${({ readOnly }) => (readOnly ? 'not-allowed' : 'pointer')};
|
|
20
20
|
user-select: none;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: space-between;
|
|
25
24
|
`;
|
|
26
25
|
|
|
27
26
|
export const ContentContainer = styled.div`
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export interface PaginationProps {
|
|
2
|
+
isFetching: boolean;
|
|
3
|
+
hasNextPage: boolean;
|
|
4
|
+
isFetchingNextPage: boolean;
|
|
5
|
+
fetchNextPage: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
export { ControlledCheckBox as CheckBox } from './CheckBox';
|
|
2
9
|
export type { ControlledCheckBoxProps as CheckBoxProps } from './CheckBox';
|
|
3
10
|
export { GenericCheckBox as UnControlledCheckBox } from './CheckBox/Generic';
|
|
@@ -29,6 +29,11 @@ export const ControlledSelectQueryField: FC<ControlledSelectQueryFieldProps> & S
|
|
|
29
29
|
inPortal,
|
|
30
30
|
debounce,
|
|
31
31
|
isLoadingData,
|
|
32
|
+
hasNextPage,
|
|
33
|
+
fetchNextPage,
|
|
34
|
+
isFetching,
|
|
35
|
+
isFetchingNextPage,
|
|
36
|
+
optionCount,
|
|
32
37
|
handleInputValueChange,
|
|
33
38
|
} = defaultsApplier(props);
|
|
34
39
|
|
|
@@ -85,7 +90,12 @@ export const ControlledSelectQueryField: FC<ControlledSelectQueryFieldProps> & S
|
|
|
85
90
|
onFocus={handleOnFocus}
|
|
86
91
|
value={field.value}
|
|
87
92
|
debounce={debounce}
|
|
93
|
+
optionCount={optionCount}
|
|
88
94
|
handleInputValueChange={handleInputValueChange}
|
|
95
|
+
isFetching={isFetching}
|
|
96
|
+
isFetchingNextPage={isFetchingNextPage}
|
|
97
|
+
hasNextPage={hasNextPage}
|
|
98
|
+
fetchNextPage={fetchNextPage}
|
|
89
99
|
>
|
|
90
100
|
{children}
|
|
91
101
|
</GenericSelectQueryField>
|
|
@@ -28,14 +28,15 @@ import { useDebounce } from '../../../../../hooks';
|
|
|
28
28
|
import { setAriaDescribedBy } from '../../../layout';
|
|
29
29
|
import { FeedBackContainer } from '../style';
|
|
30
30
|
import { SelectItem, SelectContext, getLabelFromChildren } from '../../';
|
|
31
|
+
import { PaginationProps } from '../../../';
|
|
31
32
|
|
|
32
33
|
/* The SearchField depends on a few things of <Select/> */
|
|
33
34
|
import { GroupLabel } from '../../SelectField/style';
|
|
34
35
|
import { SelectContainer, SelectButton, StyledArrowIcon, StyledFloatingOverlay } from '../../sharedStyle';
|
|
35
|
-
import { IconButton, Spinner } from '../../../../../components';
|
|
36
|
+
import { IconButton, InfiniteScroll, Spinner } from '../../../../../components';
|
|
36
37
|
import { GenericTextField } from '../../../TextField/Generic';
|
|
37
38
|
|
|
38
|
-
interface SharedSelectQueryFieldProps {
|
|
39
|
+
interface SharedSelectQueryFieldProps extends PaginationProps {
|
|
39
40
|
// Enables loading data feedback for user
|
|
40
41
|
isLoadingData?: boolean;
|
|
41
42
|
/// The placeholder text to show when the input is empty
|
|
@@ -44,7 +45,7 @@ interface SharedSelectQueryFieldProps {
|
|
|
44
45
|
debounce?: number;
|
|
45
46
|
/// Triggered whenever the input value changes.
|
|
46
47
|
/// This is used to trigger the API call to get the new options
|
|
47
|
-
handleInputValueChange
|
|
48
|
+
handleInputValueChange?: (value: string) => void;
|
|
48
49
|
/// render inPortal
|
|
49
50
|
inPortal?: boolean;
|
|
50
51
|
|
|
@@ -53,6 +54,9 @@ interface SharedSelectQueryFieldProps {
|
|
|
53
54
|
|
|
54
55
|
/// The selected items shown in the select field
|
|
55
56
|
render?: (selectedItems: SelectItem[]) => React.ReactNode;
|
|
57
|
+
|
|
58
|
+
/// The total options that will be visible when fully loaded
|
|
59
|
+
optionCount?: number;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
interface SingleSelectQueryFieldProps extends SharedSelectQueryFieldProps {
|
|
@@ -100,12 +104,17 @@ export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelec
|
|
|
100
104
|
hasError,
|
|
101
105
|
children,
|
|
102
106
|
readOnly,
|
|
107
|
+
isFetchingNextPage,
|
|
108
|
+
isFetching,
|
|
109
|
+
fetchNextPage,
|
|
110
|
+
hasNextPage,
|
|
103
111
|
render,
|
|
104
112
|
multiple = false,
|
|
105
113
|
canClear = false,
|
|
106
114
|
debounce = 250,
|
|
107
115
|
isLoadingData: isLoading = false,
|
|
108
116
|
handleInputValueChange,
|
|
117
|
+
optionCount,
|
|
109
118
|
} = defaultsApplier(props);
|
|
110
119
|
|
|
111
120
|
const [open, setOpen] = useState<boolean>(false);
|
|
@@ -117,8 +126,10 @@ export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelec
|
|
|
117
126
|
const listItemsRef = useRef<Array<HTMLLIElement | null>>([]);
|
|
118
127
|
|
|
119
128
|
useEffect(() => {
|
|
120
|
-
if (
|
|
121
|
-
|
|
129
|
+
if (handleInputValueChange) {
|
|
130
|
+
if ((inputValue.shouldUpdate && debouncedValue) || (inputValue && debouncedValue === ''))
|
|
131
|
+
handleInputValueChange(debouncedValue);
|
|
132
|
+
}
|
|
122
133
|
}, [debouncedValue]);
|
|
123
134
|
|
|
124
135
|
const { refs, strategy, x, y, context } = useFloating<HTMLInputElement>({
|
|
@@ -196,17 +207,21 @@ export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelec
|
|
|
196
207
|
},
|
|
197
208
|
})}
|
|
198
209
|
>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
+
{' '}
|
|
211
|
+
{handleInputValueChange && (
|
|
212
|
+
<GenericTextField
|
|
213
|
+
id={`${name}-input`}
|
|
214
|
+
name={`${name}-input`}
|
|
215
|
+
hasDescription={false}
|
|
216
|
+
icon={<SearchIcon />}
|
|
217
|
+
suffix={isLoading ? 'Loading' : optionCount !== undefined ? `Result: ${optionCount}` : undefined}
|
|
218
|
+
hasError={hasError}
|
|
219
|
+
value={inputValue.value}
|
|
220
|
+
onChange={onInputChange}
|
|
221
|
+
placeholder={placeholder}
|
|
222
|
+
ref={ref}
|
|
223
|
+
/>
|
|
224
|
+
)}
|
|
210
225
|
{/* it will always contain 1 because of the group label */}
|
|
211
226
|
{isLoading && (
|
|
212
227
|
<FeedBackContainer>
|
|
@@ -215,6 +230,14 @@ export const GenericSelectQueryField = forwardRef<HTMLInputElement, GenericSelec
|
|
|
215
230
|
</FeedBackContainer>
|
|
216
231
|
)}
|
|
217
232
|
{hasOptions && options}
|
|
233
|
+
{hasOptions && !isLoading && (
|
|
234
|
+
<InfiniteScroll
|
|
235
|
+
isFetching={isFetching}
|
|
236
|
+
hasNextPage={hasNextPage}
|
|
237
|
+
fetchNextPage={fetchNextPage}
|
|
238
|
+
isFetchingNextPage={isFetchingNextPage}
|
|
239
|
+
/>
|
|
240
|
+
)}
|
|
218
241
|
{/* Basically first interaction */}
|
|
219
242
|
{!hasOptions && inputValue.value === '' && <FeedBackContainer>Start typing to search</FeedBackContainer>}
|
|
220
243
|
{/* When there is no result */}
|
|
@@ -69,6 +69,11 @@ export const ServerSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
|
|
|
69
69
|
handleInputValueChange={mockAPICall}
|
|
70
70
|
isLoadingData={loading}
|
|
71
71
|
required={false}
|
|
72
|
+
hasNextPage={false}
|
|
73
|
+
optionCount={10}
|
|
74
|
+
isFetching={false}
|
|
75
|
+
isFetchingNextPage={false}
|
|
76
|
+
fetchNextPage={() => {}}
|
|
72
77
|
name="film"
|
|
73
78
|
>
|
|
74
79
|
{/* In this case the label is the same as the value but ofcourse that can differ*/}
|
|
@@ -124,6 +129,11 @@ export const ClientSideSubmit: StoryFn<SelectQueryFieldProps> = (args) => {
|
|
|
124
129
|
handleInputValueChange={handleInputChange}
|
|
125
130
|
required={false}
|
|
126
131
|
debounce={0}
|
|
132
|
+
hasNextPage={false}
|
|
133
|
+
optionCount={10}
|
|
134
|
+
isFetching={false}
|
|
135
|
+
isFetchingNextPage={false}
|
|
136
|
+
fetchNextPage={() => {}}
|
|
127
137
|
name="film"
|
|
128
138
|
>
|
|
129
139
|
{/* In this case the label is the same as the value but ofcourse that can differ*/}
|
|
@@ -186,6 +196,11 @@ export const ClientSideMultiSelectSubmit: StoryFn<SelectQueryFieldProps> = (args
|
|
|
186
196
|
required={false}
|
|
187
197
|
canClear={args.canClear}
|
|
188
198
|
debounce={0}
|
|
199
|
+
hasNextPage={false}
|
|
200
|
+
optionCount={10}
|
|
201
|
+
isFetching={false}
|
|
202
|
+
isFetchingNextPage={false}
|
|
203
|
+
fetchNextPage={() => {}}
|
|
189
204
|
multiple
|
|
190
205
|
name="films"
|
|
191
206
|
>
|
|
@@ -240,6 +255,11 @@ export const Generic: StoryFn<SelectQueryFieldProps> = () => {
|
|
|
240
255
|
hasDescription={false}
|
|
241
256
|
value={result}
|
|
242
257
|
name="film"
|
|
258
|
+
hasNextPage={false}
|
|
259
|
+
optionCount={10}
|
|
260
|
+
isFetching={false}
|
|
261
|
+
isFetchingNextPage={false}
|
|
262
|
+
fetchNextPage={() => {}}
|
|
243
263
|
>
|
|
244
264
|
{/* In this case the label is the same as the value but ofcourse that can differ*/}
|
|
245
265
|
<SelectQueryField.OptionGroup>
|
|
@@ -6,10 +6,12 @@ export interface OptionGroupProps extends PropsWithChildren {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export const OptionGroup: FC<OptionGroupProps> = ({ children, label }) => {
|
|
9
|
-
|
|
9
|
+
{
|
|
10
|
+
/* This is actually never rendered, the optiongroup is build in the select fields themself*/
|
|
11
|
+
}
|
|
10
12
|
return (
|
|
11
13
|
<li>
|
|
12
|
-
{label
|
|
14
|
+
{label && <div>{label}</div>}
|
|
13
15
|
<ul>{children}</ul>
|
|
14
16
|
</li>
|
|
15
17
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FC, PropsWithChildren, ReactElement, useState } from 'react';
|
|
2
2
|
import { styled } from '../../../styled';
|
|
3
3
|
import { IoMdArrowDropup as ArrowUp } from 'react-icons/io';
|
|
4
|
-
import {
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
5
|
import { useTheme } from '../../../hooks';
|
|
6
6
|
|
|
7
7
|
const StyledList = styled.div`
|
|
@@ -78,36 +78,31 @@ const Item: FC<PropsWithChildren<ItemProps>> = ({ collapsed = false, title, chil
|
|
|
78
78
|
<ArrowUp size={18} />
|
|
79
79
|
</Header>
|
|
80
80
|
{description && <p>{description}</p>}
|
|
81
|
-
<
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{children}
|
|
107
|
-
</motion.div>
|
|
108
|
-
</motion.div>
|
|
109
|
-
)}
|
|
110
|
-
</AnimatePresence>
|
|
81
|
+
<motion.div
|
|
82
|
+
style={{ maxHeight: '100%', overflowY: 'hidden' }}
|
|
83
|
+
key={`collapse-item-${title}`}
|
|
84
|
+
variants={{
|
|
85
|
+
open: { opacity: 1, height: 'auto', flexGrow: 1, minHeight: 0, overflowY: 'auto', visibility: 'visible' },
|
|
86
|
+
collapsed: { opacity: 0, height: 0, visibility: 'hidden' },
|
|
87
|
+
}}
|
|
88
|
+
initial="collapsed"
|
|
89
|
+
animate={isCollapsed ? 'collapsed' : 'open'}
|
|
90
|
+
transition={{ duration: 0.125, ease: 'linear' }}
|
|
91
|
+
>
|
|
92
|
+
<motion.div
|
|
93
|
+
variants={{
|
|
94
|
+
open: { y: 0 },
|
|
95
|
+
collapsed: { y: -6 },
|
|
96
|
+
}}
|
|
97
|
+
transition={{ duration: 0.125, ease: 'linear' }}
|
|
98
|
+
style={{
|
|
99
|
+
transformOrigin: 'top center',
|
|
100
|
+
padding: `${theme.spacing['0_75']} ${theme.spacing['0_5']} ${theme.spacing['1_5']} ${theme.spacing['1']}`,
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
{children}
|
|
104
|
+
</motion.div>
|
|
105
|
+
</motion.div>
|
|
111
106
|
</div>
|
|
112
107
|
);
|
|
113
108
|
};
|
|
@@ -13,7 +13,10 @@ export default {
|
|
|
13
13
|
export const Default: StoryFn<CardProps> = (args) => {
|
|
14
14
|
return (
|
|
15
15
|
<Card variant={args.variant} onClick={() => {}}>
|
|
16
|
-
|
|
16
|
+
<Card.Title label="This is the title">
|
|
17
|
+
<span>Here we can put logic that goes on the right side</span>
|
|
18
|
+
</Card.Title>
|
|
19
|
+
<Card.Body>this is the body</Card.Body>
|
|
17
20
|
</Card>
|
|
18
21
|
);
|
|
19
22
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
|
2
|
+
import { styled } from '../../../styled';
|
|
3
|
+
|
|
4
|
+
const Container = styled.div`
|
|
5
|
+
padding: ${({ theme }) => theme.spacing[2]};
|
|
6
|
+
min-width: 20rem;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const CardBody: FC<PropsWithChildren> = (props) => {
|
|
10
|
+
return <Container>{props.children}</Container>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FC, PropsWithChildren } from 'react';
|
|
2
|
+
import { styled } from '../../../styled';
|
|
3
|
+
|
|
4
|
+
const Container = styled.div`
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
align-items: center;
|
|
8
|
+
border-bottom: 1px solid ${({ theme }) => theme.colors.backgroundAccent};
|
|
9
|
+
padding: ${({ theme }) => theme.spacing[1]};
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
interface CardTitleProps {
|
|
13
|
+
label: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const CardTitle: FC<PropsWithChildren<CardTitleProps>> = (props) => {
|
|
17
|
+
return (
|
|
18
|
+
<Container>
|
|
19
|
+
<h2>{props.label}</h2>
|
|
20
|
+
<div>{props.children}</div>
|
|
21
|
+
</Container>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FC, HTMLProps, PropsWithChildren } from 'react';
|
|
2
2
|
import { styled } from '../../../styled';
|
|
3
|
+
import { CardTitle } from './CardTitle';
|
|
4
|
+
import { CardBody } from './CardBody';
|
|
3
5
|
|
|
4
6
|
type Variant = 'default' | 'outline';
|
|
5
7
|
|
|
@@ -8,8 +10,8 @@ const Container = styled.div<{ canClick: boolean; variant: Variant }>`
|
|
|
8
10
|
background-color: ${({ theme, variant }) =>
|
|
9
11
|
variant === 'outline' ? theme.colors.background : theme.colors.backgroundAlt};
|
|
10
12
|
border: 0.1rem solid ${({ theme }) => theme.colors.backgroundAccent};
|
|
11
|
-
padding: ${({ theme }) => theme.spacing[2]};
|
|
12
13
|
cursor: ${({ canClick }) => (canClick ? 'pointer' : 'default')};
|
|
14
|
+
height: fit-content;
|
|
13
15
|
|
|
14
16
|
&:focus-within {
|
|
15
17
|
border-color: none;
|
|
@@ -31,22 +33,27 @@ export interface CardProps extends HTMLProps<HTMLDivElement> {
|
|
|
31
33
|
variant?: Variant;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
) {
|
|
39
|
-
const canClick = 'onClick' in props;
|
|
36
|
+
interface SubComponentTypes {
|
|
37
|
+
Title: typeof CardTitle;
|
|
38
|
+
Body: typeof CardBody;
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
export const Card: FC<PropsWithChildren<CardProps>> & SubComponentTypes = function Card({
|
|
42
|
+
children,
|
|
43
|
+
variant = 'default',
|
|
44
|
+
...props
|
|
45
|
+
}) {
|
|
46
|
+
const canClick = 'onClick' in props;
|
|
42
47
|
const { className, ...restProps } = props;
|
|
43
48
|
|
|
44
49
|
return (
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
<Container ref={ref} canClick={canClick} variant={variant} className={className} {...restProps}>
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
<Container canClick={canClick} variant={variant} className={className} {...restProps}>
|
|
49
53
|
{children}
|
|
50
54
|
</Container>
|
|
51
55
|
);
|
|
52
|
-
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
Card.Title = CardTitle;
|
|
59
|
+
Card.Body = CardBody;
|