funda-ui 4.5.666 → 4.5.671

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.
Files changed (65) hide show
  1. package/ColorPicker/index.js +3 -1
  2. package/Date/index.js +14 -1
  3. package/DragDropList/index.css +188 -0
  4. package/DragDropList/index.d.ts +44 -0
  5. package/DragDropList/index.js +1587 -0
  6. package/Input/index.d.ts +2 -0
  7. package/Input/index.js +14 -1
  8. package/LICENSE +21 -0
  9. package/MultipleSelect/index.css +237 -144
  10. package/MultipleSelect/index.d.ts +24 -10
  11. package/MultipleSelect/index.js +2240 -1225
  12. package/README.md +3 -1
  13. package/RangeSlider/index.js +14 -1
  14. package/Textarea/index.d.ts +2 -0
  15. package/Textarea/index.js +14 -1
  16. package/Tree/index.d.ts +1 -0
  17. package/Tree/index.js +29 -0
  18. package/Utils/useBoundedDrag.d.ts +125 -0
  19. package/Utils/useBoundedDrag.js +380 -0
  20. package/Utils/useDragDropPosition.d.ts +169 -0
  21. package/Utils/useDragDropPosition.js +456 -0
  22. package/Utils/useIsMobile.d.ts +2 -0
  23. package/Utils/useIsMobile.js +168 -0
  24. package/all.d.ts +1 -0
  25. package/all.js +1 -1
  26. package/lib/cjs/ColorPicker/index.js +3 -1
  27. package/lib/cjs/Date/index.js +14 -1
  28. package/lib/cjs/DragDropList/index.d.ts +44 -0
  29. package/lib/cjs/DragDropList/index.js +1587 -0
  30. package/lib/cjs/Input/index.d.ts +2 -0
  31. package/lib/cjs/Input/index.js +14 -1
  32. package/lib/cjs/MultipleSelect/index.d.ts +24 -10
  33. package/lib/cjs/MultipleSelect/index.js +2240 -1225
  34. package/lib/cjs/RangeSlider/index.js +14 -1
  35. package/lib/cjs/Textarea/index.d.ts +2 -0
  36. package/lib/cjs/Textarea/index.js +14 -1
  37. package/lib/cjs/Tree/index.d.ts +1 -0
  38. package/lib/cjs/Tree/index.js +29 -0
  39. package/lib/cjs/Utils/useBoundedDrag.d.ts +125 -0
  40. package/lib/cjs/Utils/useBoundedDrag.js +380 -0
  41. package/lib/cjs/Utils/useDragDropPosition.d.ts +169 -0
  42. package/lib/cjs/Utils/useDragDropPosition.js +456 -0
  43. package/lib/cjs/Utils/useIsMobile.d.ts +2 -0
  44. package/lib/cjs/Utils/useIsMobile.js +168 -0
  45. package/lib/cjs/index.d.ts +1 -0
  46. package/lib/cjs/index.js +1 -1
  47. package/lib/css/DragDropList/index.css +188 -0
  48. package/lib/css/MultipleSelect/index.css +237 -144
  49. package/lib/esm/ColorPicker/index.tsx +53 -49
  50. package/lib/esm/DragDropList/index.scss +245 -0
  51. package/lib/esm/DragDropList/index.tsx +494 -0
  52. package/lib/esm/Input/index.tsx +17 -3
  53. package/lib/esm/MultipleSelect/index.scss +288 -183
  54. package/lib/esm/MultipleSelect/index.tsx +305 -166
  55. package/lib/esm/MultipleSelect/utils/func.ts +21 -1
  56. package/lib/esm/Tabs/Tabs.tsx +1 -1
  57. package/lib/esm/Textarea/index.tsx +18 -1
  58. package/lib/esm/Tree/TreeList.tsx +32 -0
  59. package/lib/esm/Tree/index.tsx +3 -0
  60. package/lib/esm/Utils/hooks/useBoundedDrag.tsx +301 -0
  61. package/lib/esm/Utils/hooks/useDragDropPosition.tsx +420 -0
  62. package/lib/esm/Utils/hooks/useIsMobile.tsx +56 -0
  63. package/lib/esm/index.js +1 -0
  64. package/package.json +1 -1
  65. package/lib/esm/MultipleSelect/ItemList.tsx +0 -323
@@ -0,0 +1,420 @@
1
+ /**
2
+ * Drag Drop Object
3
+ *
4
+ * @usage:
5
+
6
+ import { useState, useCallback } from 'react';
7
+ import { useDragDropPosition } from '@/utils/hooks/useDragDropPosition';
8
+
9
+ const App = () => {
10
+
11
+ const [show, setShow] = useState<boolean>(false);
12
+
13
+ // drag & drop
14
+ //---------------、
15
+ const moveDelay = 150;
16
+ const pin = false;
17
+ const dimension = 32; // onject with dimension
18
+ const [objPosition, setObjPosition] = useState<{
19
+ x: number;
20
+ y: number;
21
+ }>({ x: 0, y: 0 });
22
+ const [isDragged, setIsDragged] = useState<boolean>(false);
23
+ const [isPressed, setIsPressed] = useState<boolean>(false);
24
+
25
+
26
+ const { setup, ref } = useDragDropPosition({
27
+ // usePercentage: true, // Enable percentage values
28
+ dimension,
29
+ onDragEnd: ({position, hasContainer}) => {
30
+ const { left, top } = position;
31
+ setObjPosition({
32
+ x: left || 0,
33
+ y: (top || 0),
34
+ });
35
+ setIsPressed(false);
36
+ setIsDragged(false);
37
+
38
+ // click event here (restore)
39
+ setShow(false);
40
+ },
41
+ onDragStart: ({position, hasContainer}) => {
42
+ const { left, top } = position;
43
+ setObjPosition({
44
+ x: left || 0,
45
+ y: (top || 0),
46
+ });
47
+ setIsDragged(true);
48
+
49
+ // click event here (restore)
50
+ setShow(false);
51
+ },
52
+ onInit: ({position, hasContainer}) => {
53
+ const { left, top } = position;
54
+ setObjPosition({
55
+ x: left || 0,
56
+ y: (top || 0),
57
+ });
58
+ },
59
+ onPointerDown: () => {
60
+ setIsPressed(true);
61
+ },
62
+ onPointerUp: useCallback(() => {
63
+ setIsPressed(false);
64
+
65
+ // click event here
66
+ setShow((prev) => !prev);
67
+
68
+ }, []),
69
+ onMove: ({position, hasContainer}) => {
70
+ const { left, top } = position;
71
+ setObjPosition({
72
+ x: left || 0,
73
+ y: (top || 0),
74
+ });
75
+ },
76
+ pin,
77
+ moveDelay
78
+ });
79
+
80
+
81
+
82
+ return (
83
+
84
+
85
+ <>
86
+
87
+ <div
88
+ ref={setup}
89
+ className="float-btn"
90
+ style={{position: 'fixed', left: '50%', top: '50%', zIndex: 1000, background: 'red'}}
91
+
92
+ >Move Here<small>{JSON.stringify(objPosition)}</small><br /><strong>{show ? 'Clicked' : 'None'}</strong></div>
93
+
94
+ </>
95
+ )
96
+ }
97
+
98
+
99
+
100
+
101
+ const App2 = () => {
102
+
103
+ const dragdropContainerRef = useRef<HTMLDivElement>(null);
104
+ ....
105
+
106
+ const { setup, ref } = useDragDropPosition({
107
+ container: dragdropContainerRef.current, // If there is a container with a drag range
108
+ ...
109
+ });
110
+
111
+
112
+ return (
113
+
114
+ <>
115
+
116
+ <div
117
+ ref={dragdropContainerRef}
118
+ style={{
119
+ width: '300px',
120
+ height: '300px',
121
+ border: '1px solid #ddd',
122
+ background: '#efefef',
123
+ position: 'relative'
124
+ }}
125
+ >
126
+ <div
127
+ ref={setup}
128
+ className="float-btn"
129
+ style={{ position: 'absolute', left: '50%', top: '50%', zIndex: 1000, background: 'red' }}
130
+
131
+ >Move Here<small>{JSON.stringify(objPosition)}</small><br /><strong>{show ? 'Clicked' : 'None'}</strong></div>
132
+
133
+ </div>
134
+
135
+
136
+
137
+ </>
138
+ )
139
+ }
140
+
141
+ */
142
+
143
+ import { useCallback, useEffect, useRef } from "react";
144
+
145
+ interface Position {
146
+ left: number;
147
+ top: number;
148
+ }
149
+
150
+ interface ContainerDimensions {
151
+ width: number;
152
+ height: number;
153
+ left: number;
154
+ top: number;
155
+ }
156
+
157
+ interface PositionResult {
158
+ position: Position;
159
+ hasContainer: boolean;
160
+ }
161
+
162
+ interface DragDropSettings {
163
+ container?: HTMLElement | null;
164
+ onPointerDown?: () => void;
165
+ onPointerUp?: () => void;
166
+ onDragStart?: (position: PositionResult) => void;
167
+ onDragEnd?: (position: PositionResult) => void;
168
+ onMove?: (position: PositionResult) => void;
169
+ onInit?: (position: PositionResult) => void;
170
+ dimension?: number;
171
+ pin?: boolean;
172
+ moveDelay?: number;
173
+ usePercentage?: boolean;
174
+ }
175
+
176
+ const useDragDropPosition = (settings: DragDropSettings) => {
177
+ const {
178
+ container = null,
179
+ onPointerDown,
180
+ onPointerUp,
181
+ onDragStart,
182
+ onDragEnd,
183
+ onMove,
184
+ dimension = 0,
185
+ onInit,
186
+ pin,
187
+ moveDelay = 150,
188
+ usePercentage = false
189
+ } = settings;
190
+
191
+ const ref = useRef<HTMLElement | null>(null);
192
+ const isClicked = useRef<boolean>(false);
193
+ const isDragged = useRef<boolean>(false);
194
+ const keyPressed = useRef<boolean>(false);
195
+
196
+ const convertToPercentage = useCallback((position: Position): PositionResult => {
197
+ if (usePercentage) {
198
+ if (!container) return {
199
+ position,
200
+ hasContainer: Boolean(container)
201
+ };
202
+
203
+ const containerDim = getContainerDimensions();
204
+ return {
205
+ position: {
206
+ left: (position.left / containerDim.width) * 100,
207
+ top: (position.top / containerDim.height) * 100
208
+ },
209
+ hasContainer: Boolean(container)
210
+ };
211
+ } else {
212
+ return {
213
+ position,
214
+ hasContainer: false
215
+ };
216
+ }
217
+ }, [container, usePercentage]);
218
+
219
+ const getContainerDimensions = (): ContainerDimensions => {
220
+ if (!container) {
221
+ return {
222
+ width: window.innerWidth,
223
+ height: window.innerHeight,
224
+ left: 0,
225
+ top: 0
226
+ };
227
+ }
228
+
229
+ const rect = container.getBoundingClientRect();
230
+ return {
231
+ width: rect.width,
232
+ height: rect.height,
233
+ left: rect.left,
234
+ top: rect.top
235
+ };
236
+ };
237
+
238
+ const getLeft = (left: number, dimension: number): number => {
239
+ const containerDim = getContainerDimensions();
240
+ const minLeft = container ? 0 : containerDim.left;
241
+ const maxLeft = containerDim.width - dimension;
242
+
243
+ if (left < minLeft) {
244
+ return minLeft;
245
+ } else if (left > maxLeft) {
246
+ return maxLeft;
247
+ }
248
+ return left;
249
+ };
250
+
251
+ const getTop = (top: number, dimension: number): number => {
252
+ const containerDim = getContainerDimensions();
253
+ const minTop = container ? 0 : containerDim.top;
254
+ const maxTop = containerDim.height - dimension;
255
+
256
+ if (top < minTop) {
257
+ return minTop;
258
+ } else if (top > maxTop) {
259
+ return maxTop;
260
+ }
261
+ return top;
262
+ };
263
+
264
+ const moveTimeout = useRef<NodeJS.Timeout>();
265
+ const moveDisabled = useRef<boolean>(true);
266
+
267
+ const moveDelayInit = useCallback(() => {
268
+ moveTimeout.current = setTimeout(() => {
269
+ moveDisabled.current = false;
270
+ }, moveDelay);
271
+ }, [moveDelay]);
272
+
273
+ const moveDelayInitClear = useCallback(() => {
274
+ moveDisabled.current = true;
275
+ if (moveTimeout.current) {
276
+ clearTimeout(moveTimeout.current);
277
+ }
278
+ }, []);
279
+
280
+ const positionRef = useRef<Position>({
281
+ left: 0,
282
+ top: 0,
283
+ });
284
+
285
+ const calculateRelativePosition = (clientX: number, clientY: number) => {
286
+ const containerDim = getContainerDimensions();
287
+ const halfWidth = Math.round(dimension / 2);
288
+
289
+ let x = clientX;
290
+ let y = clientY;
291
+
292
+ if (container) {
293
+ x = clientX - containerDim.left;
294
+ y = clientY - containerDim.top;
295
+ }
296
+
297
+ return {
298
+ x: x - halfWidth,
299
+ y: y - halfWidth
300
+ };
301
+ };
302
+
303
+ const handlePointerDown = (ev: PointerEvent | KeyboardEvent) => {
304
+ moveDelayInit();
305
+ isClicked.current = true;
306
+ const ele = ev.target as HTMLElement;
307
+ ev.stopPropagation();
308
+
309
+ if (ev instanceof PointerEvent) {
310
+ keyPressed.current = false;
311
+ ele.setPointerCapture(ev.pointerId);
312
+ } else if (ev instanceof KeyboardEvent) {
313
+ keyPressed.current = true;
314
+ }
315
+
316
+ onPointerDown?.();
317
+ };
318
+
319
+ const handlePointerUp = (ev: PointerEvent | KeyboardEvent) => {
320
+ moveDelayInitClear();
321
+ isClicked.current = false;
322
+
323
+ if (ev instanceof PointerEvent) {
324
+ const ele = ev.target as HTMLElement;
325
+ ele.releasePointerCapture(ev.pointerId);
326
+ }
327
+
328
+ if (onDragEnd) {
329
+ const finalPosition = convertToPercentage(positionRef.current);
330
+ onDragEnd(finalPosition);
331
+ }
332
+
333
+ if (!isDragged.current) {
334
+ onPointerUp?.();
335
+ } else {
336
+ isDragged.current = false;
337
+ }
338
+ };
339
+
340
+ const onPointerMove = (e: MouseEvent | TouchEvent) => {
341
+ if (moveDisabled.current || !isClicked.current || !ref.current || keyPressed.current) {
342
+ return;
343
+ }
344
+
345
+ const touches = 'touches' in e ? e.touches : null;
346
+ const clientX = touches && touches.length ? touches[0].clientX : (e as MouseEvent).clientX;
347
+ const clientY = touches && touches.length ? touches[0].clientY : (e as MouseEvent).clientY;
348
+
349
+ const { x, y } = calculateRelativePosition(clientX, clientY);
350
+
351
+ const position: Position = {
352
+ left: getLeft(x, dimension),
353
+ top: getTop(y, dimension),
354
+ };
355
+
356
+ if (!isDragged.current) {
357
+ isDragged.current = true;
358
+ if (onDragStart) {
359
+ const startPosition = convertToPercentage(position);
360
+ onDragStart(startPosition);
361
+ }
362
+ }
363
+
364
+ positionRef.current = position;
365
+ ref.current.style.cssText += `top: ${position.top}px;left: ${position.left}px;`;
366
+
367
+ if (onMove) {
368
+ const movePosition = convertToPercentage(position);
369
+ onMove(movePosition);
370
+ }
371
+ };
372
+
373
+ const setup = useCallback((node: HTMLElement | null) => {
374
+ if (node) {
375
+ ref.current = node;
376
+ node.addEventListener("pointerdown", handlePointerDown as EventListener);
377
+ node.addEventListener("keydown", handlePointerDown as EventListener);
378
+ node.addEventListener("mouseup", handlePointerUp as EventListener);
379
+ node.style.touchAction = "none";
380
+
381
+ const rect = node.getBoundingClientRect();
382
+ const containerDim = getContainerDimensions();
383
+ const initialPosition: Position = {
384
+ left: container ? rect.left - containerDim.left : rect.left,
385
+ top: container ? rect.top - containerDim.top : rect.top,
386
+ };
387
+
388
+ if (onInit) {
389
+ const initPosition = convertToPercentage(initialPosition);
390
+ onInit(initPosition);
391
+ }
392
+ }
393
+ }, [container, onInit, convertToPercentage]);
394
+
395
+ useEffect(() => {
396
+ if (!pin) {
397
+ document.addEventListener("mousemove", onPointerMove as EventListener);
398
+ document.addEventListener("touchmove", onPointerMove as EventListener);
399
+
400
+ return () => {
401
+ document.removeEventListener("mousemove", onPointerMove as EventListener);
402
+ document.removeEventListener("touchmove", onPointerMove as EventListener);
403
+ };
404
+ }
405
+ }, [container, pin]);
406
+
407
+ useEffect(() => {
408
+ return () => {
409
+ moveDelayInitClear();
410
+ };
411
+ }, [moveDelayInitClear]);
412
+
413
+ return {
414
+ ref,
415
+ setup,
416
+ };
417
+ };
418
+
419
+ export { useDragDropPosition };
420
+ export type { DragDropSettings, Position, PositionResult };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Determine whether it is the mobile terminal of the specified breakpoint
3
+ * *
4
+ * @usage:
5
+ *
6
+
7
+ const App = () => {
8
+
9
+ const isMobile = useIsMobile();
10
+
11
+ return (
12
+ <div>
13
+ {isMobile ? (
14
+ <p>This content is hidden on mobile devices.</p>
15
+ ) : (
16
+ <p>This content is visible on larger screens.</p>
17
+ )}
18
+ </div>
19
+ );
20
+ }
21
+
22
+
23
+ */
24
+ import { useEffect, useState } from 'react';
25
+
26
+
27
+ const useIsMobile = (breakpoint: number = 768): boolean => {
28
+ const [isMobile, setIsMobile] = useState<boolean>(false);
29
+ const [isMounted, setIsMounted] = useState<boolean>(false);
30
+
31
+ useEffect(() => {
32
+ // Set the mounted state to true after the component has mounted
33
+ setIsMounted(true);
34
+
35
+ const handleResize = () => {
36
+ if (window) {
37
+ setIsMobile(window.innerWidth <= breakpoint);
38
+ }
39
+ };
40
+
41
+ // Add event listener for resize
42
+ window.addEventListener('resize', handleResize);
43
+ // Call the handler once to set the initial state
44
+ handleResize();
45
+
46
+ // Cleanup the event listener on component unmount
47
+ return () => {
48
+ window.removeEventListener('resize', handleResize);
49
+ };
50
+ }, [breakpoint]);
51
+
52
+ // Only return the isMobile state if the component is mounted
53
+ return isMounted ? isMobile : false;
54
+ };
55
+
56
+ export default useIsMobile;
package/lib/esm/index.js CHANGED
@@ -6,6 +6,7 @@ export { default as Checkbox } from './Checkbox';
6
6
  export { default as ColorPicker } from './ColorPicker';
7
7
  export { default as Date } from './Date';
8
8
  export { default as DigitalClock } from './DigitalClock';
9
+ export { default as DragDropList } from './DragDropList';
9
10
  export { default as DropdownMenu } from './DropdownMenu';
10
11
  export { default as DynamicFields } from './DynamicFields';
11
12
  export { default as EventCalendar } from './EventCalendar';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "UIUX Lab",
3
3
  "email": "uiuxlab@gmail.com",
4
4
  "name": "funda-ui",
5
- "version": "4.5.666",
5
+ "version": "4.5.671",
6
6
  "description": "React components using pure Bootstrap 5+ which does not contain any external style and script libraries.",
7
7
  "repository": {
8
8
  "type": "git",