@addev-be/ui 0.9.0 → 0.10.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/package.json +1 -1
- package/src/components/auth/LoginForm.tsx +1 -1
- package/src/components/auth/PasswordRecoveryForm.tsx +1 -1
- package/src/components/auth/PasswordResetForm.tsx +1 -1
- package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +1 -1
- package/src/components/data/DataGrid/DataGridFilterMenu/hooks.tsx +2 -2
- package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +60 -42
- package/src/components/data/DataGrid/DataGridHeader.tsx +3 -3
- package/src/components/data/DataGrid/DataGridHeaderCell.tsx +1 -1
- package/src/components/data/DataGrid/index.tsx +1 -0
- package/src/components/data/DataGrid/styles.ts +2 -2
- package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +6 -5
- package/src/components/data/SqlRequestGrid/filters/FiltersSidebar.tsx +102 -0
- package/src/components/data/SqlRequestGrid/filters/styles.ts +83 -0
- package/src/components/data/SqlRequestGrid/index.tsx +159 -29
- package/src/components/data/SqlRequestGrid/styles.ts +6 -36
- package/src/components/data/SqlRequestGrid/types.ts +2 -0
- package/src/components/data/VirtualScroller/index.tsx +28 -18
- package/src/components/data/VirtualScroller/styles.ts +10 -1
- package/src/components/forms/Button.tsx +40 -16
- package/src/components/ui/Label.tsx +90 -0
- package/src/components/ui/index.ts +1 -0
- package/src/providers/ThemeProvider/defaultTheme.ts +12 -0
- package/src/providers/ThemeProvider/types.ts +7 -1
package/package.json
CHANGED
|
@@ -43,7 +43,7 @@ export const useDataGridColumnsModal = <R,>(context: DataGridContext<R>) => {
|
|
|
43
43
|
<Modal.Footer>
|
|
44
44
|
<Button onClick={closeModal}>Annuler</Button>
|
|
45
45
|
<Button
|
|
46
|
-
color="primary"
|
|
46
|
+
$color="primary"
|
|
47
47
|
style={{ marginLeft: 'auto' }}
|
|
48
48
|
onClick={onApplyClicked}
|
|
49
49
|
>
|
|
@@ -55,12 +55,12 @@ export const useFilterModal = <R,>({
|
|
|
55
55
|
/>
|
|
56
56
|
</Modal.ContentWithIcon>
|
|
57
57
|
<Modal.Buttons>
|
|
58
|
-
<Button color="danger" icon={FilterSlashIcon} onClick={onClearClicked}>
|
|
58
|
+
<Button $color="danger" icon={FilterSlashIcon} onClick={onClearClicked}>
|
|
59
59
|
Supprimer
|
|
60
60
|
</Button>
|
|
61
61
|
<Button
|
|
62
62
|
style={{ marginLeft: 'auto' }}
|
|
63
|
-
color="primary"
|
|
63
|
+
$color="primary"
|
|
64
64
|
icon={FilterIcon}
|
|
65
65
|
onClick={onApplyClicked}
|
|
66
66
|
>
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
import { ContextMenu } from '../../../ui/ContextMenu';
|
|
47
47
|
import { FilterValuesScroller } from './FilterValuesScroller';
|
|
48
48
|
import { Input } from '../../../forms';
|
|
49
|
+
import { MenuContainer } from '../../../ui/ContextMenu/styles';
|
|
49
50
|
import { useFilterModal } from './hooks';
|
|
50
51
|
|
|
51
52
|
type FilterValuesProps<R> = {
|
|
@@ -53,6 +54,8 @@ type FilterValuesProps<R> = {
|
|
|
53
54
|
columnIndex: number;
|
|
54
55
|
context: DataGridContext<R>;
|
|
55
56
|
onClose?: () => void;
|
|
57
|
+
contextMenu?: boolean;
|
|
58
|
+
showTotalButton?: boolean;
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
const sortAsc: Record<DataGridFilterType, [string, IconFC]> = {
|
|
@@ -87,6 +90,8 @@ export const DataGridFilterMenu = <R,>({
|
|
|
87
90
|
columnKey,
|
|
88
91
|
context,
|
|
89
92
|
onClose,
|
|
93
|
+
contextMenu = true,
|
|
94
|
+
showTotalButton = true,
|
|
90
95
|
}: FilterValuesProps<R>) => {
|
|
91
96
|
const { openModal, modal } = useFilterModal({ columnKey, context });
|
|
92
97
|
const {
|
|
@@ -258,8 +263,8 @@ export const DataGridFilterMenu = <R,>({
|
|
|
258
263
|
onClose?.();
|
|
259
264
|
}, [columnKey, onClose, setFooters]);
|
|
260
265
|
|
|
261
|
-
|
|
262
|
-
|
|
266
|
+
const content = (
|
|
267
|
+
<>
|
|
263
268
|
{modal}
|
|
264
269
|
{column.sortGetter && (
|
|
265
270
|
<>
|
|
@@ -283,48 +288,55 @@ export const DataGridFilterMenu = <R,>({
|
|
|
283
288
|
<ContextMenu.Divider />
|
|
284
289
|
</>
|
|
285
290
|
)}
|
|
286
|
-
{
|
|
291
|
+
{showTotalButton && (
|
|
287
292
|
<>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
293
|
+
{!isFooterVisible && typeof column.footer === 'function' && (
|
|
294
|
+
<>
|
|
295
|
+
<ContextMenu.Item onClick={() => showFooter('count')}>
|
|
296
|
+
<TableFooterIcon />
|
|
297
|
+
Afficher le total
|
|
298
|
+
</ContextMenu.Item>
|
|
299
|
+
<ContextMenu.Divider />
|
|
300
|
+
</>
|
|
301
|
+
)}
|
|
302
|
+
{showTotalButton && typeof column.footer === 'object' && (
|
|
303
|
+
<>
|
|
304
|
+
<ContextMenu.ParentItem>
|
|
305
|
+
<TableFooterIcon />
|
|
306
|
+
Afficher le total
|
|
307
|
+
<ContextMenu.SubMenu>
|
|
308
|
+
{Object.keys(column.footer).map((key) => {
|
|
309
|
+
const TotalIcon =
|
|
310
|
+
footerFunctionsIcons[
|
|
311
|
+
key as DataGridFooterPredefinedFunction
|
|
312
|
+
] ?? TableFooterIcon;
|
|
313
|
+
return (
|
|
314
|
+
<ContextMenu.Item
|
|
315
|
+
key={key}
|
|
316
|
+
onClick={() => showFooter(key)}
|
|
317
|
+
>
|
|
318
|
+
<TotalIcon />
|
|
319
|
+
{key in footerFunctionsTexts
|
|
320
|
+
? footerFunctionsTexts[
|
|
321
|
+
key as DataGridFooterPredefinedFunction
|
|
322
|
+
]
|
|
323
|
+
: key}
|
|
324
|
+
</ContextMenu.Item>
|
|
325
|
+
);
|
|
326
|
+
})}
|
|
327
|
+
<ContextMenu.Divider />
|
|
328
|
+
<ContextMenu.Item
|
|
329
|
+
onClick={hideFooter}
|
|
330
|
+
disabled={!isFooterVisible}
|
|
331
|
+
>
|
|
332
|
+
<TableFooterSlashIcon />
|
|
333
|
+
Masquer le total
|
|
314
334
|
</ContextMenu.Item>
|
|
315
|
-
|
|
316
|
-
|
|
335
|
+
</ContextMenu.SubMenu>
|
|
336
|
+
</ContextMenu.ParentItem>
|
|
317
337
|
<ContextMenu.Divider />
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
disabled={!isFooterVisible}
|
|
321
|
-
>
|
|
322
|
-
<TableFooterSlashIcon />
|
|
323
|
-
Masquer le total
|
|
324
|
-
</ContextMenu.Item>
|
|
325
|
-
</ContextMenu.SubMenu>
|
|
326
|
-
</ContextMenu.ParentItem>
|
|
327
|
-
<ContextMenu.Divider />
|
|
338
|
+
</>
|
|
339
|
+
)}
|
|
328
340
|
</>
|
|
329
341
|
)}
|
|
330
342
|
<ContextMenu.Item onClick={openModal}>
|
|
@@ -355,6 +367,12 @@ export const DataGridFilterMenu = <R,>({
|
|
|
355
367
|
<styles.CheckboxesContainer>
|
|
356
368
|
{checkboxesComponent}
|
|
357
369
|
</styles.CheckboxesContainer>
|
|
358
|
-
|
|
370
|
+
</>
|
|
359
371
|
);
|
|
372
|
+
|
|
373
|
+
if (!contextMenu) {
|
|
374
|
+
return <MenuContainer>{content}</MenuContainer>;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return <ContextMenu>{content}</ContextMenu>;
|
|
360
378
|
};
|
|
@@ -76,16 +76,16 @@ export const DataGridHeader = <R,>({
|
|
|
76
76
|
Rafraîchir
|
|
77
77
|
</Button>
|
|
78
78
|
)}
|
|
79
|
-
<Button color="emerald" size="small" onClick={runCopyTable}>
|
|
79
|
+
<Button $color="emerald" size="small" onClick={runCopyTable}>
|
|
80
80
|
<CopyIcon />
|
|
81
81
|
Copier la table
|
|
82
82
|
</Button>
|
|
83
|
-
<Button size="small" color="danger" onClick={() => setFilters({})}>
|
|
83
|
+
<Button size="small" $color="danger" onClick={() => setFilters({})}>
|
|
84
84
|
<FilterSlashIcon />
|
|
85
85
|
Supprimer les filtres
|
|
86
86
|
</Button>
|
|
87
87
|
{name && (
|
|
88
|
-
<Button color="info" size="small" onClick={openModal}>
|
|
88
|
+
<Button $color="info" size="small" onClick={openModal}>
|
|
89
89
|
<TableColumnsIcon />
|
|
90
90
|
Paramètres des colonnes
|
|
91
91
|
</Button>
|
|
@@ -108,7 +108,7 @@ export const DataGridHeaderCell = <R,>({
|
|
|
108
108
|
className={hasFilters ? 'danger' : ''}
|
|
109
109
|
ref={filterButtonRef}
|
|
110
110
|
icon={ChevronDownIcon}
|
|
111
|
-
color={hasFilters ? 'danger' : headerColor}
|
|
111
|
+
$color={hasFilters ? 'danger' : headerColor}
|
|
112
112
|
onClick={onFilterButtonClicked}
|
|
113
113
|
/>
|
|
114
114
|
)}
|
|
@@ -66,6 +66,7 @@ export const DataGridInner = <R,>(
|
|
|
66
66
|
>
|
|
67
67
|
<DataGridHeader context={DataGridContext} />
|
|
68
68
|
<VirtualScroller<R, { context: Context<DataGridContextProps<R>> }>
|
|
69
|
+
integrated
|
|
69
70
|
gridTemplateColumns={gridTemplateColumns}
|
|
70
71
|
items={sortedRows}
|
|
71
72
|
itemTemplate={rowTemplate}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styled, { css } from 'styled-components';
|
|
2
2
|
|
|
3
3
|
import { ThemeColor } from '../../../providers/ThemeProvider/types';
|
|
4
|
-
import {
|
|
4
|
+
import { VirtualScrollerFiller } from '../VirtualScroller/styles';
|
|
5
5
|
|
|
6
6
|
export const TOOLBAR_HEIGHT = 40;
|
|
7
7
|
export const DEFAULT_HEADER_ROW_HEIGHT = 40;
|
|
@@ -168,7 +168,7 @@ export const DataGridContainer = styled.div<{
|
|
|
168
168
|
box-sizing: border-box;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
${
|
|
171
|
+
${VirtualScrollerFiller} {
|
|
172
172
|
grid-column-start: 1;
|
|
173
173
|
grid-column-end: -1;
|
|
174
174
|
grid-row: 3;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { SqlRequestDataGridColumn, SqlRequestDataGridColumns } from '../types';
|
|
4
4
|
import {
|
|
5
5
|
buildExcelFormat,
|
|
6
|
+
dateFilter,
|
|
6
7
|
numberFilter,
|
|
7
8
|
textFilter,
|
|
8
9
|
} from '../../DataGrid/helpers';
|
|
@@ -110,7 +111,7 @@ export const sqlDateColumn = <R extends Record<string, any>>(
|
|
|
110
111
|
excelFormatter: () => 'dd/mm/yyyy',
|
|
111
112
|
excelValue: (value) => formatDate(value, 'YYYY-MM-DD'),
|
|
112
113
|
filter: {
|
|
113
|
-
...
|
|
114
|
+
...dateFilter(key),
|
|
114
115
|
getter: (value) => value[key] ?? '',
|
|
115
116
|
formatter: (value) => formatDate(value),
|
|
116
117
|
renderer: (value) => formatDate(value),
|
|
@@ -134,7 +135,7 @@ export const sqlDateTimeColumn = <R extends Record<string, any>>(
|
|
|
134
135
|
excelFormatter: () => 'dd/mm/yyyy hh:mm:ss',
|
|
135
136
|
excelValue: (value) => formatDateTime(value, 'YYYY-MM-DD HH:mm:ss'),
|
|
136
137
|
filter: {
|
|
137
|
-
...
|
|
138
|
+
...dateFilter(key),
|
|
138
139
|
getter: (value) => value[key] ?? '',
|
|
139
140
|
formatter: (value) => formatDateTime(value),
|
|
140
141
|
renderer: (value) => formatDateTime(value),
|
|
@@ -172,7 +173,7 @@ export const sqlNumberColumn = <R extends Record<string, any>>(
|
|
|
172
173
|
excelFormatter: () => buildExcelFormat(decimals),
|
|
173
174
|
excelValue: (value) => formatNumberInvariant(value, decimals),
|
|
174
175
|
getter: (row) => row[key] ?? '',
|
|
175
|
-
sortGetter: (row) => row[key] ??
|
|
176
|
+
sortGetter: (row) => row[key] ?? 0,
|
|
176
177
|
filter: {
|
|
177
178
|
...numberFilter(key),
|
|
178
179
|
getter: (value) => value[key] ?? 0,
|
|
@@ -202,7 +203,7 @@ export const sqlMoneyColumn = <R extends Record<string, any>>(
|
|
|
202
203
|
excelFormatter: () => buildExcelFormat(decimals, ' €'),
|
|
203
204
|
excelValue: (value) => formatNumberInvariant(value, decimals),
|
|
204
205
|
getter: (row) => row[key] ?? '',
|
|
205
|
-
sortGetter: (row) => row[key] ??
|
|
206
|
+
sortGetter: (row) => row[key] ?? 0,
|
|
206
207
|
filter: {
|
|
207
208
|
...numberFilter(key),
|
|
208
209
|
getter: (value) => value[key] ?? 0,
|
|
@@ -231,7 +232,7 @@ export const sqlPercentageColumn = <R extends Record<string, any>>(
|
|
|
231
232
|
excelFormatter: () => buildExcelFormat(decimals, '%'),
|
|
232
233
|
excelValue: (value) => formatNumberInvariant(value, decimals),
|
|
233
234
|
getter: (row) => row[key] ?? '',
|
|
234
|
-
sortGetter: (row) => row[key] ??
|
|
235
|
+
sortGetter: (row) => row[key] ?? 0,
|
|
235
236
|
filter: {
|
|
236
237
|
...numberFilter(key),
|
|
237
238
|
getter: (value) => value[key] ?? 0,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as styles from './styles';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CircleXMarkIcon,
|
|
5
|
+
FilterSlashIcon,
|
|
6
|
+
LeftIcon,
|
|
7
|
+
RightIcon,
|
|
8
|
+
} from '../../../../Icons';
|
|
9
|
+
import { MouseEvent, useCallback, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import { DataGridContext } from '../../DataGrid/types';
|
|
12
|
+
import { DataGridFilterMenu } from '../../DataGrid/DataGridFilterMenu';
|
|
13
|
+
import { IconButton } from '../../../forms';
|
|
14
|
+
import { SqlRequestGridProps } from '../types';
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
17
|
+
type FiltersSidebarProps<R, P extends object = {}> = {
|
|
18
|
+
props: SqlRequestGridProps<R, P>;
|
|
19
|
+
context: DataGridContext<R>;
|
|
20
|
+
onClose?: () => void;
|
|
21
|
+
onClearFilters?: () => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
25
|
+
export const FiltersSidebar = <R, P extends object = {}>({
|
|
26
|
+
props,
|
|
27
|
+
context,
|
|
28
|
+
onClose,
|
|
29
|
+
onClearFilters,
|
|
30
|
+
}: FiltersSidebarProps<R, P>) => {
|
|
31
|
+
const [columnKey, setColumnKey] = useState<string | null>(null);
|
|
32
|
+
const column = columnKey ? props.fields[columnKey] : null;
|
|
33
|
+
const visible = !!(columnKey && column);
|
|
34
|
+
|
|
35
|
+
const stopPropagation = useCallback((e: MouseEvent) => {
|
|
36
|
+
e.stopPropagation();
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const onFilterClick = useCallback((columnKey: string | null) => {
|
|
40
|
+
setColumnKey(columnKey);
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<styles.Backdrop onClick={onClose}>
|
|
45
|
+
<styles.FiltersSidebarContainer onClick={stopPropagation}>
|
|
46
|
+
{visible ? (
|
|
47
|
+
<>
|
|
48
|
+
<styles.FiltersSidebarHeader>
|
|
49
|
+
<IconButton
|
|
50
|
+
rounded
|
|
51
|
+
icon={LeftIcon}
|
|
52
|
+
color="secondary"
|
|
53
|
+
onClick={() => onFilterClick(null)}
|
|
54
|
+
/>
|
|
55
|
+
<h3>{column.name}</h3>
|
|
56
|
+
<IconButton
|
|
57
|
+
rounded
|
|
58
|
+
icon={CircleXMarkIcon}
|
|
59
|
+
color="secondary"
|
|
60
|
+
onClick={onClose}
|
|
61
|
+
/>
|
|
62
|
+
</styles.FiltersSidebarHeader>
|
|
63
|
+
<DataGridFilterMenu
|
|
64
|
+
contextMenu={false}
|
|
65
|
+
columnKey={columnKey}
|
|
66
|
+
columnIndex={0}
|
|
67
|
+
context={context}
|
|
68
|
+
showTotalButton={false}
|
|
69
|
+
/>
|
|
70
|
+
</>
|
|
71
|
+
) : (
|
|
72
|
+
<>
|
|
73
|
+
<styles.FiltersSidebarHeader>
|
|
74
|
+
<h3>Filtres</h3>
|
|
75
|
+
<IconButton
|
|
76
|
+
rounded
|
|
77
|
+
icon={FilterSlashIcon}
|
|
78
|
+
color="danger"
|
|
79
|
+
onClick={onClearFilters}
|
|
80
|
+
/>
|
|
81
|
+
<IconButton
|
|
82
|
+
rounded
|
|
83
|
+
icon={CircleXMarkIcon}
|
|
84
|
+
color="secondary"
|
|
85
|
+
onClick={onClose}
|
|
86
|
+
/>
|
|
87
|
+
</styles.FiltersSidebarHeader>
|
|
88
|
+
{Object.entries(props.fields).map(([key, field], index) => (
|
|
89
|
+
<styles.FiltersSidebarFilter
|
|
90
|
+
key={index}
|
|
91
|
+
onClick={() => onFilterClick(key)}
|
|
92
|
+
>
|
|
93
|
+
{field.name}
|
|
94
|
+
<RightIcon />
|
|
95
|
+
</styles.FiltersSidebarFilter>
|
|
96
|
+
))}
|
|
97
|
+
</>
|
|
98
|
+
)}
|
|
99
|
+
</styles.FiltersSidebarContainer>
|
|
100
|
+
</styles.Backdrop>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Divider,
|
|
3
|
+
MenuContainer,
|
|
4
|
+
MenuItemContainer,
|
|
5
|
+
} from '../../../ui/ContextMenu/styles';
|
|
6
|
+
|
|
7
|
+
import styled from 'styled-components';
|
|
8
|
+
|
|
9
|
+
export const FiltersSidebarContainer = styled.div`
|
|
10
|
+
position: absolute;
|
|
11
|
+
left: 0;
|
|
12
|
+
top: 0;
|
|
13
|
+
bottom: 0;
|
|
14
|
+
width: 100%;
|
|
15
|
+
max-width: var(--space-96);
|
|
16
|
+
border-radius: var(--rounded-none);
|
|
17
|
+
padding: 0;
|
|
18
|
+
z-index: 1;
|
|
19
|
+
overflow-y: auto;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
background-color: var(--color-neutral-50);
|
|
22
|
+
border-right: 1px solid var(--color-neutral-300);
|
|
23
|
+
box-shadow: var(--shadow-sm);
|
|
24
|
+
|
|
25
|
+
& > ${MenuContainer} {
|
|
26
|
+
position: relative;
|
|
27
|
+
background: none;
|
|
28
|
+
padding: var(--space-2) 0;
|
|
29
|
+
|
|
30
|
+
${MenuItemContainer} {
|
|
31
|
+
background: none;
|
|
32
|
+
/* height: var(--size-6); */
|
|
33
|
+
padding: var(--space-2) var(--space-4);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
${Divider} {
|
|
37
|
+
margin: var(--space-2) 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
export const FiltersSidebarHeader = styled.div`
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: space-between;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--space-4);
|
|
47
|
+
padding: var(--space-2);
|
|
48
|
+
|
|
49
|
+
padding-bottom: var(--space-2);
|
|
50
|
+
border-bottom: 1px solid var(--color-neutral-300);
|
|
51
|
+
|
|
52
|
+
h3 {
|
|
53
|
+
margin: 0;
|
|
54
|
+
margin-right: auto;
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
export const FiltersSidebarFilter = styled.div`
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
padding: var(--space-4) var(--space-2);
|
|
62
|
+
border-bottom: 1px solid var(--color-neutral-300);
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
|
|
65
|
+
&:hover {
|
|
66
|
+
background-color: var(--color-neutral-100);
|
|
67
|
+
}
|
|
68
|
+
svg {
|
|
69
|
+
margin-left: auto;
|
|
70
|
+
width: var(--space-4);
|
|
71
|
+
height: var(--space-4);
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export const Backdrop = styled.div`
|
|
76
|
+
position: sticky;
|
|
77
|
+
top: 0;
|
|
78
|
+
left: 0;
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 100%;
|
|
81
|
+
z-index: 1;
|
|
82
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
83
|
+
`;
|
|
@@ -15,30 +15,53 @@ import {
|
|
|
15
15
|
useRef,
|
|
16
16
|
useState,
|
|
17
17
|
} from 'react';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
SqlRequestGridFilters,
|
|
20
|
+
SqlRequestGridProps,
|
|
21
|
+
SqlRequestGridRefProps,
|
|
22
|
+
} from './types';
|
|
23
|
+
import { debounce, pickBy } from 'lodash';
|
|
19
24
|
|
|
25
|
+
import { DataGridSort } from '../DataGrid/types';
|
|
26
|
+
import { FilterFullIcon } from '../../../Icons';
|
|
27
|
+
import { FiltersSidebar } from './filters/FiltersSidebar';
|
|
28
|
+
import { IconButton } from '../../forms';
|
|
20
29
|
import { VirtualScroller } from '../VirtualScroller';
|
|
21
|
-
import {
|
|
30
|
+
import { convertSqlFiltersToConditions } from './helpers';
|
|
22
31
|
import { isColumnVisible } from '../DataGrid/helpers';
|
|
32
|
+
import { useDataGrid } from '../DataGrid/hooks';
|
|
23
33
|
|
|
24
34
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
25
35
|
export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
26
|
-
|
|
36
|
+
allProps: SqlRequestGridProps<R, P>,
|
|
37
|
+
ref: ForwardedRef<SqlRequestGridRefProps>
|
|
38
|
+
) => {
|
|
39
|
+
const {
|
|
27
40
|
rowHeight = styles.DEFAULT_ROW_HEIGHT,
|
|
28
41
|
itemsPerRow,
|
|
29
42
|
itemTemplate,
|
|
30
43
|
itemProps,
|
|
31
44
|
gap,
|
|
32
45
|
...props
|
|
33
|
-
}
|
|
34
|
-
ref: ForwardedRef<SqlRequestGridRefProps>
|
|
35
|
-
) => {
|
|
46
|
+
} = allProps;
|
|
36
47
|
const currentRows = useRef<R[]>([]);
|
|
37
48
|
const [rows, setRows] = useState<R[]>([]);
|
|
38
49
|
const [start, setStart] = useState(0);
|
|
39
50
|
const [length, setLength] = useState(50);
|
|
40
51
|
const [count, setCount] = useState(-1);
|
|
41
52
|
const [sqlRequest] = useSqlRequestHandler<R>(props.type);
|
|
53
|
+
const [conditions, setConditions] = useState<Record<string, ConditionDTO>>(
|
|
54
|
+
{}
|
|
55
|
+
);
|
|
56
|
+
const [orderBy, setOrderBy] = useState<OrderByDTO[]>(
|
|
57
|
+
Object.entries(props.initialSorts ?? {}).map(
|
|
58
|
+
([columnKey, direction]): OrderByDTO => ({
|
|
59
|
+
field: props.fields[columnKey].field?.fieldAlias ?? columnKey,
|
|
60
|
+
type: props.fields[columnKey].type ?? 'text',
|
|
61
|
+
direction: direction.toUpperCase() as 'ASC' | 'DESC',
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
);
|
|
42
65
|
|
|
43
66
|
const [columnsKeys, visibleColumnsKeys] = useMemo(
|
|
44
67
|
() => [
|
|
@@ -107,6 +130,69 @@ export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
|
107
130
|
)
|
|
108
131
|
);
|
|
109
132
|
|
|
133
|
+
const refresh = useCallback(() => {
|
|
134
|
+
setRows([]);
|
|
135
|
+
setStart(0);
|
|
136
|
+
setLength(50);
|
|
137
|
+
setCount(-1);
|
|
138
|
+
}, []);
|
|
139
|
+
|
|
140
|
+
const onFiltersChanged = useCallback(
|
|
141
|
+
(filters: SqlRequestGridFilters) => {
|
|
142
|
+
const newConditions = convertSqlFiltersToConditions(filters);
|
|
143
|
+
setConditions(newConditions);
|
|
144
|
+
refresh();
|
|
145
|
+
},
|
|
146
|
+
[refresh]
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const onSortsChanged = useCallback(
|
|
150
|
+
(sorts: Record<string, DataGridSort>) => {
|
|
151
|
+
refresh();
|
|
152
|
+
const newOrderBy = Object.entries(sorts).map(
|
|
153
|
+
([columnKey, direction]) =>
|
|
154
|
+
({
|
|
155
|
+
field: columnKey,
|
|
156
|
+
direction: direction.toUpperCase(),
|
|
157
|
+
} as OrderByDTO)
|
|
158
|
+
);
|
|
159
|
+
setOrderBy(newOrderBy);
|
|
160
|
+
},
|
|
161
|
+
[refresh]
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const loadFilterValues = useCallback(
|
|
165
|
+
(columnKey: string) => {
|
|
166
|
+
return sqlRequest({
|
|
167
|
+
columns: columnsKeys,
|
|
168
|
+
returnColumns: [columnKey],
|
|
169
|
+
columnTypes: [props.fields[columnKey].type ?? 'text'],
|
|
170
|
+
conditions: [
|
|
171
|
+
...(props.conditions ?? []),
|
|
172
|
+
...Object.values(pickBy(conditions, (_, key) => key !== columnKey)),
|
|
173
|
+
].filter((condition) => condition.field !== columnKey),
|
|
174
|
+
orderBy: [
|
|
175
|
+
{
|
|
176
|
+
field:
|
|
177
|
+
props.fields[columnKey].filterField ??
|
|
178
|
+
props.fields[columnKey].field?.fieldAlias ??
|
|
179
|
+
props.fields[columnKey].field?.fieldName ??
|
|
180
|
+
columnKey,
|
|
181
|
+
type: props.fields[columnKey].type ?? 'text',
|
|
182
|
+
direction: 'ASC',
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
getCount: false,
|
|
186
|
+
unique: true,
|
|
187
|
+
}).then((response) =>
|
|
188
|
+
response.data.map(
|
|
189
|
+
(row) => props.fields[columnKey].filter?.getter?.(row) ?? null
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
},
|
|
193
|
+
[columnsKeys, conditions, props.fields, props.conditions, sqlRequest]
|
|
194
|
+
);
|
|
195
|
+
|
|
110
196
|
useEffect(() => {
|
|
111
197
|
if (
|
|
112
198
|
!rows.length ||
|
|
@@ -115,8 +201,8 @@ export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
|
115
201
|
loadRows.current(
|
|
116
202
|
columnsKeys,
|
|
117
203
|
visibleColumnsKeys,
|
|
118
|
-
props.conditions,
|
|
119
|
-
|
|
204
|
+
[...(props.conditions ?? []), ...Object.values(conditions)],
|
|
205
|
+
orderBy,
|
|
120
206
|
start,
|
|
121
207
|
length,
|
|
122
208
|
count < 0
|
|
@@ -127,11 +213,12 @@ export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
|
127
213
|
start,
|
|
128
214
|
length,
|
|
129
215
|
count,
|
|
130
|
-
|
|
216
|
+
conditions,
|
|
131
217
|
columnsKeys,
|
|
132
218
|
visibleColumnsKeys,
|
|
133
219
|
rows,
|
|
134
|
-
|
|
220
|
+
orderBy,
|
|
221
|
+
props.conditions,
|
|
135
222
|
]);
|
|
136
223
|
|
|
137
224
|
const onVisibleRowsChanged = useCallback(
|
|
@@ -144,13 +231,6 @@ export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
|
144
231
|
[length, start]
|
|
145
232
|
);
|
|
146
233
|
|
|
147
|
-
const refresh = useCallback(() => {
|
|
148
|
-
setRows([]);
|
|
149
|
-
setStart(0);
|
|
150
|
-
setLength(50);
|
|
151
|
-
setCount(-1);
|
|
152
|
-
}, []);
|
|
153
|
-
|
|
154
234
|
useImperativeHandle(
|
|
155
235
|
ref,
|
|
156
236
|
() => ({
|
|
@@ -159,19 +239,69 @@ export const SqlRequestGridInner = <R, P extends object = {}>(
|
|
|
159
239
|
[refresh]
|
|
160
240
|
);
|
|
161
241
|
|
|
242
|
+
const [contextProps, DataGridContext] = useDataGrid({
|
|
243
|
+
columns: props.fields,
|
|
244
|
+
rows,
|
|
245
|
+
onFiltersChanged,
|
|
246
|
+
filterValuesLoader: loadFilterValues,
|
|
247
|
+
onSortsChanged,
|
|
248
|
+
onSelectionChange: () => {},
|
|
249
|
+
onSelectedRowsChanged: () => {},
|
|
250
|
+
selectable: false,
|
|
251
|
+
rowKey: () => '',
|
|
252
|
+
filter: false,
|
|
253
|
+
sort: false,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const [sidebarVisible, setSidebarVisible] = useState(false);
|
|
257
|
+
const onSidebarClose = useCallback(() => {
|
|
258
|
+
setSidebarVisible(false);
|
|
259
|
+
}, []);
|
|
260
|
+
const onClearFilters = useCallback(() => {
|
|
261
|
+
onFiltersChanged({});
|
|
262
|
+
setSidebarVisible(false);
|
|
263
|
+
}, [onFiltersChanged]);
|
|
264
|
+
|
|
162
265
|
return (
|
|
163
|
-
<
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
266
|
+
<DataGridContext.Provider value={contextProps}>
|
|
267
|
+
<styles.SqlRequestGridContainer>
|
|
268
|
+
{sidebarVisible ? (
|
|
269
|
+
<>
|
|
270
|
+
<FiltersSidebar
|
|
271
|
+
props={allProps}
|
|
272
|
+
context={DataGridContext}
|
|
273
|
+
onClose={onSidebarClose}
|
|
274
|
+
onClearFilters={onClearFilters}
|
|
275
|
+
/>
|
|
276
|
+
</>
|
|
277
|
+
) : (
|
|
278
|
+
<IconButton
|
|
279
|
+
size="large"
|
|
280
|
+
onClick={() => setSidebarVisible(true)}
|
|
281
|
+
icon={FilterFullIcon}
|
|
282
|
+
color="primary"
|
|
283
|
+
rounded
|
|
284
|
+
style={{
|
|
285
|
+
position: 'absolute',
|
|
286
|
+
bottom: 'var(--space-2)',
|
|
287
|
+
right: 'var(--space-2)',
|
|
288
|
+
zIndex: 1,
|
|
289
|
+
}}
|
|
290
|
+
/>
|
|
291
|
+
)}
|
|
292
|
+
|
|
293
|
+
<VirtualScroller
|
|
294
|
+
gridTemplateColumns={`repeat(${itemsPerRow}, 1fr)`}
|
|
295
|
+
items={rows}
|
|
296
|
+
itemTemplate={itemTemplate}
|
|
297
|
+
itemsPerRow={itemsPerRow}
|
|
298
|
+
itemProps={itemProps}
|
|
299
|
+
rowHeightInPx={rowHeight}
|
|
300
|
+
onRangeChanged={onVisibleRowsChanged}
|
|
301
|
+
gap={gap}
|
|
302
|
+
/>
|
|
303
|
+
</styles.SqlRequestGridContainer>
|
|
304
|
+
</DataGridContext.Provider>
|
|
175
305
|
);
|
|
176
306
|
};
|
|
177
307
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VirtualScrollerContainer } from '../VirtualScroller/styles';
|
|
1
2
|
import styled from 'styled-components';
|
|
2
3
|
|
|
3
4
|
export const DEFAULT_ROW_HEIGHT = 200;
|
|
@@ -8,43 +9,12 @@ export const SqlRequestGridContainer = styled.div.attrs({
|
|
|
8
9
|
height: 100%;
|
|
9
10
|
width: 100%;
|
|
10
11
|
overflow: auto;
|
|
11
|
-
`;
|
|
12
|
-
|
|
13
|
-
export const TopPaddingRow = styled.div``;
|
|
14
|
-
export const BottomPaddingRow = styled.div``;
|
|
15
|
-
|
|
16
|
-
export const VirtualScrollerContainer = styled.div<{
|
|
17
|
-
$height: number;
|
|
18
|
-
}>`
|
|
19
12
|
position: relative;
|
|
20
|
-
overflow: visible;
|
|
21
|
-
height: ${({ $height }) => `${$height}px`};
|
|
22
|
-
`;
|
|
23
|
-
export const VirtualScrollerRowsContainer = styled.div.attrs<{
|
|
24
|
-
$gridTemplateColumns: string;
|
|
25
|
-
$topPadding: number;
|
|
26
|
-
$rowHeight?: number;
|
|
27
|
-
}>(({ $gridTemplateColumns, $topPadding, $rowHeight = DEFAULT_ROW_HEIGHT }) => {
|
|
28
|
-
const rowHeightValue = `${$rowHeight}px`;
|
|
29
|
-
return {
|
|
30
|
-
style: {
|
|
31
|
-
top: `${$topPadding}px`,
|
|
32
|
-
gridTemplateColumns: $gridTemplateColumns,
|
|
33
|
-
gridAutoRows: rowHeightValue,
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
})`
|
|
37
|
-
display: grid;
|
|
38
|
-
position: absolute;
|
|
39
13
|
|
|
40
|
-
${
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
${BottomPaddingRow} {
|
|
46
|
-
grid-column-start: 1;
|
|
47
|
-
grid-column-end: -1;
|
|
48
|
-
grid-row: -1;
|
|
14
|
+
${VirtualScrollerContainer} {
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: 0;
|
|
17
|
+
left: 0;
|
|
18
|
+
right: 0;
|
|
49
19
|
}
|
|
50
20
|
`;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DataGridColumn,
|
|
11
11
|
DataGridFilter,
|
|
12
12
|
DataGridFilterType,
|
|
13
|
+
DataGridSort,
|
|
13
14
|
} from '../DataGrid/types';
|
|
14
15
|
|
|
15
16
|
import { VirtualScrollerTemplateFC } from '../VirtualScroller/types';
|
|
@@ -44,6 +45,7 @@ export type SqlRequestGridProps<R, P extends object = {}> = {
|
|
|
44
45
|
conditions?: ConditionDTO[];
|
|
45
46
|
parser?: (row: SqlRequestRow<R>) => R;
|
|
46
47
|
itemProps: P;
|
|
48
|
+
initialSorts?: Record<string, DataGridSort>;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
export type SqlRequestGridRefProps = {
|
|
@@ -17,6 +17,7 @@ type VirtualScrollerProps<R, P extends object> = {
|
|
|
17
17
|
tolerance?: number;
|
|
18
18
|
itemProps: P;
|
|
19
19
|
onRangeChanged?: (index: number, length: number) => void;
|
|
20
|
+
integrated?: boolean;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export const VirtualScroller = <R, P extends object>({
|
|
@@ -29,6 +30,7 @@ export const VirtualScroller = <R, P extends object>({
|
|
|
29
30
|
gap,
|
|
30
31
|
itemsPerRow,
|
|
31
32
|
tolerance,
|
|
33
|
+
integrated,
|
|
32
34
|
}: VirtualScrollerProps<R, P>) => {
|
|
33
35
|
const [scrollableElement, setScrollableElement] =
|
|
34
36
|
useState<HTMLElement | null>(null);
|
|
@@ -51,25 +53,33 @@ export const VirtualScroller = <R, P extends object>({
|
|
|
51
53
|
}, [indexWithTolerance, lengthWithTolerance, onRangeChanged]);
|
|
52
54
|
|
|
53
55
|
return (
|
|
54
|
-
<styles.VirtualScrollerContainer
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
<styles.VirtualScrollerContainer $integrated={integrated}>
|
|
57
|
+
<styles.VirtualScrollerFiller
|
|
58
|
+
$height={totalHeight}
|
|
59
|
+
ref={(element) =>
|
|
60
|
+
setScrollableElement(
|
|
61
|
+
(integrated
|
|
62
|
+
? element?.parentElement?.parentElement
|
|
63
|
+
: element?.parentElement) ?? null
|
|
64
|
+
)
|
|
65
|
+
}
|
|
63
66
|
>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
<styles.VirtualScrollerItemsContainer
|
|
68
|
+
$gridTemplateColumns={gridTemplateColumns}
|
|
69
|
+
$topPadding={topPadding}
|
|
70
|
+
$itemHeight={rowHeightInPx}
|
|
71
|
+
$gap={gap}
|
|
72
|
+
>
|
|
73
|
+
{visibleItems.map((item, currentIndex) => (
|
|
74
|
+
<ItemTemplate
|
|
75
|
+
key={indexWithTolerance + currentIndex}
|
|
76
|
+
item={item}
|
|
77
|
+
index={currentIndex}
|
|
78
|
+
{...itemProps}
|
|
79
|
+
/>
|
|
80
|
+
))}
|
|
81
|
+
</styles.VirtualScrollerItemsContainer>
|
|
82
|
+
</styles.VirtualScrollerFiller>
|
|
73
83
|
</styles.VirtualScrollerContainer>
|
|
74
84
|
);
|
|
75
85
|
};
|
|
@@ -5,7 +5,16 @@ export const DEFAULT_ROW_HEIGHT = 32;
|
|
|
5
5
|
export const TopPaddingItem = styled.div``;
|
|
6
6
|
export const BottomPaddingItem = styled.div``;
|
|
7
7
|
|
|
8
|
-
export const VirtualScrollerContainer = styled.div
|
|
8
|
+
export const VirtualScrollerContainer = styled.div<{
|
|
9
|
+
$integrated?: boolean;
|
|
10
|
+
}>`
|
|
11
|
+
position: relative;
|
|
12
|
+
overflow: auto;
|
|
13
|
+
height: 100%;
|
|
14
|
+
display: ${({ $integrated }) => ($integrated ? 'contents' : 'block')};
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const VirtualScrollerFiller = styled.div.attrs<{
|
|
9
18
|
$height: number;
|
|
10
19
|
}>(({ $height }) => ({
|
|
11
20
|
className: 'VirtualScrollerFiller',
|
|
@@ -4,9 +4,14 @@ import styled, { css } from 'styled-components';
|
|
|
4
4
|
import { IconFC } from '../../Icons';
|
|
5
5
|
import { ThemeColor } from '../../providers/ThemeProvider/types';
|
|
6
6
|
|
|
7
|
+
type StyledButtonProps = {
|
|
8
|
+
$color?: ThemeColor;
|
|
9
|
+
$rounded?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
7
12
|
export const StyledButton = styled.button.withConfig({
|
|
8
13
|
shouldForwardProp: () => true,
|
|
9
|
-
})<
|
|
14
|
+
})<StyledButtonProps>`
|
|
10
15
|
display: inline-flex;
|
|
11
16
|
vertical-align: middle;
|
|
12
17
|
align-items: center;
|
|
@@ -17,18 +22,18 @@ export const StyledButton = styled.button.withConfig({
|
|
|
17
22
|
font-family: var(--font-sans);
|
|
18
23
|
cursor: pointer;
|
|
19
24
|
|
|
20
|
-
${({ color }) =>
|
|
21
|
-
color
|
|
25
|
+
${({ $color }) =>
|
|
26
|
+
$color
|
|
22
27
|
? css`
|
|
23
|
-
background-color: var(--color-${color}-400);
|
|
24
|
-
border: 1px solid var(--color-${color}-500);
|
|
28
|
+
background-color: var(--color-${$color}-400);
|
|
29
|
+
border: 1px solid var(--color-${$color}-500);
|
|
25
30
|
&:hover {
|
|
26
|
-
background-color: var(--color-${color}-300);
|
|
27
|
-
border: 1px solid var(--color-${color}-400);
|
|
31
|
+
background-color: var(--color-${$color}-300);
|
|
32
|
+
border: 1px solid var(--color-${$color}-400);
|
|
28
33
|
}
|
|
29
|
-
color: var(--color-${color}-950);
|
|
34
|
+
color: var(--color-${$color}-950);
|
|
30
35
|
svg {
|
|
31
|
-
fill: var(--color-${color}-950);
|
|
36
|
+
fill: var(--color-${$color}-950);
|
|
32
37
|
}
|
|
33
38
|
`
|
|
34
39
|
: css`
|
|
@@ -44,7 +49,7 @@ export const StyledButton = styled.button.withConfig({
|
|
|
44
49
|
}
|
|
45
50
|
`}
|
|
46
51
|
|
|
47
|
-
${({ rounded }) => rounded && 'border-radius: var(--rounded-full);'}
|
|
52
|
+
${({ $rounded }) => $rounded && 'border-radius: var(--rounded-full);'}
|
|
48
53
|
|
|
49
54
|
&.small {
|
|
50
55
|
padding: var(--space-1) var(--space-1_5);
|
|
@@ -91,9 +96,28 @@ export type ButtonProps = {
|
|
|
91
96
|
export const Button = forwardRef<
|
|
92
97
|
HTMLButtonElement,
|
|
93
98
|
ComponentProps<typeof StyledButton> & ButtonProps
|
|
94
|
-
>(
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
>(
|
|
100
|
+
(
|
|
101
|
+
{
|
|
102
|
+
children,
|
|
103
|
+
size = 'medium',
|
|
104
|
+
icon: Icon,
|
|
105
|
+
className,
|
|
106
|
+
rounded = false,
|
|
107
|
+
color = 'secondary',
|
|
108
|
+
...props
|
|
109
|
+
},
|
|
110
|
+
ref
|
|
111
|
+
) => (
|
|
112
|
+
<StyledButton
|
|
113
|
+
ref={ref}
|
|
114
|
+
className={`${size} ${className}`}
|
|
115
|
+
$color={color}
|
|
116
|
+
$rounded={rounded}
|
|
117
|
+
{...props}
|
|
118
|
+
>
|
|
119
|
+
{Icon && <Icon />}
|
|
120
|
+
{children}
|
|
121
|
+
</StyledButton>
|
|
122
|
+
)
|
|
123
|
+
);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ComponentProps, forwardRef } from 'react';
|
|
2
|
+
import styled, { css } from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import { ThemeColor } from '../../providers/ThemeProvider/types';
|
|
5
|
+
|
|
6
|
+
export const StyledLabel = styled.span.withConfig({
|
|
7
|
+
shouldForwardProp: () => true,
|
|
8
|
+
})<LabelProps>`
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
font-family: var(--font-sans);
|
|
13
|
+
font-weight: 500;
|
|
14
|
+
|
|
15
|
+
${({ color }) =>
|
|
16
|
+
color
|
|
17
|
+
? css`
|
|
18
|
+
background-color: var(--color-${color}-100);
|
|
19
|
+
color: var(--color-${color}-700);
|
|
20
|
+
svg {
|
|
21
|
+
fill: var(--color-${color}-700);
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
: css`
|
|
25
|
+
background-color: var(--color-neutral-100);
|
|
26
|
+
color: var(--color-neutral-700);
|
|
27
|
+
svg {
|
|
28
|
+
fill: var(--color-neutral-700);
|
|
29
|
+
}
|
|
30
|
+
`}
|
|
31
|
+
|
|
32
|
+
${({ bordered, color }) =>
|
|
33
|
+
bordered
|
|
34
|
+
? css`
|
|
35
|
+
border: 1px solid
|
|
36
|
+
${color ? `var(--color-${color}-200)` : 'var(--color-neutral-200)'};
|
|
37
|
+
`
|
|
38
|
+
: 'border: none;'}
|
|
39
|
+
|
|
40
|
+
${({ rounded }) => rounded && 'border-radius: var(--rounded-full);'}
|
|
41
|
+
|
|
42
|
+
&.small {
|
|
43
|
+
padding: var(--space-0_5) var(--space-1_5);
|
|
44
|
+
font-size: var(--text-xs);
|
|
45
|
+
border-radius: var(--rounded-sm);
|
|
46
|
+
svg {
|
|
47
|
+
margin-right: var(--space-1);
|
|
48
|
+
width: var(--space-3);
|
|
49
|
+
height: var(--space-3);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&.medium {
|
|
54
|
+
padding: var(--space-1) var(--space-2);
|
|
55
|
+
font-size: var(--text-sm);
|
|
56
|
+
border-radius: var(--rounded-md);
|
|
57
|
+
svg {
|
|
58
|
+
margin-right: var(--space-1);
|
|
59
|
+
width: var(--space-3_5);
|
|
60
|
+
height: var(--space-3_5);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&.large {
|
|
65
|
+
padding: var(--space-1_5) var(--space-2_5);
|
|
66
|
+
font-size: var(--text-base);
|
|
67
|
+
border-radius: var(--rounded-lg);
|
|
68
|
+
svg {
|
|
69
|
+
margin-right: var(--space-1_5);
|
|
70
|
+
width: var(--space-4);
|
|
71
|
+
height: var(--space-4);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
export type LabelProps = {
|
|
77
|
+
color?: ThemeColor;
|
|
78
|
+
size?: 'small' | 'medium' | 'large';
|
|
79
|
+
rounded?: boolean;
|
|
80
|
+
bordered?: boolean;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const Label = forwardRef<
|
|
84
|
+
HTMLSpanElement,
|
|
85
|
+
ComponentProps<typeof StyledLabel> & LabelProps
|
|
86
|
+
>(({ children, size = 'medium', className = '', ...props }, ref) => (
|
|
87
|
+
<StyledLabel ref={ref} className={`${size} ${className}`} {...props}>
|
|
88
|
+
{children}
|
|
89
|
+
</StyledLabel>
|
|
90
|
+
));
|
|
@@ -400,6 +400,12 @@ export const defaultTheme: Theme = {
|
|
|
400
400
|
'32': '8rem',
|
|
401
401
|
'40': '10rem',
|
|
402
402
|
'48': '12rem',
|
|
403
|
+
'56': '14rem',
|
|
404
|
+
'64': '16rem',
|
|
405
|
+
'72': '18rem',
|
|
406
|
+
'80': '20rem',
|
|
407
|
+
'96': '24rem',
|
|
408
|
+
'128': '32rem',
|
|
403
409
|
},
|
|
404
410
|
|
|
405
411
|
sizes: {
|
|
@@ -422,6 +428,12 @@ export const defaultTheme: Theme = {
|
|
|
422
428
|
'32': '8rem',
|
|
423
429
|
'40': '10rem',
|
|
424
430
|
'48': '12rem',
|
|
431
|
+
'56': '14rem',
|
|
432
|
+
'64': '16rem',
|
|
433
|
+
'72': '18rem',
|
|
434
|
+
'80': '20rem',
|
|
435
|
+
'96': '24rem',
|
|
436
|
+
'128': '32rem',
|
|
425
437
|
},
|
|
426
438
|
|
|
427
439
|
rounded: {
|