pixelize-design-library 2.4.2-beta.34 → 2.4.2-beta.35
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/dist/Components/AppSwitcher/AppSwitcher.js +10 -4
- package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -3
- package/dist/Components/Common/fieldStyles.js +1 -1
- package/dist/Components/CopyButton/CopyButton.js +7 -6
- package/dist/Components/DatePicker/CalendarPanel.js +8 -5
- package/dist/Components/DatePicker/RangeDatePicker.js +27 -3
- package/dist/Components/DatePicker/SingleDatePicker.js +48 -14
- package/dist/Components/DatePicker/TimeOnlyPicker.js +7 -1
- package/dist/Components/DatePicker/TimePicker.js +3 -3
- package/dist/Components/DatePicker/TimePickerInput.js +1 -1
- package/dist/Components/Dropdown/DropDown.js +19 -6
- package/dist/Components/EmptyState/EmptyState.js +1 -1
- package/dist/Components/FileUpload/FileUpload.js +2 -2
- package/dist/Components/FilterSidebar/FilterSidebar.js +5 -5
- package/dist/Components/FilterSidebar/filterHoverStyle.d.ts +2 -1
- package/dist/Components/FilterSidebar/filterHoverStyle.js +3 -4
- package/dist/Components/Input/TextInput.styles.js +2 -2
- package/dist/Components/InputTextArea/InputTextArea.style.js +2 -2
- package/dist/Components/MoreItems/MoreItems.js +3 -1
- package/dist/Components/MultiSelect/MultiSelect.js +2 -2
- package/dist/Components/NavigationBar/NavigationBar.js +6 -7
- package/dist/Components/NumberInput/NumberInput.styles.js +2 -2
- package/dist/Components/OrgSwitcher/OrgSwitcher.js +14 -10
- package/dist/Components/PdfViewer/PdfViewer.js +4 -4
- package/dist/Components/RolesPermission/RolesPermission.js +4 -3
- package/dist/Components/SearchSelect/SearchSelect.js +46 -41
- package/dist/Components/Select/Select.styles.js +1 -1
- package/dist/Components/SelectSearch/SelectSearch.js +35 -17
- package/dist/Components/SelectV2/SelectV2.js +3 -0
- package/dist/Components/Table/TableProps.d.ts +2 -0
- package/dist/Components/Table/components/TableBody.js +7 -10
- package/dist/Components/Table/filters/CompactSelect.js +29 -8
- package/dist/Components/Table/settings/ManageColumns.js +5 -3
- package/dist/Components/Table/settings/TableSettings.js +4 -2
- package/dist/Components/Trail/EditableCell.js +1 -1
- package/dist/Components/UserDetails/DeactivateConfirmModal.js +1 -1
- package/dist/Components/UserDetails/UserDetails.js +5 -3
- package/dist/Hooks/exclusiveOverlay.d.ts +4 -0
- package/dist/Hooks/exclusiveOverlay.js +22 -0
- package/dist/Hooks/useExclusiveOverlay.d.ts +5 -0
- package/dist/Hooks/useExclusiveOverlay.js +24 -0
- package/dist/Theme/chakra/Menu.styles.js +4 -2
- package/dist/Utils/table.d.ts +3 -0
- package/dist/Utils/table.js +44 -1
- package/dist/esm/Components/AppSwitcher/AppSwitcher.js +11 -5
- package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +1 -3
- package/dist/esm/Components/Common/fieldStyles.js +1 -1
- package/dist/esm/Components/CopyButton/CopyButton.js +7 -6
- package/dist/esm/Components/DatePicker/CalendarPanel.js +9 -6
- package/dist/esm/Components/DatePicker/RangeDatePicker.js +28 -4
- package/dist/esm/Components/DatePicker/SingleDatePicker.js +49 -15
- package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +7 -1
- package/dist/esm/Components/DatePicker/TimePicker.js +3 -3
- package/dist/esm/Components/DatePicker/TimePickerInput.js +1 -1
- package/dist/esm/Components/Dropdown/DropDown.js +20 -7
- package/dist/esm/Components/EmptyState/EmptyState.js +1 -1
- package/dist/esm/Components/FileUpload/FileUpload.js +2 -2
- package/dist/esm/Components/FilterSidebar/FilterSidebar.js +5 -5
- package/dist/esm/Components/FilterSidebar/filterHoverStyle.js +3 -4
- package/dist/esm/Components/Input/TextInput.styles.js +2 -2
- package/dist/esm/Components/InputTextArea/InputTextArea.style.js +2 -2
- package/dist/esm/Components/MoreItems/MoreItems.js +3 -1
- package/dist/esm/Components/MultiSelect/MultiSelect.js +2 -2
- package/dist/esm/Components/NavigationBar/NavigationBar.js +6 -7
- package/dist/esm/Components/NumberInput/NumberInput.styles.js +2 -2
- package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +14 -10
- package/dist/esm/Components/PdfViewer/PdfViewer.js +4 -4
- package/dist/esm/Components/RolesPermission/RolesPermission.js +4 -3
- package/dist/esm/Components/SearchSelect/SearchSelect.js +46 -41
- package/dist/esm/Components/Select/Select.styles.js +1 -1
- package/dist/esm/Components/SelectSearch/SelectSearch.js +35 -17
- package/dist/esm/Components/SelectV2/SelectV2.js +3 -0
- package/dist/esm/Components/Table/components/TableBody.js +7 -10
- package/dist/esm/Components/Table/filters/CompactSelect.js +29 -8
- package/dist/esm/Components/Table/settings/ManageColumns.js +5 -3
- package/dist/esm/Components/Table/settings/TableSettings.js +5 -3
- package/dist/esm/Components/Trail/EditableCell.js +1 -1
- package/dist/esm/Components/UserDetails/DeactivateConfirmModal.js +1 -1
- package/dist/esm/Components/UserDetails/UserDetails.js +5 -3
- package/dist/esm/Hooks/exclusiveOverlay.js +16 -0
- package/dist/esm/Hooks/useExclusiveOverlay.js +20 -0
- package/dist/esm/Theme/chakra/Menu.styles.js +4 -2
- package/dist/esm/Utils/table.js +45 -3
- package/package.json +1 -1
package/dist/Utils/table.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.TableCellCalculation = exports.pageSizeCalculation = exports.searchAndSortData = exports.calculateLeftOffset = void 0;
|
|
37
37
|
exports.compareValues = compareValues;
|
|
38
38
|
exports.SortMultiColumnData = SortMultiColumnData;
|
|
39
|
+
exports.buildSemanticStatusPalette = buildSemanticStatusPalette;
|
|
39
40
|
exports.buildTablePalette = buildTablePalette;
|
|
40
41
|
exports.pickTableColor = pickTableColor;
|
|
41
42
|
exports.groupRows = groupRows;
|
|
@@ -45,6 +46,8 @@ exports.useDebounce = useDebounce;
|
|
|
45
46
|
exports.globalSearchFilter = globalSearchFilter;
|
|
46
47
|
const react_1 = __importStar(require("react"));
|
|
47
48
|
const accentText_1 = require("../Theme/tokens/builders/accentText");
|
|
49
|
+
const color_1 = require("../Theme/tokens/builders/color");
|
|
50
|
+
const outlineRung_1 = require("../Theme/tokens/builders/outlineRung");
|
|
48
51
|
const filledSurface_1 = require("../Theme/tokens/builders/filledSurface");
|
|
49
52
|
const statusTone_1 = require("../Theme/tokens/builders/statusTone");
|
|
50
53
|
// Built once, not per comparison: sorting 10k rows runs this ~130k times, and constructing a
|
|
@@ -99,7 +102,45 @@ function SortMultiColumnData(data, sortConfig) {
|
|
|
99
102
|
return 0;
|
|
100
103
|
});
|
|
101
104
|
}
|
|
105
|
+
/** Theme-aware status palette per value — soft fill + semantic ink from `resolveStatusTone`. */
|
|
106
|
+
function buildSemanticStatusPalette(toneByValue, theme) {
|
|
107
|
+
const c = theme.colors;
|
|
108
|
+
const mode = (0, accentText_1.isDarkCanvas)(c.backgroundColor.main) ? "dark" : "light";
|
|
109
|
+
const scales = {
|
|
110
|
+
info: c.semantic.info,
|
|
111
|
+
warning: c.semantic.warning,
|
|
112
|
+
success: c.semantic.success,
|
|
113
|
+
error: c.semantic.error,
|
|
114
|
+
neutral: c.gray,
|
|
115
|
+
};
|
|
116
|
+
return Object.fromEntries(Object.entries(toneByValue).map(([value, key]) => {
|
|
117
|
+
const scale = scales[key];
|
|
118
|
+
const tone = (0, statusTone_1.resolveStatusTone)(scale, mode);
|
|
119
|
+
const solidRung = (0, filledSurface_1.solidFillRung)(scale, c.white);
|
|
120
|
+
const solid = scale[solidRung];
|
|
121
|
+
return [
|
|
122
|
+
value,
|
|
123
|
+
{
|
|
124
|
+
solid,
|
|
125
|
+
soft: tone.bg,
|
|
126
|
+
text: tone.fg,
|
|
127
|
+
onSolid: (0, filledSurface_1.labelOnFill)(solid, c.white, c.black),
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
102
132
|
const withAlpha = (hex, aa) => /^#([0-9a-fA-F]{6})$/.test(hex) ? `${hex}${aa}` : hex;
|
|
133
|
+
/** Consumer `statusColors` values are fill seeds — derive bleed + pill ink from them. */
|
|
134
|
+
const resolveStatusOverride = (fill, white, black, surface) => {
|
|
135
|
+
const soft = withAlpha(fill, "22");
|
|
136
|
+
const solid = (0, statusTone_1.resolveAvatarFill)(fill);
|
|
137
|
+
return {
|
|
138
|
+
solid,
|
|
139
|
+
soft,
|
|
140
|
+
text: (0, outlineRung_1.liftToContrast)(fill, (0, color_1.compositeOver)(soft, surface), accentText_1.AA_NORMAL_TEXT),
|
|
141
|
+
onSolid: (0, accentText_1.onFilled)(solid, white, black),
|
|
142
|
+
};
|
|
143
|
+
};
|
|
103
144
|
/** Deterministic, theme-aware color palette for groups + status pills. */
|
|
104
145
|
function buildTablePalette(theme) {
|
|
105
146
|
const c = theme.colors;
|
|
@@ -137,10 +178,12 @@ const hashKey = (value) => {
|
|
|
137
178
|
};
|
|
138
179
|
/** Pick a deterministic palette color for a value, with optional consumer override hex. */
|
|
139
180
|
function pickTableColor(value, palette, override, theme) {
|
|
181
|
+
var _a;
|
|
140
182
|
const white = theme ? theme.colors.white : accentText_1.DEFAULT_WHITE;
|
|
141
183
|
const black = theme ? theme.colors.black : accentText_1.DEFAULT_BLACK;
|
|
142
184
|
if (override) {
|
|
143
|
-
|
|
185
|
+
const surface = (_a = theme === null || theme === void 0 ? void 0 : theme.colors.background[50]) !== null && _a !== void 0 ? _a : accentText_1.DEFAULT_WHITE;
|
|
186
|
+
return resolveStatusOverride(override, white, black, surface);
|
|
144
187
|
}
|
|
145
188
|
if (!palette.length) {
|
|
146
189
|
throw new Error("pickTableColor: empty palette — build it with buildTablePalette(theme).");
|
|
@@ -5,7 +5,9 @@ import { Grip, Lock, Search } from "lucide-react";
|
|
|
5
5
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
6
6
|
import { chartMode } from "../../Theme/tokens/builders/chartColorsFromTheme.js";
|
|
7
7
|
import { AA_NORMAL_TEXT } from "../../Theme/tokens/builders/accentText.js";
|
|
8
|
-
import { liftToContrast, neutralStep,
|
|
8
|
+
import { liftToContrast, neutralStep, ruleInk, AA_NON_TEXT, CHROME_RULE, MIN_PERCEPTIBLE_STEP, } from "../../Theme/tokens/builders/outlineRung.js";
|
|
9
|
+
import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
|
|
10
|
+
import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
|
|
9
11
|
import AppMark, { assignAppHues } from "./AppMark.js";
|
|
10
12
|
import { filterApps, formatShortcut, } from "./AppSwitcherProps.js";
|
|
11
13
|
import { useAppSwitcherShortcut } from "./useAppSwitcherShortcut.js";
|
|
@@ -43,6 +45,7 @@ const SEARCH_OPENS_BY_COUNT = false;
|
|
|
43
45
|
const AppSwitcher = ({ apps, currentAppId, onSelect, onOpenChange, isSearchable, searchThreshold = 8, shortcut = null, showShortcutHint = true, hideWhenAlone = true, emptyMessage = "No app matches that name.", footer, ariaLabel = "Switch app", panelWidth, maxHeight = "24rem", isLoading = false, }) => {
|
|
44
46
|
const theme = useCustomTheme();
|
|
45
47
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
48
|
+
const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
|
|
46
49
|
const [query, setQuery] = useState("");
|
|
47
50
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
48
51
|
const searchRef = useRef(null);
|
|
@@ -59,12 +62,15 @@ const AppSwitcher = ({ apps, currentAppId, onSelect, onOpenChange, isSearchable,
|
|
|
59
62
|
const hues = useMemo(() => assignAppHues(apps, chartMode(theme.colors)), [apps, theme.colors]);
|
|
60
63
|
const visible = useMemo(() => filterApps(apps, query), [apps, query]);
|
|
61
64
|
const setOpen = useCallback((next) => {
|
|
62
|
-
if (next)
|
|
65
|
+
if (next) {
|
|
66
|
+
requestExclusiveOpen();
|
|
63
67
|
onOpen();
|
|
64
|
-
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
65
70
|
onClose();
|
|
71
|
+
}
|
|
66
72
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
|
|
67
|
-
}, [onOpen, onClose, onOpenChange]);
|
|
73
|
+
}, [onOpen, onClose, onOpenChange, requestExclusiveOpen]);
|
|
68
74
|
const cancelHoverTimer = useCallback(() => {
|
|
69
75
|
if (hoverTimer.current)
|
|
70
76
|
clearTimeout(hoverTimer.current);
|
|
@@ -208,7 +214,7 @@ const AppSwitcher = ({ apps, currentAppId, onSelect, onOpenChange, isSearchable,
|
|
|
208
214
|
const nothingToSwitchTo = apps.length === 0 || (hideWhenAlone && apps.every((a) => a.id === currentAppId));
|
|
209
215
|
if (nothingToSwitchTo)
|
|
210
216
|
return null;
|
|
211
|
-
const rowHoverBg =
|
|
217
|
+
const rowHoverBg = listRowBackgrounds(theme.colors).active;
|
|
212
218
|
const footerRule = ruleInk(theme.colors.boxborder[200], [theme.colors.backgroundColor.subtle], CHROME_RULE);
|
|
213
219
|
// Neutral, not `backgroundColor.tertiary`: that rung is brand-tinted in the hand-authored light
|
|
214
220
|
// palettes, so lifting it painted the row a saturated block. The rail identifies the row, so the
|
|
@@ -79,7 +79,7 @@ rightIconDropdown, menulistStyle, menuItemStyle, isLoading, divider = true, left
|
|
|
79
79
|
borderRadius: "lg",
|
|
80
80
|
fontSize: "13px",
|
|
81
81
|
fontWeight: 500,
|
|
82
|
-
color: theme.colors.
|
|
82
|
+
color: theme.colors.text[700],
|
|
83
83
|
transition: "background 0.12s",
|
|
84
84
|
"& svg": { width: "16px", height: "16px" },
|
|
85
85
|
...(divider
|
|
@@ -90,8 +90,6 @@ rightIconDropdown, menulistStyle, menuItemStyle, isLoading, divider = true, left
|
|
|
90
90
|
borderColor: theme.colors.boxborder[200],
|
|
91
91
|
}
|
|
92
92
|
: {}),
|
|
93
|
-
_hover: { bg: theme.colors.primary[50], color: theme.colors.primary[700] },
|
|
94
|
-
_focus: { bg: theme.colors.primary[50], color: theme.colors.primary[700] },
|
|
95
93
|
"&:last-child": { borderBottom: "none" },
|
|
96
94
|
}, children: [option === null || option === void 0 ? void 0 : option.image, option.label] }, index))) }) })] })) : (rightIcon && (_jsx(IconButton, { "aria-label": "Right icon button", icon: rightIcon, isLoading: RightIconLoading, onClick: onRightIconClick, onBlur: onBlurRightIcon, style: buttonGroupRightIconStyle, sx: gradientItemSx })))] }));
|
|
97
95
|
}
|
|
@@ -17,7 +17,7 @@ export const getFieldStateStyles = (theme, { error = false, focused = false } =
|
|
|
17
17
|
const ringPrimary = theme.colors.boxShadow.primary;
|
|
18
18
|
const ringError = theme.colors.boxShadow.error;
|
|
19
19
|
return {
|
|
20
|
-
bg: theme.colors.
|
|
20
|
+
bg: theme.colors.background[50],
|
|
21
21
|
borderRadius: FIELD_RADIUS,
|
|
22
22
|
border: `${FIELD_BORDER_WIDTH} solid`,
|
|
23
23
|
borderColor: error ? errorColor : focused ? primary : idleBorder,
|
|
@@ -4,6 +4,7 @@ import { Box, Flex, IconButton, Text } from "@chakra-ui/react";
|
|
|
4
4
|
import { Check, Copy } from "lucide-react";
|
|
5
5
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
6
6
|
import { accentTextOnCanvas, AA_NORMAL_TEXT } from "../../Theme/tokens/builders/accentText.js";
|
|
7
|
+
import { listRowBackgrounds } from "../../Theme/tokens/builders/rowStates.js";
|
|
7
8
|
import { liftToContrast } from "../../Theme/tokens/builders/outlineRung.js";
|
|
8
9
|
import ToolTip from "../ToolTip/ToolTip.js";
|
|
9
10
|
const CopyButton = ({ value, variant = "icon", label = "Copy", copiedLabel = "Copied!", tooltip = "Copy", feedbackDuration = 1500, iconSize = 16, size = "sm", onCopy, }) => {
|
|
@@ -29,17 +30,17 @@ const CopyButton = ({ value, variant = "icon", label = "Copy", copiedLabel = "Co
|
|
|
29
30
|
// nearest rung that clears AA against the canvas this button actually sits on.
|
|
30
31
|
const accent = accentTextOnCanvas(theme.colors.primary, theme.colors.backgroundColor.main);
|
|
31
32
|
const success = theme.colors.semanticText.success;
|
|
33
|
+
const rowBackgrounds = listRowBackgrounds(theme.colors);
|
|
32
34
|
if (variant === "menu-item") {
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
return (_jsxs(Flex, { align: "center", gap: "0.5rem", px: "12px", py: "8px", width: "100%", cursor: "pointer", borderRadius: "md", transition: "background 0.15s ease", _hover: { bg: theme.colors.gray[100] }, onClick: handleCopy, children: [copied ? (_jsx(Check, { size: iconSize, color: hoverSuccess })) : (_jsx(Copy, { size: iconSize, color: hoverAccent })), _jsx(Box, { fontSize: "14px", fontWeight: 500, color: copied ? hoverSuccess : hoverAccent, children: copied ? copiedLabel : label })] }));
|
|
35
|
+
const hoverAccent = accentTextOnCanvas(theme.colors.primary, rowBackgrounds.active);
|
|
36
|
+
const hoverSuccess = liftToContrast(theme.colors.semantic.success[500], rowBackgrounds.active, AA_NORMAL_TEXT);
|
|
37
|
+
return (_jsxs(Flex, { align: "center", gap: "0.5rem", px: "12px", py: "8px", width: "100%", cursor: "pointer", borderRadius: "md", transition: "background 0.15s ease", _hover: { bg: rowBackgrounds.active }, onClick: handleCopy, children: [copied ? (_jsx(Check, { size: iconSize, color: hoverSuccess })) : (_jsx(Copy, { size: iconSize, color: hoverAccent })), _jsx(Box, { fontSize: "14px", fontWeight: 500, color: copied ? hoverSuccess : hoverAccent, children: copied ? copiedLabel : label })] }));
|
|
37
38
|
}
|
|
38
39
|
if (variant === "button") {
|
|
39
40
|
return (_jsxs(Flex, { as: "button", align: "center", gap: "6px", px: "12px", py: "6px", borderRadius: "lg", border: "1px solid",
|
|
40
41
|
// [800], not [500]: a real control boundary needs >=3:1 on every surface up to `muted`.
|
|
41
|
-
borderColor: copied ? success : theme.colors.boxborder[500], bg: "transparent", color: copied ? success : theme.colors.
|
|
42
|
+
borderColor: copied ? success : theme.colors.boxborder[500], bg: "transparent", color: copied ? success : theme.colors.text[700], fontSize: "14px", fontWeight: 500, transition: "all 0.15s ease", _hover: { borderColor: accent, color: accent }, onClick: handleCopy, children: [copied ? _jsx(Check, { size: iconSize }) : _jsx(Copy, { size: iconSize }), _jsx(Text, { children: copied ? copiedLabel : label })] }));
|
|
42
43
|
}
|
|
43
|
-
return (_jsx(ToolTip, { label: copied ? copiedLabel : tooltip, placement: "top", children: _jsx(IconButton, { "aria-label": tooltip, size: size, variant: "ghost", onClick: handleCopy, color: copied ? success : theme.colors.
|
|
44
|
+
return (_jsx(ToolTip, { label: copied ? copiedLabel : tooltip, placement: "top", children: _jsx(IconButton, { "aria-label": tooltip, size: size, variant: "ghost", onClick: handleCopy, color: copied ? success : theme.colors.textMuted, _hover: { color: accent, bg: rowBackgrounds.active }, icon: copied ? _jsx(Check, { size: iconSize }) : _jsx(Copy, { size: iconSize }) }) }));
|
|
44
45
|
};
|
|
45
46
|
export default CopyButton;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box
|
|
2
|
+
import { Box } from "@chakra-ui/react";
|
|
3
3
|
import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays } from "date-fns";
|
|
4
4
|
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
5
5
|
import Button from "../Button/Button.js";
|
|
@@ -118,7 +118,10 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
|
|
|
118
118
|
const customContent = renderDayContent ? renderDayContent(thisDay, states) : null;
|
|
119
119
|
const markerColor = customContent == null && (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.markerColor) ? stateVisual.markerColor : null;
|
|
120
120
|
const hasDayOverlay = customContent != null || markerColor != null;
|
|
121
|
-
|
|
121
|
+
const dayLabel = dayStates
|
|
122
|
+
? dayAccessibleName(format(thisDay, "d MMMM yyyy"), states)
|
|
123
|
+
: format(thisDay, "d MMMM yyyy");
|
|
124
|
+
days.push(_jsx(Box, { role: "gridcell", h: "2rem", display: "flex", alignItems: "center", justifyContent: "center", style: cellBg ? { background: cellBg } : undefined, children: _jsxs(Box, { as: "button", type: "button", disabled: disabled, className: dayStates ? dayStateClassName(states) : undefined, "aria-label": dayLabel, "aria-selected": isSelected || isStart || isEnd || undefined, "aria-current": isToday ? "date" : undefined, onClick: () => !disabled && onDaySelect(new Date(thisDay)), onMouseEnter: () => !disabled && (onDayHover === null || onDayHover === void 0 ? void 0 : onDayHover(new Date(thisDay))), position: hasDayOverlay ? "relative" : undefined, w: "1.75rem", h: "1.75rem", borderRadius: "full", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "0.8125rem", fontWeight: circleSolid ? 600 : 500, lineHeight: "1", cursor: disabled ? "not-allowed" : "pointer", bg: circleSolid ? solidFill : "transparent", color: dayColor, textDecoration: (stateVisual === null || stateVisual === void 0 ? void 0 : stateVisual.strikethrough) ? "line-through" : undefined, border: dayBorder, transition: "background 0.12s, color 0.12s", _hover: disabled
|
|
122
125
|
? {}
|
|
123
126
|
: circleSolid
|
|
124
127
|
? { bg: solidHoverFill, color: circleHoverColor }
|
|
@@ -127,14 +130,14 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
|
|
|
127
130
|
pointerEvents: "none", children: customContent !== null && customContent !== void 0 ? customContent : (_jsx(Box, { as: "span", className: `${DAY_CLASS}__marker`, w: "0.25rem", h: "0.25rem", borderRadius: "full", bg: markerColor })) }))] }) }, thisDay.toString()));
|
|
128
131
|
day = addDays(day, 1);
|
|
129
132
|
}
|
|
130
|
-
rows.push(_jsx(
|
|
133
|
+
rows.push(_jsx(Box, { role: "row", display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 0, children: days }, day.toString()));
|
|
131
134
|
}
|
|
132
135
|
return rows;
|
|
133
136
|
};
|
|
134
|
-
return (_jsxs(Box, { children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2, gap: 1, children: [_jsx(Button, { variant: "ghost", size: "xs", sx: { flexShrink: 0 }, onClick: () => setCurrentMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1)), "aria-label": "Previous month", children: _jsx(ChevronLeftIcon, { size: 16 }) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 1.5, minW: 0, children: [_jsx(Box, { as: "select", value: currentMonth.getMonth(), onChange: (e) => {
|
|
137
|
+
return (_jsxs(Box, { children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2, gap: 1, children: [_jsx(Button, { variant: "ghost", size: "xs", sx: { flexShrink: 0 }, onClick: () => setCurrentMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1)), "aria-label": "Previous month", children: _jsx(ChevronLeftIcon, { size: 16 }) }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 1.5, minW: 0, children: [_jsx(Box, { as: "select", "aria-label": "Month", value: currentMonth.getMonth(), onChange: (e) => {
|
|
135
138
|
const newMonth = parseInt(e.target.value, 10);
|
|
136
139
|
setCurrentMonth((prev) => new Date(prev.getFullYear(), newMonth, 1));
|
|
137
|
-
}, ...selectStyles, children: Array.from({ length: 12 }).map((_, i) => (_jsx("option", { value: i, children: format(new Date(2000, i, 1), "MMMM") }, i))) }), _jsx(Box, { as: "select", value: currentMonth.getFullYear(), onChange: (e) => {
|
|
140
|
+
}, ...selectStyles, children: Array.from({ length: 12 }).map((_, i) => (_jsx("option", { value: i, children: format(new Date(2000, i, 1), "MMMM") }, i))) }), _jsx(Box, { as: "select", "aria-label": "Year", value: currentMonth.getFullYear(), onChange: (e) => {
|
|
138
141
|
const newYear = parseInt(e.target.value, 10);
|
|
139
142
|
setCurrentMonth((prev) => new Date(newYear, prev.getMonth(), 1));
|
|
140
143
|
}, ...selectStyles, children: Array.from({ length: 100 }).map((_, i) => {
|
|
@@ -145,6 +148,6 @@ export const CalendarPanel = ({ currentMonth, setCurrentMonth, today, isRange, t
|
|
|
145
148
|
if (!disableToday) {
|
|
146
149
|
onDaySelect(new Date(today));
|
|
147
150
|
}
|
|
148
|
-
}, "aria-label": "Today", sx: { fontSize: "0.7rem", px: 2, flexShrink: 0 }, isDisabled: disableToday, children: "Today" })), _jsx(Button, { variant: "ghost", size: "xs", sx: { flexShrink: 0 }, onClick: () => setCurrentMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1)), "aria-label": "Next month", children: _jsx(ChevronRightIcon, { size: 16 }) })] })] }), renderWeekdays !== null && renderWeekdays !== void 0 ? renderWeekdays : (_jsx(
|
|
151
|
+
}, "aria-label": "Today", sx: { fontSize: "0.7rem", px: 2, flexShrink: 0 }, isDisabled: disableToday, children: "Today" })), _jsx(Button, { variant: "ghost", size: "xs", sx: { flexShrink: 0 }, onClick: () => setCurrentMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1)), "aria-label": "Next month", children: _jsx(ChevronRightIcon, { size: 16 }) })] })] }), _jsxs(Box, { role: "grid", "aria-label": "Calendar", children: [renderWeekdays !== null && renderWeekdays !== void 0 ? renderWeekdays : (_jsx(Box, { role: "row", display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 0, mb: 1, children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => (_jsx(Box, { role: "columnheader", textAlign: "center", fontSize: "0.7rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.02em", color: theme.colors.textMuted, py: 1, children: day }, day))) })), _jsx(Box, { onMouseLeave: () => onDayHover === null || onDayHover === void 0 ? void 0 : onDayHover(null), children: renderDays() })] })] }));
|
|
149
152
|
};
|
|
150
153
|
export default CalendarPanel;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { Box, FormControl, Input, InputGroup, InputRightElement, Popover, PopoverBody, PopoverContent,
|
|
3
|
+
import { Box, FormControl, IconButton, Input, InputGroup, InputRightElement, Popover, PopoverAnchor, PopoverBody, PopoverContent, useDisclosure, } from "@chakra-ui/react";
|
|
4
4
|
import { format, isAfter, isBefore, isSameDay, subDays, startOfMonth, endOfMonth } from "date-fns";
|
|
5
5
|
import { CalendarIcon } from "lucide-react";
|
|
6
6
|
import Button from "../Button/Button.js";
|
|
@@ -12,6 +12,7 @@ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
|
12
12
|
import { getTextInputIconSizePx, getTextInputIconWrapperSx, } from "../Input/textInputIconSize.js";
|
|
13
13
|
import TimePicker from "./TimePicker.js";
|
|
14
14
|
import { TimePickerInput } from "./TimePickerInput.js";
|
|
15
|
+
import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
|
|
15
16
|
// helper to set time on date while preserving date part
|
|
16
17
|
const setTimeFrom = (base, time) => {
|
|
17
18
|
const b = base ? new Date(base) : new Date();
|
|
@@ -25,6 +26,9 @@ export const RangeDatePicker = (props) => {
|
|
|
25
26
|
const calendarIconPx = getTextInputIconSizePx(sizeKey);
|
|
26
27
|
const calendarIconWrapperSx = getTextInputIconWrapperSx(sizeKey);
|
|
27
28
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
29
|
+
const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
|
|
30
|
+
const errorFieldId = id ? `${id}-error` : undefined;
|
|
31
|
+
const calendarLabel = label !== null && label !== void 0 ? label : "Choose date range";
|
|
28
32
|
const inputRef = useRef(null);
|
|
29
33
|
const triggerRef = useRef(null);
|
|
30
34
|
const popoverRef = useRef(null);
|
|
@@ -91,8 +95,20 @@ export const RangeDatePicker = (props) => {
|
|
|
91
95
|
onClose();
|
|
92
96
|
};
|
|
93
97
|
const handleOpen = () => {
|
|
98
|
+
requestExclusiveOpen();
|
|
94
99
|
onOpen();
|
|
95
100
|
};
|
|
101
|
+
const handleInputKeyDown = (e) => {
|
|
102
|
+
if (e.key === "Escape" && isOpen) {
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
onClose();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!isOpen && (e.key === "ArrowDown" || e.key === "Enter")) {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
handleOpen();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
96
112
|
const handleDaySelect = (day) => {
|
|
97
113
|
const updated = new Date(day);
|
|
98
114
|
if (selectingStart) {
|
|
@@ -159,7 +175,7 @@ export const RangeDatePicker = (props) => {
|
|
|
159
175
|
return `${format(tempRangeStart, dateFormat)} -`;
|
|
160
176
|
return "";
|
|
161
177
|
}, [inputValue, tempRangeStart, tempRangeEnd, dateFormat]);
|
|
162
|
-
return (_jsxs(FormControl, { id: id, isInvalid: error, isRequired: isRequired, isDisabled: disabled, width: width, children: [label && (_jsx(TextLabel, { label: label, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), _jsxs(Popover, { isLazy: true, isOpen: isOpen, onClose: finalize, placement: "bottom-start", closeOnBlur: false, returnFocusOnClose:
|
|
178
|
+
return (_jsxs(FormControl, { id: id, isInvalid: error, isRequired: isRequired, isDisabled: disabled, width: width, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), _jsxs(Popover, { isLazy: true, isOpen: isOpen, onClose: finalize, placement: "bottom-start", closeOnBlur: false, returnFocusOnClose: true, children: [_jsx(PopoverAnchor, { children: _jsx(Box, { ref: triggerRef, as: "div", children: _jsxs(InputGroup, { size: sizeKey, children: [_jsx(Input, { ref: inputRef, id: id, name: name, size: sizeKey, placeholder: placeholder, value: displayValue, readOnly: true, isDisabled: disabled, isInvalid: error, isRequired: isRequired, "aria-describedby": error && errorMessage ? errorFieldId : undefined, autoComplete: autoComplete, onKeyDown: handleInputKeyDown, onFocus: () => {
|
|
163
179
|
if (!isOpen)
|
|
164
180
|
handleOpen();
|
|
165
181
|
}, onClick: () => {
|
|
@@ -172,7 +188,15 @@ export const RangeDatePicker = (props) => {
|
|
|
172
188
|
: `0 0 0 1px ${theme.colors.primary[500]}`,
|
|
173
189
|
}, _hover: {
|
|
174
190
|
borderColor: error ? theme.colors.semanticText.error : undefined,
|
|
175
|
-
}, cursor: "pointer" }), _jsx(InputRightElement, { height: "100%", display: "flex", alignItems: "center", pointerEvents: "auto",
|
|
191
|
+
}, cursor: "pointer" }), _jsx(InputRightElement, { height: "100%", display: "flex", alignItems: "center", pointerEvents: "auto", children: _jsx(IconButton, { "aria-label": "Open calendar", variant: "ghost", size: "sm", minW: "auto", h: "auto", isDisabled: disabled, onClick: (e) => {
|
|
192
|
+
e.stopPropagation();
|
|
193
|
+
if (!isOpen) {
|
|
194
|
+
handleOpen();
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
onClose();
|
|
198
|
+
}
|
|
199
|
+
}, icon: _jsx(Box, { as: "span", sx: calendarIconWrapperSx, children: _jsx(CalendarIcon, { size: calendarIconPx, color: theme.colors.textMuted }) }) }) })] }) }) }), _jsx(PopoverContent, { w: "18rem", maxW: "18rem", p: 3, ref: popoverRef, boxShadow: "lg", borderRadius: "xl", bg: theme.colors.background[50], role: "dialog", "aria-label": calendarLabel, children: _jsxs(PopoverBody, { p: 0, children: [_jsx(Box, { display: "flex", flexWrap: "wrap", gap: 2, mb: 3, children: presets.map((p) => (_jsx(Button, { size: "xs", variant: "outline", colorScheme: "gray", sx: { flex: "1 1 auto" }, onClick: () => {
|
|
176
200
|
const [from, to] = p.getRange();
|
|
177
201
|
applyPreset(from, to);
|
|
178
202
|
}, children: p.label }, p.label))) }), _jsx(CalendarPanel, { currentMonth: currentMonth, setCurrentMonth: (updater) => setCurrentMonthState((prev) => updater(prev)), today: today, isRange: true, tempDate: null, tempRangeStart: tempRangeStart, tempRangeEnd: tempRangeEnd, hoveredDate: hoveredDate, onDayHover: setHoveredDate, isSameDay: isSameDay, isBefore: isBefore, isAfter: isAfter, minDate: minDate, maxDate: maxDate, disablePastDates: disablePastDates, disableFutureDates: disableFutureDates, disableToday: disableToday, onDaySelect: handleDaySelect, dayStates: dayStates, renderDayContent: renderDayContent }), formatHasTime && (_jsxs(Box, { mt: 3, display: "grid", gridTemplateColumns: "1fr", gap: 2, children: [_jsxs(Box, { children: [_jsx(Box, { fontSize: "xs", color: theme.colors.textMuted, mb: 1, children: "Start time" }), shouldUseSelectTimePicker ? (_jsx(TimePicker, { date: startTimeBaseDate, onChange: (updated) => {
|
|
@@ -201,6 +225,6 @@ export const RangeDatePicker = (props) => {
|
|
|
201
225
|
return;
|
|
202
226
|
}
|
|
203
227
|
setTempRangeEnd(setTimeFrom(endTimeBaseDate, t));
|
|
204
|
-
}, dateFormat: timePickerFormat, disabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
|
|
228
|
+
}, dateFormat: timePickerFormat, disabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) })] }), error && errorMessage && (_jsx(ErrorMessage, { id: errorFieldId, errorMessage: errorMessage })), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
|
|
205
229
|
};
|
|
206
230
|
export default RangeDatePicker;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from "react";
|
|
3
|
-
import { Box, Popover,
|
|
3
|
+
import { Box, Popover, PopoverAnchor, PopoverContent, PopoverBody, useDisclosure, Input, InputGroup, InputRightElement, IconButton, FormControl, } from "@chakra-ui/react";
|
|
4
4
|
import { format, parse, isValid, isSameDay, isBefore, isAfter, addDays, } from "date-fns";
|
|
5
5
|
import { CalendarIcon } from "lucide-react";
|
|
6
6
|
import Button from "../Button/Button.js";
|
|
@@ -12,6 +12,7 @@ import ErrorMessage from "../Common/ErrorMessage.js";
|
|
|
12
12
|
import TimePicker from "./TimePicker.js";
|
|
13
13
|
import { TimePickerInput } from "./TimePickerInput.js";
|
|
14
14
|
import CalendarPanel from "./CalendarPanel.js";
|
|
15
|
+
import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
|
|
15
16
|
const TOKEN_CHARS = /[dMyHhmsaAm]/;
|
|
16
17
|
const getPlaceholderForToken = (token, length) => {
|
|
17
18
|
const lower = token.toLowerCase();
|
|
@@ -226,6 +227,9 @@ export const SingleDatePicker = (props) => {
|
|
|
226
227
|
const calendarIconPx = getTextInputIconSizePx(sizeKey);
|
|
227
228
|
const calendarIconWrapperSx = getTextInputIconWrapperSx(sizeKey);
|
|
228
229
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
230
|
+
const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
|
|
231
|
+
const errorFieldId = id ? `${id}-error` : undefined;
|
|
232
|
+
const calendarLabel = label !== null && label !== void 0 ? label : "Choose date";
|
|
229
233
|
const inputRef = useRef(null);
|
|
230
234
|
const popoverRef = useRef(null);
|
|
231
235
|
const triggerRef = useRef(null);
|
|
@@ -387,6 +391,7 @@ export const SingleDatePicker = (props) => {
|
|
|
387
391
|
}
|
|
388
392
|
}, [inputValue, tokenSegments, enableMask, isMaskActive]);
|
|
389
393
|
const handleOpen = () => {
|
|
394
|
+
requestExclusiveOpen();
|
|
390
395
|
if (!selectedDate && showDate) {
|
|
391
396
|
setTempDate(disableToday ? tomorrow : new Date());
|
|
392
397
|
}
|
|
@@ -777,14 +782,28 @@ export const SingleDatePicker = (props) => {
|
|
|
777
782
|
}
|
|
778
783
|
if (key === "Escape") {
|
|
779
784
|
e.preventDefault();
|
|
780
|
-
(
|
|
785
|
+
if (isOpen) {
|
|
786
|
+
onClose();
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
(_d = inputRef.current) === null || _d === void 0 ? void 0 : _d.blur();
|
|
790
|
+
}
|
|
781
791
|
return;
|
|
782
792
|
}
|
|
783
793
|
if (key === "Enter") {
|
|
784
794
|
e.preventDefault();
|
|
795
|
+
if (!isOpen && showDate) {
|
|
796
|
+
handleOpen();
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
785
799
|
handleInputBlur();
|
|
786
800
|
return;
|
|
787
801
|
}
|
|
802
|
+
if (key === "ArrowDown" && !isOpen && showDate) {
|
|
803
|
+
e.preventDefault();
|
|
804
|
+
handleOpen();
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
788
807
|
if (key === "Backspace" || key === "Delete") {
|
|
789
808
|
e.preventDefault();
|
|
790
809
|
const baseValue = ensureMaskValue();
|
|
@@ -926,20 +945,35 @@ export const SingleDatePicker = (props) => {
|
|
|
926
945
|
};
|
|
927
946
|
const handleInputFocusMask = enableMask ? handleInputFocus : undefined;
|
|
928
947
|
const handleInputClickMask = enableMask ? handleInputClick : undefined;
|
|
929
|
-
const handleKeyDownMask = enableMask ? handleKeyDown : undefined;
|
|
930
948
|
const handlePasteMask = enableMask ? handlePaste : undefined;
|
|
949
|
+
const handleInputKeyDown = (e) => {
|
|
950
|
+
if (!enableMask) {
|
|
951
|
+
if (e.key === "Escape" && isOpen) {
|
|
952
|
+
e.preventDefault();
|
|
953
|
+
onClose();
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
if (!isOpen && showDate && (e.key === "ArrowDown" || e.key === "Enter")) {
|
|
957
|
+
e.preventDefault();
|
|
958
|
+
handleOpen();
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
handleKeyDown(e);
|
|
964
|
+
};
|
|
931
965
|
const displayValue = isTyping
|
|
932
966
|
? inputValue
|
|
933
967
|
: tempDate
|
|
934
968
|
? format(tempDate, resolvedDateFormat)
|
|
935
969
|
: "";
|
|
936
|
-
return (_jsxs(FormControl, { id: id, isDisabled: disabled, width: width, children: [label && (_jsx(TextLabel, { label: label, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), _jsxs(Popover, { isLazy: true, isOpen: isOpen, onClose: () => {
|
|
970
|
+
return (_jsxs(FormControl, { id: id, isDisabled: disabled, isInvalid: error, isRequired: isRequired, width: width, children: [label && (_jsx(TextLabel, { label: label, id: id, isRequired: isRequired, isInformation: isInformation, informationMessage: informationMessage })), _jsxs(Popover, { isLazy: true, isOpen: isOpen, onClose: () => {
|
|
937
971
|
if (suppressOnCloseFinalizeRef.current) {
|
|
938
972
|
suppressOnCloseFinalizeRef.current = false;
|
|
939
973
|
return;
|
|
940
974
|
}
|
|
941
975
|
finalize();
|
|
942
|
-
}, placement: "bottom-start", closeOnBlur: false, returnFocusOnClose:
|
|
976
|
+
}, placement: "bottom-start", closeOnBlur: false, returnFocusOnClose: true, children: [_jsx(PopoverAnchor, { children: _jsx(Box, { ref: triggerRef, as: "div", children: _jsxs(InputGroup, { size: sizeKey, children: [_jsx(Input, { ref: inputRef, id: id, name: name, size: sizeKey, placeholder: displayPlaceholder, value: displayValue, onChange: handleInputChange, onKeyDown: handleInputKeyDown, onPaste: handlePasteMask, onBlur: handleInputBlur, onClick: handleInputClickMask, onFocus: handleInputFocusMask, isDisabled: disabled, isInvalid: error, isRequired: isRequired, "aria-describedby": error && errorMessage ? errorFieldId : undefined, autoComplete: autoComplete, bg: theme.colors.background[50], borderColor: error
|
|
943
977
|
? theme.colors.semanticText.error
|
|
944
978
|
: theme.colors.boxborder[500], _focus: {
|
|
945
979
|
borderColor: error ? theme.colors.semanticText.error : theme.colors.primary[500],
|
|
@@ -948,15 +982,15 @@ export const SingleDatePicker = (props) => {
|
|
|
948
982
|
: `0 0 0 0.125rem ${theme.colors.boxShadow.primary}`,
|
|
949
983
|
}, _hover: {
|
|
950
984
|
borderColor: error ? theme.colors.semanticText.error : theme.colors.primary[500],
|
|
951
|
-
}, cursor: "text", boxShadow: error ? `0 0 0 0.125rem ${theme.colors.boxShadow.error}` : `` }), _jsx(InputRightElement, { height: "100%", display: "flex", alignItems: "center", pointerEvents: "auto", onClick: (e) => {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
985
|
+
}, cursor: "text", boxShadow: error ? `0 0 0 0.125rem ${theme.colors.boxShadow.error}` : `` }), _jsx(InputRightElement, { height: "100%", display: "flex", alignItems: "center", pointerEvents: "auto", children: _jsx(IconButton, { "aria-label": "Open calendar", variant: "ghost", size: "sm", minW: "auto", h: "auto", isDisabled: disabled, onClick: (e) => {
|
|
986
|
+
e.stopPropagation();
|
|
987
|
+
if (!isOpen) {
|
|
988
|
+
handleOpen();
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
onClose();
|
|
992
|
+
}
|
|
993
|
+
}, icon: _jsx(Box, { as: "span", sx: calendarIconWrapperSx, children: _jsx(CalendarIcon, { size: calendarIconPx, color: theme.colors.textMuted }) }) }) })] }) }) }), _jsx(PopoverContent, { width: "auto", p: 3, ref: popoverRef, boxShadow: "lg", borderRadius: "xl", bg: theme.colors.background[50], role: "dialog", "aria-label": calendarLabel, children: _jsxs(PopoverBody, { p: 0, children: [showDate && (_jsx(CalendarPanel, { currentMonth: currentMonth, setCurrentMonth: (updater) => setCurrentMonth((prev) => updater(prev)), today: today, isRange: false, tempDate: tempDate, tempRangeStart: null, tempRangeEnd: null, isSameDay: isSameDay, isBefore: isBefore, isAfter: isAfter, minDate: minDate, maxDate: maxDate, disablePastDates: disablePastDates, disableFutureDates: disableFutureDates, disableToday: disableToday, onDaySelect: handleDaySelect })), showTime && (_jsx(Box, { mt: showDate ? 3 : 0, children: resolvedPickerType === "time" ? (_jsx(TimePickerInput, { value: tempDate, onChange: (updatedDate) => {
|
|
960
994
|
setTempDate(updatedDate);
|
|
961
995
|
setInputValue(updatedDate ? format(updatedDate, resolvedDateFormat) : "");
|
|
962
996
|
setIsTyping(false);
|
|
@@ -967,6 +1001,6 @@ export const SingleDatePicker = (props) => {
|
|
|
967
1001
|
}, disabled: disabled })) })), _jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(Button, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: () => {
|
|
968
1002
|
setTempDate(null);
|
|
969
1003
|
requestClose(null);
|
|
970
|
-
}, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: () => requestClose(), children: "Apply" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
|
|
1004
|
+
}, children: "Clear" }), _jsx(Button, { size: "sm", variant: "gradient", onClick: () => requestClose(), children: "Apply" })] })] }) })] }), error && errorMessage && (_jsx(ErrorMessage, { id: errorFieldId, errorMessage: errorMessage })), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
|
|
971
1005
|
};
|
|
972
1006
|
export default SingleDatePicker;
|
|
@@ -7,6 +7,7 @@ import HelperText from "../Common/HelperText.js";
|
|
|
7
7
|
import ErrorMessage from "../Common/ErrorMessage.js";
|
|
8
8
|
import TimePicker from "./TimePicker.js";
|
|
9
9
|
import { TimePickerInput } from "./TimePickerInput.js";
|
|
10
|
+
import { useExclusiveOverlay } from "../../Hooks/useExclusiveOverlay.js";
|
|
10
11
|
import { useCustomTheme } from "../../Theme/useCustomTheme.js";
|
|
11
12
|
const formatToPlaceholder = (formatStr) => formatStr.replace(/h{1,2}/gi, "HH").replace(/m{1,2}/gi, "mm").replace(/a{1,2}/gi, "AM");
|
|
12
13
|
export const TimeOnlyPicker = (props) => {
|
|
@@ -14,6 +15,11 @@ export const TimeOnlyPicker = (props) => {
|
|
|
14
15
|
const { id, label, isRequired, isInformation, informationMessage, error, errorMessage, helperText, placeholderText, dateFormat = "HH:mm", disabled, width = "100%", disableToday = false, size = "md", } = props;
|
|
15
16
|
const theme = useCustomTheme();
|
|
16
17
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
18
|
+
const requestExclusiveOpen = useExclusiveOverlay(isOpen, onClose);
|
|
19
|
+
const openPicker = () => {
|
|
20
|
+
requestExclusiveOpen();
|
|
21
|
+
onOpen();
|
|
22
|
+
};
|
|
17
23
|
const popoverRef = useRef(null);
|
|
18
24
|
const triggerRef = useRef(null);
|
|
19
25
|
const inputWrapperRef = useRef(null);
|
|
@@ -70,7 +76,7 @@ export const TimeOnlyPicker = (props) => {
|
|
|
70
76
|
handleTimeInputChange(date);
|
|
71
77
|
}, dateFormat: dateFormat, disabled: disabled, placeholder: placeholder, onFocus: () => {
|
|
72
78
|
if (!disabled && !isOpen)
|
|
73
|
-
|
|
79
|
+
openPicker();
|
|
74
80
|
}, error: error, size: sizeKey }) }) }) }), _jsx(PopoverContent, { width: "auto", p: 4, ref: popoverRef, boxShadow: "lg", bg: theme.colors.background[50], children: _jsxs(PopoverBody, { children: [_jsx(TimePicker, { date: resolvedTempDate, dateFormat: dateFormat, onChange: (updatedDate) => {
|
|
75
81
|
handleTimePickerChange(updatedDate);
|
|
76
82
|
} }), _jsxs(Box, { display: "flex", justifyContent: "space-between", mt: 4, pt: 4, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [_jsx(ChakraButton, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }), _jsx(ChakraButton, { size: "sm", colorScheme: "primary", onClick: handleOk, children: "OK" })] })] }) })] }), error && errorMessage && _jsx(ErrorMessage, { errorMessage: errorMessage }), helperText && !error && _jsx(HelperText, { helperText: helperText })] }));
|
|
@@ -52,16 +52,16 @@ const TimePicker = ({ date, onChange, dateFormat, disabled = false }) => {
|
|
|
52
52
|
updateTime(hour, minute, newMeridiem);
|
|
53
53
|
};
|
|
54
54
|
const displayHour = is12HourFormat ? (hour % 12 === 0 ? 12 : hour % 12) : hour;
|
|
55
|
-
return (_jsxs(HStack, { spacing: 1.5, w: "100%", children: [_jsx(Select, { value: displayHour, onChange: handleHourChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.
|
|
55
|
+
return (_jsxs(HStack, { spacing: 1.5, w: "100%", children: [_jsx(Select, { "aria-label": "Hour", value: displayHour, onChange: handleHourChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.background[50], borderColor: theme.colors.boxborder[500], _focus: {
|
|
56
56
|
borderColor: theme.colors.primary[500],
|
|
57
57
|
boxShadow: `0 0 0 0.125rem ${theme.colors.boxShadow.primary}`,
|
|
58
58
|
}, _hover: { borderColor: theme.colors.primary[500] }, children: Array.from({ length: is12HourFormat ? 12 : 24 }, (_, i) => {
|
|
59
59
|
const value = is12HourFormat ? i + 1 : i;
|
|
60
60
|
return (_jsx("option", { value: value, children: value.toString().padStart(2, "0") }, value));
|
|
61
|
-
}) }), _jsx(Select, { value: minute, onChange: handleMinuteChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.
|
|
61
|
+
}) }), _jsx(Select, { "aria-label": "Minute", value: minute, onChange: handleMinuteChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.background[50], borderColor: theme.colors.boxborder[500], _focus: {
|
|
62
62
|
borderColor: theme.colors.primary[500],
|
|
63
63
|
boxShadow: `0 0 0 0.125rem ${theme.colors.boxShadow.primary}`,
|
|
64
|
-
}, _hover: { borderColor: theme.colors.primary[500] }, children: Array.from({ length: 60 }, (_, i) => (_jsx("option", { value: i, children: i.toString().padStart(2, "0") }, i))) }), is12HourFormat && (_jsxs(Select, { value: ampm, onChange: handleAmpmChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.
|
|
64
|
+
}, _hover: { borderColor: theme.colors.primary[500] }, children: Array.from({ length: 60 }, (_, i) => (_jsx("option", { value: i, children: i.toString().padStart(2, "0") }, i))) }), is12HourFormat && (_jsxs(Select, { "aria-label": "AM or PM", value: ampm, onChange: handleAmpmChange, flex: "1", minW: 0, size: "sm", isDisabled: disabled, bg: theme.colors.background[50], borderColor: theme.colors.boxborder[500], _focus: {
|
|
65
65
|
borderColor: theme.colors.primary[500],
|
|
66
66
|
boxShadow: `0 0 0 0.125rem ${theme.colors.boxShadow.primary}`,
|
|
67
67
|
}, _hover: { borderColor: theme.colors.primary[500] }, children: [_jsx("option", { value: "AM", children: "AM" }), _jsx("option", { value: "PM", children: "PM" })] }))] }));
|
|
@@ -400,7 +400,7 @@ export const TimePickerInput = ({ value, onChange, dateFormat, disabled = false,
|
|
|
400
400
|
inputRef.current.value = is12Hour && formatted ? `${formatted} ${ampm}` : formatted;
|
|
401
401
|
}
|
|
402
402
|
}, [digits, ampm, is12Hour]);
|
|
403
|
-
return (_jsxs(InputGroup, { size: sizeKey, children: [_jsx(Input, { ref: inputRef, defaultValue: "", onChange: handleInput, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, onClick: handleClick, onPaste: handlePaste, placeholder: placeholderText, isDisabled: disabled, autoComplete: "off", isInvalid: error, size: sizeKey, bg: theme.colors.
|
|
403
|
+
return (_jsxs(InputGroup, { size: sizeKey, children: [_jsx(Input, { ref: inputRef, defaultValue: "", onChange: handleInput, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, onClick: handleClick, onPaste: handlePaste, placeholder: placeholderText, isDisabled: disabled, autoComplete: "off", isInvalid: error, size: sizeKey, bg: theme.colors.background[50], borderColor: error ? theme.colors.semanticText.error : theme.colors.boxborder[500], _focus: {
|
|
404
404
|
borderColor: error ? theme.colors.semanticText.error : theme.colors.primary[500],
|
|
405
405
|
boxShadow: error
|
|
406
406
|
? `0 0 0 0.125rem ${theme.colors.boxShadow.error}`
|