cynx-ui 1.2.35 → 1.2.37
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/components/DatePicker.jsx +50 -15
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useRef, useEffect } from 'react';
|
|
1
|
+
import { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';
|
|
2
2
|
import { createPortal } from 'react-dom';
|
|
3
3
|
import { ChevronLeft, ChevronRight, Calendar } from 'lucide-react';
|
|
4
4
|
|
|
@@ -21,6 +21,17 @@ function toKey(y, m, d) { return `${y}-${pad(m+1)}-${pad(d)}`; }
|
|
|
21
21
|
function toDate(val) {
|
|
22
22
|
if (!val) return null;
|
|
23
23
|
if (val instanceof Date) return isNaN(val.getTime()) ? null : val;
|
|
24
|
+
if (typeof val === 'string') {
|
|
25
|
+
const parts = val.split('-');
|
|
26
|
+
if (parts.length === 3) {
|
|
27
|
+
const y = parseInt(parts[0], 10);
|
|
28
|
+
const m = parseInt(parts[1], 10) - 1;
|
|
29
|
+
const d = parseInt(parts[2], 10);
|
|
30
|
+
if (!isNaN(y) && !isNaN(m) && !isNaN(d)) {
|
|
31
|
+
return new Date(y, m, d);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
24
35
|
const d = new Date(val);
|
|
25
36
|
return isNaN(d.getTime()) ? null : d;
|
|
26
37
|
}
|
|
@@ -58,20 +69,44 @@ export function DatePicker({ value, onChange, placeholder = 'Select date', badge
|
|
|
58
69
|
if (d) setCursor(d);
|
|
59
70
|
}, [value]);
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
const calcPos = useCallback(() => {
|
|
73
|
+
if (!btnRef.current) return;
|
|
74
|
+
const r = btnRef.current.getBoundingClientRect();
|
|
75
|
+
const dropW = Math.max(r.width, 260);
|
|
76
|
+
const dropH = dropRef.current ? dropRef.current.offsetHeight : 280;
|
|
77
|
+
|
|
78
|
+
let left = r.left;
|
|
79
|
+
if (left + dropW > window.innerWidth - 12) {
|
|
80
|
+
left = Math.max(12, r.right - dropW);
|
|
69
81
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
if (left < 12) left = 12;
|
|
83
|
+
|
|
84
|
+
let top = r.bottom + 6;
|
|
85
|
+
if (top + dropH > window.innerHeight - 12 && r.top - 6 - dropH > 12) {
|
|
86
|
+
top = r.top - 6 - dropH;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setPos({ top, left, width: dropW });
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
useLayoutEffect(() => {
|
|
93
|
+
if (!open) return;
|
|
94
|
+
calcPos();
|
|
95
|
+
window.addEventListener('scroll', calcPos, true);
|
|
96
|
+
window.addEventListener('resize', calcPos);
|
|
97
|
+
return () => {
|
|
98
|
+
window.removeEventListener('scroll', calcPos, true);
|
|
99
|
+
window.removeEventListener('resize', calcPos);
|
|
100
|
+
};
|
|
101
|
+
}, [open, calcPos]);
|
|
102
|
+
|
|
103
|
+
const toggleOpen = () => {
|
|
104
|
+
if (disabled) return;
|
|
105
|
+
if (!open) {
|
|
106
|
+
calcPos();
|
|
107
|
+
}
|
|
108
|
+
setOpen(o => !o);
|
|
109
|
+
};
|
|
75
110
|
|
|
76
111
|
function pick(date) {
|
|
77
112
|
if (typeof value === 'string') {
|
|
@@ -240,7 +275,7 @@ export function DatePicker({ value, onChange, placeholder = 'Select date', badge
|
|
|
240
275
|
return (
|
|
241
276
|
<div ref={ref} style={{ position: 'relative', display: 'inline-block', ...style }}>
|
|
242
277
|
{/* Trigger */}
|
|
243
|
-
<button ref={btnRef} type="button" onClick={
|
|
278
|
+
<button ref={btnRef} type="button" onClick={toggleOpen} style={{
|
|
244
279
|
display: 'flex', alignItems: 'center', gap: 7,
|
|
245
280
|
padding: '5px 10px', borderRadius: 'var(--rads)',
|
|
246
281
|
border: '1px solid var(--border)', background: 'var(--surface)',
|