cozy-ui 123.2.1 → 124.0.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/CHANGELOG.md +29 -0
- package/package.json +11 -6
- package/react/Filename/Readme.md +10 -8
- package/react/Filename/index.jsx +56 -10
- package/react/Filename/styles.styl +3 -0
- package/react/MuiCozyTheme/overrides/makeLightNormalOverrides.js +60 -0
- package/react/Table/Readme.md +80 -0
- package/react/Table/Virtualized/Cell.jsx +41 -0
- package/react/Table/Virtualized/Dnd/CustomDrag/CustomDragLayer.jsx +45 -0
- package/react/Table/Virtualized/Dnd/CustomDrag/DragPreview.jsx +43 -0
- package/react/Table/Virtualized/Dnd/CustomDrag/DragPreviewWrapper.jsx +52 -0
- package/react/Table/Virtualized/Dnd/DnDConfigWrapper.jsx +48 -0
- package/react/Table/Virtualized/Dnd/TableRow.jsx +86 -0
- package/react/Table/Virtualized/FixedHeaderContent.jsx +58 -0
- package/react/Table/Virtualized/HeadCell.jsx +45 -0
- package/react/Table/Virtualized/RowContent.jsx +35 -0
- package/react/Table/Virtualized/helpers.js +41 -0
- package/react/Table/Virtualized/helpers.spec.js +108 -0
- package/react/Table/Virtualized/index.jsx +104 -0
- package/react/Table/Virtualized/virtuosoComponents.jsx +61 -0
- package/react/TableRow/index.js +16 -1
- package/transpiled/react/Filename/index.d.ts +2 -1
- package/transpiled/react/Filename/index.js +49 -16
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkInvertedOverrides.d.ts +56 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkNormalOverrides.d.ts +56 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightInvertedOverrides.d.ts +56 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightNormalOverrides.d.ts +56 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightNormalOverrides.js +59 -0
- package/transpiled/react/Table/Virtualized/Cell.d.ts +8 -0
- package/transpiled/react/Table/Virtualized/Cell.js +46 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/CustomDragLayer.d.ts +4 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/CustomDragLayer.js +47 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/DragPreview.d.ts +6 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/DragPreview.js +34 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/DragPreviewWrapper.d.ts +8 -0
- package/transpiled/react/Table/Virtualized/Dnd/CustomDrag/DragPreviewWrapper.js +63 -0
- package/transpiled/react/Table/Virtualized/Dnd/DnDConfigWrapper.d.ts +2 -0
- package/transpiled/react/Table/Virtualized/Dnd/DnDConfigWrapper.js +55 -0
- package/transpiled/react/Table/Virtualized/Dnd/TableRow.d.ts +8 -0
- package/transpiled/react/Table/Virtualized/Dnd/TableRow.js +130 -0
- package/transpiled/react/Table/Virtualized/FixedHeaderContent.d.ts +10 -0
- package/transpiled/react/Table/Virtualized/FixedHeaderContent.js +54 -0
- package/transpiled/react/Table/Virtualized/HeadCell.d.ts +8 -0
- package/transpiled/react/Table/Virtualized/HeadCell.js +44 -0
- package/transpiled/react/Table/Virtualized/RowContent.d.ts +10 -0
- package/transpiled/react/Table/Virtualized/RowContent.js +34 -0
- package/transpiled/react/Table/Virtualized/helpers.d.ts +2 -0
- package/transpiled/react/Table/Virtualized/helpers.js +64 -0
- package/transpiled/react/Table/Virtualized/helpers.spec.d.ts +1 -0
- package/transpiled/react/Table/Virtualized/index.d.ts +2 -0
- package/transpiled/react/Table/Virtualized/index.js +115 -0
- package/transpiled/react/Table/Virtualized/virtuosoComponents.d.ts +10 -0
- package/transpiled/react/Table/Virtualized/virtuosoComponents.js +100 -0
- package/transpiled/react/TableRow/index.d.ts +2 -1
- package/transpiled/react/TableRow/index.js +20 -1
- package/transpiled/react/stylesheet.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
# [124.0.0](https://github.com/cozy/cozy-ui/compare/v123.2.1...v124.0.0) (2025-05-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Add dragndrop on virtualized table ([519e610](https://github.com/cozy/cozy-ui/commit/519e610))
|
|
7
|
+
* Add react-dnd ([4f2805e](https://github.com/cozy/cozy-ui/commit/4f2805e))
|
|
8
|
+
* Add react-virtuoso ([e121afe](https://github.com/cozy/cozy-ui/commit/e121afe))
|
|
9
|
+
* Add Virtual table example and adjust style ([9cc9506](https://github.com/cozy/cozy-ui/commit/9cc9506))
|
|
10
|
+
* **Filename:** Add `path` and rework `icon` ([35a8459](https://github.com/cozy/cozy-ui/commit/35a8459))
|
|
11
|
+
* Memo rows and cells ([bae4212](https://github.com/cozy/cozy-ui/commit/bae4212))
|
|
12
|
+
* **TableRow:** Add disabled style ([2a0d626](https://github.com/cozy/cozy-ui/commit/2a0d626))
|
|
13
|
+
* Upgrade react ([fe320be](https://github.com/cozy/cozy-ui/commit/fe320be))
|
|
14
|
+
* **VirtualizedTable:** Add selection props ([f819531](https://github.com/cozy/cozy-ui/commit/f819531))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### BREAKING CHANGES
|
|
18
|
+
|
|
19
|
+
* You have to add `react-dnd ^16.0.1` and `react-dnd-html5-backend ^16.0.1` to use dragndrop on virtualized table. Typically if you use `dragProps: {{ enabled: true }}` on `react/Table/Virtualized` component.
|
|
20
|
+
You also need to wrap your table into the DnD Provider like so:
|
|
21
|
+
```
|
|
22
|
+
import { DndProvider } from 'react-dnd'
|
|
23
|
+
import { HTML5Backend } from 'react-dnd-html5-backend'
|
|
24
|
+
|
|
25
|
+
<DndProvider backend={HTML5Backend}>...</DndProvider>
|
|
26
|
+
```
|
|
27
|
+
* **Filename:** You must use `<Icon />` component to use `icon` prop. So replace `<Filename icon={something} />` by `<Filename icon={<Icon icon={something} />} />`
|
|
28
|
+
* You must have `react ^16.14.0` and `react-dom ^16.14.0`.
|
|
29
|
+
|
|
1
30
|
## [123.2.1](https://github.com/cozy/cozy-ui/compare/v123.2.0...v123.2.1) (2025-05-20)
|
|
2
31
|
|
|
3
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "124.0.0",
|
|
4
4
|
"description": "Cozy apps UI SDK",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -130,12 +130,14 @@
|
|
|
130
130
|
"postcss-loader": "2.1.6",
|
|
131
131
|
"prettier": "2.6.0",
|
|
132
132
|
"prop-types": "15.7.2",
|
|
133
|
-
"react": "16.
|
|
134
|
-
"react-
|
|
133
|
+
"react": "16.14.0",
|
|
134
|
+
"react-dnd": "16.0.1",
|
|
135
|
+
"react-dnd-html5-backend": "16.0.1",
|
|
136
|
+
"react-dom": "16.14.0",
|
|
135
137
|
"react-hot-loader": "^4.3.11",
|
|
136
138
|
"react-redux": "7.2.7",
|
|
137
139
|
"react-styleguidist": "10.6.2",
|
|
138
|
-
"react-test-renderer": "16.
|
|
140
|
+
"react-test-renderer": "16.14.0",
|
|
139
141
|
"redux": "3.7.2",
|
|
140
142
|
"redux-mock-store": "^1.5.4",
|
|
141
143
|
"remark-cli": "^8.0.1",
|
|
@@ -179,6 +181,7 @@
|
|
|
179
181
|
"react-remove-scroll": "^2.4.0",
|
|
180
182
|
"react-select": "^4.3.0",
|
|
181
183
|
"react-swipeable-views": "^0.13.3",
|
|
184
|
+
"react-virtuoso": "4.12.7",
|
|
182
185
|
"rooks": "^5.11.2"
|
|
183
186
|
},
|
|
184
187
|
"peerDependencies": {
|
|
@@ -186,8 +189,10 @@
|
|
|
186
189
|
"cozy-device-helper": ">=2.0.0",
|
|
187
190
|
"cozy-flags": ">=2.10.1",
|
|
188
191
|
"cozy-intent": ">=2.29.1",
|
|
189
|
-
"react": "^16.
|
|
190
|
-
"react-
|
|
192
|
+
"react": "^16.14.0",
|
|
193
|
+
"react-dnd": "^16.0.1",
|
|
194
|
+
"react-dnd-html5-backend": "^16.0.1",
|
|
195
|
+
"react-dom": "^16.14.0"
|
|
191
196
|
},
|
|
192
197
|
"eslintConfig": {
|
|
193
198
|
"extends": [
|
package/react/Filename/Readme.md
CHANGED
|
@@ -3,23 +3,25 @@
|
|
|
3
3
|
```jsx
|
|
4
4
|
import Filename from 'cozy-ui/transpiled/react/Filename'
|
|
5
5
|
import FileIcon from 'cozy-ui/transpiled/react/Icons/File'
|
|
6
|
+
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
6
7
|
import Variants from 'cozy-ui/docs/components/Variants'
|
|
7
8
|
|
|
8
9
|
const initialVariants = [
|
|
9
|
-
{ midEllipsis: false, icon:
|
|
10
|
+
{ midEllipsis: false, icon: true, body1Variant: false, extension: true, short: false, withPath: true }
|
|
10
11
|
]
|
|
11
12
|
|
|
12
13
|
;
|
|
13
14
|
|
|
14
15
|
<Variants initialVariants={initialVariants} screenshotAllVariants>
|
|
15
16
|
{variant => (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
<Filename
|
|
18
|
+
icon={variant.icon ? <Icon icon={FileIcon} size={32} /> : undefined}
|
|
19
|
+
variant={variant.body1Variant ? 'body1' : undefined}
|
|
20
|
+
midEllipsis={variant.midEllipsis}
|
|
21
|
+
filename={variant.short ? "Lacinia condimentum this is the end" : "Lacinia condimentum potenti id est tortor dictumst lectus tincidunt hac ultricies, curae mattis nisi neque sodales sagittis dui nulla aliquam turpis eros, finibus ac iaculis dictum et orci elit posuere ex and this is the end"}
|
|
22
|
+
extension={variant.extension ? ".pdf" : undefined}
|
|
23
|
+
path={variant.withPath ? '/some/folder/and/subfolder' : undefined}
|
|
24
|
+
/>
|
|
23
25
|
)}
|
|
24
26
|
</Variants>
|
|
25
27
|
```
|
package/react/Filename/index.jsx
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
1
2
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React from 'react'
|
|
3
|
+
import React, { Fragment } from 'react'
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import styles from './styles.styl'
|
|
6
|
+
import { iconPropType } from '../Icon'
|
|
5
7
|
import MidEllipsis from '../MidEllipsis'
|
|
6
8
|
import Typography from '../Typography'
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const NameAndExtension = ({ filename, extension, variant, midEllipsis }) => {
|
|
9
11
|
return (
|
|
10
|
-
|
|
11
|
-
{icon && (
|
|
12
|
-
<div className="u-mr-1">
|
|
13
|
-
<Icon icon={icon} width={30} height={30} />
|
|
14
|
-
</div>
|
|
15
|
-
)}
|
|
12
|
+
<>
|
|
16
13
|
{filename && (
|
|
17
14
|
<Typography variant={variant} component="span" noWrap>
|
|
18
15
|
{midEllipsis ? <MidEllipsis text={filename} /> : filename}
|
|
@@ -23,7 +20,56 @@ const Filename = ({ icon, filename, extension, midEllipsis, variant }) => {
|
|
|
23
20
|
{extension}
|
|
24
21
|
</Typography>
|
|
25
22
|
)}
|
|
26
|
-
|
|
23
|
+
</>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const Filename = ({
|
|
28
|
+
icon,
|
|
29
|
+
filename,
|
|
30
|
+
extension,
|
|
31
|
+
midEllipsis,
|
|
32
|
+
variant,
|
|
33
|
+
path
|
|
34
|
+
}) => {
|
|
35
|
+
const [Wrapper, wrapperProps] = path
|
|
36
|
+
? [Fragment, {}]
|
|
37
|
+
: ['div', { className: cx('u-flex u-flex-items-center') }]
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Wrapper {...wrapperProps}>
|
|
41
|
+
{icon && (
|
|
42
|
+
<div
|
|
43
|
+
className={cx('u-flex u-pos-relative u-mr-1', {
|
|
44
|
+
[styles['icon-withPath']]: !!path
|
|
45
|
+
})}
|
|
46
|
+
>
|
|
47
|
+
{icon}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
{path ? (
|
|
51
|
+
<>
|
|
52
|
+
<div className="u-flex">
|
|
53
|
+
<NameAndExtension
|
|
54
|
+
filename={filename}
|
|
55
|
+
extension={extension}
|
|
56
|
+
variant={variant}
|
|
57
|
+
midEllipsis={midEllipsis}
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
<Typography variant="body2" component="div" noWrap>
|
|
61
|
+
{path}
|
|
62
|
+
</Typography>
|
|
63
|
+
</>
|
|
64
|
+
) : (
|
|
65
|
+
<NameAndExtension
|
|
66
|
+
filename={filename}
|
|
67
|
+
extension={extension}
|
|
68
|
+
variant={variant}
|
|
69
|
+
midEllipsis={midEllipsis}
|
|
70
|
+
/>
|
|
71
|
+
)}
|
|
72
|
+
</Wrapper>
|
|
27
73
|
)
|
|
28
74
|
}
|
|
29
75
|
|
|
@@ -506,6 +506,66 @@ export const makeLightNormalOverrides = theme => ({
|
|
|
506
506
|
paddingRight: 16
|
|
507
507
|
}
|
|
508
508
|
},
|
|
509
|
+
MuiTableHead: {
|
|
510
|
+
root: {
|
|
511
|
+
backgroundColor: theme.palette.background.paper
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
MuiTableRow: {
|
|
515
|
+
root: {
|
|
516
|
+
'&.disabled': {
|
|
517
|
+
cursor: 'pointer',
|
|
518
|
+
pointerEvents: 'none',
|
|
519
|
+
opacity: 0.5
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
MuiTableCell: {
|
|
524
|
+
root: {
|
|
525
|
+
padding: '8px 4px'
|
|
526
|
+
},
|
|
527
|
+
head: {
|
|
528
|
+
...theme.typography.subtitle2,
|
|
529
|
+
color: theme.palette.text.secondary,
|
|
530
|
+
lineHeight: 1.292
|
|
531
|
+
},
|
|
532
|
+
body: {
|
|
533
|
+
color: theme.palette.text.secondary,
|
|
534
|
+
'&.sortable': {
|
|
535
|
+
'&$paddingNone': {
|
|
536
|
+
'&$alignLeft': {
|
|
537
|
+
paddingLeft: '12px'
|
|
538
|
+
},
|
|
539
|
+
'&$alignRight': {
|
|
540
|
+
paddingRight: '12px'
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
'&$alignLeft': {
|
|
544
|
+
paddingLeft: '16px'
|
|
545
|
+
},
|
|
546
|
+
'&$alignRight': {
|
|
547
|
+
paddingRight: '16px'
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
stickyHeader: {
|
|
552
|
+
backgroundColor: theme.palette.background.paper
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
MuiTableSortLabel: {
|
|
556
|
+
root: {
|
|
557
|
+
padding: '8px 12px',
|
|
558
|
+
color: theme.palette.text.secondary,
|
|
559
|
+
'&:hover': {
|
|
560
|
+
color: theme.palette.text.primary,
|
|
561
|
+
borderRadius: 999,
|
|
562
|
+
backgroundColor: theme.palette.action.hover
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
icon: {
|
|
566
|
+
fontSize: 14
|
|
567
|
+
}
|
|
568
|
+
},
|
|
509
569
|
MuiFormLabel: {
|
|
510
570
|
root: {
|
|
511
571
|
color: theme.palette.text.secondary,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
### React-Virtuoso
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
import VirtualizedTable from 'cozy-ui/transpiled/react/Table/Virtualized'
|
|
5
|
+
|
|
6
|
+
const createData = (id, name, calories, fat, carbs, protein) => {
|
|
7
|
+
return { id, name, calories, fat, carbs, protein }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const rows = [
|
|
11
|
+
createData(0, 'Cupcake', 305, 3.7, 67, 4.3),
|
|
12
|
+
createData(1, 'Donut', 452, 25.0, 51, 4.9),
|
|
13
|
+
createData(2, 'Eclair', 262, 16.0, 24, 6.0),
|
|
14
|
+
createData(3, 'Frozen yoghurt', 159, 6.0, 24, 4.0),
|
|
15
|
+
createData(4, 'Gingerbread', 356, 16.0, 49, 3.9),
|
|
16
|
+
createData(5, 'Honeycomb', 408, 3.2, 87, 6.5),
|
|
17
|
+
createData(6, 'Ice cream sandwich', 237, 9.0, 37, 4.3),
|
|
18
|
+
createData(7, 'Jelly Bean', 375, 0.0, 94, 0.0),
|
|
19
|
+
createData(8, 'KitKat', 518, 26.0, 65, 7.0),
|
|
20
|
+
createData(9, 'Lollipop', 392, 0.2, 98, 0.0),
|
|
21
|
+
createData(10, 'Marshmallow', 318, 0, 81, 2.0),
|
|
22
|
+
createData(11, 'Nougat', 360, 19.0, 9, 37.0),
|
|
23
|
+
createData(12, 'Oreo', 437, 18.0, 63, 4.0),
|
|
24
|
+
createData(
|
|
25
|
+
6,
|
|
26
|
+
'Ice cream with a very long list of ingredient to see how the table can handle this kind of item, and this is the end',
|
|
27
|
+
237,
|
|
28
|
+
9.0,
|
|
29
|
+
37,
|
|
30
|
+
4.3
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const columns = [
|
|
35
|
+
{
|
|
36
|
+
id: 'name',
|
|
37
|
+
disablePadding: true,
|
|
38
|
+
label: 'Dessert'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'calories',
|
|
42
|
+
disablePadding: false,
|
|
43
|
+
width: 80,
|
|
44
|
+
label: 'Calories',
|
|
45
|
+
textAlign: 'left',
|
|
46
|
+
sortable: false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'fat',
|
|
50
|
+
disablePadding: false,
|
|
51
|
+
width: 85,
|
|
52
|
+
label: 'Fat (g)',
|
|
53
|
+
textAlign: 'right'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'carbs',
|
|
57
|
+
disablePadding: false,
|
|
58
|
+
width: 115,
|
|
59
|
+
label: 'Carbs (g)',
|
|
60
|
+
textAlign: 'right'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'protein',
|
|
64
|
+
disablePadding: false,
|
|
65
|
+
width: 115,
|
|
66
|
+
label: 'Protein (g)',
|
|
67
|
+
textAlign: 'right'
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
;
|
|
72
|
+
|
|
73
|
+
<div style={{ border: "1px solid var(--borderMainColor)", height: 400, width: "100%" }}>
|
|
74
|
+
<VirtualizedTable
|
|
75
|
+
rows={rows}
|
|
76
|
+
columns={columns}
|
|
77
|
+
defaultOrder={columns[0].id}
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import TableCell from '../../TableCell'
|
|
5
|
+
import { makeStyles } from '../../styles'
|
|
6
|
+
|
|
7
|
+
const useStyles = makeStyles({
|
|
8
|
+
root: {
|
|
9
|
+
width: ({ column }) => column.width,
|
|
10
|
+
maxWidth: ({ column }) => column.maxWidth
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const Cell = ({ row, columns, column, children }) => {
|
|
15
|
+
const classes = useStyles({ column })
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<TableCell
|
|
19
|
+
key={column.id}
|
|
20
|
+
classes={classes}
|
|
21
|
+
className={cx({ sortable: column.sortable !== false })}
|
|
22
|
+
align={column.textAlign ?? 'left'}
|
|
23
|
+
padding={column.disablePadding ? 'none' : 'normal'}
|
|
24
|
+
>
|
|
25
|
+
{children
|
|
26
|
+
? React.Children.map(children, child =>
|
|
27
|
+
React.isValidElement(child)
|
|
28
|
+
? React.cloneElement(child, {
|
|
29
|
+
row,
|
|
30
|
+
columns,
|
|
31
|
+
column,
|
|
32
|
+
cell: row[column.id]
|
|
33
|
+
})
|
|
34
|
+
: null
|
|
35
|
+
)
|
|
36
|
+
: row[column.id]}
|
|
37
|
+
</TableCell>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default React.memo(Cell)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useDragLayer } from 'react-dnd'
|
|
3
|
+
|
|
4
|
+
import DragPreviewWrapper from './DragPreviewWrapper'
|
|
5
|
+
|
|
6
|
+
const layerStyles = {
|
|
7
|
+
position: 'fixed',
|
|
8
|
+
pointerEvents: 'none',
|
|
9
|
+
zIndex: 100,
|
|
10
|
+
left: 0,
|
|
11
|
+
top: 0,
|
|
12
|
+
width: '100%',
|
|
13
|
+
height: '100%'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Example find in the official documentation
|
|
17
|
+
// https://react-dnd.github.io/react-dnd/examples/drag-around/custom-drag-layer
|
|
18
|
+
export const CustomDragLayer = ({ dragId }) => {
|
|
19
|
+
const { itemType, isDragging, item, initialOffset, currentOffset } =
|
|
20
|
+
useDragLayer(monitor => ({
|
|
21
|
+
item: monitor.getItem(),
|
|
22
|
+
itemType: monitor.getItemType(),
|
|
23
|
+
initialOffset: monitor.getInitialSourceClientOffset(),
|
|
24
|
+
currentOffset: monitor.getSourceClientOffset(),
|
|
25
|
+
isDragging: monitor.isDragging()
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
if (!isDragging) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div style={layerStyles}>
|
|
34
|
+
<DragPreviewWrapper
|
|
35
|
+
item={item}
|
|
36
|
+
itemType={itemType}
|
|
37
|
+
dragId={dragId}
|
|
38
|
+
initialOffset={initialOffset}
|
|
39
|
+
currentOffset={currentOffset}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default CustomDragLayer
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import Badge from '../../../../Badge'
|
|
4
|
+
import Paper from '../../../../Paper'
|
|
5
|
+
import Typography from '../../../../Typography'
|
|
6
|
+
import { makeStyles } from '../../../../styles'
|
|
7
|
+
|
|
8
|
+
const useStyles = makeStyles({
|
|
9
|
+
root: {
|
|
10
|
+
width: 'fit-content'
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const DragPreview = ({ fileName, selectedCount }) => {
|
|
15
|
+
const classes = useStyles()
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
{selectedCount > 1 ? (
|
|
20
|
+
<Badge
|
|
21
|
+
badgeContent={selectedCount}
|
|
22
|
+
size="large"
|
|
23
|
+
color="primary"
|
|
24
|
+
anchorOrigin={{
|
|
25
|
+
vertical: 'top',
|
|
26
|
+
horizontal: 'right'
|
|
27
|
+
}}
|
|
28
|
+
overlap="rectangular"
|
|
29
|
+
>
|
|
30
|
+
<Paper classes={classes} className="u-p-half u-maw-5">
|
|
31
|
+
<Typography>{fileName}</Typography>
|
|
32
|
+
</Paper>
|
|
33
|
+
</Badge>
|
|
34
|
+
) : (
|
|
35
|
+
<Paper classes={classes} className="u-p-half u-maw-5">
|
|
36
|
+
<Typography>{fileName}</Typography>
|
|
37
|
+
</Paper>
|
|
38
|
+
)}
|
|
39
|
+
</>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default React.memo(DragPreview)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import DragPreview from './DragPreview'
|
|
4
|
+
|
|
5
|
+
const makeStyles = ({ x, y }) => {
|
|
6
|
+
if (!x || !y) {
|
|
7
|
+
return { display: 'none' }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const transform = `translate(${x}px, ${y}px)`
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
transform,
|
|
14
|
+
WebkitTransform: transform
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DragPreviewWrapper = ({
|
|
19
|
+
item,
|
|
20
|
+
itemType,
|
|
21
|
+
dragId,
|
|
22
|
+
initialOffset,
|
|
23
|
+
currentOffset
|
|
24
|
+
}) => {
|
|
25
|
+
const [mousePosition, setMousePosition] = useState({ x: null, y: null })
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const handleMouseMove = e => {
|
|
29
|
+
setMousePosition({ x: e.clientX, y: e.clientY })
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
window.addEventListener('dragover', handleMouseMove)
|
|
33
|
+
return () => {
|
|
34
|
+
window.removeEventListener('dragover', handleMouseMove)
|
|
35
|
+
}
|
|
36
|
+
}, [])
|
|
37
|
+
|
|
38
|
+
if (!initialOffset || !currentOffset || itemType !== dragId) {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div style={makeStyles(mousePosition)}>
|
|
44
|
+
<DragPreview
|
|
45
|
+
fileName={item.draggedItems[0].name}
|
|
46
|
+
selectedCount={item.draggedItems.length}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default DragPreviewWrapper
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useState } from 'react'
|
|
2
|
+
import { useDragDropManager } from 'react-dnd'
|
|
3
|
+
|
|
4
|
+
const DnDConfigWrapper = forwardRef(({ children }, ref) => {
|
|
5
|
+
const dragDropManager = useDragDropManager()
|
|
6
|
+
const monitor = dragDropManager.getMonitor()
|
|
7
|
+
const [isDragging, setIsDragging] = useState(false)
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const unsubscribe = monitor.subscribeToStateChange(() => {
|
|
11
|
+
setIsDragging(monitor.isDragging())
|
|
12
|
+
})
|
|
13
|
+
return () => unsubscribe()
|
|
14
|
+
}, [monitor])
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!isDragging) return
|
|
18
|
+
|
|
19
|
+
const scrollThreshold = 100
|
|
20
|
+
const scrollMaxSpeed = 75
|
|
21
|
+
|
|
22
|
+
const intervalId = setInterval(() => {
|
|
23
|
+
const offset = monitor.getClientOffset()
|
|
24
|
+
const container = ref.current
|
|
25
|
+
if (!offset || !container) return
|
|
26
|
+
|
|
27
|
+
const { top, bottom } = container.getBoundingClientRect()
|
|
28
|
+
const distanceToTop = offset.y - top
|
|
29
|
+
const distanceToBottom = bottom - offset.y
|
|
30
|
+
|
|
31
|
+
if (distanceToTop < scrollThreshold) {
|
|
32
|
+
const speed = scrollMaxSpeed * (1 - distanceToTop / scrollThreshold)
|
|
33
|
+
container.scrollBy(0, -speed)
|
|
34
|
+
} else if (distanceToBottom < scrollThreshold) {
|
|
35
|
+
const speed = scrollMaxSpeed * (1 - distanceToBottom / scrollThreshold)
|
|
36
|
+
container.scrollBy(0, speed)
|
|
37
|
+
}
|
|
38
|
+
}, 16) // ~60fps
|
|
39
|
+
|
|
40
|
+
return () => clearInterval(intervalId)
|
|
41
|
+
}, [isDragging, monitor, ref])
|
|
42
|
+
|
|
43
|
+
return children
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
DnDConfigWrapper.displayName = 'DnDConfigWrapper'
|
|
47
|
+
|
|
48
|
+
export default DnDConfigWrapper
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
|
+
import { useDrag, useDrop } from 'react-dnd'
|
|
3
|
+
import { getEmptyImage } from 'react-dnd-html5-backend'
|
|
4
|
+
|
|
5
|
+
import TableRowClassic from '../../../TableRow'
|
|
6
|
+
|
|
7
|
+
const TableRow = ({ item, context, selected, disabled, ...props }) => {
|
|
8
|
+
const { selectedItems, setItemsInDropProcess, dragProps } = context
|
|
9
|
+
const {
|
|
10
|
+
onDrop,
|
|
11
|
+
canDrop: canDropProps,
|
|
12
|
+
canDrag: canDragProps,
|
|
13
|
+
dragId
|
|
14
|
+
} = dragProps
|
|
15
|
+
|
|
16
|
+
const [dragCollect, dragRef, dragRefPreview] = useDrag(
|
|
17
|
+
() => ({
|
|
18
|
+
type: dragId,
|
|
19
|
+
isDragging: monitor => {
|
|
20
|
+
// put all selected items in isDragging state
|
|
21
|
+
if (selectedItems.length > 0) {
|
|
22
|
+
return selectedItems.some(
|
|
23
|
+
selectedItem => selectedItem._id === item._id
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return item._id === monitor.getItem().draggedItems[0]._id
|
|
28
|
+
},
|
|
29
|
+
item: {
|
|
30
|
+
draggedItems: selectedItems.length > 0 ? selectedItems : [item]
|
|
31
|
+
},
|
|
32
|
+
canDrag: () => {
|
|
33
|
+
const defaultCanDrag = canDragProps?.(item) || true
|
|
34
|
+
// if selectedItems is not empty, only the selected items can be dragged
|
|
35
|
+
if (selectedItems.length > 0) {
|
|
36
|
+
return defaultCanDrag && selected
|
|
37
|
+
}
|
|
38
|
+
return defaultCanDrag
|
|
39
|
+
},
|
|
40
|
+
collect: monitor => {
|
|
41
|
+
return {
|
|
42
|
+
isDragging: monitor.isDragging()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}),
|
|
46
|
+
[item, selectedItems] // used to pass args inside returned object attributes
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const [dropCollect, dropRef] = useDrop(
|
|
50
|
+
() => ({
|
|
51
|
+
accept: dragId,
|
|
52
|
+
canDrop: () => (canDropProps ? canDropProps(item) : true),
|
|
53
|
+
drop: async draggedItem => {
|
|
54
|
+
setItemsInDropProcess(
|
|
55
|
+
draggedItem.draggedItems.map(draggedItem => draggedItem._id)
|
|
56
|
+
)
|
|
57
|
+
await onDrop(draggedItem.draggedItems, item, selectedItems)
|
|
58
|
+
setItemsInDropProcess([])
|
|
59
|
+
},
|
|
60
|
+
collect: monitor => {
|
|
61
|
+
return {
|
|
62
|
+
isOver: monitor.isOver()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}),
|
|
66
|
+
[item._id, selectedItems] // used to pass args inside returned object attributes
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// Tricks for the preview image to be empty
|
|
70
|
+
// https://react-dnd.github.io/react-dnd/examples/drag-around/custom-drag-layer
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
dragRefPreview(getEmptyImage(), { captureDraggingState: true })
|
|
73
|
+
}, [dragRefPreview])
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<TableRowClassic
|
|
77
|
+
{...props}
|
|
78
|
+
ref={node => dragRef(dropRef(node))}
|
|
79
|
+
selected={selected || dropCollect.isOver}
|
|
80
|
+
className={dragCollect.isDragging ? 'u-o-50' : ''}
|
|
81
|
+
disabled={disabled}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default TableRow
|