@etsoo/materialui 1.6.12 → 1.6.13
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/lib/cjs/ButtonPopupCheckbox.d.ts +6 -0
- package/lib/cjs/ButtonPopupCheckbox.js +4 -4
- package/lib/cjs/ButtonPopupRadio.d.ts +6 -0
- package/lib/cjs/ButtonPopupRadio.js +4 -4
- package/lib/cjs/DnDSortableList.d.ts +1 -1
- package/lib/cjs/DnDSortableList.js +22 -1
- package/lib/mjs/ButtonPopupCheckbox.d.ts +6 -0
- package/lib/mjs/ButtonPopupCheckbox.js +4 -4
- package/lib/mjs/ButtonPopupRadio.d.ts +6 -0
- package/lib/mjs/ButtonPopupRadio.js +4 -4
- package/lib/mjs/DnDSortableList.d.ts +1 -1
- package/lib/mjs/DnDSortableList.js +23 -2
- package/package.json +1 -1
- package/src/ButtonPopupCheckbox.tsx +12 -3
- package/src/ButtonPopupRadio.tsx +12 -3
- package/src/DnDSortableList.tsx +31 -4
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ButtonProps } from "@mui/material/Button";
|
|
2
2
|
import { IdType } from "@etsoo/shared";
|
|
3
|
+
import { GridSize } from "@mui/material/Grid";
|
|
3
4
|
import { DnDSortableListProps } from "./DnDSortableList";
|
|
5
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
4
6
|
type DnDItemType = {
|
|
5
7
|
id: IdType;
|
|
6
8
|
};
|
|
@@ -64,6 +66,10 @@ export type ButtonPopupCheckboxProps<D extends DnDItemType> = Omit<ButtonProps,
|
|
|
64
66
|
* The field is required or not
|
|
65
67
|
*/
|
|
66
68
|
required?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Item size
|
|
71
|
+
*/
|
|
72
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
67
73
|
/**
|
|
68
74
|
* Value
|
|
69
75
|
*/
|
|
@@ -22,7 +22,7 @@ const FormLabel_1 = __importDefault(require("@mui/material/FormLabel"));
|
|
|
22
22
|
const DnDSortableList_1 = require("./DnDSortableList");
|
|
23
23
|
function ButtonPopupList(props) {
|
|
24
24
|
// Destruct
|
|
25
|
-
const { addSplitter = /\s*[,;]\s*/, value = [], items, labelField, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
25
|
+
const { addSplitter = /\s*[,;]\s*/, value = [], items, itemSize = { xs: 12, md: 6, lx: 4 }, labelField, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
26
26
|
// Methods
|
|
27
27
|
const dndRef = react_1.default.createRef();
|
|
28
28
|
// Refs
|
|
@@ -45,7 +45,7 @@ function ButtonPopupList(props) {
|
|
|
45
45
|
.filter((item) => tempSelectedIds.current.includes(item.id))
|
|
46
46
|
.map((item) => item.id);
|
|
47
47
|
onValueChange(ids);
|
|
48
|
-
}, itemRenderer: (item, style, { sortable: { index }, ref, handleRef }) => ((0, jsx_runtime_1.jsxs)(Grid_1.default, { size:
|
|
48
|
+
}, itemRenderer: (item, style, { sortable: { index }, ref, handleRef }) => ((0, jsx_runtime_1.jsxs)(Grid_1.default, { size: itemSize, display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 1, ref: ref, style: style, children: [(0, jsx_runtime_1.jsx)(IconButton_1.default, { style: { cursor: "move" }, size: "small", title: labels?.dragIndicator, ref: handleRef, children: (0, jsx_runtime_1.jsx)(DragIndicator_1.default, {}) }), (0, jsx_runtime_1.jsx)(FormControlLabel_1.default, { control: (0, jsx_runtime_1.jsx)(Checkbox_1.default, { name: "item", value: item.id, checked: selectedIds.includes(item.id), onChange: (e) => {
|
|
49
49
|
const checked = e.target.checked;
|
|
50
50
|
const newIds = [
|
|
51
51
|
...selectedIds.toggleItem(item.id, checked)
|
|
@@ -81,7 +81,7 @@ function ButtonPopupCheckbox(props) {
|
|
|
81
81
|
// App
|
|
82
82
|
const app = (0, ReactApp_1.useRequiredAppContext)();
|
|
83
83
|
// Destruct
|
|
84
|
-
const { addSplitter, value = [], inputName, label, labelEnd, labelFormatter = (data) => {
|
|
84
|
+
const { addSplitter, value = [], inputName, itemSize, label, labelEnd, labelFormatter = (data) => {
|
|
85
85
|
if (typeof labelField === "function")
|
|
86
86
|
return labelField(data);
|
|
87
87
|
if (labelField in data) {
|
|
@@ -130,7 +130,7 @@ function ButtonPopupCheckbox(props) {
|
|
|
130
130
|
setSelectedIds(ids);
|
|
131
131
|
onValueChange?.(ids);
|
|
132
132
|
},
|
|
133
|
-
inputs: ((0, jsx_runtime_1.jsx)(ButtonPopupList, { addSplitter: addSplitter, value: selectedIds, items: items, labelFormatter: labelFormatter, labelField: labelField, labels: labels, onAdd: onAdd, onValueChange: (ids) => {
|
|
133
|
+
inputs: ((0, jsx_runtime_1.jsx)(ButtonPopupList, { addSplitter: addSplitter, value: selectedIds, items: items, labelFormatter: labelFormatter, labelField: labelField, itemSize: itemSize, labels: labels, onAdd: onAdd, onValueChange: (ids) => {
|
|
134
134
|
tempSelectedIds.current = ids;
|
|
135
135
|
} })),
|
|
136
136
|
fullScreen: app.smDown
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ButtonProps } from "@mui/material/Button";
|
|
2
2
|
import { DataTypes, IdType } from "@etsoo/shared";
|
|
3
|
+
import { GridSize } from "@mui/material/Grid";
|
|
4
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
3
5
|
type DnDItemType = {
|
|
4
6
|
id: IdType;
|
|
5
7
|
};
|
|
@@ -63,6 +65,10 @@ export type ButtonPopupRadioProps<D extends DnDItemType> = Omit<ButtonProps, "ch
|
|
|
63
65
|
* The field is required or not
|
|
64
66
|
*/
|
|
65
67
|
required?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Item size
|
|
70
|
+
*/
|
|
71
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
66
72
|
/**
|
|
67
73
|
* Value
|
|
68
74
|
*/
|
|
@@ -21,7 +21,7 @@ const FlexBox_1 = require("./FlexBox");
|
|
|
21
21
|
const ReactApp_1 = require("./app/ReactApp");
|
|
22
22
|
function ButtonPopupList(props) {
|
|
23
23
|
// Destruct
|
|
24
|
-
const { addSplitter = /\s*[,;]\s*/, value, items, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
24
|
+
const { addSplitter = /\s*[,;]\s*/, value, items, labelFormatter, labels, itemSize = { xs: 12, md: 6, lx: 4 }, onAdd, onValueChange } = props;
|
|
25
25
|
// Ref
|
|
26
26
|
const inputRef = react_1.default.useRef(null);
|
|
27
27
|
// State
|
|
@@ -38,7 +38,7 @@ function ButtonPopupList(props) {
|
|
|
38
38
|
: undefined;
|
|
39
39
|
setCurrentValue(value);
|
|
40
40
|
onValueChange(value);
|
|
41
|
-
}, children: (0, jsx_runtime_1.jsx)(Grid_1.default, { container: true, spacing: 0, children: items.map((item) => ((0, jsx_runtime_1.jsx)(Grid_1.default, { size:
|
|
41
|
+
}, children: (0, jsx_runtime_1.jsx)(Grid_1.default, { container: true, spacing: 0, children: items.map((item) => ((0, jsx_runtime_1.jsx)(Grid_1.default, { size: itemSize, display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 1, children: (0, jsx_runtime_1.jsx)(FormControlLabel_1.default, { control: (0, jsx_runtime_1.jsx)(Radio_1.default, { value: item.id }), label: `${labelFormatter(item)}` }) }, item.id))) }) }), onAdd && ((0, jsx_runtime_1.jsxs)(FlexBox_1.HBox, { gap: 1, children: [(0, jsx_runtime_1.jsx)(TextField_1.default, { variant: "outlined", label: labels?.more, fullWidth: true, inputRef: inputRef }), (0, jsx_runtime_1.jsx)(Button_1.default, { sx: { width: "120px" }, variant: "contained", startIcon: (0, jsx_runtime_1.jsx)(Add_1.default, {}), size: "small", onClick: async () => {
|
|
42
42
|
if (inputRef.current == null)
|
|
43
43
|
return;
|
|
44
44
|
const input = inputRef.current.value.trim();
|
|
@@ -66,7 +66,7 @@ function ButtonPopupRadio(props) {
|
|
|
66
66
|
// App
|
|
67
67
|
const app = (0, ReactApp_1.useRequiredAppContext)();
|
|
68
68
|
// Destruct
|
|
69
|
-
const { addSplitter, inputName, label, labelEnd, labelFormatter = (data) => {
|
|
69
|
+
const { addSplitter, inputName, itemSize, label, labelEnd, labelFormatter = (data) => {
|
|
70
70
|
if (labelField in data) {
|
|
71
71
|
return data[labelField];
|
|
72
72
|
}
|
|
@@ -115,7 +115,7 @@ function ButtonPopupRadio(props) {
|
|
|
115
115
|
setCurrentValue(id);
|
|
116
116
|
onValueChange?.(id);
|
|
117
117
|
},
|
|
118
|
-
inputs: ((0, jsx_runtime_1.jsx)(ButtonPopupList, { addSplitter: addSplitter, value: currentValue, items: items, labelFormatter: labelFormatter, labels: labels, onAdd: onAdd, onValueChange: (id) => {
|
|
118
|
+
inputs: ((0, jsx_runtime_1.jsx)(ButtonPopupList, { addSplitter: addSplitter, value: currentValue, items: items, itemSize: itemSize, labelFormatter: labelFormatter, labels: labels, onAdd: onAdd, onValueChange: (id) => {
|
|
119
119
|
tempSelectedId.current = id;
|
|
120
120
|
} })),
|
|
121
121
|
fullScreen: app.smDown
|
|
@@ -91,7 +91,7 @@ export type DnDSortableListProps<D extends object, E extends React.ElementType =
|
|
|
91
91
|
/**
|
|
92
92
|
* Drag start handler
|
|
93
93
|
*/
|
|
94
|
-
onDragStart?: (items: D[],
|
|
94
|
+
onDragStart?: (items: D[], event: Parameters<DragDropEvents["dragstart"]>[0]) => void;
|
|
95
95
|
/**
|
|
96
96
|
* Drag end handler
|
|
97
97
|
*/
|
|
@@ -123,7 +123,28 @@ function DnDSortableList(props) {
|
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
125
|
}, [items, labelFn, changeItems]);
|
|
126
|
-
|
|
126
|
+
function handleDragEnd(...args) {
|
|
127
|
+
// Event
|
|
128
|
+
const event = args[0];
|
|
129
|
+
// Cancelled
|
|
130
|
+
if (event.canceled)
|
|
131
|
+
return;
|
|
132
|
+
if ((0, sortable_1.isSortableOperation)(event.operation) && event.operation.source) {
|
|
133
|
+
const { initialIndex, index } = event.operation.source;
|
|
134
|
+
if (initialIndex === index)
|
|
135
|
+
return;
|
|
136
|
+
// Clone
|
|
137
|
+
const newItems = [...items];
|
|
138
|
+
// Removed item
|
|
139
|
+
const [removed] = newItems.splice(initialIndex, 1);
|
|
140
|
+
// Insert to the destination index
|
|
141
|
+
newItems.splice(index, 0, removed);
|
|
142
|
+
changeItems(newItems);
|
|
143
|
+
// Drag end handler
|
|
144
|
+
onDragEnd?.(newItems, ...args);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return ((0, jsx_runtime_1.jsx)(react_2.DragDropProvider, { onDragStart: (event) => onDragStart?.(items, event), onDragEnd: (event, manager) => handleDragEnd(event, manager), children: (0, jsx_runtime_1.jsx)(Component, { ...componentProps, children: items.map((item, index) => {
|
|
127
148
|
const id = idFn(item);
|
|
128
149
|
return ((0, jsx_runtime_1.jsx)(SortableItem, { id: id, index: index, data: item, itemRenderer: itemRenderer, itemStyle: itemStyle }, id));
|
|
129
150
|
}) }) }));
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ButtonProps } from "@mui/material/Button";
|
|
2
2
|
import { IdType } from "@etsoo/shared";
|
|
3
|
+
import { GridSize } from "@mui/material/Grid";
|
|
3
4
|
import { DnDSortableListProps } from "./DnDSortableList";
|
|
5
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
4
6
|
type DnDItemType = {
|
|
5
7
|
id: IdType;
|
|
6
8
|
};
|
|
@@ -64,6 +66,10 @@ export type ButtonPopupCheckboxProps<D extends DnDItemType> = Omit<ButtonProps,
|
|
|
64
66
|
* The field is required or not
|
|
65
67
|
*/
|
|
66
68
|
required?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Item size
|
|
71
|
+
*/
|
|
72
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
67
73
|
/**
|
|
68
74
|
* Value
|
|
69
75
|
*/
|
|
@@ -16,7 +16,7 @@ import FormLabel from "@mui/material/FormLabel";
|
|
|
16
16
|
import { DnDSortableList } from "./DnDSortableList";
|
|
17
17
|
function ButtonPopupList(props) {
|
|
18
18
|
// Destruct
|
|
19
|
-
const { addSplitter = /\s*[,;]\s*/, value = [], items, labelField, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
19
|
+
const { addSplitter = /\s*[,;]\s*/, value = [], items, itemSize = { xs: 12, md: 6, lx: 4 }, labelField, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
20
20
|
// Methods
|
|
21
21
|
const dndRef = React.createRef();
|
|
22
22
|
// Refs
|
|
@@ -39,7 +39,7 @@ function ButtonPopupList(props) {
|
|
|
39
39
|
.filter((item) => tempSelectedIds.current.includes(item.id))
|
|
40
40
|
.map((item) => item.id);
|
|
41
41
|
onValueChange(ids);
|
|
42
|
-
}, itemRenderer: (item, style, { sortable: { index }, ref, handleRef }) => (_jsxs(Grid, { size:
|
|
42
|
+
}, itemRenderer: (item, style, { sortable: { index }, ref, handleRef }) => (_jsxs(Grid, { size: itemSize, display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 1, ref: ref, style: style, children: [_jsx(IconButton, { style: { cursor: "move" }, size: "small", title: labels?.dragIndicator, ref: handleRef, children: _jsx(DragIndicatorIcon, {}) }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { name: "item", value: item.id, checked: selectedIds.includes(item.id), onChange: (e) => {
|
|
43
43
|
const checked = e.target.checked;
|
|
44
44
|
const newIds = [
|
|
45
45
|
...selectedIds.toggleItem(item.id, checked)
|
|
@@ -75,7 +75,7 @@ export function ButtonPopupCheckbox(props) {
|
|
|
75
75
|
// App
|
|
76
76
|
const app = useRequiredAppContext();
|
|
77
77
|
// Destruct
|
|
78
|
-
const { addSplitter, value = [], inputName, label, labelEnd, labelFormatter = (data) => {
|
|
78
|
+
const { addSplitter, value = [], inputName, itemSize, label, labelEnd, labelFormatter = (data) => {
|
|
79
79
|
if (typeof labelField === "function")
|
|
80
80
|
return labelField(data);
|
|
81
81
|
if (labelField in data) {
|
|
@@ -124,7 +124,7 @@ export function ButtonPopupCheckbox(props) {
|
|
|
124
124
|
setSelectedIds(ids);
|
|
125
125
|
onValueChange?.(ids);
|
|
126
126
|
},
|
|
127
|
-
inputs: (_jsx(ButtonPopupList, { addSplitter: addSplitter, value: selectedIds, items: items, labelFormatter: labelFormatter, labelField: labelField, labels: labels, onAdd: onAdd, onValueChange: (ids) => {
|
|
127
|
+
inputs: (_jsx(ButtonPopupList, { addSplitter: addSplitter, value: selectedIds, items: items, labelFormatter: labelFormatter, labelField: labelField, itemSize: itemSize, labels: labels, onAdd: onAdd, onValueChange: (ids) => {
|
|
128
128
|
tempSelectedIds.current = ids;
|
|
129
129
|
} })),
|
|
130
130
|
fullScreen: app.smDown
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ButtonProps } from "@mui/material/Button";
|
|
2
2
|
import { DataTypes, IdType } from "@etsoo/shared";
|
|
3
|
+
import { GridSize } from "@mui/material/Grid";
|
|
4
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
3
5
|
type DnDItemType = {
|
|
4
6
|
id: IdType;
|
|
5
7
|
};
|
|
@@ -63,6 +65,10 @@ export type ButtonPopupRadioProps<D extends DnDItemType> = Omit<ButtonProps, "ch
|
|
|
63
65
|
* The field is required or not
|
|
64
66
|
*/
|
|
65
67
|
required?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Item size
|
|
70
|
+
*/
|
|
71
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
66
72
|
/**
|
|
67
73
|
* Value
|
|
68
74
|
*/
|
|
@@ -15,7 +15,7 @@ import { HBox, VBox } from "./FlexBox";
|
|
|
15
15
|
import { useRequiredAppContext } from "./app/ReactApp";
|
|
16
16
|
function ButtonPopupList(props) {
|
|
17
17
|
// Destruct
|
|
18
|
-
const { addSplitter = /\s*[,;]\s*/, value, items, labelFormatter, labels, onAdd, onValueChange } = props;
|
|
18
|
+
const { addSplitter = /\s*[,;]\s*/, value, items, labelFormatter, labels, itemSize = { xs: 12, md: 6, lx: 4 }, onAdd, onValueChange } = props;
|
|
19
19
|
// Ref
|
|
20
20
|
const inputRef = React.useRef(null);
|
|
21
21
|
// State
|
|
@@ -32,7 +32,7 @@ function ButtonPopupList(props) {
|
|
|
32
32
|
: undefined;
|
|
33
33
|
setCurrentValue(value);
|
|
34
34
|
onValueChange(value);
|
|
35
|
-
}, children: _jsx(Grid, { container: true, spacing: 0, children: items.map((item) => (_jsx(Grid, { size:
|
|
35
|
+
}, children: _jsx(Grid, { container: true, spacing: 0, children: items.map((item) => (_jsx(Grid, { size: itemSize, display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 1, children: _jsx(FormControlLabel, { control: _jsx(Radio, { value: item.id }), label: `${labelFormatter(item)}` }) }, item.id))) }) }), onAdd && (_jsxs(HBox, { gap: 1, children: [_jsx(TextField, { variant: "outlined", label: labels?.more, fullWidth: true, inputRef: inputRef }), _jsx(Button, { sx: { width: "120px" }, variant: "contained", startIcon: _jsx(AddIcon, {}), size: "small", onClick: async () => {
|
|
36
36
|
if (inputRef.current == null)
|
|
37
37
|
return;
|
|
38
38
|
const input = inputRef.current.value.trim();
|
|
@@ -60,7 +60,7 @@ export function ButtonPopupRadio(props) {
|
|
|
60
60
|
// App
|
|
61
61
|
const app = useRequiredAppContext();
|
|
62
62
|
// Destruct
|
|
63
|
-
const { addSplitter, inputName, label, labelEnd, labelFormatter = (data) => {
|
|
63
|
+
const { addSplitter, inputName, itemSize, label, labelEnd, labelFormatter = (data) => {
|
|
64
64
|
if (labelField in data) {
|
|
65
65
|
return data[labelField];
|
|
66
66
|
}
|
|
@@ -109,7 +109,7 @@ export function ButtonPopupRadio(props) {
|
|
|
109
109
|
setCurrentValue(id);
|
|
110
110
|
onValueChange?.(id);
|
|
111
111
|
},
|
|
112
|
-
inputs: (_jsx(ButtonPopupList, { addSplitter: addSplitter, value: currentValue, items: items, labelFormatter: labelFormatter, labels: labels, onAdd: onAdd, onValueChange: (id) => {
|
|
112
|
+
inputs: (_jsx(ButtonPopupList, { addSplitter: addSplitter, value: currentValue, items: items, itemSize: itemSize, labelFormatter: labelFormatter, labels: labels, onAdd: onAdd, onValueChange: (id) => {
|
|
113
113
|
tempSelectedId.current = id;
|
|
114
114
|
} })),
|
|
115
115
|
fullScreen: app.smDown
|
|
@@ -91,7 +91,7 @@ export type DnDSortableListProps<D extends object, E extends React.ElementType =
|
|
|
91
91
|
/**
|
|
92
92
|
* Drag start handler
|
|
93
93
|
*/
|
|
94
|
-
onDragStart?: (items: D[],
|
|
94
|
+
onDragStart?: (items: D[], event: Parameters<DragDropEvents["dragstart"]>[0]) => void;
|
|
95
95
|
/**
|
|
96
96
|
* Drag end handler
|
|
97
97
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { useTheme } from "@mui/material/styles";
|
|
4
|
-
import { useSortable } from "@dnd-kit/react/sortable";
|
|
4
|
+
import { isSortableOperation, useSortable } from "@dnd-kit/react/sortable";
|
|
5
5
|
import { DragDropProvider } from "@dnd-kit/react";
|
|
6
6
|
/**
|
|
7
7
|
* DnD sortable item default style
|
|
@@ -115,7 +115,28 @@ export function DnDSortableList(props) {
|
|
|
115
115
|
}
|
|
116
116
|
};
|
|
117
117
|
}, [items, labelFn, changeItems]);
|
|
118
|
-
|
|
118
|
+
function handleDragEnd(...args) {
|
|
119
|
+
// Event
|
|
120
|
+
const event = args[0];
|
|
121
|
+
// Cancelled
|
|
122
|
+
if (event.canceled)
|
|
123
|
+
return;
|
|
124
|
+
if (isSortableOperation(event.operation) && event.operation.source) {
|
|
125
|
+
const { initialIndex, index } = event.operation.source;
|
|
126
|
+
if (initialIndex === index)
|
|
127
|
+
return;
|
|
128
|
+
// Clone
|
|
129
|
+
const newItems = [...items];
|
|
130
|
+
// Removed item
|
|
131
|
+
const [removed] = newItems.splice(initialIndex, 1);
|
|
132
|
+
// Insert to the destination index
|
|
133
|
+
newItems.splice(index, 0, removed);
|
|
134
|
+
changeItems(newItems);
|
|
135
|
+
// Drag end handler
|
|
136
|
+
onDragEnd?.(newItems, ...args);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return (_jsx(DragDropProvider, { onDragStart: (event) => onDragStart?.(items, event), onDragEnd: (event, manager) => handleDragEnd(event, manager), children: _jsx(Component, { ...componentProps, children: items.map((item, index) => {
|
|
119
140
|
const id = idFn(item);
|
|
120
141
|
return (_jsx(SortableItem, { id: id, index: index, data: item, itemRenderer: itemRenderer, itemStyle: itemStyle }, id));
|
|
121
142
|
}) }) }));
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@ import Button, { ButtonProps } from "@mui/material/Button";
|
|
|
2
2
|
import Chip from "@mui/material/Chip";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { DataTypes, IdType } from "@etsoo/shared";
|
|
5
|
-
import Grid from "@mui/material/Grid";
|
|
5
|
+
import Grid, { GridSize } from "@mui/material/Grid";
|
|
6
6
|
import Typography from "@mui/material/Typography";
|
|
7
7
|
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
|
|
8
8
|
import AddIcon from "@mui/icons-material/Add";
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
DnDSortableListProps,
|
|
19
19
|
DnDSortableListRef
|
|
20
20
|
} from "./DnDSortableList";
|
|
21
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
21
22
|
|
|
22
23
|
type DnDItemType = {
|
|
23
24
|
id: IdType;
|
|
@@ -99,6 +100,11 @@ export type ButtonPopupCheckboxProps<D extends DnDItemType> = Omit<
|
|
|
99
100
|
*/
|
|
100
101
|
required?: boolean;
|
|
101
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Item size
|
|
105
|
+
*/
|
|
106
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
107
|
+
|
|
102
108
|
/**
|
|
103
109
|
* Value
|
|
104
110
|
*/
|
|
@@ -107,7 +113,7 @@ export type ButtonPopupCheckboxProps<D extends DnDItemType> = Omit<
|
|
|
107
113
|
|
|
108
114
|
type ButtonPopupListProps<D extends DnDItemType> = Pick<
|
|
109
115
|
ButtonPopupCheckboxProps<D>,
|
|
110
|
-
"addSplitter" | "labelField" | "labels" | "onAdd" | "value"
|
|
116
|
+
"addSplitter" | "labelField" | "labels" | "onAdd" | "value" | "itemSize"
|
|
111
117
|
> &
|
|
112
118
|
Required<Pick<ButtonPopupCheckboxProps<D>, "labelFormatter">> & {
|
|
113
119
|
/**
|
|
@@ -130,6 +136,7 @@ function ButtonPopupList<D extends DnDItemType>(
|
|
|
130
136
|
addSplitter = /\s*[,;]\s*/,
|
|
131
137
|
value = [],
|
|
132
138
|
items,
|
|
139
|
+
itemSize = { xs: 12, md: 6, lx: 4 },
|
|
133
140
|
labelField,
|
|
134
141
|
labelFormatter,
|
|
135
142
|
labels,
|
|
@@ -180,7 +187,7 @@ function ButtonPopupList<D extends DnDItemType>(
|
|
|
180
187
|
{ sortable: { index }, ref, handleRef }
|
|
181
188
|
) => (
|
|
182
189
|
<Grid
|
|
183
|
-
size={
|
|
190
|
+
size={itemSize}
|
|
184
191
|
display="flex"
|
|
185
192
|
justifyContent="flex-start"
|
|
186
193
|
alignItems="center"
|
|
@@ -281,6 +288,7 @@ export function ButtonPopupCheckbox<D extends DnDItemType>(
|
|
|
281
288
|
addSplitter,
|
|
282
289
|
value = [],
|
|
283
290
|
inputName,
|
|
291
|
+
itemSize,
|
|
284
292
|
label,
|
|
285
293
|
labelEnd,
|
|
286
294
|
labelFormatter = (data) => {
|
|
@@ -353,6 +361,7 @@ export function ButtonPopupCheckbox<D extends DnDItemType>(
|
|
|
353
361
|
items={items}
|
|
354
362
|
labelFormatter={labelFormatter}
|
|
355
363
|
labelField={labelField}
|
|
364
|
+
itemSize={itemSize}
|
|
356
365
|
labels={labels}
|
|
357
366
|
onAdd={onAdd}
|
|
358
367
|
onValueChange={(ids) => {
|
package/src/ButtonPopupRadio.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import Button, { ButtonProps } from "@mui/material/Button";
|
|
|
2
2
|
import Chip from "@mui/material/Chip";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { DataTypes, IdType, NumberUtils } from "@etsoo/shared";
|
|
5
|
-
import Grid from "@mui/material/Grid";
|
|
5
|
+
import Grid, { GridSize } from "@mui/material/Grid";
|
|
6
6
|
import Typography from "@mui/material/Typography";
|
|
7
7
|
import AddIcon from "@mui/icons-material/Add";
|
|
8
8
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
@@ -12,6 +12,7 @@ import FormLabel from "@mui/material/FormLabel";
|
|
|
12
12
|
import RadioGroup from "@mui/material/RadioGroup";
|
|
13
13
|
import { HBox, VBox } from "./FlexBox";
|
|
14
14
|
import { useRequiredAppContext } from "./app/ReactApp";
|
|
15
|
+
import { ResponsiveStyleValue } from "./ResponsiveStyleValue";
|
|
15
16
|
|
|
16
17
|
type DnDItemType = {
|
|
17
18
|
id: IdType;
|
|
@@ -93,6 +94,11 @@ export type ButtonPopupRadioProps<D extends DnDItemType> = Omit<
|
|
|
93
94
|
*/
|
|
94
95
|
required?: boolean;
|
|
95
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Item size
|
|
99
|
+
*/
|
|
100
|
+
itemSize?: ResponsiveStyleValue<GridSize>;
|
|
101
|
+
|
|
96
102
|
/**
|
|
97
103
|
* Value
|
|
98
104
|
*/
|
|
@@ -101,7 +107,7 @@ export type ButtonPopupRadioProps<D extends DnDItemType> = Omit<
|
|
|
101
107
|
|
|
102
108
|
type ButtonPopupListProps<D extends DnDItemType> = Pick<
|
|
103
109
|
ButtonPopupRadioProps<D>,
|
|
104
|
-
"addSplitter" | "labels" | "onAdd" | "value"
|
|
110
|
+
"addSplitter" | "labels" | "onAdd" | "value" | "itemSize"
|
|
105
111
|
> &
|
|
106
112
|
Required<Pick<ButtonPopupRadioProps<D>, "labelFormatter">> & {
|
|
107
113
|
/**
|
|
@@ -126,6 +132,7 @@ function ButtonPopupList<D extends DnDItemType>(
|
|
|
126
132
|
items,
|
|
127
133
|
labelFormatter,
|
|
128
134
|
labels,
|
|
135
|
+
itemSize = { xs: 12, md: 6, lx: 4 },
|
|
129
136
|
onAdd,
|
|
130
137
|
onValueChange
|
|
131
138
|
} = props;
|
|
@@ -159,7 +166,7 @@ function ButtonPopupList<D extends DnDItemType>(
|
|
|
159
166
|
<Grid container spacing={0}>
|
|
160
167
|
{items.map((item) => (
|
|
161
168
|
<Grid
|
|
162
|
-
size={
|
|
169
|
+
size={itemSize}
|
|
163
170
|
display="flex"
|
|
164
171
|
justifyContent="flex-start"
|
|
165
172
|
alignItems="center"
|
|
@@ -233,6 +240,7 @@ export function ButtonPopupRadio<D extends DnDItemType>(
|
|
|
233
240
|
const {
|
|
234
241
|
addSplitter,
|
|
235
242
|
inputName,
|
|
243
|
+
itemSize,
|
|
236
244
|
label,
|
|
237
245
|
labelEnd,
|
|
238
246
|
labelFormatter = (data) => {
|
|
@@ -305,6 +313,7 @@ export function ButtonPopupRadio<D extends DnDItemType>(
|
|
|
305
313
|
addSplitter={addSplitter}
|
|
306
314
|
value={currentValue}
|
|
307
315
|
items={items}
|
|
316
|
+
itemSize={itemSize}
|
|
308
317
|
labelFormatter={labelFormatter}
|
|
309
318
|
labels={labels}
|
|
310
319
|
onAdd={onAdd}
|
package/src/DnDSortableList.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DataTypes, IdType } from "@etsoo/shared";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { CSSProperties, Theme, useTheme } from "@mui/material/styles";
|
|
4
|
-
import { useSortable } from "@dnd-kit/react/sortable";
|
|
4
|
+
import { isSortableOperation, useSortable } from "@dnd-kit/react/sortable";
|
|
5
5
|
import { DragDropEvents, DragDropProvider } from "@dnd-kit/react";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -126,7 +126,7 @@ export type DnDSortableListProps<
|
|
|
126
126
|
*/
|
|
127
127
|
onDragStart?: (
|
|
128
128
|
items: D[],
|
|
129
|
-
|
|
129
|
+
event: Parameters<DragDropEvents["dragstart"]>[0]
|
|
130
130
|
) => void;
|
|
131
131
|
|
|
132
132
|
/**
|
|
@@ -293,10 +293,37 @@ export function DnDSortableList<
|
|
|
293
293
|
};
|
|
294
294
|
}, [items, labelFn, changeItems]);
|
|
295
295
|
|
|
296
|
+
function handleDragEnd(...args: Parameters<DragDropEvents["dragend"]>) {
|
|
297
|
+
// Event
|
|
298
|
+
const event = args[0];
|
|
299
|
+
|
|
300
|
+
// Cancelled
|
|
301
|
+
if (event.canceled) return;
|
|
302
|
+
|
|
303
|
+
if (isSortableOperation(event.operation) && event.operation.source) {
|
|
304
|
+
const { initialIndex, index } = event.operation.source;
|
|
305
|
+
if (initialIndex === index) return;
|
|
306
|
+
|
|
307
|
+
// Clone
|
|
308
|
+
const newItems = [...items];
|
|
309
|
+
|
|
310
|
+
// Removed item
|
|
311
|
+
const [removed] = newItems.splice(initialIndex, 1);
|
|
312
|
+
|
|
313
|
+
// Insert to the destination index
|
|
314
|
+
newItems.splice(index, 0, removed);
|
|
315
|
+
|
|
316
|
+
changeItems(newItems);
|
|
317
|
+
|
|
318
|
+
// Drag end handler
|
|
319
|
+
onDragEnd?.(newItems, ...args);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
296
323
|
return (
|
|
297
324
|
<DragDropProvider
|
|
298
|
-
onDragStart={(
|
|
299
|
-
onDragEnd={(
|
|
325
|
+
onDragStart={(event) => onDragStart?.(items, event)}
|
|
326
|
+
onDragEnd={(event, manager) => handleDragEnd(event, manager)}
|
|
300
327
|
>
|
|
301
328
|
<Component {...componentProps}>
|
|
302
329
|
{items.map((item, index) => {
|