@cwellt_software/cwellt-reactjs-lib 1.4.7 → 1.4.9

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
@@ -1641,48 +1641,6 @@ const CwModalHover = ({ children, hovereable, onFirstOpened, ...dialogProps }) =
1641
1641
  }, children: children })] }));
1642
1642
  };
1643
1643
 
1644
- class CwDialogManager {
1645
- static openDialogs = new Map();
1646
- static OpenDialog(id, props) {
1647
- if (!CwDialogManager.openDialogs.has(id)) {
1648
- const container = document.createElement("div");
1649
- document.body.appendChild(container);
1650
- const root = client.createRoot(container);
1651
- root.render(jsxRuntime.jsx(CwDialog, { ...props }));
1652
- CwDialogManager.openDialogs.set(id, { props, container });
1653
- }
1654
- }
1655
- static CloseDialog(id) {
1656
- const dialog = CwDialogManager.openDialogs.get(id);
1657
- if (dialog) {
1658
- const root = client.createRoot(dialog.container);
1659
- root.unmount();
1660
- dialog.container.remove();
1661
- CwDialogManager.openDialogs.delete(id);
1662
- }
1663
- }
1664
- static CloseAllDialogs() {
1665
- CwDialogManager.openDialogs.forEach((_dialog, id) => {
1666
- CwDialogManager.CloseDialog(id);
1667
- });
1668
- }
1669
- static CloseLastDialog() {
1670
- const lastDialogId = Array.from(CwDialogManager.openDialogs.keys()).pop();
1671
- if (lastDialogId) {
1672
- CwDialogManager.CloseDialog(lastDialogId);
1673
- }
1674
- }
1675
- static CloseFirstDialog() {
1676
- const firstDialogId = Array.from(CwDialogManager.openDialogs.keys())[0];
1677
- if (firstDialogId) {
1678
- CwDialogManager.CloseDialog(firstDialogId);
1679
- }
1680
- }
1681
- static GetOpenDialogCount() {
1682
- return CwDialogManager.openDialogs.size;
1683
- }
1684
- }
1685
-
1686
1644
  /**
1687
1645
  * General purpose aligner flex container, useful for column or row view.
1688
1646
  * @remarks
@@ -1838,14 +1796,16 @@ function CwOption(props) {
1838
1796
  * </CwSelect>
1839
1797
  */
1840
1798
  function CwSelect(props) {
1841
- const { alignProps, labelProps, buttonProps, iconProps, placeholder, feedback, children, style, className, ...selectProps } = props;
1799
+ const { alignProps, labelProps, buttonProps, iconProps, placeholder, feedback, handleChange, children, style, className, ...selectProps } = props;
1842
1800
  const feedbackMessages = feedback
1843
1801
  ? Array.isArray(feedback) ? feedback : [feedback]
1844
1802
  : [];
1845
1803
  const flexDirection = alignProps?.flexDirection ?? "row";
1846
1804
  const dataDirection = { 'data-direction': flexDirection };
1847
1805
  const { backgroundColor, color: textColor, ...wrapperStyle } = style ?? {};
1848
- return (jsxRuntime.jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: wrapperStyle, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxRuntime.jsxs("select", { ...selectProps, style: backgroundColor ? { backgroundColor, color: textColor } : undefined, children: [placeholder && jsxRuntime.jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
1806
+ return (jsxRuntime.jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: wrapperStyle, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxRuntime.jsxs("select", { ...selectProps, style: backgroundColor ? { backgroundColor, color: textColor } : undefined, onChange: handleChange
1807
+ ? (e) => { handleChange(e.currentTarget.value); selectProps.onChange?.(e); }
1808
+ : selectProps.onChange, children: [placeholder && jsxRuntime.jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
1849
1809
  }
1850
1810
 
1851
1811
  function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, emptyState, sortOptions = [], defaultSortKey, keyExtractor, ...htmlProps }) {
@@ -3542,237 +3502,6 @@ function CwTextArea(props) {
3542
3502
  return (jsxRuntime.jsxs("div", { className: "cw-text-area", ...dataDirection, style: style, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsx("textarea", { ...textareaProps, itemProp: textareaProps.required === true ? "required" : "", style: { resize: resize } }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
3543
3503
  }
3544
3504
 
3545
- /**
3546
- * Input for entering a string of text.
3547
- * @remarks
3548
- * ```txt
3549
- * CwIcon CwLabel input type=date CwButton
3550
- * ↑ ↑ ↑ ↑
3551
- * ╭────────────────────╮╭════╮
3552
- * ⌂ Birthdate │ 0000 / 00 / 00 │║ Ok ║
3553
- * ╰────────────────────╯╰════╯
3554
- * ```
3555
- * @example
3556
- * ```tsx
3557
- * <CwInputDate
3558
- * iconProps={{ iconId: "Birthdate" }}
3559
- * labelProps={{ children: "Name", width: "100px" }}
3560
- * buttonProps={{ children: "Ok", onClick:()=>{alert("happy happy joy joy")} }}
3561
- * />
3562
- * ```
3563
- */
3564
- function CwInputDate(props) {
3565
- const { alignProps, buttonProps, iconProps, labelProps, ...inputProps } = props;
3566
- inputProps.max = inputProps.max ?? "9999-01-01";
3567
- return (jsxRuntime.jsx("div", { className: "cw-input-date", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsx("input", { type: "date", ...inputProps }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3568
- }
3569
-
3570
- var classes = {"datePicker":"cw-input-date-picker-module__datePicker__jogOq","input":"cw-input-date-picker-module__input__uQshH","calendar":"cw-input-date-picker-module__calendar__q39ic","calendarHeader":"cw-input-date-picker-module__calendarHeader__1btPK","arrowButton":"cw-input-date-picker-module__arrowButton__23tNc","calendarTitle":"cw-input-date-picker-module__calendarTitle__oOODw","calendarBody":"cw-input-date-picker-module__calendarBody__-711a","calendarDay":"cw-input-date-picker-module__calendarDay__z-Mmv","selected":"cw-input-date-picker-module__selected__XQgR7","todayButton":"cw-input-date-picker-module__todayButton__oYamC","emptyDay":"cw-input-date-picker-module__emptyDay__lbI5B"};
3571
-
3572
- /**
3573
- * Converts a Date or ISO string to a Temporal.PlainDate.
3574
- */
3575
- function toPlainDate$1(dateString) {
3576
- if (dateString instanceof Date) {
3577
- return Temporal.PlainDate.from({
3578
- year: dateString.getFullYear(),
3579
- month: dateString.getMonth() + 1,
3580
- day: dateString.getDate(),
3581
- });
3582
- }
3583
- // ISO "YYYY-MM-DD" → direct parse
3584
- return Temporal.PlainDate.from(dateString);
3585
- }
3586
- /**
3587
- * Formats a date as DD.MM.YYYY (German locale).
3588
- */
3589
- function toGermanDate(dateString) {
3590
- const pd = toPlainDate$1(dateString);
3591
- const day = String(pd.day).padStart(2, "0");
3592
- const month = String(pd.month).padStart(2, "0");
3593
- return `${day}.${month}.${pd.year}`;
3594
- }
3595
- /**
3596
- * Formats a date as YYYY-MM-DD (ISO).
3597
- */
3598
- function toISODate(dateString) {
3599
- return toPlainDate$1(dateString).toString();
3600
- }
3601
- /**
3602
- * Validates whether a string is a valid DD.MM.YYYY date.
3603
- */
3604
- function isValidGermanDate(textDate) {
3605
- return parseGermanDate(textDate) !== null;
3606
- }
3607
- /**
3608
- * Converts a DD.MM.YYYY string to YYYY-MM-DD, or null if invalid.
3609
- */
3610
- function germanDateToISO(textDate) {
3611
- const pd = parseGermanDate(textDate);
3612
- return pd ? pd.toString() : null;
3613
- }
3614
- /**
3615
- * Converts a DD.MM.YYYY string to a Date object, or null if invalid.
3616
- */
3617
- function germanDateToDate(textDate) {
3618
- const pd = parseGermanDate(textDate);
3619
- if (!pd)
3620
- return null;
3621
- return new Date(pd.year, pd.month - 1, pd.day);
3622
- }
3623
- /**
3624
- * Returns the number of days in the month and the Monday-based
3625
- * weekday offset (0 = Monday) for the 1st of the month.
3626
- */
3627
- function computeCalendarGrid(internalDate) {
3628
- const pd = Temporal.PlainDate.from({
3629
- year: internalDate.getFullYear(),
3630
- month: internalDate.getMonth() + 1,
3631
- day: 1,
3632
- });
3633
- const daysInMonth = pd.daysInMonth;
3634
- const startDay = pd.dayOfWeek - 1; // Temporal: 1=Mon … 7=Sun → 0-based Mon
3635
- return { daysInMonth, startDay };
3636
- }
3637
- /**
3638
- * Returns true when the given day in the internalDate's month/year
3639
- * matches the selected ISO value string.
3640
- */
3641
- function isSelectedDay(internalDate, day, value) {
3642
- const pd = Temporal.PlainDate.from({
3643
- year: internalDate.getFullYear(),
3644
- month: internalDate.getMonth() + 1,
3645
- day,
3646
- });
3647
- return pd.toString() === value;
3648
- }
3649
- /**
3650
- * Returns a new Date set to the 1st of the month offset by `direction` months.
3651
- */
3652
- function computeNextMonthDate(currentDate, direction) {
3653
- const pd = Temporal.PlainDate.from({
3654
- year: currentDate.getFullYear(),
3655
- month: currentDate.getMonth() + 1,
3656
- day: 1,
3657
- });
3658
- const moved = pd.add({ months: direction });
3659
- return new Date(moved.year, moved.month - 1, moved.day);
3660
- }
3661
- // ── internal helper ────────────────────────────────────────────────────
3662
- /**
3663
- * Strictly parses a DD.MM.YYYY string into a Temporal.PlainDate, or null.
3664
- */
3665
- function parseGermanDate(text) {
3666
- const match = /^(\d{2})\.(\d{2})\.(\d{4})$/.exec(text);
3667
- if (!match)
3668
- return null;
3669
- const day = Number(match[1]);
3670
- const month = Number(match[2]);
3671
- const year = Number(match[3]);
3672
- try {
3673
- return Temporal.PlainDate.from({ year, month, day }, { overflow: "reject" });
3674
- }
3675
- catch {
3676
- return null;
3677
- }
3678
- }
3679
-
3680
- const CwInputDatePicker = ({ value, onChange }) => {
3681
- const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
3682
- const [internalDate, setInternalDate] = React.useState(new Date(value || new Date().toISOString()));
3683
- const [textDate, setTextDate] = React.useState(toGermanDate(value));
3684
- const inputRef = React.useRef(null);
3685
- const calendarRef = React.useRef(null);
3686
- React.useEffect(() => {
3687
- const handleClickOutside = (event) => {
3688
- if (calendarRef.current &&
3689
- !calendarRef.current.contains(event.target) &&
3690
- inputRef.current &&
3691
- !inputRef.current.contains(event.target)) {
3692
- setIsCalendarOpen(false);
3693
- }
3694
- };
3695
- document.addEventListener("mousedown", handleClickOutside);
3696
- return () => {
3697
- document.removeEventListener("mousedown", handleClickOutside);
3698
- };
3699
- }, []);
3700
- React.useEffect(() => {
3701
- setTextDate(toGermanDate(value));
3702
- }, [value]);
3703
- const submitInput = () => {
3704
- if (isValidGermanDate(textDate)) {
3705
- const newDateString = germanDateToISO(textDate);
3706
- const newDate = germanDateToDate(textDate);
3707
- if (newDateString && newDate) {
3708
- if (newDateString !== value) {
3709
- setInternalDate(newDate);
3710
- onChange?.(newDateString);
3711
- }
3712
- setIsCalendarOpen(false);
3713
- return true;
3714
- }
3715
- else {
3716
- console.error("Invalid date format");
3717
- return false;
3718
- }
3719
- }
3720
- else {
3721
- setTextDate(toGermanDate(new Date(value)));
3722
- return false;
3723
- }
3724
- };
3725
- const handleClickToday = () => {
3726
- const today = toISODate(new Date());
3727
- const currentDate = value;
3728
- if (currentDate != today) {
3729
- setTextDate(toGermanDate(today));
3730
- setInternalDate(new Date(today));
3731
- onChange?.(today);
3732
- }
3733
- setIsCalendarOpen(false);
3734
- };
3735
- const handleClickDay = (day) => {
3736
- const newDate = new Date(internalDate.getFullYear(), internalDate.getMonth(), day);
3737
- const newDateString = toISODate(newDate);
3738
- if (newDateString !== value) {
3739
- setTextDate(toGermanDate(newDate));
3740
- setInternalDate(newDate);
3741
- onChange?.(newDateString);
3742
- }
3743
- setIsCalendarOpen(false);
3744
- };
3745
- const handleClickMonthArrow = (direction) => {
3746
- setInternalDate(prevDate => computeNextMonthDate(prevDate, direction));
3747
- };
3748
- const handlePressEnter = (event) => {
3749
- if (event.key === "Enter" && submitInput()) {
3750
- event.currentTarget.blur();
3751
- }
3752
- };
3753
- const handleBlurInput = (event) => {
3754
- if (value != toISODate(internalDate) && submitInput()) {
3755
- event.currentTarget?.blur();
3756
- }
3757
- };
3758
- const generateCalendarDays = () => {
3759
- const { daysInMonth, startDay } = computeCalendarGrid(internalDate);
3760
- const calendarDays = new Array;
3761
- for (let i = 0; i < startDay; i++) {
3762
- calendarDays.push(jsxRuntime.jsx("div", { className: classes.emptyDay }, `empty-${i}`));
3763
- }
3764
- for (let day = 1; day <= daysInMonth; day++) {
3765
- const selected = isSelectedDay(internalDate, day, value);
3766
- calendarDays.push(jsxRuntime.jsx("div", { className: `${classes.calendarDay}${selected ? ` ${classes.selected}` : ""}`, onClick: () => handleClickDay(day), children: day }, day));
3767
- }
3768
- return calendarDays;
3769
- };
3770
- return (jsxRuntime.jsxs("div", { className: classes.datePicker, children: [jsxRuntime.jsx("input", { type: "text", value: textDate, onChange: e => setTextDate(e.currentTarget.value), onFocus: () => {
3771
- setInternalDate(new Date(value));
3772
- setIsCalendarOpen(true);
3773
- }, onBlur: handleBlurInput, onKeyDown: handlePressEnter, "data-valid": isValidGermanDate(textDate), ref: inputRef, className: classes.input }), isCalendarOpen && (jsxRuntime.jsxs("div", { className: classes.calendar, ref: calendarRef, children: [jsxRuntime.jsxs("div", { className: classes.calendarHeader, children: [jsxRuntime.jsx("button", { className: classes.arrowButton, onClick: () => handleClickMonthArrow(-1), children: "<" }), jsxRuntime.jsxs("span", { className: classes.calendarTitle, children: [internalDate.toLocaleString("default", { month: "long" }), " ", internalDate.getFullYear()] }), jsxRuntime.jsx("button", { className: classes.arrowButton, onClick: () => handleClickMonthArrow(1), children: ">" })] }), jsxRuntime.jsx("div", { className: classes.calendarBody, children: generateCalendarDays() }), jsxRuntime.jsx("button", { className: classes.todayButton, onClick: handleClickToday, children: "Today" })] }))] }));
3774
- };
3775
-
3776
3505
  /**
3777
3506
  * Input for entering a string of text.
3778
3507
  * @remarks
@@ -4376,8 +4105,9 @@ function useDropdownPortal({ anchorRef, isOpen, onClose, positionStrategy = defa
4376
4105
  zIndex: 1000,
4377
4106
  right: "auto",
4378
4107
  marginLeft: 0,
4108
+ visibility: "hidden",
4379
4109
  });
4380
- const reposition = React.useCallback(() => {
4110
+ const reposition = React.useCallback((visibility = "visible") => {
4381
4111
  const anchor = anchorRef.current;
4382
4112
  if (!anchor)
4383
4113
  return;
@@ -4392,15 +4122,18 @@ function useDropdownPortal({ anchorRef, isOpen, onClose, positionStrategy = defa
4392
4122
  zIndex: 1000,
4393
4123
  right: "auto",
4394
4124
  marginLeft: 0,
4125
+ visibility,
4395
4126
  });
4396
4127
  }, [anchorRef, positionStrategy]);
4397
- // Reposition when opened; re-measure after first paint to get real panel size
4128
+ // Reposition when opened. First pass is hidden (panel not yet measured), second
4129
+ // pass fires in a RAF with the real panel size and reveals the panel — preventing
4130
+ // the one-frame flicker at top:0/left:0 or at the wrong position.
4398
4131
  React.useEffect(() => {
4399
4132
  if (!isOpen)
4400
4133
  return;
4401
- reposition();
4402
- const raf = requestAnimationFrame(reposition);
4403
- const handleUpdate = () => reposition();
4134
+ reposition("hidden");
4135
+ const raf = requestAnimationFrame(() => reposition("visible"));
4136
+ const handleUpdate = () => reposition("visible");
4404
4137
  window.addEventListener("resize", handleUpdate);
4405
4138
  // Capture phase catches scroll on all scrollable ancestors
4406
4139
  window.addEventListener("scroll", handleUpdate, true);
@@ -4594,18 +4327,50 @@ var styles$a = {"container":"cw-popover-button-module__container__YSWQU","panel"
4594
4327
  function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-start", panelClassName, ...buttonProps }) {
4595
4328
  const containerRef = React.useRef(null);
4596
4329
  const panelRef = React.useRef(null);
4330
+ const isOpenRef = React.useRef(false);
4331
+ const lastToggleClosedAtRef = React.useRef(0);
4332
+ const RECENT_CLOSE_MS = 200;
4597
4333
  const panelCallbackRef = React.useCallback((node) => {
4598
4334
  panelRef.current = node;
4599
4335
  node?.setAttribute("popover", "auto");
4600
4336
  }, []);
4337
+ // Sync isOpenRef with the native popover toggle event so we know the real
4338
+ // open state at the moment handleClick fires (light-dismiss closes on pointerdown,
4339
+ // before the click event, so we can't rely on a React state for this).
4340
+ React.useEffect(() => {
4341
+ const panel = panelRef.current;
4342
+ if (!panel)
4343
+ return;
4344
+ const handler = (e) => {
4345
+ const newState = e.newState;
4346
+ isOpenRef.current = newState === "open";
4347
+ if (newState === "closed") {
4348
+ lastToggleClosedAtRef.current = Date.now();
4349
+ }
4350
+ };
4351
+ panel.addEventListener("toggle", handler);
4352
+ return () => panel.removeEventListener("toggle", handler);
4353
+ }, []);
4601
4354
  const handleClick = React.useCallback(() => {
4602
4355
  const panel = panelRef.current;
4603
4356
  const container = containerRef.current;
4604
4357
  if (!panel || !container)
4605
4358
  return;
4359
+ // Light-dismiss already closed the panel on pointerdown — don't reopen.
4360
+ if (isOpenRef.current)
4361
+ return;
4362
+ if (Date.now() - lastToggleClosedAtRef.current < RECENT_CLOSE_MS)
4363
+ return;
4606
4364
  const rect = container.getBoundingClientRect();
4607
4365
  panel.style.top = `${rect.bottom + 4}px`;
4608
- if (placement === "bottom-start") {
4366
+ // Prefer the requested placement, but flip if the panel would overflow the viewport.
4367
+ const panelWidth = panel.offsetWidth || 240;
4368
+ const spaceOnRight = window.innerWidth - rect.left;
4369
+ const spaceOnLeft = rect.right;
4370
+ const effectivePlacement = placement === "bottom-end" && spaceOnLeft < panelWidth ? "bottom-start" :
4371
+ placement === "bottom-start" && spaceOnRight < panelWidth ? "bottom-end" :
4372
+ placement;
4373
+ if (effectivePlacement === "bottom-start") {
4609
4374
  panel.style.left = `${rect.left}px`;
4610
4375
  panel.style.right = "auto";
4611
4376
  }
@@ -4613,7 +4378,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4613
4378
  panel.style.right = `${window.innerWidth - rect.right}px`;
4614
4379
  panel.style.left = "auto";
4615
4380
  }
4616
- panel.togglePopover();
4381
+ panel.showPopover();
4617
4382
  }, [placement]);
4618
4383
  return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$a.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$a.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4619
4384
  }
@@ -5500,25 +5265,41 @@ const CwContextMenu = ({ children, options, offset = DEFAULT_OFFSET, onSelect })
5500
5265
  };
5501
5266
 
5502
5267
  /**
5503
- * Save button wrapper
5268
+ * Save button wrapper (6 uses pending delete)
5504
5269
  * @deprecated Use <CwButton variant="icon" icon="save" onClick={...} /> instead
5505
5270
  */
5506
5271
  function CwBtnSave({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...rest }) {
5507
- return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "save", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled }));
5272
+ return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "save", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Save" }));
5508
5273
  }
5509
5274
  /**
5510
- * Edit button wrapper
5275
+ * Edit button wrapper (5 uses pending delete)
5511
5276
  * @deprecated Use <CwButton variant="icon" icon="edit" onClick={...} /> instead
5512
5277
  */
5513
5278
  function CwBtnEdit({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...rest }) {
5514
- return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "edit", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled }));
5279
+ return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "edit", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Edit" }));
5515
5280
  }
5516
5281
  /**
5517
- * Delete button wrapper
5282
+ * Delete button wrapper (4 uses pending delete)
5518
5283
  * @deprecated Use <CwButton variant="icon" icon="delete" color="danger" onClick={...} /> instead
5519
5284
  */
5520
5285
  function CwBtnDelete({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...rest }) {
5521
- return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "delete", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled }));
5286
+ return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "delete", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Delete" }));
5287
+ }
5288
+ /**
5289
+ * Approve button wrapper.
5290
+ * DO NOT DELETE — used by Operon (lib pinned at ^1.0.9, currently dormant).
5291
+ * @deprecated Use <CwButton variant="icon" icon="check-circle" onClick={...} /> instead
5292
+ */
5293
+ function CwBtnApprove({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...rest }) {
5294
+ return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "check-circle", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Approve" }));
5295
+ }
5296
+ /**
5297
+ * Cancel button wrapper.
5298
+ * DO NOT DELETE — used by Operon (lib pinned at ^1.0.9, currently dormant).
5299
+ * @deprecated Use <CwButton variant="icon" icon="cancel" color="danger" onClick={...} /> instead
5300
+ */
5301
+ function CwBtnCancel({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...rest }) {
5302
+ return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "cancel", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Cancel" }));
5522
5303
  }
5523
5304
 
5524
5305
  var styles$4 = {"pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
@@ -5765,7 +5546,7 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
5765
5546
  } }), 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)))] }));
5766
5547
  }
5767
5548
 
5768
- var rangeStyles = {"rangeWrapper":"cw-range-picker-module__rangeWrapper__1nIVs","rangePopup":"cw-range-picker-module__rangePopup__E5jd1","presetList":"cw-range-picker-module__presetList__INiLo"};
5549
+ var rangeStyles = {"rangeWrapper":"cw-range-picker-module__rangeWrapper__1nIVs","rangePopup":"cw-range-picker-module__rangePopup__E5jd1","rangeCalendarRow":"cw-range-picker-module__rangeCalendarRow__VTxi0","presetList":"cw-range-picker-module__presetList__INiLo","rangeError":"cw-range-picker-module__rangeError__qHMdi"};
5769
5550
 
5770
5551
  const PRESET_LIBRARY = {
5771
5552
  // === PAST DAYS ===
@@ -6040,6 +5821,7 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6040
5821
  const [isOpen, setIsOpen] = React.useState(false);
6041
5822
  const [inputFromValue, setInputFromValue] = React.useState("");
6042
5823
  const [inputToValue, setInputToValue] = React.useState("");
5824
+ const [rangeErrorMessage, setRangeErrorMessage] = React.useState(null);
6043
5825
  const [focusedInput, setFocusedInput] = React.useState();
6044
5826
  const containerRef = React.useRef(null);
6045
5827
  const wrapperRef = React.useRef(null);
@@ -6164,21 +5946,27 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6164
5946
  }
6165
5947
  }
6166
5948
  }, [value, displayFormat]);
6167
- const handleRangeSelect = React.useCallback((range, // El rango sugerido por react-day-picker
6168
- selectedDay) => {
5949
+ const handleRangeSelect = React.useCallback((range, selectedDay) => {
6169
5950
  let newRange;
6170
5951
  if (focusedInput === 'from') {
6171
5952
  newRange = { from: selectedDay, to: value?.to };
6172
5953
  if (newRange.to && selectedDay > newRange.to) {
6173
5954
  newRange.to = undefined;
6174
5955
  setFocusedInput('to');
5956
+ setRangeErrorMessage(null);
6175
5957
  }
6176
5958
  else if (newRange.to) {
5959
+ if (!validateRange(newRange.from, newRange.to)) {
5960
+ setRangeErrorMessage(maxRangeDays ? `Range cannot exceed ${maxRangeDays} days` : "Invalid date range");
5961
+ return;
5962
+ }
5963
+ setRangeErrorMessage(null);
6177
5964
  setIsOpen(false);
6178
5965
  setFocusedInput(undefined);
6179
5966
  }
6180
5967
  else {
6181
5968
  setFocusedInput('to');
5969
+ setRangeErrorMessage(null);
6182
5970
  }
6183
5971
  }
6184
5972
  else if (focusedInput === 'to') {
@@ -6186,13 +5974,20 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6186
5974
  if (newRange.from && selectedDay < newRange.from) {
6187
5975
  newRange.from = undefined;
6188
5976
  setFocusedInput('from');
5977
+ setRangeErrorMessage(null);
6189
5978
  }
6190
5979
  else if (newRange.from) {
5980
+ if (!validateRange(newRange.from, newRange.to)) {
5981
+ setRangeErrorMessage(maxRangeDays ? `Range cannot exceed ${maxRangeDays} days` : "Invalid date range");
5982
+ return;
5983
+ }
5984
+ setRangeErrorMessage(null);
6191
5985
  setIsOpen(false);
6192
5986
  setFocusedInput(undefined);
6193
5987
  }
6194
5988
  else {
6195
5989
  setFocusedInput('from');
5990
+ setRangeErrorMessage(null);
6196
5991
  }
6197
5992
  }
6198
5993
  else {
@@ -6202,20 +5997,23 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6202
5997
  }
6203
5998
  newRange = { from: range.from, to: range.to };
6204
5999
  if (range.from && range.to) {
6000
+ if (!validateRange(newRange.from, newRange.to)) {
6001
+ setRangeErrorMessage(maxRangeDays ? `Range cannot exceed ${maxRangeDays} days` : "Invalid date range");
6002
+ return;
6003
+ }
6004
+ setRangeErrorMessage(null);
6205
6005
  setIsOpen(false);
6206
6006
  setFocusedInput(undefined);
6207
6007
  }
6208
6008
  else if (range.from) {
6209
6009
  setFocusedInput('to');
6010
+ setRangeErrorMessage(null);
6210
6011
  }
6211
6012
  else {
6212
6013
  setFocusedInput('from');
6014
+ setRangeErrorMessage(null);
6213
6015
  }
6214
6016
  }
6215
- // Validate range before sending
6216
- if (newRange.from && newRange.to && !validateRange(newRange.from, newRange.to)) {
6217
- return;
6218
- }
6219
6017
  onChange(newRange);
6220
6018
  }, [onChange, validateRange, value, focusedInput]);
6221
6019
  const handleClearFrom = React.useCallback((e) => {
@@ -6384,11 +6182,11 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6384
6182
  }
6385
6183
  return undefined;
6386
6184
  }, [value]);
6387
- 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: [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: defaultMonth || value?.from || undefined, modifiers: {
6388
- today: new Date(),
6389
- }, modifiersClassNames: {
6390
- today: "rdp-day-today",
6391
- } })] }))] })] }) }));
6185
+ 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: defaultMonth || value?.from || undefined, modifiers: {
6186
+ today: new Date(),
6187
+ }, modifiersClassNames: {
6188
+ today: "rdp-day-today",
6189
+ } })] }), jsxRuntime.jsx("div", { role: "alert", "aria-live": "polite", className: rangeStyles.rangeError, children: rangeErrorMessage })] }))] })] }) }));
6392
6190
  }
6393
6191
 
6394
6192
  var timeStyles = {"timePickerPopup":"cw-time-picker-module__timePickerPopup__BN63t","timePickerList":"cw-time-picker-module__timePickerList__E88pr","selected":"cw-time-picker-module__selected__qVnfL","hasIcons":"cw-time-picker-module__hasIcons__ZiGUf","notIcons":"cw-time-picker-module__notIcons__3icu1"};
@@ -9792,13 +9590,13 @@ const PinRowHeader = ({ value, width, onEvent }) => {
9792
9590
  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);
9793
9591
  };
9794
9592
 
9795
- const SuperScheduler = ({ id, state, header, rows, events, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75 }) => {
9593
+ const SuperScheduler = ({ id, state, header, rows, events, headerColumnComp, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75 }) => {
9796
9594
  const pinnedRows = rows.filter((it) => it.isPinned);
9797
9595
  const notPinnedRows = rows.filter((it) => !it.isPinned);
9798
9596
  const isFirstVisible = pinnedRows.length > 0;
9799
- 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: PinRowHeader, rowHeightRem: rowHeightRem }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
9597
+ 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 }), jsxRuntime.jsx("div", { children: jsxRuntime.jsx(CwButton, { onClick: () => {
9800
9598
  onEvent(new OnClearPinned());
9801
- }, 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: PinRowHeader, rowHeightRem: rowHeightRem })] }));
9599
+ }, 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 })] }));
9802
9600
  };
9803
9601
 
9804
9602
  /**
@@ -10239,6 +10037,8 @@ exports.CblDragAndDrop = CblDragAndDrop;
10239
10037
  exports.CwAccordionContainer = CwAccordionContainer;
10240
10038
  exports.CwAlign = CwAlign;
10241
10039
  exports.CwAnchoredMenu = CwAnchoredMenu;
10040
+ exports.CwBtnApprove = CwBtnApprove;
10041
+ exports.CwBtnCancel = CwBtnCancel;
10242
10042
  exports.CwBtnDelete = CwBtnDelete;
10243
10043
  exports.CwBtnEdit = CwBtnEdit;
10244
10044
  exports.CwBtnSave = CwBtnSave;
@@ -10258,7 +10058,6 @@ exports.CwDateRangePicker = CwDateRangePicker;
10258
10058
  exports.CwDateTimePicker = CwDateTimePicker;
10259
10059
  exports.CwDateTimePickerCompact = CwDateTimePickerCompact;
10260
10060
  exports.CwDialog = CwDialog;
10261
- exports.CwDialogManager = CwDialogManager;
10262
10061
  exports.CwDigit = CwDigit;
10263
10062
  exports.CwDisplayMessage = CwDisplayMessage;
10264
10063
  exports.CwDropdown = CwDropdown;
@@ -10277,8 +10076,6 @@ exports.CwImageGallery = CwImageGallery;
10277
10076
  exports.CwImageZoom = CwImageZoom;
10278
10077
  exports.CwInput = CwInput;
10279
10078
  exports.CwInputColor = CwInputColor;
10280
- exports.CwInputDate = CwInputDate;
10281
- exports.CwInputDatePicker = CwInputDatePicker;
10282
10079
  exports.CwInputDateText = CwInputDateText;
10283
10080
  exports.CwInputDatetime = CwInputDatetime;
10284
10081
  exports.CwInputImage = CwInputImage;