@diwauhris/ui 1.7.24 → 1.7.25
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/index.cjs +28 -12
- package/lib/index.mjs +28 -12
- package/lib/types/ui-library/gallery/date-picker/DatePicker.d.ts +22 -2
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -1398,7 +1398,8 @@ function getScrollParent(el) {
|
|
|
1398
1398
|
if (["auto", "scroll"].includes(overflowY) || ["auto", "scroll"].includes(overflow)) return el;
|
|
1399
1399
|
return getScrollParent(el.parentElement);
|
|
1400
1400
|
}
|
|
1401
|
-
function computePopupStyle(rect, placement = "auto") {
|
|
1401
|
+
function computePopupStyle(rect, placement = "auto", measuredHeight) {
|
|
1402
|
+
const height = measuredHeight ?? CALENDAR_HEIGHT;
|
|
1402
1403
|
const spaceBelow = window.innerHeight - rect.bottom;
|
|
1403
1404
|
const spaceAbove = rect.top;
|
|
1404
1405
|
const isNarrow = window.innerWidth < 368;
|
|
@@ -1407,23 +1408,29 @@ function computePopupStyle(rect, placement = "auto") {
|
|
|
1407
1408
|
left: isNarrow ? 8 : Math.max(8, Math.min(rect.left, window.innerWidth - POPOVER_WIDTH - 8)),
|
|
1408
1409
|
width: isNarrow ? `calc(100vw - 16px)` : void 0
|
|
1409
1410
|
};
|
|
1410
|
-
if (placement === "below" ? true : placement === "above" ? false : spaceBelow >=
|
|
1411
|
-
else style.top = Math.max(rect.top -
|
|
1411
|
+
if (placement === "below" ? true : placement === "above" ? false : spaceBelow >= height || spaceBelow >= spaceAbove) style.top = Math.min(rect.bottom + 6, window.innerHeight - height - 8);
|
|
1412
|
+
else style.top = Math.max(rect.top - height - 6, 8);
|
|
1412
1413
|
return style;
|
|
1413
1414
|
}
|
|
1414
|
-
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required, dateFormat = "MMM d, yyyy", clearable = false, onOpenChange, placement = "auto", locale, name }) {
|
|
1415
|
-
const
|
|
1415
|
+
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required, dateFormat = "MMM d, yyyy", clearable = false, onOpenChange, placement = "auto", locale, name, isDateDisabled, readOnly = false, open, defaultOpen = false }) {
|
|
1416
|
+
const isControlled = open !== void 0;
|
|
1417
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, react.useState)(defaultOpen);
|
|
1418
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1416
1419
|
const [popupStyle, setPopupStyle] = (0, react.useState)({});
|
|
1417
1420
|
const wrapperRef = (0, react.useRef)(null);
|
|
1418
1421
|
const popoverRef = (0, react.useRef)(null);
|
|
1419
1422
|
const inputRef = (0, react.useRef)(null);
|
|
1420
1423
|
const internalId = (0, react.useId)();
|
|
1421
1424
|
const setIsOpen = (0, react.useCallback)((next) => {
|
|
1422
|
-
|
|
1425
|
+
if (isControlled) {
|
|
1426
|
+
onOpenChange?.(next);
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
setUncontrolledOpen((prev) => {
|
|
1423
1430
|
if (prev !== next) onOpenChange?.(next);
|
|
1424
1431
|
return next;
|
|
1425
1432
|
});
|
|
1426
|
-
}, [onOpenChange]);
|
|
1433
|
+
}, [isControlled, onOpenChange]);
|
|
1427
1434
|
const ctx = useFieldContext();
|
|
1428
1435
|
const inputId = id ?? ctx?.inputId ?? internalId;
|
|
1429
1436
|
const resolvedRequired = required ?? ctx?.required ?? false;
|
|
@@ -1438,7 +1445,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1438
1445
|
const displayValue = selectedDate ? (0, date_fns.format)(selectedDate, dateFormat) : "";
|
|
1439
1446
|
const skipNextOpen = (0, react.useRef)(false);
|
|
1440
1447
|
const openPopup = (0, react.useCallback)(() => {
|
|
1441
|
-
if (disabled) return;
|
|
1448
|
+
if (disabled || readOnly) return;
|
|
1442
1449
|
if (skipNextOpen.current) {
|
|
1443
1450
|
skipNextOpen.current = false;
|
|
1444
1451
|
return;
|
|
@@ -1454,9 +1461,16 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1454
1461
|
}, 50);
|
|
1455
1462
|
}, [
|
|
1456
1463
|
disabled,
|
|
1464
|
+
readOnly,
|
|
1457
1465
|
placement,
|
|
1458
1466
|
setIsOpen
|
|
1459
1467
|
]);
|
|
1468
|
+
(0, react.useEffect)(() => {
|
|
1469
|
+
if (!isOpen || !popoverRef.current || !wrapperRef.current) return;
|
|
1470
|
+
const measuredHeight = popoverRef.current.offsetHeight;
|
|
1471
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
1472
|
+
setPopupStyle(computePopupStyle(rect, placement, measuredHeight));
|
|
1473
|
+
}, [isOpen, placement]);
|
|
1460
1474
|
(0, react.useEffect)(() => {
|
|
1461
1475
|
function handleClickOutside(e) {
|
|
1462
1476
|
const target = e.target;
|
|
@@ -1528,11 +1542,12 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1528
1542
|
"aria-required": resolvedRequired ? "true" : void 0,
|
|
1529
1543
|
"aria-invalid": resolvedInvalid ? "true" : void 0,
|
|
1530
1544
|
"aria-describedby": describedBy,
|
|
1531
|
-
"aria-
|
|
1532
|
-
"aria-
|
|
1545
|
+
"aria-readonly": readOnly ? "true" : void 0,
|
|
1546
|
+
"aria-haspopup": readOnly ? void 0 : "dialog",
|
|
1547
|
+
"aria-expanded": readOnly ? void 0 : isOpen,
|
|
1533
1548
|
role: "combobox",
|
|
1534
1549
|
className: inputClasses
|
|
1535
|
-
}), clearable && value && !disabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1550
|
+
}), clearable && value && !disabled && !readOnly ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1536
1551
|
type: "button",
|
|
1537
1552
|
"aria-label": "Clear date",
|
|
1538
1553
|
onMouseDown: (e) => {
|
|
@@ -1551,7 +1566,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1551
1566
|
className: `absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none ${isOpen ? "text-brand-blue" : "text-slate-300"}`,
|
|
1552
1567
|
"aria-hidden": "true"
|
|
1553
1568
|
})]
|
|
1554
|
-
}), isOpen && !disabled && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1569
|
+
}), isOpen && !disabled && !readOnly && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1555
1570
|
ref: popoverRef,
|
|
1556
1571
|
className: "pis-datepicker-popover",
|
|
1557
1572
|
style: popupStyle,
|
|
@@ -1571,6 +1586,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1571
1586
|
defaultActiveStartDate: selectedDate ?? minDate,
|
|
1572
1587
|
minDate,
|
|
1573
1588
|
maxDate,
|
|
1589
|
+
tileDisabled: isDateDisabled ? ({ date, view }) => view === "month" && isDateDisabled(date) : void 0,
|
|
1574
1590
|
locale,
|
|
1575
1591
|
defaultView: "month",
|
|
1576
1592
|
showNeighboringDecade: true,
|
package/lib/index.mjs
CHANGED
|
@@ -1374,7 +1374,8 @@ function getScrollParent(el) {
|
|
|
1374
1374
|
if (["auto", "scroll"].includes(overflowY) || ["auto", "scroll"].includes(overflow)) return el;
|
|
1375
1375
|
return getScrollParent(el.parentElement);
|
|
1376
1376
|
}
|
|
1377
|
-
function computePopupStyle(rect, placement = "auto") {
|
|
1377
|
+
function computePopupStyle(rect, placement = "auto", measuredHeight) {
|
|
1378
|
+
const height = measuredHeight ?? CALENDAR_HEIGHT;
|
|
1378
1379
|
const spaceBelow = window.innerHeight - rect.bottom;
|
|
1379
1380
|
const spaceAbove = rect.top;
|
|
1380
1381
|
const isNarrow = window.innerWidth < 368;
|
|
@@ -1383,23 +1384,29 @@ function computePopupStyle(rect, placement = "auto") {
|
|
|
1383
1384
|
left: isNarrow ? 8 : Math.max(8, Math.min(rect.left, window.innerWidth - POPOVER_WIDTH - 8)),
|
|
1384
1385
|
width: isNarrow ? `calc(100vw - 16px)` : void 0
|
|
1385
1386
|
};
|
|
1386
|
-
if (placement === "below" ? true : placement === "above" ? false : spaceBelow >=
|
|
1387
|
-
else style.top = Math.max(rect.top -
|
|
1387
|
+
if (placement === "below" ? true : placement === "above" ? false : spaceBelow >= height || spaceBelow >= spaceAbove) style.top = Math.min(rect.bottom + 6, window.innerHeight - height - 8);
|
|
1388
|
+
else style.top = Math.max(rect.top - height - 6, 8);
|
|
1388
1389
|
return style;
|
|
1389
1390
|
}
|
|
1390
|
-
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required, dateFormat = "MMM d, yyyy", clearable = false, onOpenChange, placement = "auto", locale, name }) {
|
|
1391
|
-
const
|
|
1391
|
+
function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required, dateFormat = "MMM d, yyyy", clearable = false, onOpenChange, placement = "auto", locale, name, isDateDisabled, readOnly = false, open, defaultOpen = false }) {
|
|
1392
|
+
const isControlled = open !== void 0;
|
|
1393
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
1394
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1392
1395
|
const [popupStyle, setPopupStyle] = useState({});
|
|
1393
1396
|
const wrapperRef = useRef(null);
|
|
1394
1397
|
const popoverRef = useRef(null);
|
|
1395
1398
|
const inputRef = useRef(null);
|
|
1396
1399
|
const internalId = useId();
|
|
1397
1400
|
const setIsOpen = useCallback((next) => {
|
|
1398
|
-
|
|
1401
|
+
if (isControlled) {
|
|
1402
|
+
onOpenChange?.(next);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
setUncontrolledOpen((prev) => {
|
|
1399
1406
|
if (prev !== next) onOpenChange?.(next);
|
|
1400
1407
|
return next;
|
|
1401
1408
|
});
|
|
1402
|
-
}, [onOpenChange]);
|
|
1409
|
+
}, [isControlled, onOpenChange]);
|
|
1403
1410
|
const ctx = useFieldContext();
|
|
1404
1411
|
const inputId = id ?? ctx?.inputId ?? internalId;
|
|
1405
1412
|
const resolvedRequired = required ?? ctx?.required ?? false;
|
|
@@ -1414,7 +1421,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1414
1421
|
const displayValue = selectedDate ? format(selectedDate, dateFormat) : "";
|
|
1415
1422
|
const skipNextOpen = useRef(false);
|
|
1416
1423
|
const openPopup = useCallback(() => {
|
|
1417
|
-
if (disabled) return;
|
|
1424
|
+
if (disabled || readOnly) return;
|
|
1418
1425
|
if (skipNextOpen.current) {
|
|
1419
1426
|
skipNextOpen.current = false;
|
|
1420
1427
|
return;
|
|
@@ -1430,9 +1437,16 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1430
1437
|
}, 50);
|
|
1431
1438
|
}, [
|
|
1432
1439
|
disabled,
|
|
1440
|
+
readOnly,
|
|
1433
1441
|
placement,
|
|
1434
1442
|
setIsOpen
|
|
1435
1443
|
]);
|
|
1444
|
+
useEffect(() => {
|
|
1445
|
+
if (!isOpen || !popoverRef.current || !wrapperRef.current) return;
|
|
1446
|
+
const measuredHeight = popoverRef.current.offsetHeight;
|
|
1447
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
1448
|
+
setPopupStyle(computePopupStyle(rect, placement, measuredHeight));
|
|
1449
|
+
}, [isOpen, placement]);
|
|
1436
1450
|
useEffect(() => {
|
|
1437
1451
|
function handleClickOutside(e) {
|
|
1438
1452
|
const target = e.target;
|
|
@@ -1504,11 +1518,12 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1504
1518
|
"aria-required": resolvedRequired ? "true" : void 0,
|
|
1505
1519
|
"aria-invalid": resolvedInvalid ? "true" : void 0,
|
|
1506
1520
|
"aria-describedby": describedBy,
|
|
1507
|
-
"aria-
|
|
1508
|
-
"aria-
|
|
1521
|
+
"aria-readonly": readOnly ? "true" : void 0,
|
|
1522
|
+
"aria-haspopup": readOnly ? void 0 : "dialog",
|
|
1523
|
+
"aria-expanded": readOnly ? void 0 : isOpen,
|
|
1509
1524
|
role: "combobox",
|
|
1510
1525
|
className: inputClasses
|
|
1511
|
-
}), clearable && value && !disabled ? /* @__PURE__ */ jsx("button", {
|
|
1526
|
+
}), clearable && value && !disabled && !readOnly ? /* @__PURE__ */ jsx("button", {
|
|
1512
1527
|
type: "button",
|
|
1513
1528
|
"aria-label": "Clear date",
|
|
1514
1529
|
onMouseDown: (e) => {
|
|
@@ -1527,7 +1542,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1527
1542
|
className: `absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none ${isOpen ? "text-brand-blue" : "text-slate-300"}`,
|
|
1528
1543
|
"aria-hidden": "true"
|
|
1529
1544
|
})]
|
|
1530
|
-
}), isOpen && !disabled && createPortal(/* @__PURE__ */ jsx("div", {
|
|
1545
|
+
}), isOpen && !disabled && !readOnly && createPortal(/* @__PURE__ */ jsx("div", {
|
|
1531
1546
|
ref: popoverRef,
|
|
1532
1547
|
className: "pis-datepicker-popover",
|
|
1533
1548
|
style: popupStyle,
|
|
@@ -1547,6 +1562,7 @@ function DatePicker({ value, onChange, placeholder, className, disabled, error,
|
|
|
1547
1562
|
defaultActiveStartDate: selectedDate ?? minDate,
|
|
1548
1563
|
minDate,
|
|
1549
1564
|
maxDate,
|
|
1565
|
+
tileDisabled: isDateDisabled ? ({ date, view }) => view === "month" && isDateDisabled(date) : void 0,
|
|
1550
1566
|
locale,
|
|
1551
1567
|
defaultView: "month",
|
|
1552
1568
|
showNeighboringDecade: true,
|
|
@@ -32,7 +32,27 @@ interface DatePickerProps {
|
|
|
32
32
|
locale?: string;
|
|
33
33
|
/** Name forwarded to the trigger input for form association. */
|
|
34
34
|
name?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Per-day predicate to disable individual dates that min/maxDate can't express
|
|
37
|
+
* (weekends, holidays, already-booked days). Return true to disable the date.
|
|
38
|
+
* Only consulted on the day (month) view.
|
|
39
|
+
*/
|
|
40
|
+
isDateDisabled?: (date: Date) => boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Read-only: the value is shown but the calendar can't be opened and no date
|
|
43
|
+
* can be picked. Unlike `disabled`, it keeps normal (non-greyed) styling for
|
|
44
|
+
* view/detail screens.
|
|
45
|
+
*/
|
|
46
|
+
readOnly?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Controlled open state. When provided, the component no longer manages its
|
|
49
|
+
* own open/close — the parent owns it via `onOpenChange`. Leave undefined for
|
|
50
|
+
* the default uncontrolled behavior.
|
|
51
|
+
*/
|
|
52
|
+
open?: boolean;
|
|
53
|
+
/** Initial open state when uncontrolled. Ignored when `open` is provided. */
|
|
54
|
+
defaultOpen?: boolean;
|
|
35
55
|
}
|
|
36
|
-
export declare function computePopupStyle(rect: DOMRect, placement?: 'auto' | 'below' | 'above'): React.CSSProperties;
|
|
37
|
-
export declare function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, required, dateFormat, clearable, onOpenChange, placement, locale, name, }: DatePickerProps): import("react").JSX.Element;
|
|
56
|
+
export declare function computePopupStyle(rect: DOMRect, placement?: 'auto' | 'below' | 'above', measuredHeight?: number): React.CSSProperties;
|
|
57
|
+
export declare function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, maxDate, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, required, dateFormat, clearable, onOpenChange, placement, locale, name, isDateDisabled, readOnly, open, defaultOpen, }: DatePickerProps): import("react").JSX.Element;
|
|
38
58
|
export {};
|