PluginProbe
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News / 4.0.3
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News v4.0.3
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 2.3.5 2.3.6 2.4.0 2.4.1 2.4.10 2.4.11 2.4.12 2.4.13 2.4.14 2.4.15 2.4.16 2.4.17 2.4.18 2.4.19 2.4.2 2.4.20 2.4.21 All 88 releases
post-carousel / src / components / multipleSelect / multipleSelectWithDnd.js

multipleSelectWithDnd.js in Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News 4.0.3, at src/components/multipleSelect/multipleSelectWithDnd.js

191 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useEffect, useRef, useState } from "@wordpress/element";
2 import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
3 import { arrayMoveImmutable } from "array-move";
4 import "./dnd-select.scss";
5
6 let optionOpen = true;
7 const MultipleSelectWithDnd = ({ label = "", items, values, onChange, onInputChange = false, searchable = false }) => {
8 const [allOptions, setAllOptions] = useState([]);
9 const [searchFieldData, setSearchFieldData] = useState("");
10 const [toggleSelectField, setToggleSelectField] = useState(false);
11 const allValues = values?.map((item) => item.value);
12 const containerRef = useRef(null);
13
14 const filterNotSelectedItems = (selectFieldItems) => {
15 const result = selectFieldItems?.filter((item) => !allValues.includes(item.value));
16 return result;
17 };
18
19 useEffect(() => {
20 let options = [];
21 if (toggleSelectField) {
22 options = filterNotSelectedItems(items);
23 } else {
24 options = [];
25 }
26 setAllOptions(options);
27 }, [items, values, toggleSelectField]);
28
29 const handleSelectField = (data) => {
30 const { id, value, _label } = data;
31 const newValue = [...values, { id: id, value: value, label: _label }];
32 setSearchFieldData("");
33 onChange(newValue);
34 };
35
36 const handleSearchField = (event) => {
37 const value = event.target.value.toLowerCase();
38 setSearchFieldData(value);
39 const searchableArray = filterNotSelectedItems(items);
40 const matchedOption = searchableArray.filter((i) => i.label.toLowerCase().includes(value));
41 onInputChange ? onInputChange(value) : setAllOptions(matchedOption);
42 };
43
44 const handleRemoveItems = (id) => {
45 const updatedValues = values?.filter((val) => val.id !== id);
46 onChange(updatedValues);
47 };
48
49 useEffect(() => {
50 const handleClick = (e) => {
51 if (!e.target.closest(".sp-multiple-select-dnd-container")) {
52 setToggleSelectField(false);
53 }
54 };
55 document.addEventListener("click", handleClick);
56
57 return () => {
58 document.removeEventListener("click", handleClick);
59 };
60 }, []);
61
62 const dndRef = useRef(null);
63
64 // icons
65 const DeleteIcon = () => {
66 return (
67 <svg xmlns="http://www.w3.org/2000/svg" width={8} height={8} fill="none">
68 <path
69 fill="#2F2F2F"
70 d="M4 4.778 6.722 7.5l.778-.778L4.778 4 7.5 1.278 6.722.5 4 3.222 1.278.5.5 1.278 3.222 4 .5 6.722l.778.778L4 4.778Z"
71 />
72 </svg>
73 );
74 };
75 const ArrowIconOne = () => (
76 <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} aria-hidden="true" className="">
77 <path d="M17.5 11.6 12 16l-5.5-4.4.9-1.2L12 14l4.5-3.6 1 1.2z" />
78 </svg>
79 );
80 const ArrowIconTwo = () => (
81 <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} aria-hidden="true">
82 <path d="M6.5 12.4 12 8l5.5 4.4-.9 1.2L12 10l-4.5 3.6-1-1.2z" />
83 </svg>
84 );
85
86 // dnd
87 const onDragEnd = (result) => {
88 setToggleSelectField(false);
89 const { source, destination } = result;
90 if (!destination) {
91 return;
92 }
93 const from = source.index;
94 const to = destination.index;
95 const updatedArray = arrayMoveImmutable(values, from, to);
96 onChange(updatedArray);
97 optionOpen = true;
98 };
99
100 const onDragStart = () => {
101 optionOpen = false;
102 setToggleSelectField(false);
103 };
104
105 const toggleSelectFieldVal = () => {
106 if (optionOpen) {
107 setToggleSelectField((prev) => !prev);
108 }
109 };
110
111 const containerHeight = values?.length * 34 + 2 + "px";
112
113 return (
114 <div className="shaped-plugin-multiple-select sp-smart-post-component-mb" ref={dndRef}>
115 <div className="sp-multiple-select-dnd-label">
116 <p> {label}</p>
117 </div>
118 <div className="sp-multiple-select-dnd-container" ref={containerRef}>
119 <div onClick={toggleSelectFieldVal} className="sp-select-header">
120 <div className="sp-selected-options" style={{ height: containerHeight }}>
121 <DragDropContext onDragEnd={onDragEnd} onDragStart={onDragStart}>
122 <Droppable droppableId={`${dndRef?.current}`} direction="vertical">
123 {(provided) => (
124 <div ref={provided.innerRef} {...provided.droppableProps}>
125 {values?.map((item, i) => (
126 <Draggable key={item?.id} draggableId={`${item?.id}`} index={i}>
127 {(provided) => (
128 <div
129 ref={provided.innerRef}
130 {...provided.draggableProps}
131 {...provided.dragHandleProps}
132 >
133 <div className="sp-selected-option">
134 <span className="sp-select-label">{item?.label}</span>
135 <span
136 className="sp-select-remove-button"
137 onClick={() => handleRemoveItems(item.id)}
138 >
139 <DeleteIcon />
140 </span>
141 </div>
142 </div>
143 )}
144 </Draggable>
145 ))}
146 {provided.placeholder}
147 </div>
148 )}
149 </Droppable>
150 </DragDropContext>
151 </div>
152 <span className="custom-select-arrow">
153 {toggleSelectField ? <ArrowIconTwo /> : <ArrowIconOne />}
154 </span>
155 </div>
156 {toggleSelectField && (
157 <div className="sp-select-options">
158 {searchable && (
159 <input
160 placeholder="Search here for more..."
161 value={searchFieldData}
162 onChange={(e) => handleSearchField(e)}
163 className="sp-select-search-field"
164 />
165 )}
166 {allOptions?.length > 0 &&
167 allOptions?.map((option, i) => {
168 return (
169 <div key={i}>
170 {option.label && option.value && (
171 <p
172 onClick={() => handleSelectField(option)}
173 className={`sp-select-option ${
174 values === option.value ? "selected" : ""
175 }`}
176 >
177 {option.label}
178 </p>
179 )}
180 </div>
181 );
182 })}
183 </div>
184 )}
185 </div>
186 </div>
187 );
188 };
189
190 export default MultipleSelectWithDnd;
191