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.
@@ -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
- // Compute button position when dropdown opens
62
- useEffect(() => {
63
- if (!open || !btnRef.current) return;
64
- function updatePos() {
65
- if (btnRef.current) {
66
- const r = btnRef.current.getBoundingClientRect();
67
- setPos({ top: r.bottom + 6, left: r.left, width: Math.max(r.width, 252) });
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
- updatePos();
71
- window.addEventListener('scroll', updatePos, true);
72
- window.addEventListener('resize', updatePos);
73
- return () => { window.removeEventListener('scroll', updatePos, true); window.removeEventListener('resize', updatePos); };
74
- }, [open]);
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={() => !disabled && setOpen(o => !o)} style={{
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)',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cynx-ui",
3
- "version": "1.2.35",
3
+ "version": "1.2.37",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js"