@cwellt_software/cwellt-reactjs-lib 1.4.10 → 1.4.12

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/index.cjs.js CHANGED
@@ -5037,6 +5037,265 @@ function CwSearchInput(optionsProps) {
5037
5037
  return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option) => (jsxRuntime.jsx("li", { className: dropdownStyles.option, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5038
5038
  }
5039
5039
 
5040
+ /**
5041
+ * Generic API-backed search input. Fetches matching options from a caller-supplied `onSearch`
5042
+ * callback as the user types (debounced), renders them in a portal-based dropdown with keyboard
5043
+ * navigation, and commits the selected id via `onChange`.
5044
+ *
5045
+ * All domain logic — API URLs, auth/config, display formatting, provider/secondary lookups — lives
5046
+ * in the caller's callbacks, so this component stays application-agnostic. It is the base for thin
5047
+ * wrappers such as `FindAirport` / `FindCrewmember`.
5048
+ *
5049
+ * Improvements over the legacy `CwFindAirport` / `CwFindCrewmember`: an `AbortController` cancels
5050
+ * superseded in-flight requests (fixes out-of-order results), and `minChars` / `debounceMs` are
5051
+ * configurable.
5052
+ *
5053
+ * @example
5054
+ * <CwSearchAsync
5055
+ * onSearch={(text, signal) => repo.search(text, signal)}
5056
+ * onChange={(id) => setSelectedId(id)}
5057
+ * labelProps={{ text: 'Airport' }}
5058
+ * icon={{ iconId: 'control-tower' }}
5059
+ * />
5060
+ */
5061
+ const CwSearchAsync = ({ onSearch, onChange, value, onResolveInitial, onResolveSelection, icon, placeholder = "Search…", minChars = 2, debounceMs = 300, disabled = false, required = false, initialDisplayText, searchTrigger, labelProps, alignProps, width, className = "", }) => {
5062
+ // State
5063
+ const [inputValue, setInputValue] = React.useState("");
5064
+ const [options, setOptions] = React.useState([]);
5065
+ const [isLoading, setIsLoading] = React.useState(false);
5066
+ const [isInitialLoading, setIsInitialLoading] = React.useState(false);
5067
+ const [showDropdown, setShowDropdown] = React.useState(false);
5068
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
5069
+ const [tooltipText, setTooltipText] = React.useState("");
5070
+ // Refs
5071
+ const inputRef = React.useRef(null);
5072
+ const wrapperRef = React.useRef(null);
5073
+ const debounceRef = React.useRef();
5074
+ const abortRef = React.useRef(null);
5075
+ const lastQueryRef = React.useRef("");
5076
+ const didMountRef = React.useRef(false);
5077
+ const lastResolvedValueRef = React.useRef(undefined);
5078
+ const initialResolveAbortRef = React.useRef(null);
5079
+ // Stable ids wiring the combobox input to its listbox popup for assistive tech.
5080
+ const listboxId = React.useId();
5081
+ const optionId = (index) => `${listboxId}-opt-${index}`;
5082
+ // Cancel a pending initial-value resolve when the user takes over (typing / clearing / reset),
5083
+ // so a slow resolve can't overwrite newer input and the loading flag never sticks.
5084
+ const cancelInitialResolve = React.useCallback(() => {
5085
+ initialResolveAbortRef.current?.abort();
5086
+ initialResolveAbortRef.current = null;
5087
+ setIsInitialLoading(false);
5088
+ }, []);
5089
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5090
+ anchorRef: wrapperRef,
5091
+ isOpen: showDropdown && options.length > 0,
5092
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
5093
+ });
5094
+ // Core search runner — aborts superseded requests and drops stale responses.
5095
+ const runSearch = React.useCallback(async (text) => {
5096
+ abortRef.current?.abort();
5097
+ if (text.length < minChars) {
5098
+ setOptions([]);
5099
+ setShowDropdown(false);
5100
+ setHighlightedIndex(-1);
5101
+ return;
5102
+ }
5103
+ const controller = new AbortController();
5104
+ abortRef.current = controller;
5105
+ lastQueryRef.current = text;
5106
+ setIsLoading(true);
5107
+ try {
5108
+ const results = await onSearch(text, controller.signal);
5109
+ if (controller.signal.aborted)
5110
+ return; // superseded → drop
5111
+ setOptions(results);
5112
+ setShowDropdown(results.length > 0); // empty → close silently (dark cockpit)
5113
+ setHighlightedIndex(-1);
5114
+ }
5115
+ catch (error) {
5116
+ if (controller.signal.aborted)
5117
+ return; // aborts reject with AbortError → ignore
5118
+ console.error("CwSearchAsync onSearch failed:", error);
5119
+ setOptions([]);
5120
+ setShowDropdown(false);
5121
+ }
5122
+ finally {
5123
+ if (abortRef.current === controller) {
5124
+ setIsLoading(false);
5125
+ abortRef.current = null;
5126
+ }
5127
+ }
5128
+ }, [minChars, onSearch]);
5129
+ // Keep a stable handle to the latest runSearch for the searchTrigger effect.
5130
+ const runSearchRef = React.useRef(runSearch);
5131
+ React.useEffect(() => { runSearchRef.current = runSearch; });
5132
+ const debouncedSearch = React.useCallback((text) => {
5133
+ if (debounceRef.current)
5134
+ window.clearTimeout(debounceRef.current);
5135
+ // Abort eagerly on every keystroke so a fast typist never has two live fetches.
5136
+ abortRef.current?.abort();
5137
+ debounceRef.current = window.setTimeout(() => runSearch(text), debounceMs);
5138
+ }, [runSearch, debounceMs]);
5139
+ const handleInputChange = (e) => {
5140
+ const newValue = e.target.value;
5141
+ setInputValue(newValue);
5142
+ if (newValue !== inputValue) {
5143
+ cancelInitialResolve();
5144
+ debouncedSearch(newValue);
5145
+ }
5146
+ };
5147
+ const handleOptionSelect = async (optionId) => {
5148
+ const picked = options.find(o => o.id === optionId);
5149
+ if (!picked)
5150
+ return;
5151
+ setShowDropdown(false);
5152
+ let committed = picked;
5153
+ if (onResolveSelection) {
5154
+ abortRef.current?.abort();
5155
+ const controller = new AbortController();
5156
+ abortRef.current = controller;
5157
+ try {
5158
+ const resolved = await onResolveSelection(picked, controller.signal);
5159
+ if (controller.signal.aborted)
5160
+ return;
5161
+ committed = resolved;
5162
+ setOptions([resolved]);
5163
+ }
5164
+ catch (error) {
5165
+ if (controller.signal.aborted)
5166
+ return;
5167
+ console.error("CwSearchAsync onResolveSelection failed:", error);
5168
+ return; // abort the commit, mirroring the legacy provider-airport behaviour
5169
+ }
5170
+ finally {
5171
+ if (abortRef.current === controller)
5172
+ abortRef.current = null;
5173
+ }
5174
+ }
5175
+ setInputValue(committed.inputLabel ?? committed.label);
5176
+ setTooltipText(committed.label);
5177
+ onChange(committed.id);
5178
+ };
5179
+ const handleKeyDown = (e) => {
5180
+ if (!showDropdown || options.length === 0)
5181
+ return;
5182
+ switch (e.key) {
5183
+ case "ArrowDown":
5184
+ e.preventDefault();
5185
+ setHighlightedIndex(prev => (prev < options.length - 1 ? prev + 1 : 0));
5186
+ break;
5187
+ case "ArrowUp":
5188
+ e.preventDefault();
5189
+ setHighlightedIndex(prev => (prev > 0 ? prev - 1 : options.length - 1));
5190
+ break;
5191
+ case "Enter":
5192
+ e.preventDefault();
5193
+ if (highlightedIndex >= 0 && highlightedIndex < options.length) {
5194
+ handleOptionSelect(options[highlightedIndex].id);
5195
+ }
5196
+ break;
5197
+ case "Escape":
5198
+ setShowDropdown(false);
5199
+ setHighlightedIndex(-1);
5200
+ break;
5201
+ }
5202
+ };
5203
+ const handleInputFocus = () => {
5204
+ if (options.length > 0)
5205
+ setShowDropdown(true);
5206
+ };
5207
+ const handleClear = () => {
5208
+ if (debounceRef.current)
5209
+ window.clearTimeout(debounceRef.current);
5210
+ abortRef.current?.abort();
5211
+ cancelInitialResolve();
5212
+ setInputValue("");
5213
+ setTooltipText("");
5214
+ setOptions([]);
5215
+ setShowDropdown(false);
5216
+ lastQueryRef.current = "";
5217
+ onChange(null);
5218
+ inputRef.current?.focus();
5219
+ };
5220
+ // Resolve a preselected value to display text.
5221
+ React.useEffect(() => {
5222
+ if (value == null)
5223
+ return;
5224
+ if (initialDisplayText) {
5225
+ setInputValue(initialDisplayText);
5226
+ setTooltipText(initialDisplayText);
5227
+ lastResolvedValueRef.current = value;
5228
+ return;
5229
+ }
5230
+ if (!onResolveInitial)
5231
+ return;
5232
+ if (lastResolvedValueRef.current === value)
5233
+ return; // already resolved this value
5234
+ const controller = new AbortController();
5235
+ initialResolveAbortRef.current = controller;
5236
+ setIsInitialLoading(true);
5237
+ onResolveInitial(value, controller.signal)
5238
+ .then(opt => {
5239
+ if (controller.signal.aborted)
5240
+ return;
5241
+ lastResolvedValueRef.current = value; // mark resolved only on success
5242
+ setOptions([opt]);
5243
+ setInputValue(opt.inputLabel ?? opt.label);
5244
+ setTooltipText(opt.label);
5245
+ })
5246
+ .catch(error => {
5247
+ if (!controller.signal.aborted)
5248
+ console.error("CwSearchAsync onResolveInitial failed:", error);
5249
+ })
5250
+ .finally(() => {
5251
+ // Clear the spinner only if this resolve is still the current one (not superseded/cancelled).
5252
+ if (initialResolveAbortRef.current === controller) {
5253
+ setIsInitialLoading(false);
5254
+ initialResolveAbortRef.current = null;
5255
+ }
5256
+ });
5257
+ return () => controller.abort();
5258
+ }, [value, initialDisplayText, onResolveInitial]);
5259
+ // Reset when the controlled value is cleared by the parent.
5260
+ React.useEffect(() => {
5261
+ if (value == null) {
5262
+ if (debounceRef.current)
5263
+ window.clearTimeout(debounceRef.current);
5264
+ abortRef.current?.abort();
5265
+ cancelInitialResolve();
5266
+ setInputValue("");
5267
+ setTooltipText("");
5268
+ setOptions([]);
5269
+ setShowDropdown(false);
5270
+ setHighlightedIndex(-1);
5271
+ lastQueryRef.current = "";
5272
+ lastResolvedValueRef.current = undefined;
5273
+ }
5274
+ }, [value, cancelInitialResolve]);
5275
+ // Re-run the last query when searchTrigger changes (skip first mount).
5276
+ React.useEffect(() => {
5277
+ if (!didMountRef.current) {
5278
+ didMountRef.current = true;
5279
+ return;
5280
+ }
5281
+ if (searchTrigger === undefined)
5282
+ return;
5283
+ if (lastQueryRef.current)
5284
+ runSearchRef.current(lastQueryRef.current);
5285
+ }, [searchTrigger]);
5286
+ // Cleanup on unmount.
5287
+ React.useEffect(() => () => {
5288
+ if (debounceRef.current)
5289
+ window.clearTimeout(debounceRef.current);
5290
+ abortRef.current?.abort();
5291
+ }, []);
5292
+ const direction = alignProps?.flexDirection || "row";
5293
+ return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className}`, style: {
5294
+ ...(width ? { width } : {}),
5295
+ ...(labelProps?.labelWidth ? { "--label-width": labelProps.labelWidth } : {}),
5296
+ }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeholder, disabled: disabled, required: required, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined, title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selection", variant: "icon", icon: "close", color: "neutral" })) : (icon ? jsxRuntime.jsx(CwIcon, { ...icon }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.id), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.subLabel ? (jsxRuntime.jsxs("span", { className: "cw-search-async-option-lines", children: [jsxRuntime.jsx("span", { children: option.label }), jsxRuntime.jsx("span", { className: "cw-search-async-option-sub", children: option.subLabel })] })) : (option.label) }, option.id))) }) }))] }));
5297
+ };
5298
+
5040
5299
  var styles$5 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
5041
5300
 
5042
5301
  const ARROW_SIZE = 8;
@@ -7003,7 +7262,7 @@ function formatPlainDate(pd, fmt) {
7003
7262
  .replace("dd", String(pd.day).padStart(2, "0"));
7004
7263
  }
7005
7264
 
7006
- function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, todayLabel = "Today", feedback, }) {
7265
+ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, locale: locale$1 = locale.enGB, todayLabel = "Today", yearRangeStart, yearRangeEnd, feedback, }) {
7007
7266
  const [isOpen, setIsOpen] = React.useState(false);
7008
7267
  const [inputValue, setInputValue] = React.useState();
7009
7268
  const containerRef = React.useRef(null);
@@ -7092,6 +7351,19 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7092
7351
  setIsOpen(false);
7093
7352
  }
7094
7353
  }, [minDate, maxDate, onChange]);
7354
+ // Derive start/end months for the year dropdown range, guarding against inverted yearRange props
7355
+ const dropdownStartMonth = React.useMemo(() => {
7356
+ const inferredStart = minDate ? minDate.year : Temporal.Now.plainDateISO().year - 10;
7357
+ const inferredEnd = yearRangeEnd ?? (maxDate ? maxDate.year : Temporal.Now.plainDateISO().year + 5);
7358
+ const year = Math.min(yearRangeStart ?? inferredStart, inferredEnd);
7359
+ return new Date(year, 0, 1);
7360
+ }, [yearRangeStart, yearRangeEnd, minDate, maxDate]);
7361
+ const dropdownEndMonth = React.useMemo(() => {
7362
+ const inferredEnd = maxDate ? maxDate.year : Temporal.Now.plainDateISO().year + 5;
7363
+ const inferredStart = yearRangeStart ?? (minDate ? minDate.year : Temporal.Now.plainDateISO().year - 10);
7364
+ const year = Math.max(yearRangeEnd ?? inferredEnd, inferredStart);
7365
+ return new Date(year, 11, 31);
7366
+ }, [yearRangeStart, yearRangeEnd, minDate, maxDate]);
7095
7367
  // Memoize disabled days (convert PlainDate[] to Date[] for DayPicker)
7096
7368
  const disabledDays = React.useMemo(() => [
7097
7369
  ...(disabledDates?.map(plainDateToJsDate) || []),
@@ -7103,13 +7375,463 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7103
7375
  const defaultMonthJsDate = defaultMonth
7104
7376
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
7105
7377
  : selectedJsDate;
7106
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, modifiers: {
7378
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7107
7379
  today: new Date(),
7108
7380
  }, modifiersClassNames: {
7109
7381
  today: "rdp-day-today",
7110
7382
  } }), showTodayButton && (jsxRuntime.jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
7111
7383
  }
7112
7384
 
7385
+ // dateRangePresetsTemporal.ts
7386
+ // Temporal-typed counterpart of dateRangePresets.ts (used by CwDateRangePickerTemporal).
7387
+ // Each preset is evaluated at click time; a reference date can be injected for testing.
7388
+ const ref = (today) => today ?? Temporal.Now.plainDateISO();
7389
+ /** Monday as first day of the week (ISO dayOfWeek: 1 = Mon … 7 = Sun). */
7390
+ const startOfWeek = (d) => d.subtract({ days: d.dayOfWeek - 1 });
7391
+ const startOfMonth = (d) => d.with({ day: 1 });
7392
+ const endOfMonth = (d) => d.with({ day: d.daysInMonth });
7393
+ /** First day of the quarter that contains `d`. */
7394
+ const startOfQuarter = (d) => Temporal.PlainDate.from({ year: d.year, month: Math.floor((d.month - 1) / 3) * 3 + 1, day: 1 });
7395
+ const PRESET_LIBRARY_TEMPORAL = {
7396
+ // === PAST DAYS ===
7397
+ today: {
7398
+ key: "today",
7399
+ label: "Today",
7400
+ getValue: (t) => { const d = ref(t); return { from: d, to: d }; },
7401
+ },
7402
+ yesterday: {
7403
+ key: "yesterday",
7404
+ label: "Yesterday",
7405
+ getValue: (t) => { const d = ref(t).subtract({ days: 1 }); return { from: d, to: d }; },
7406
+ },
7407
+ past2Days: {
7408
+ key: "past2Days",
7409
+ label: "Past 2 Days",
7410
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 2 }), to: d }; },
7411
+ },
7412
+ past3Days: {
7413
+ key: "past3Days",
7414
+ label: "Past 3 Days",
7415
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 3 }), to: d }; },
7416
+ },
7417
+ past7Days: {
7418
+ key: "past7Days",
7419
+ label: "Past 7 days",
7420
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 7 }), to: d }; },
7421
+ },
7422
+ past14Days: {
7423
+ key: "past14Days",
7424
+ label: "Past 14 days",
7425
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 14 }), to: d }; },
7426
+ },
7427
+ past30Days: {
7428
+ key: "past30Days",
7429
+ label: "Past 30 days",
7430
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 30 }), to: d }; },
7431
+ },
7432
+ past90Days: {
7433
+ key: "past90Days",
7434
+ label: "Past 90 days",
7435
+ getValue: (t) => { const d = ref(t); return { from: d.subtract({ days: 90 }), to: d }; },
7436
+ },
7437
+ // === NEXT DAYS ===
7438
+ next7Days: {
7439
+ key: "next7Days",
7440
+ label: "Next 7 days",
7441
+ getValue: (t) => { const d = ref(t); return { from: d, to: d.add({ days: 7 }) }; },
7442
+ },
7443
+ next14Days: {
7444
+ key: "next14Days",
7445
+ label: "Next 14 days",
7446
+ getValue: (t) => { const d = ref(t); return { from: d, to: d.add({ days: 14 }) }; },
7447
+ },
7448
+ next30Days: {
7449
+ key: "next30Days",
7450
+ label: "Next 30 days",
7451
+ getValue: (t) => { const d = ref(t); return { from: d, to: d.add({ days: 30 }) }; },
7452
+ },
7453
+ // === WEEKS (Monday-first) ===
7454
+ thisWeek: {
7455
+ key: "thisWeek",
7456
+ label: "This week",
7457
+ getValue: (t) => { const s = startOfWeek(ref(t)); return { from: s, to: s.add({ days: 6 }) }; },
7458
+ },
7459
+ lastWeek: {
7460
+ key: "lastWeek",
7461
+ label: "Last week",
7462
+ getValue: (t) => { const end = startOfWeek(ref(t)).subtract({ days: 1 }); return { from: end.subtract({ days: 6 }), to: end }; },
7463
+ },
7464
+ nextWeek: {
7465
+ key: "nextWeek",
7466
+ label: "Next week",
7467
+ getValue: (t) => { const s = startOfWeek(ref(t)).add({ days: 7 }); return { from: s, to: s.add({ days: 6 }) }; },
7468
+ },
7469
+ // === MONTHS ===
7470
+ thisMonth: {
7471
+ key: "thisMonth",
7472
+ label: "This month",
7473
+ getValue: (t) => { const d = ref(t); return { from: startOfMonth(d), to: endOfMonth(d) }; },
7474
+ },
7475
+ lastMonth: {
7476
+ key: "lastMonth",
7477
+ label: "Last month",
7478
+ getValue: (t) => { const d = startOfMonth(ref(t)).subtract({ months: 1 }); return { from: d, to: endOfMonth(d) }; },
7479
+ },
7480
+ nextMonth: {
7481
+ key: "nextMonth",
7482
+ label: "Next month",
7483
+ getValue: (t) => { const d = startOfMonth(ref(t)).add({ months: 1 }); return { from: d, to: endOfMonth(d) }; },
7484
+ },
7485
+ // === QUARTERS ===
7486
+ thisQuarter: {
7487
+ key: "thisQuarter",
7488
+ label: "This quarter",
7489
+ getValue: (t) => { const from = startOfQuarter(ref(t)); return { from, to: from.add({ months: 3 }).subtract({ days: 1 }) }; },
7490
+ },
7491
+ lastQuarter: {
7492
+ key: "lastQuarter",
7493
+ label: "Last quarter",
7494
+ getValue: (t) => { const from = startOfQuarter(ref(t)).subtract({ months: 3 }); return { from, to: from.add({ months: 3 }).subtract({ days: 1 }) }; },
7495
+ },
7496
+ nextQuarter: {
7497
+ key: "nextQuarter",
7498
+ label: "Next quarter",
7499
+ getValue: (t) => { const from = startOfQuarter(ref(t)).add({ months: 3 }); return { from, to: from.add({ months: 3 }).subtract({ days: 1 }) }; },
7500
+ },
7501
+ // === YEAR ===
7502
+ thisYear: {
7503
+ key: "thisYear",
7504
+ label: "This year",
7505
+ getValue: (t) => {
7506
+ const y = ref(t).year;
7507
+ return { from: Temporal.PlainDate.from({ year: y, month: 1, day: 1 }), to: Temporal.PlainDate.from({ year: y, month: 12, day: 31 }) };
7508
+ },
7509
+ },
7510
+ lastYear: {
7511
+ key: "lastYear",
7512
+ label: "Last year",
7513
+ getValue: (t) => {
7514
+ const y = ref(t).year - 1;
7515
+ return { from: Temporal.PlainDate.from({ year: y, month: 1, day: 1 }), to: Temporal.PlainDate.from({ year: y, month: 12, day: 31 }) };
7516
+ },
7517
+ },
7518
+ };
7519
+ /**
7520
+ * Helper to get presets by their keys.
7521
+ * @example getPresetsByKeysTemporal(['thisWeek', 'past7Days', 'past30Days'])
7522
+ */
7523
+ const getPresetsByKeysTemporal = (keys) => keys.map((key) => PRESET_LIBRARY_TEMPORAL[key]).filter((preset) => preset !== undefined);
7524
+
7525
+ function CwDateRangePickerTemporal({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, maxRangeDays, defaultMonth, labelProps, alignProps, placeholderFrom = "From date", placeholderTo = "To date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 2, locale: locale$1 = locale.enGB, yearRangeStart, yearRangeEnd, showPresets = false, presetKeys, customPresets, }) {
7526
+ const [isOpen, setIsOpen] = React.useState(false);
7527
+ const [inputFromValue, setInputFromValue] = React.useState("");
7528
+ const [inputToValue, setInputToValue] = React.useState("");
7529
+ const [rangeErrorMessage, setRangeErrorMessage] = React.useState(null);
7530
+ const [focusedInput, setFocusedInput] = React.useState();
7531
+ const containerRef = React.useRef(null);
7532
+ const wrapperRef = React.useRef(null);
7533
+ const inputFromRef = React.useRef(null);
7534
+ const inputToRef = React.useRef(null);
7535
+ const prevValueRef = React.useRef(undefined);
7536
+ const prevDisplayFormatRef = React.useRef(displayFormat);
7537
+ const rangeError = React.useCallback(() => (maxRangeDays ? `Range cannot exceed ${maxRangeDays} days` : "Invalid date range"), [maxRangeDays]);
7538
+ const handleClose = React.useCallback(() => {
7539
+ setIsOpen(false);
7540
+ setFocusedInput(undefined);
7541
+ }, []);
7542
+ const { popupRef, popupStyle, renderPopup } = usePickerPopup({
7543
+ anchorRef: wrapperRef,
7544
+ isOpen,
7545
+ onClose: handleClose,
7546
+ position: popupPosition,
7547
+ });
7548
+ // Calculate presets to render
7549
+ const presetsToRender = React.useMemo(() => {
7550
+ let presets = [];
7551
+ if (presetKeys && presetKeys.length > 0) {
7552
+ presets = getPresetsByKeysTemporal(presetKeys);
7553
+ }
7554
+ if (customPresets && customPresets.length > 0) {
7555
+ presets = [...presets, ...customPresets];
7556
+ }
7557
+ return presets;
7558
+ }, [presetKeys, customPresets]);
7559
+ // Validate date range
7560
+ const validateRange = React.useCallback((from, to) => {
7561
+ if (!from || !to)
7562
+ return true; // Partial ranges are OK during selection
7563
+ if (Temporal.PlainDate.compare(from, to) > 0)
7564
+ return false;
7565
+ if (maxRangeDays) {
7566
+ const daysDiff = from.until(to, { largestUnit: "day" }).days;
7567
+ if (daysDiff > maxRangeDays)
7568
+ return false;
7569
+ }
7570
+ return true;
7571
+ }, [maxRangeDays]);
7572
+ // Sync input values with prop value
7573
+ React.useEffect(() => {
7574
+ const currentFrom = value?.from?.toString();
7575
+ const currentTo = value?.to?.toString();
7576
+ const prevFrom = prevValueRef.current?.from;
7577
+ const prevTo = prevValueRef.current?.to;
7578
+ if (currentFrom !== prevFrom ||
7579
+ currentTo !== prevTo ||
7580
+ prevDisplayFormatRef.current !== displayFormat) {
7581
+ prevValueRef.current = { from: currentFrom, to: currentTo };
7582
+ prevDisplayFormatRef.current = displayFormat;
7583
+ setInputFromValue(value?.from ? formatPlainDate(value.from, displayFormat) : "");
7584
+ setInputToValue(value?.to ? formatPlainDate(value.to, displayFormat) : "");
7585
+ }
7586
+ }, [value, displayFormat]);
7587
+ const handleRangeSelect = React.useCallback((range, selectedDay) => {
7588
+ const selected = jsDateToPlainDate(selectedDay);
7589
+ let newRange;
7590
+ if (focusedInput === 'from') {
7591
+ newRange = { from: selected, to: value?.to };
7592
+ if (newRange.to && Temporal.PlainDate.compare(selected, newRange.to) > 0) {
7593
+ newRange.to = undefined;
7594
+ setFocusedInput('to');
7595
+ setRangeErrorMessage(null);
7596
+ }
7597
+ else if (newRange.to) {
7598
+ if (!validateRange(newRange.from, newRange.to)) {
7599
+ setRangeErrorMessage(rangeError());
7600
+ return;
7601
+ }
7602
+ setRangeErrorMessage(null);
7603
+ setIsOpen(false);
7604
+ setFocusedInput(undefined);
7605
+ }
7606
+ else {
7607
+ setFocusedInput('to');
7608
+ setRangeErrorMessage(null);
7609
+ }
7610
+ }
7611
+ else if (focusedInput === 'to') {
7612
+ newRange = { from: value?.from, to: selected };
7613
+ if (newRange.from && Temporal.PlainDate.compare(selected, newRange.from) < 0) {
7614
+ newRange.from = undefined;
7615
+ setFocusedInput('from');
7616
+ setRangeErrorMessage(null);
7617
+ }
7618
+ else if (newRange.from) {
7619
+ if (!validateRange(newRange.from, newRange.to)) {
7620
+ setRangeErrorMessage(rangeError());
7621
+ return;
7622
+ }
7623
+ setRangeErrorMessage(null);
7624
+ setIsOpen(false);
7625
+ setFocusedInput(undefined);
7626
+ }
7627
+ else {
7628
+ setFocusedInput('from');
7629
+ setRangeErrorMessage(null);
7630
+ }
7631
+ }
7632
+ else {
7633
+ if (!range) {
7634
+ onChange(undefined);
7635
+ return;
7636
+ }
7637
+ newRange = {
7638
+ from: range.from ? jsDateToPlainDate(range.from) : undefined,
7639
+ to: range.to ? jsDateToPlainDate(range.to) : undefined,
7640
+ };
7641
+ if (range.from && range.to) {
7642
+ if (!validateRange(newRange.from, newRange.to)) {
7643
+ setRangeErrorMessage(rangeError());
7644
+ return;
7645
+ }
7646
+ setRangeErrorMessage(null);
7647
+ setIsOpen(false);
7648
+ setFocusedInput(undefined);
7649
+ }
7650
+ else if (range.from) {
7651
+ setFocusedInput('to');
7652
+ setRangeErrorMessage(null);
7653
+ }
7654
+ else {
7655
+ setFocusedInput('from');
7656
+ setRangeErrorMessage(null);
7657
+ }
7658
+ }
7659
+ onChange(newRange);
7660
+ }, [onChange, validateRange, value, focusedInput, rangeError]);
7661
+ const handleClearFrom = React.useCallback((e) => {
7662
+ e.stopPropagation();
7663
+ onChange({ from: undefined, to: value?.to });
7664
+ setInputFromValue("");
7665
+ }, [onChange, value]);
7666
+ const handleClearTo = React.useCallback((e) => {
7667
+ e.stopPropagation();
7668
+ onChange({ from: value?.from, to: undefined });
7669
+ setInputToValue("");
7670
+ }, [onChange, value]);
7671
+ const handleInputFromClick = React.useCallback(() => {
7672
+ if (!disabled) {
7673
+ setIsOpen(true);
7674
+ setFocusedInput('from');
7675
+ }
7676
+ }, [disabled]);
7677
+ const handleInputToClick = React.useCallback(() => {
7678
+ if (!disabled) {
7679
+ setIsOpen(true);
7680
+ setFocusedInput('to');
7681
+ }
7682
+ }, [disabled]);
7683
+ const handleInputFromChange = React.useCallback((e) => {
7684
+ const newValue = e.currentTarget.value;
7685
+ setInputFromValue(newValue);
7686
+ const parsed = parseDate(newValue, displayFormat);
7687
+ if (parsed) {
7688
+ if (validate(parsed, minDate, maxDate) && validateRange(parsed, value?.to)) {
7689
+ onChange({ from: parsed, to: value?.to });
7690
+ }
7691
+ }
7692
+ else if (newValue === "") {
7693
+ onChange({ from: undefined, to: value?.to });
7694
+ }
7695
+ }, [displayFormat, minDate, maxDate, validateRange, onChange, value]);
7696
+ const handleInputToChange = React.useCallback((e) => {
7697
+ const newValue = e.currentTarget.value;
7698
+ setInputToValue(newValue);
7699
+ const parsed = parseDate(newValue, displayFormat);
7700
+ if (parsed) {
7701
+ if (validate(parsed, minDate, maxDate) && validateRange(value?.from, parsed)) {
7702
+ onChange({ from: value?.from, to: parsed });
7703
+ }
7704
+ }
7705
+ else if (newValue === "") {
7706
+ onChange({ from: value?.from, to: undefined });
7707
+ }
7708
+ }, [displayFormat, minDate, maxDate, validateRange, onChange, value]);
7709
+ const handleInputBlur = React.useCallback((type) => {
7710
+ const inputValue = type === 'from' ? inputFromValue : inputToValue;
7711
+ const currentValue = type === 'from' ? value?.from : value?.to;
7712
+ const trimmed = inputValue?.trim();
7713
+ if (trimmed) {
7714
+ const parsed = parseDate(trimmed, displayFormat);
7715
+ if (parsed && validate(parsed, minDate, maxDate)) {
7716
+ const newRange = type === 'from'
7717
+ ? { from: parsed, to: value?.to }
7718
+ : { from: value?.from, to: parsed };
7719
+ if (validateRange(newRange.from, newRange.to)) {
7720
+ onChange(newRange);
7721
+ if (type === 'from') {
7722
+ setInputFromValue(formatPlainDate(parsed, displayFormat));
7723
+ }
7724
+ else {
7725
+ setInputToValue(formatPlainDate(parsed, displayFormat));
7726
+ }
7727
+ return;
7728
+ }
7729
+ }
7730
+ }
7731
+ // Reset to current value if invalid
7732
+ if (type === 'from') {
7733
+ setInputFromValue(currentValue ? formatPlainDate(currentValue, displayFormat) : "");
7734
+ }
7735
+ else {
7736
+ setInputToValue(currentValue ? formatPlainDate(currentValue, displayFormat) : "");
7737
+ }
7738
+ }, [inputFromValue, inputToValue, value, displayFormat, minDate, maxDate, validateRange, onChange]);
7739
+ const handleInputKeyDown = React.useCallback((e, type) => {
7740
+ if (e.key === "Enter") {
7741
+ e.preventDefault();
7742
+ if (type === 'from') {
7743
+ inputFromRef.current?.blur();
7744
+ inputToRef.current?.focus();
7745
+ }
7746
+ else {
7747
+ inputToRef.current?.blur();
7748
+ setIsOpen(false);
7749
+ }
7750
+ }
7751
+ else if (e.key === "Escape") {
7752
+ setIsOpen(false);
7753
+ if (type === 'from') {
7754
+ inputFromRef.current?.blur();
7755
+ }
7756
+ else {
7757
+ inputToRef.current?.blur();
7758
+ }
7759
+ }
7760
+ }, []);
7761
+ // Handle preset click
7762
+ const handlePresetClick = React.useCallback((preset, e) => {
7763
+ e.preventDefault();
7764
+ e.stopPropagation();
7765
+ const nextRange = preset.getValue();
7766
+ if (!validate(nextRange.from, minDate, maxDate) ||
7767
+ !validate(nextRange.to, minDate, maxDate) ||
7768
+ !validateRange(nextRange.from, nextRange.to)) {
7769
+ setRangeErrorMessage(rangeError());
7770
+ return;
7771
+ }
7772
+ setRangeErrorMessage(null);
7773
+ onChange(nextRange);
7774
+ setIsOpen(false);
7775
+ }, [maxDate, minDate, onChange, rangeError, validateRange]);
7776
+ // Derive start/end months for the year dropdown range, guarding against inverted yearRange props
7777
+ const dropdownStartMonth = React.useMemo(() => {
7778
+ const inferredStart = minDate ? minDate.year : Temporal.Now.plainDateISO().year - 10;
7779
+ const inferredEnd = yearRangeEnd ?? (maxDate ? maxDate.year : Temporal.Now.plainDateISO().year + 5);
7780
+ const year = Math.min(yearRangeStart ?? inferredStart, inferredEnd);
7781
+ return new Date(year, 0, 1);
7782
+ }, [yearRangeStart, yearRangeEnd, minDate, maxDate]);
7783
+ const dropdownEndMonth = React.useMemo(() => {
7784
+ const inferredEnd = maxDate ? maxDate.year : Temporal.Now.plainDateISO().year + 5;
7785
+ const inferredStart = yearRangeStart ?? (minDate ? minDate.year : Temporal.Now.plainDateISO().year - 10);
7786
+ const year = Math.max(yearRangeEnd ?? inferredEnd, inferredStart);
7787
+ return new Date(year, 11, 31);
7788
+ }, [yearRangeStart, yearRangeEnd, minDate, maxDate]);
7789
+ // Memoize disabled days (convert Temporal → Date for DayPicker)
7790
+ const disabledDays = React.useMemo(() => {
7791
+ const baseDisabled = [
7792
+ ...(disabledDates?.map(plainDateToJsDate) || []),
7793
+ ...(minDate ? [{ before: plainDateToJsDate(minDate) }] : []),
7794
+ ...(maxDate ? [{ after: plainDateToJsDate(maxDate) }] : []),
7795
+ ...(disabledMatcher ? [disabledMatcher] : []),
7796
+ ];
7797
+ // If maxRangeDays is set and we have a "from" date, disable dates beyond the range
7798
+ if (maxRangeDays) {
7799
+ if (value?.from) {
7800
+ const maxAllowedDate = value.from.add({ days: maxRangeDays });
7801
+ if (focusedInput !== 'from') {
7802
+ baseDisabled.push({ after: plainDateToJsDate(maxAllowedDate) });
7803
+ }
7804
+ if (focusedInput === 'to' && !value?.to) {
7805
+ const minAllowedDate = value.from.subtract({ days: maxRangeDays });
7806
+ baseDisabled.push({ before: plainDateToJsDate(minAllowedDate) });
7807
+ }
7808
+ }
7809
+ if (value?.to && !value?.from && focusedInput === 'from') {
7810
+ const minAllowedDate = value.to.subtract({ days: maxRangeDays });
7811
+ baseDisabled.push({ before: plainDateToJsDate(minAllowedDate) });
7812
+ }
7813
+ }
7814
+ return baseDisabled;
7815
+ }, [disabledDates, minDate, maxDate, disabledMatcher, maxRangeDays, value, focusedInput]);
7816
+ const selectedRange = React.useMemo(() => {
7817
+ if (value?.from || value?.to) {
7818
+ return {
7819
+ from: value?.from ? plainDateToJsDate(value.from) : undefined,
7820
+ to: value?.to ? plainDateToJsDate(value.to) : undefined,
7821
+ };
7822
+ }
7823
+ return undefined;
7824
+ }, [value]);
7825
+ const defaultMonthJsDate = defaultMonth
7826
+ ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
7827
+ : (value?.from ? plainDateToJsDate(value.from) : undefined);
7828
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxRuntime.jsxs("div", { className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, required: required, "data-focused": focusedInput === 'from' }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) })] }), jsxRuntime.jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxRuntime.jsxs("div", { className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, required: required, "data-focused": focusedInput === 'to' }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxRuntime.jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsxRuntime.jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsxRuntime.jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7829
+ today: new Date(),
7830
+ }, modifiersClassNames: {
7831
+ today: "rdp-day-today",
7832
+ } })] }), jsxRuntime.jsx("div", { role: "alert", "aria-live": "polite", className: rangeStyles.rangeError, children: rangeErrorMessage })] }))] })] }) }));
7833
+ }
7834
+
7113
7835
  const ResourcesTitleList = ({ resources, canBePinned, includesPinned, onCrewPinning, onClickResourceContextMenu, ResourceTitleComponent, }) => {
7114
7836
  const onClickContextMenu = React.useCallback((key, resource) => {
7115
7837
  if (onClickResourceContextMenu) {
@@ -9602,13 +10324,13 @@ const PinRowHeader = ({ value, width, onEvent }) => {
9602
10324
  jsxRuntime.jsxs("span", { className: styles["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxRuntime.jsxs("span", { children: ["-", value.subtitle2] })] })] }), isLoading ? jsxRuntime.jsx("span", { className: "cwi-icons cwi-spinner" }) : undefined] }) }, value.rowId) }, value.rowId);
9603
10325
  };
9604
10326
 
9605
- const SuperScheduler = ({ id, state, header, rows, events, headerColumnComp, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75, rowHeaderWidth, maxEventHeightRem, }) => {
10327
+ const SuperScheduler = ({ id, state, header, rows, events, headerColumnComp, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75, rowHeaderWidth, maxEventHeightRem, EventComp = SchedulerEvent, }) => {
9606
10328
  const pinnedRows = rows.filter((it) => it.isPinned);
9607
10329
  const notPinnedRows = rows.filter((it) => !it.isPinned);
9608
10330
  const isFirstVisible = pinnedRows.length > 0;
9609
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFirstVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Scheduler, { id: `${id}-pinned`, state: state, header: header, rows: pinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: pinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: headerColumnComp, rowHeightRem: rowHeightRem, rowHeaderWidth: rowHeaderWidth, maxEventHeightRem: maxEventHeightRem }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
10331
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFirstVisible && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Scheduler, { id: `${id}-pinned`, state: state, header: header, rows: pinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: pinnedOrderCategory, onEvent: onEvent, EventComp: EventComp, RowTitleComp: headerColumnComp, rowHeightRem: rowHeightRem, rowHeaderWidth: rowHeaderWidth, maxEventHeightRem: maxEventHeightRem }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
9610
10332
  onEvent(new OnClearPinned());
9611
- }, children: "Clear pinned" }) })] })), jsxRuntime.jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: headerColumnComp, rowHeightRem: rowHeightRem, rowHeaderWidth: rowHeaderWidth, maxEventHeightRem: maxEventHeightRem })] }));
10333
+ }, children: "Clear pinned" }) })] })), jsxRuntime.jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: EventComp, RowTitleComp: headerColumnComp, rowHeightRem: rowHeightRem, rowHeaderWidth: rowHeaderWidth, maxEventHeightRem: maxEventHeightRem })] }));
9612
10334
  };
9613
10335
 
9614
10336
  /**
@@ -10067,6 +10789,7 @@ exports.CwContextMenu = CwContextMenu;
10067
10789
  exports.CwDatePicker = CwDatePicker;
10068
10790
  exports.CwDatePickerTemporal = CwDatePickerTemporal;
10069
10791
  exports.CwDateRangePicker = CwDateRangePicker;
10792
+ exports.CwDateRangePickerTemporal = CwDateRangePickerTemporal;
10070
10793
  exports.CwDateTimePicker = CwDateTimePicker;
10071
10794
  exports.CwDateTimePickerCompact = CwDateTimePickerCompact;
10072
10795
  exports.CwDialog = CwDialog;
@@ -10111,6 +10834,7 @@ exports.CwOption = CwOption;
10111
10834
  exports.CwPopoverButton = CwPopoverButton;
10112
10835
  exports.CwReportModal = CwReportModal;
10113
10836
  exports.CwScheduler = CwScheduler;
10837
+ exports.CwSearchAsync = CwSearchAsync;
10114
10838
  exports.CwSearchInput = CwSearchInput;
10115
10839
  exports.CwSelect = CwSelect;
10116
10840
  exports.CwSelectList = CwSelectList;
@@ -10153,6 +10877,7 @@ exports.OnRightClickRow = OnRightClickRow;
10153
10877
  exports.OnRightDragStart = OnRightDragStart;
10154
10878
  exports.OnStartClickHeaderEvent = OnStartClickHeaderEvent;
10155
10879
  exports.OnUnpinRow = OnUnpinRow;
10880
+ exports.PRESET_LIBRARY_TEMPORAL = PRESET_LIBRARY_TEMPORAL;
10156
10881
  exports.PinRowHeader = PinRowHeader;
10157
10882
  exports.Resource = Resource;
10158
10883
  exports.Scheduler = Scheduler;
@@ -10166,6 +10891,7 @@ exports.eventIsVisible = eventIsVisible;
10166
10891
  exports.filterVisibleEvents = filterVisibleEvents;
10167
10892
  exports.getDefaultDivisions = getDefaultDivisions;
10168
10893
  exports.getEventSizes = getEventSizes;
10894
+ exports.getPresetsByKeysTemporal = getPresetsByKeysTemporal;
10169
10895
  exports.itemsToMultiFilterTags = itemsToMultiFilterTags;
10170
10896
  exports.useCwMessage = useCwMessage;
10171
10897
  exports.useSortableList = useSortableList;