@cwellt_software/cwellt-reactjs-lib 1.5.2 → 1.5.3

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.
Files changed (58) hide show
  1. package/dist/content/icons/new-cw-icons/css/new-cw-icons.css +6 -0
  2. package/dist/index.cjs.js +258 -83
  3. package/dist/index.css +2 -2
  4. package/dist/index.d.ts +122 -16
  5. package/dist/index.es.js +258 -84
  6. package/dist/src/components/control/action/button/CwButton.d.ts +5 -0
  7. package/dist/src/components/control/action/button/CwButton.d.ts.map +1 -1
  8. package/dist/src/components/control/action/button/CwButtonBadge.d.ts +63 -0
  9. package/dist/src/components/control/action/button/CwButtonBadge.d.ts.map +1 -0
  10. package/dist/src/components/control/choice/checkbox/CwCheckboxGroup.d.ts.map +1 -1
  11. package/dist/src/components/control/choice/checkbox/CwRadioGroup.d.ts.map +1 -1
  12. package/dist/src/components/control/choice/select/CwDropdown.d.ts.map +1 -1
  13. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts.map +1 -1
  14. package/dist/src/components/control/input/digit/CwDigit.d.ts +6 -0
  15. package/dist/src/components/control/input/digit/CwDigit.d.ts.map +1 -1
  16. package/dist/src/components/control/input/new-dates/CwDatePicker.d.ts.map +1 -1
  17. package/dist/src/components/control/input/new-dates/CwDatePickerTemporal.d.ts.map +1 -1
  18. package/dist/src/components/control/input/new-dates/CwDateRangePicker.d.ts.map +1 -1
  19. package/dist/src/components/control/input/new-dates/CwDateRangePickerTemporal.d.ts.map +1 -1
  20. package/dist/src/components/control/input/new-dates/CwTimePicker.d.ts.map +1 -1
  21. package/dist/src/components/control/input/weekday/CwWeekdaySelector.d.ts +16 -44
  22. package/dist/src/components/control/input/weekday/CwWeekdaySelector.d.ts.map +1 -1
  23. package/dist/src/components/control/input/weekday/weekdayNames.d.ts +14 -0
  24. package/dist/src/components/control/input/weekday/weekdayNames.d.ts.map +1 -0
  25. package/dist/src/components/control/input/weekday/weekdays.d.ts +65 -0
  26. package/dist/src/components/control/input/weekday/weekdays.d.ts.map +1 -0
  27. package/dist/src/components/display/graphics/progress/CwProgress.d.ts +3 -1
  28. package/dist/src/components/display/graphics/progress/CwProgress.d.ts.map +1 -1
  29. package/dist/src/components/display/text/badge/CwBadge.d.ts +48 -0
  30. package/dist/src/components/display/text/badge/CwBadge.d.ts.map +1 -0
  31. package/dist/src/components/display/text/badge/badgeContent.d.ts +33 -0
  32. package/dist/src/components/display/text/badge/badgeContent.d.ts.map +1 -0
  33. package/dist/src/components/display/text/tag/CwChip.d.ts +16 -8
  34. package/dist/src/components/display/text/tag/CwChip.d.ts.map +1 -1
  35. package/dist/src/components/layout/tabs/CwTabs.d.ts +7 -1
  36. package/dist/src/components/layout/tabs/CwTabs.d.ts.map +1 -1
  37. package/dist/src/index.d.ts +3 -1
  38. package/dist/src/index.d.ts.map +1 -1
  39. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  40. package/dist/src/playground/pages/CwBadgePage.d.ts +3 -0
  41. package/dist/src/playground/pages/CwBadgePage.d.ts.map +1 -0
  42. package/dist/src/playground/pages/CwChipPage.d.ts +3 -0
  43. package/dist/src/playground/pages/CwChipPage.d.ts.map +1 -0
  44. package/dist/src/playground/pages/CwDigitPage.d.ts +3 -0
  45. package/dist/src/playground/pages/CwDigitPage.d.ts.map +1 -0
  46. package/dist/src/playground/pages/CwWeekdaySelectorPage.d.ts +3 -0
  47. package/dist/src/playground/pages/CwWeekdaySelectorPage.d.ts.map +1 -0
  48. package/dist/src/playground/pages/FormControlLayoutsPage.d.ts +3 -0
  49. package/dist/src/playground/pages/FormControlLayoutsPage.d.ts.map +1 -0
  50. package/dist/src/playground/pages/ProgressPage.d.ts.map +1 -1
  51. package/dist/src/playground/pages/SelectorsPage.d.ts.map +1 -1
  52. package/dist/test/components/control/input/weekday/weekdayNames.test.d.ts +2 -0
  53. package/dist/test/components/control/input/weekday/weekdayNames.test.d.ts.map +1 -0
  54. package/dist/test/components/control/input/weekday/weekdays.test.d.ts +2 -0
  55. package/dist/test/components/control/input/weekday/weekdays.test.d.ts.map +1 -0
  56. package/dist/test/components/display/text/badge/badgeContent.test.d.ts +2 -0
  57. package/dist/test/components/display/text/badge/badgeContent.test.d.ts.map +1 -0
  58. package/package.json +1 -1
package/dist/index.es.js CHANGED
@@ -161,7 +161,7 @@ function getContrastColor(color) {
161
161
  return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
162
162
  }
163
163
 
164
- var styles$x = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
164
+ var styles$y = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
165
165
 
166
166
  // Constants
167
167
  const margin$1 = 16;
@@ -451,7 +451,7 @@ const CwTooltipManager = () => {
451
451
  if (!state.isVisible || !state.content) {
452
452
  return null;
453
453
  }
454
- return createPortal(jsx("div", { ref: tooltipRef, className: styles$x["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
454
+ return createPortal(jsx("div", { ref: tooltipRef, className: styles$y["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
455
455
  top: `${tooltipPosition.top}px`,
456
456
  left: `${tooltipPosition.left}px`,
457
457
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -532,7 +532,7 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
532
532
  useEffect(() => {
533
533
  ensureTooltipManager();
534
534
  }, []);
535
- return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$x["cw-tooltip"], children: children }));
535
+ return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$y["cw-tooltip"], children: children }));
536
536
  };
537
537
 
538
538
  const SVG_ICONS = {
@@ -567,25 +567,31 @@ function CwIcon(props) {
567
567
  /**
568
568
  * CwChip - A simple chip/tag component for displaying labels or categories
569
569
  *
570
+ * The colour comes from `color`; the older `colorScheme` spelling is deprecated but still
571
+ * honoured, and `color` wins when both are passed.
572
+ *
570
573
  * @example
571
- * <CwChip label="Active" colorScheme="success" />
572
- * <CwChip label="High Priority" colorScheme="danger" variant="solid" />
573
- * <CwChip label="Custom" colorScheme="custom" customColor="#8a2be2" />
574
- * <CwChip label="Outlined" colorScheme="info" variant="outline" />
574
+ * <CwChip label="Active" color="success" />
575
+ * <CwChip label="High Priority" color="danger" variant="solid" />
576
+ * <CwChip label="Custom" color="custom" customColor="#8a2be2" />
577
+ * <CwChip label="Outlined" color="info" variant="outline" />
575
578
  * <CwChip label="Removable" closable onClose={() => console.log('closed')} />
576
579
  **/
577
- const CwChip = ({ label, colorScheme = 'info', customColor, variant = 'soft', className = '', closable = false, onClose, icon, style = {}, }) => {
580
+ const CwChip = ({ label, color, colorScheme, customColor, variant = 'soft', className = '', closable = false, onClose, icon, style = {}, }) => {
581
+ const resolvedColor = color ?? colorScheme ?? 'info';
578
582
  // Basic validation
579
583
  if (closable && !onClose) {
580
584
  console.warn('CwChip: onClose prop is required when closable is true');
581
585
  }
582
- // Calculate styles based on colorScheme, customColor and variant
586
+ // One arbitrary colour can only fill two of the four roles, so soft and solid look alike here.
583
587
  const chipStyle = React__default.useMemo(() => {
584
588
  if (customColor) {
585
- // Simply set the CSS custom properties, CSS handles the rest
589
+ const contrast = getContrastColor(customColor);
586
590
  return {
587
- '--chip-accent': customColor,
588
- '--chip-text': getContrastColor(customColor),
591
+ '--accent-light': customColor,
592
+ '--accent-main': customColor,
593
+ '--accent-dark': contrast,
594
+ '--accent-on-main': contrast,
589
595
  ...style
590
596
  };
591
597
  }
@@ -604,7 +610,79 @@ const CwChip = ({ label, colorScheme = 'info', customColor, variant = 'soft', cl
604
610
  className,
605
611
  closable ? 'cw-chip-closable' : '',
606
612
  ].filter(Boolean).join(' ');
607
- return (jsxs("span", { className: chipClassNames, "data-color-scheme": colorScheme, "data-variant": variant, style: chipStyle, children: [icon && jsx(CwIcon, { iconId: icon }), label && jsx("span", { children: label }), closable && (jsx("button", { className: "cw-chip-close-button", onClick: handleClose, "aria-label": "Remove", type: "button", children: jsx("span", { className: "cwi-icons cwi-close" }) }))] }));
613
+ return (jsxs("span", { className: chipClassNames, "data-color": resolvedColor, "data-variant": variant, "data-icon-only": (Boolean(icon) && !label) || undefined, style: chipStyle, children: [icon && jsx(CwIcon, { iconId: icon }), label && jsx("span", { children: label }), closable && (jsx("button", { className: "cw-chip-close-button", onClick: handleClose, "aria-label": "Remove", type: "button", children: jsx("span", { className: "cwi-icons cwi-close" }) }))] }));
614
+ };
615
+
616
+ /**
617
+ * Normalises a raw count into the integer the badge represents: a non-negative whole number.
618
+ * Both the display string and the `showZero` decision derive from this.
619
+ */
620
+ function normalizeBadgeCount(count) {
621
+ return Number.isFinite(count) ? Math.max(0, Math.trunc(count)) : 0;
622
+ }
623
+ /**
624
+ * Formats a badge count into its display string. Both arguments are normalised, `max` with a
625
+ * floor of 1 - below that every non-zero count would overflow.
626
+ *
627
+ * @param count Raw count to display.
628
+ * @param max Highest value shown as a number; anything above renders `"{max}+"`.
629
+ *
630
+ * @example
631
+ * formatBadgeCount(7, 99); // "7"
632
+ * formatBadgeCount(100, 99); // "99+"
633
+ * formatBadgeCount(12, 9); // "9+"
634
+ */
635
+ function formatBadgeCount(count, max) {
636
+ const safeCount = normalizeBadgeCount(count);
637
+ const safeMax = Number.isFinite(max) ? Math.max(1, Math.trunc(max)) : 1;
638
+ return safeCount > safeMax ? `${safeMax}+` : `${safeCount}`;
639
+ }
640
+ /**
641
+ * Resolves the badge's accessibility attributes. A text-less badge with no label is hidden rather
642
+ * than announced as an empty element; the button or tab around it usually names the thing.
643
+ *
644
+ * @param label Caller-supplied accessible name.
645
+ * @param loading Whether the badge is showing its spinner.
646
+ * @param hasText Whether the badge renders a count or content.
647
+ */
648
+ function resolveBadgeAria(label, loading, hasText) {
649
+ if (label) {
650
+ return { role: loading ? 'status' : 'img', 'aria-label': label };
651
+ }
652
+ return hasText ? {} : { 'aria-hidden': 'true' };
653
+ }
654
+
655
+ var styles$x = {"badge":"cw-badge-module__badge__PKlak"};
656
+
657
+ /**
658
+ * CwBadge - the small coloured circle with a number, used for alert and notification counts.
659
+ *
660
+ * Always **in flow** (`inline-flex`); it never positions itself, so overlaying it on an icon
661
+ * button is the caller's job. One digit stays a circle, wider content such as `"99+"` grows into
662
+ * a pill. With neither `count` nor `content` it renders as a dot.
663
+ *
664
+ * Precedence: `loading` > `content` > `count` > dot. While loading the badge renders regardless
665
+ * of `showZero`, and the spinner replaces it - circle, background and padding come off.
666
+ *
667
+ * @example
668
+ * <CwBadge count={3} color="danger" />
669
+ * <CwBadge count={0} showZero={false} />
670
+ * <CwBadge count={128} max={99} color="warning" variant="soft" />
671
+ * <CwBadge color="warning" label="Unresolved findings" />
672
+ * <CwBadge count={0} loading />
673
+ */
674
+ const CwBadge = ({ count, content, color = 'info', variant = 'solid', size = 'small', showZero = true, loading = false, max = 99, label, className = '', style, }) => {
675
+ // null counts as absent, so `content={null}` still renders a dot rather than an empty pill.
676
+ const hasContent = content !== undefined && content !== null;
677
+ if (!loading && !hasContent && count !== undefined && !showZero && normalizeBadgeCount(count) === 0) {
678
+ return null;
679
+ }
680
+ const countText = !hasContent && count !== undefined
681
+ ? formatBadgeCount(count, max)
682
+ : undefined;
683
+ const isDot = !loading && !hasContent && count === undefined;
684
+ const badgeClassNames = ['cw-badge', styles$x.badge, className].filter(Boolean).join(' ');
685
+ return (jsx("span", { className: badgeClassNames, "data-color": color, "data-variant": variant, "data-size": size, "data-loading": loading ? 'true' : undefined, "data-dot": isDot ? 'true' : undefined, ...resolveBadgeAria(label, loading, !loading && (hasContent || countText !== undefined)), style: style, children: loading ? jsx(CwIcon, { iconId: "spinner", size: "small" }) : hasContent ? content : countText }));
608
686
  };
609
687
 
610
688
  const CW_DEFAULT_MESSAGE_DURATION = 2000;
@@ -1058,7 +1136,7 @@ var styles$v = {"progress":"cw-progress-module__progress__d-g2-","value":"cw-pro
1058
1136
  * <CwProgress value={62} label="Import" color="success" />
1059
1137
  * <CwProgress indeterminate label="Uploading" />
1060
1138
  */
1061
- function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'regular', layout = 'row', color = 'primary', monoValue = false, prominent = false }) {
1139
+ function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'regular', layout = 'row', color = 'primary', monoValue = false, prominent = false, className }) {
1062
1140
  const labelId = React__default.useId();
1063
1141
  // Determinate: a missing or non-finite value is treated as 0 (never NaN), then
1064
1142
  // clamped to [0,100] for aria-valuenow and the fill width. Indeterminate has no value.
@@ -1070,7 +1148,7 @@ function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'r
1070
1148
  const valueText = rightLabel ?? (percent !== undefined ? `${percent}%` : '');
1071
1149
  // The un-hashed cw-progress class carries no styles in the library - a stable
1072
1150
  // public hook for exceptional external overrides only.
1073
- const rootClassName = ['cw-progress', styles$v.progress].filter(Boolean).join(' ');
1151
+ const rootClassName = ['cw-progress', styles$v.progress, className].filter(Boolean).join(' ');
1074
1152
  const labelSpan = label ? jsx("span", { className: styles$v.label, id: labelId, children: label }) : null;
1075
1153
  const valueLabel = showValue ? (jsx("span", { className: styles$v.value, "data-mono": monoValue || undefined, children: valueText })) : null;
1076
1154
  return (jsxs("div", { className: rootClassName, "data-layout": layout, "data-size": size, "data-color": color, "data-prominent": prominent || undefined, "data-indeterminate": indeterminate || undefined, children: [layout === 'column' && (labelSpan || valueLabel) && (jsxs("header", { className: styles$v.header, children: [labelSpan, valueLabel] })), layout === 'row' && labelSpan, jsx("div", { className: styles$v.track, role: "progressbar", ...(label && { 'aria-labelledby': labelId }), ...(!indeterminate && percent !== undefined && {
@@ -1226,7 +1304,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1226
1304
  return (jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1227
1305
  };
1228
1306
 
1229
- const CwButton = React__default.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
1307
+ const CwButton = React__default.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", badge, children, ...buttonProps }, ref) {
1230
1308
  // Build CSS classes based on variant and props
1231
1309
  let buttonClass = `cw-button-${variant}`;
1232
1310
  // Add icon class only for icon variant without children
@@ -1239,13 +1317,19 @@ const CwButton = React__default.forwardRef(function CwButton({ text, variant = '
1239
1317
  const tooltipContent = title || (variant === 'icon' && text ? text : undefined);
1240
1318
  const iconElement = icon ? jsx(CwIcon, { iconId: icon }) : null;
1241
1319
  const textElement = text ? jsx("strong", { children: text }) : null;
1320
+ // Overlaid, not content: the `cwi-` condition above deliberately ignores it, so a badge
1321
+ // never suppresses the button's own icon. Size defaulted explicitly, not by spread order,
1322
+ // so `size: undefined` in the object cannot clobber it.
1323
+ const badgeElement = badge
1324
+ ? jsx(CwBadge, { ...badge, size: badge.size ?? (variant === 'icon' ? 'small' : size) })
1325
+ : null;
1242
1326
  // Only emit toggle attributes when `pressed` is defined; otherwise output stays identical to a normal button.
1243
1327
  const pressedProps = pressed !== undefined
1244
1328
  ? { "aria-pressed": pressed, "data-pressed": pressed ? "true" : undefined }
1245
1329
  : {};
1246
- const buttonElement = (jsx("button", { ref: ref, type: "button", className: buttonClass, ...buttonProps, "data-color": color, "data-size": size, ...pressedProps, "aria-label": tooltipContent ?? buttonProps["aria-label"], children: variant === 'icon' ? null : (children ?? (iconPosition === 'right'
1247
- ? jsxs(Fragment, { children: [textElement, iconElement] })
1248
- : jsxs(Fragment, { children: [iconElement, textElement] }))) }));
1330
+ const buttonElement = (jsx("button", { ref: ref, type: "button", className: buttonClass, ...buttonProps, "data-color": color, "data-size": size, "data-has-badge": badge ? "true" : undefined, ...pressedProps, "aria-label": buttonProps["aria-label"] ?? tooltipContent, children: variant === 'icon' ? badgeElement : (jsxs(Fragment, { children: [children ?? (iconPosition === 'right'
1331
+ ? jsxs(Fragment, { children: [textElement, iconElement] })
1332
+ : jsxs(Fragment, { children: [iconElement, textElement] })), badgeElement] })) }));
1249
1333
  return tooltipContent ? (jsx(CwTooltipNew, { content: tooltipContent, position: tooltipPosition, displayInline: true, children: buttonElement })) : (buttonElement);
1250
1334
  });
1251
1335
  CwButton.displayName = "CwButton";
@@ -2634,8 +2718,12 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2634
2718
  }, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2635
2719
  }
2636
2720
 
2637
- var styles$n = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2721
+ var styles$n = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2638
2722
 
2723
+ const BADGE_COLOR_SCHEMES = ['primary', 'danger', 'warning', 'success', 'info', 'neutral'];
2724
+ function isBadgeColorScheme(value) {
2725
+ return BADGE_COLOR_SCHEMES.includes(value);
2726
+ }
2639
2727
  const TabIcon = ({ icon }) => {
2640
2728
  if (!icon)
2641
2729
  return null;
@@ -2684,7 +2772,11 @@ function CwTabs(CwTabsProps) {
2684
2772
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2685
2773
  ? { minWidth: CwTabsProps.tabsListWidth }
2686
2774
  : undefined;
2687
- return (jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$n['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx("span", { className: styles$n['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsx("div", { className: styles$n['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, style: CwTabsProps.contentHeight ? { '--tabs-height': CwTabsProps.contentHeight } : undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2775
+ return (jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$n['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => {
2776
+ const badgeScheme = tab.badgeColor && isBadgeColorScheme(tab.badgeColor) ? tab.badgeColor : undefined;
2777
+ const rawBadgeColor = tab.badgeColor && !badgeScheme ? tab.badgeColor : undefined;
2778
+ return (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, "data-badge-themed": tab.badgeColor ? "true" : undefined, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx(CwBadge, { count: typeof tab.badge === 'number' ? tab.badge : undefined, content: typeof tab.badge === 'string' ? tab.badge : undefined, size: "medium", color: badgeScheme ?? 'primary', variant: badgeScheme ? 'solid' : 'soft', style: rawBadgeColor ? { backgroundColor: rawBadgeColor, color: getContrastColor(rawBadgeColor) } : undefined }))] }, tab.key));
2779
+ }) }), jsx("div", { className: styles$n['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, style: CwTabsProps.contentHeight ? { '--tabs-height': CwTabsProps.contentHeight } : undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2688
2780
  }
2689
2781
 
2690
2782
  /**
@@ -3233,14 +3325,16 @@ function CwInput(CwInputProps) {
3233
3325
  * ```
3234
3326
  */
3235
3327
  function CwDigit(props) {
3236
- const { alignProps, buttonProps, iconProps, labelProps, feedback, ...inputProps } = props;
3328
+ const { alignProps, buttonProps, iconProps, labelProps, feedback, feedbackPosition, ...inputProps } = props;
3237
3329
  const feedbackMessages = feedback
3238
3330
  ? Array.isArray(feedback) ? feedback : [feedback]
3239
3331
  : [];
3240
3332
  const feedbackId = useId();
3241
3333
  const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
3242
3334
  const describedBy = [inputProps["aria-describedby"], ...feedbackIds].filter(Boolean).join(" ") || undefined;
3243
- return (jsxs("div", { className: "cw-input-text", children: [jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsx("input", { type: "number", ...inputProps, "aria-describedby": describedBy }), buttonProps && jsx(CwButton, { ...buttonProps })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-info", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
3335
+ // data-direction drives the feedback indent, which only makes sense under a label column.
3336
+ const flexDirection = alignProps?.flexDirection ?? "row";
3337
+ return (jsxs("div", { className: "cw-input-text", "data-direction": labelProps ? flexDirection : "column", "data-feedback-position": feedbackPosition, children: [jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: "cw-input-button", children: [jsx("input", { type: "number", ...inputProps, "aria-describedby": describedBy }), buttonProps && jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-info", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
3244
3338
  }
3245
3339
 
3246
3340
  var styles$j = {"colorPreview":"cw-color-picker-module__colorPreview__ylJcD","hueBar":"cw-color-picker-module__hueBar__bFhyC","hueBarSlider":"cw-color-picker-module__hueBarSlider__D53IV","colorPickerInteractiveArea":"cw-color-picker-module__colorPickerInteractiveArea__KZFR1","colorArea":"cw-color-picker-module__colorArea__xgpSE","colorAreaOverlay":"cw-color-picker-module__colorAreaOverlay__pmgOc","hueBackground":"cw-color-picker-module__hueBackground__Mks78","whiteGradient":"cw-color-picker-module__whiteGradient__Bt-fU","blackGradient":"cw-color-picker-module__blackGradient__VnEKJ","colorAreaCursor":"cw-color-picker-module__colorAreaCursor__lotg3"};
@@ -4050,15 +4144,37 @@ const CwImageArea = forwardRef((props, ref) => {
4050
4144
  });
4051
4145
  CwImageArea.displayName = "CwImageArea";
4052
4146
 
4053
- var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4147
+ var styles$g = {"container":"cw-weekday-selector-module__container__pwcvx","days":"cw-weekday-selector-module__days__Dd3RH"};
4148
+
4149
+ /* 2024-01-01 was a Monday. Formatted in UTC so a negative browser offset cannot shift a day. */
4150
+ const MONDAY_UTC = Date.UTC(2024, 0, 1);
4151
+ const DAY_IN_MS = 86_400_000;
4152
+ const DAY_CODES = ["M", "T", "W", "R", "F", "S", "U"];
4153
+ /**
4154
+ * Day names in the fixed MTWRFSU order the selector renders, resolved through Intl so every
4155
+ * locale gets its own letters (es -> LMXJVSD, de -> MDMDFSS) with no table to maintain.
4156
+ *
4157
+ * @param localeCode BCP-47 tag, e.g. "en-GB" | "es" | "de"
4158
+ */
4159
+ function getWeekdayNames(localeCode) {
4160
+ const narrow = new Intl.DateTimeFormat(localeCode, { weekday: "narrow", timeZone: "UTC" });
4161
+ const full = new Intl.DateTimeFormat(localeCode, { weekday: "long", timeZone: "UTC" });
4162
+ const names = {};
4163
+ DAY_CODES.forEach((code, index) => {
4164
+ const date = new Date(MONDAY_UTC + index * DAY_IN_MS);
4165
+ names[code] = { letter: narrow.format(date), full: full.format(date) };
4166
+ });
4167
+ return names;
4168
+ }
4054
4169
 
4170
+ /* The week model behind CwWeekdaySelector, kept apart from the rendering. */
4055
4171
  /**
4056
4172
  * This class represents a week where days can be selected or unselected
4057
4173
  * @remark Selected days are in UPPERCASE, unselected days are in lowercase
4058
4174
  * ```
4059
4175
  * Monday = "M" | "m"
4060
4176
  * Tuesday = "T" | "t"
4061
- * Wendnesday = "W" | "w"
4177
+ * Wednesday = "W" | "w"
4062
4178
  * thuRsday = "R" | "r"
4063
4179
  * Friday = "F" | "f"
4064
4180
  * Saturday = "S" | "s"
@@ -4070,15 +4186,6 @@ class Weekdays {
4070
4186
  static WEEKDAYS_STANDARD_ARRAY_EMPTY = ["m", "t", "w", "r", "f", "s", "u"];
4071
4187
  static WEEKDAYS_STANDARD_STRING_FULL = "MTWRFSU";
4072
4188
  static WEEKDAYS_STANDARD_STRING_EMPTY = "mtwrfsu";
4073
- static WEEKDAYS_TO_USA_LETTER_FORMAT = new Map([
4074
- ["M", "M"],
4075
- ["T", "T"],
4076
- ["W", "W"],
4077
- ["R", "T"],
4078
- ["F", "F"],
4079
- ["S", "S"],
4080
- ["U", "S"]
4081
- ]);
4082
4189
  static WEEKDAYS_TO_USA_SHORT_FORMAT = new Map([
4083
4190
  ["M", "Mon"],
4084
4191
  ["T", "Tue"],
@@ -4097,6 +4204,7 @@ class Weekdays {
4097
4204
  5: "F",
4098
4205
  6: "S"
4099
4206
  };
4207
+ static DAY_NUMBER_BY_CODE = Object.fromEntries(Object.entries(Weekdays.WEEKDAY_MAP).map(([dayNumber, code]) => [code, Number(dayNumber)]));
4100
4208
  days;
4101
4209
  constructor(days = Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL) {
4102
4210
  if (typeof days === "string")
@@ -4140,11 +4248,11 @@ class Weekdays {
4140
4248
  toString() {
4141
4249
  return this.days.join("").trim();
4142
4250
  }
4143
- toStringFormatted(limiters = { startExistingDay: "{", endExsitingDay: "}", startMissingDay: "(", endMissingDay: ")", separator: " " }, format = Weekdays.WEEKDAYS_TO_USA_SHORT_FORMAT) {
4251
+ toStringFormatted(limiters = { startExistingDay: "{", endExistingDay: "}", startMissingDay: "(", endMissingDay: ")", separator: " " }, format = Weekdays.WEEKDAYS_TO_USA_SHORT_FORMAT) {
4144
4252
  const result = new Array();
4145
4253
  [...this.days].forEach((letter, index) => {
4146
4254
  if (letter === letter.toUpperCase()) {
4147
- result.push(limiters.startExistingDay + format.get(letter) + limiters.endExsitingDay);
4255
+ result.push(limiters.startExistingDay + format.get(letter) + limiters.endExistingDay);
4148
4256
  }
4149
4257
  else if (letter === letter.toLowerCase()) {
4150
4258
  result.push(limiters.startMissingDay +
@@ -4164,33 +4272,77 @@ class Weekdays {
4164
4272
  return this.toString() === Weekdays.WEEKDAYS_STANDARD_STRING_FULL;
4165
4273
  }
4166
4274
  static getFullWeek() {
4167
- return Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL;
4275
+ return [...Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL];
4168
4276
  }
4169
4277
  static getEmptyWeek() {
4170
- return Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY;
4278
+ return [...Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY];
4171
4279
  }
4172
- }
4173
- const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4174
- const [selectedDays, setSelectedDays] = useState(Weekdays.fromString(value));
4175
- useEffect(() => {
4176
- setSelectedDays(Weekdays.fromString(value));
4177
- }, [value]);
4178
- const handleChange = (day, checked) => {
4179
- const currentDays = selectedDays.toArray();
4180
- let updated;
4181
- if (checked) {
4182
- updated = currentDays.filter(d => d !== day.toLowerCase());
4183
- updated.push(day);
4280
+ /** A week with nothing selected. */
4281
+ static empty() {
4282
+ return new Weekdays(Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY);
4283
+ }
4284
+ /**
4285
+ * Like {@link fromString}, but yields an empty week instead of throwing on anything invalid.
4286
+ * For UI fed straight from a backend field that can arrive null, empty or partial.
4287
+ */
4288
+ static tryFromString(value) {
4289
+ if (!value)
4290
+ return Weekdays.empty();
4291
+ try {
4292
+ return Weekdays.fromString(value);
4184
4293
  }
4185
- else {
4186
- updated = currentDays.filter(d => d !== day);
4187
- updated.push(day.toLowerCase());
4294
+ catch {
4295
+ return Weekdays.empty();
4188
4296
  }
4189
- const newWeekdays = new Weekdays(updated);
4190
- setSelectedDays(newWeekdays);
4191
- onChange?.(newWeekdays.toString());
4297
+ }
4298
+ /** Selected flags in MTWRFSU order (Monday first). */
4299
+ toBooleans() {
4300
+ return this.days.map(day => day === day.toUpperCase());
4301
+ }
4302
+ /** @param flags selected flags in MTWRFSU order; missing entries count as unselected */
4303
+ static fromBooleans(flags) {
4304
+ return new Weekdays(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map((day, index) => flags[index] ? day : day.toLowerCase()));
4305
+ }
4306
+ /** 7-character mask in MTWRFSU order where "1" means selected, e.g. "1100100". */
4307
+ toMask() {
4308
+ return this.toBooleans().map(selected => (selected ? "1" : "0")).join("");
4309
+ }
4310
+ /** @param mask 7-character mask in MTWRFSU order where "1" means selected; a shorter, empty or
4311
+ * missing mask counts the absent days as unselected */
4312
+ static fromMask(mask) {
4313
+ return Weekdays.fromBooleans(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map((_, index) => mask?.[index] === "1"));
4314
+ }
4315
+ /** Selected days as Date.getDay() numbers (0 = Sunday), in MTWRFSU order. */
4316
+ toDayNumbers() {
4317
+ return this.days
4318
+ .filter(day => day === day.toUpperCase())
4319
+ .map(day => Weekdays.DAY_NUMBER_BY_CODE[day]);
4320
+ }
4321
+ /** @param days Date.getDay() numbers (0 = Sunday) */
4322
+ static fromDayNumbers(days) {
4323
+ const selected = new Set(days);
4324
+ return Weekdays.fromBooleans(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map(day => selected.has(Weekdays.DAY_NUMBER_BY_CODE[day])));
4325
+ }
4326
+ }
4327
+
4328
+ const CwWeekdaySelector = ({ value = "mtwrfsu", onChange, disabled = false, labelProps, layout, feedback, locale = "en-GB", className }) => {
4329
+ const selectedDays = Weekdays.tryFromString(value).toArray();
4330
+ const dayNames = useMemo(() => getWeekdayNames(locale), [locale]);
4331
+ const handleChange = (day, checked) => {
4332
+ const updated = selectedDays.filter(d => d !== day && d !== day.toLowerCase());
4333
+ updated.push(checked ? day : day.toLowerCase());
4334
+ onChange?.(new Weekdays(updated).toString());
4192
4335
  };
4193
- return (jsx("div", { className: styles$g["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4336
+ const feedbackMessages = feedback
4337
+ ? Array.isArray(feedback) ? feedback : [feedback]
4338
+ : [];
4339
+ const feedbackId = useId();
4340
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4341
+ const describedBy = feedbackIds.join(" ") || undefined;
4342
+ // Points at the label element rather than copying its text, which also covers a labelProps that
4343
+ // carries children instead of `text`.
4344
+ const labelId = labelProps?.id ?? `${feedbackId}-label`;
4345
+ return (jsxs("div", { className: `cw-weekday-selector ${styles$g.container}${className ? ` ${className}` : ""}`, "data-direction": labelProps ? layout?.direction ?? "row" : "column", "data-align": layout?.align, "data-gap": layout?.gap, children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsx("div", { role: "group", className: styles$g.days, "aria-labelledby": labelProps ? labelId : undefined, "aria-describedby": describedBy, children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, "data-letter": dayNames[day].letter, "aria-label": dayNames[day].full, title: dayNames[day].full, checked: selectedDays.includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4194
4346
  };
4195
4347
 
4196
4348
  var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
@@ -4238,6 +4390,9 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4238
4390
  const feedbackMessages = feedback
4239
4391
  ? Array.isArray(feedback) ? feedback : [feedback]
4240
4392
  : [];
4393
+ const feedbackId = useId();
4394
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4395
+ const describedBy = feedbackIds.join(" ") || undefined;
4241
4396
  // Effective layout — precedence: new `groupLayout`/`itemLayout` > legacy-derived > default.
4242
4397
  // Legacy `alignProps.flexDirection` drove the label-vs-options axis (default "row" = label
4243
4398
  // beside the options); map it to `groupLayout.direction`.
@@ -4250,7 +4405,7 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4250
4405
  ?? (optionsAlignment === "column" ? "row" : "column");
4251
4406
  // Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
4252
4407
  const checkDirection = itemDirection === "row" ? "column" : "row";
4253
- return (jsxs("div", { className: `cw-checkbox-group ${styles$f.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$f.options, role: "group", "aria-label": labelProps?.text, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4408
+ return (jsxs("div", { className: `cw-checkbox-group ${styles$f.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$f.options, role: "group", "aria-label": labelProps?.text, "aria-describedby": describedBy, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4254
4409
  }
4255
4410
 
4256
4411
  var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
@@ -4277,11 +4432,14 @@ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemL
4277
4432
  const feedbackMessages = feedback
4278
4433
  ? Array.isArray(feedback) ? feedback : [feedback]
4279
4434
  : [];
4435
+ const feedbackId = useId();
4436
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4437
+ const describedBy = feedbackIds.join(" ") || undefined;
4280
4438
  // Each radio's circle-to-text layout is the opposite of the options flow: a stacked list
4281
4439
  // (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
4282
4440
  // best with the circle above the text.
4283
4441
  const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
4284
- return (jsxs("div", { className: `cw-radio-group ${styles$e.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$e.options, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4442
+ return (jsxs("div", { className: `cw-radio-group ${styles$e.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$e.options, role: "radiogroup", "aria-describedby": describedBy, "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4285
4443
  }
4286
4444
 
4287
4445
  function CwToggle(props) {
@@ -4461,6 +4619,13 @@ function CwDropdown({ options, value, onChange, labelProps, alignProps, placehol
4461
4619
  const feedbackMessages = feedback
4462
4620
  ? Array.isArray(feedback) ? feedback : [feedback]
4463
4621
  : [];
4622
+ const feedbackId = useId();
4623
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4624
+ const describedBy = feedbackIds.join(" ") || undefined;
4625
+ // The trigger is named by reference - the label for the field, the content for the current
4626
+ // value - so neither has to be copied into a string.
4627
+ const labelId = labelProps?.id ?? `${feedbackId}-label`;
4628
+ const valueId = `${feedbackId}-value`;
4464
4629
  // Scroll highlighted item into view
4465
4630
  useEffect(() => {
4466
4631
  if (isOpen && highlightedItemRef.current) {
@@ -4529,12 +4694,12 @@ function CwDropdown({ options, value, onChange, labelProps, alignProps, placehol
4529
4694
  }
4530
4695
  }, [isOpen, highlightedIndex, filteredOptions, handleOptionSelect]);
4531
4696
  const flexDirection = alignProps?.flexDirection ?? "row";
4532
- return (jsxs("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsx("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": selectedOption?.label || placeholder, children: jsx("div", { className: "cw-dropdown-trigger-content", children: selectedOption ? (jsxs(Fragment, { children: [selectedOption.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsx("span", { children: selectedOption.label })] })) : (jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }) }), jsx("div", { style: { display: "flex", alignItems: "center", paddingRight: "0.5rem", flexShrink: 0, cursor: disabled ? "not-allowed" : "pointer" }, onClick: handleTriggerClick, children: jsx(CwIcon, { iconId: "chevron-down", size: "small" }) }), renderPanel(jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsx("div", { className: dropdownStyles.searchBox, children: jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4533
- dropdownStyles.option,
4534
- value === option.value ? dropdownStyles.optionSelected : "",
4535
- highlightedIndex === index ? dropdownStyles.optionFocused : "",
4536
- option.disabled ? dropdownStyles.optionDisabled : "",
4537
- ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsx("span", { children: option.label })] }, option.value)))) : (jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] })] }), feedbackMessages.map((item, index) => (jsx("p", { className: "cw-input-info", "data-color": item.type, children: item.message }, index)))] }));
4697
+ return (jsx("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsxs("div", { className: dropdownStyles.value, children: [jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxs("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-labelledby": labelProps ? `${labelId} ${valueId}` : undefined, "aria-label": labelProps ? undefined : (selectedOption?.label || placeholder), "aria-describedby": describedBy, children: [jsx("div", { className: "cw-dropdown-trigger-content", id: valueId, children: selectedOption ? (jsxs(Fragment, { children: [selectedOption.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsx("span", { children: selectedOption.label })] })) : (jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }), jsx(CwIcon, { iconId: "chevron-down", size: "small" })] }), renderPanel(jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsx("div", { className: dropdownStyles.searchBox, children: jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4698
+ dropdownStyles.option,
4699
+ value === option.value ? dropdownStyles.optionSelected : "",
4700
+ highlightedIndex === index ? dropdownStyles.optionFocused : "",
4701
+ option.disabled ? dropdownStyles.optionDisabled : "",
4702
+ ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsx("span", { children: option.label })] }, option.value)))) : (jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] }), feedbackMessages.map((item, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": item.type, "aria-live": "polite", children: item.message }, index)))] })] }) }));
4538
4703
  }
4539
4704
 
4540
4705
  function CwDropdownFilter(props) {
@@ -4942,7 +5107,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4942
5107
  } }, props.ID))) })] }))] }));
4943
5108
  };
4944
5109
 
4945
- var styles$a = {"container":"cw-tag-selector-module__container__-do8i","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
5110
+ var styles$a = {"container":"cw-tag-selector-module__container__-do8i","value":"cw-tag-selector-module__value__TDAy3","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
4946
5111
 
4947
5112
  /**
4948
5113
  * Multi-select input with chip tags and searchable dropdown.
@@ -5077,8 +5242,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5077
5242
  // Keeping containerRef for any other potential use
5078
5243
  const direction = alignProps?.flexDirection ?? "row";
5079
5244
  const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
5080
- return (jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5081
- inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$a.option}${idx === focusedIndex ? ` ${styles$a.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5245
+ const feedbackId = useId();
5246
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
5247
+ const describedBy = feedbackIds.join(" ") || undefined;
5248
+ return (jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: styles$a.value, children: [jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5249
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off", "aria-describedby": describedBy }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), feedbackMessages.map((fb, i) => (jsx("p", { id: feedbackIds[i], className: "cw-input-feedback", "data-color": fb.type, "aria-live": "polite", children: fb.message }, i)))] })] }), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$a.option}${idx === focusedIndex ? ` ${styles$a.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5082
5250
  }
5083
5251
 
5084
5252
  var styles$9 = {"tree-container":"cw-tree-view-module__tree-container__NN-HJ","tree-wrapper":"cw-tree-view-module__tree-wrapper__keBZI","tree-item":"cw-tree-view-module__tree-item__prE9N","tree-node":"cw-tree-view-module__tree-node__wfro9","selected":"cw-tree-view-module__selected__XJQ0w","non-selectable":"cw-tree-view-module__non-selectable__YuPSx","tree-children":"cw-tree-view-module__tree-children__ji8CZ","empty-state":"cw-tree-view-module__empty-state__yvRjo","tree-label":"cw-tree-view-module__tree-label__ss3Nf","tree-spacer":"cw-tree-view-module__tree-spacer__E9Ud2"};
@@ -6089,7 +6257,7 @@ function CwBtnCancel({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...res
6089
6257
  return (jsx(CwButton, { ...rest, variant: "icon", icon: "cancel", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Cancel" }));
6090
6258
  }
6091
6259
 
6092
- var styles$4 = {"pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
6260
+ var styles$4 = {"value":"cw-pickers-base-module__value__BR67P","pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
6093
6261
 
6094
6262
  /**
6095
6263
  * Renders a picker popup in a portal so it escapes overflow containers.
@@ -6146,6 +6314,9 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
6146
6314
  const feedbackMessages = feedback
6147
6315
  ? Array.isArray(feedback) ? feedback : [feedback]
6148
6316
  : [];
6317
+ const feedbackId = useId();
6318
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
6319
+ const describedBy = feedbackIds.join(" ") || undefined;
6149
6320
  const wrapperRef = useRef(null);
6150
6321
  const inputRef = useRef(null);
6151
6322
  const prevValueRef = useRef(undefined);
@@ -6326,11 +6497,11 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
6326
6497
  ...(maxDate ? [{ after: maxDate }] : []),
6327
6498
  ...(disabledMatcher ? [disabledMatcher] : []),
6328
6499
  ], [disabledDates, minDate, maxDate, disabledMatcher]);
6329
- return (jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6330
- today: new Date(),
6331
- }, modifiersClassNames: {
6332
- today: "rdp-day-today",
6333
- } }), showTodayButton && (jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
6500
+ return (jsx("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6501
+ today: new Date(),
6502
+ }, modifiersClassNames: {
6503
+ today: "rdp-day-today",
6504
+ } }), showTodayButton && (jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) }));
6334
6505
  }
6335
6506
 
6336
6507
  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"};
@@ -6969,14 +7140,14 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6969
7140
  }
6970
7141
  return undefined;
6971
7142
  }, [value]);
6972
- return (jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [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' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [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' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonth || value?.from || undefined, modifiers: {
7143
+ return (jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [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, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [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, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonth || value?.from || undefined, modifiers: {
6973
7144
  today: new Date(),
6974
7145
  }, modifiersClassNames: {
6975
7146
  today: "rdp-day-today",
6976
7147
  } })] }), jsx("div", { role: "alert", "aria-live": "polite", className: rangeStyles.rangeError, children: rangeErrorMessage })] }))] })] }) }));
6977
7148
  }
6978
7149
 
6979
- 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"};
7150
+ var timeStyles = {"timePickerPopup":"cw-time-picker-module__timePickerPopup__BN63t","timePickerList":"cw-time-picker-module__timePickerList__E88pr","selected":"cw-time-picker-module__selected__qVnfL","field":"cw-time-picker-module__field__kPvGN","narrow":"cw-time-picker-module__narrow__Z7lCI"};
6980
7151
 
6981
7152
  const isMobileDevice = () => {
6982
7153
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
@@ -7138,7 +7309,7 @@ function CwTimePicker({ value, onChange, interval = 15, minTime, maxTime, labelP
7138
7309
  return (jsx("div", { className: `cw-timepicker cw-timepicker-native ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$4.pickerWrapper, children: jsx("input", { type: "time", value: displayValue, onChange: handleNativeChange, min: minTime, max: maxTime, step: interval * 60, disabled: disabled, required: required, placeholder: placeholder, className: "cw-timepicker-native" }) })] }) }));
7139
7310
  }
7140
7311
  // Custom time picker
7141
- return (jsx("div", { ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required, maxLength: 5, className: showClear ? timeStyles.hasIcons : timeStyles.notIcons }), showClear && (jsx("div", { className: styles$4.pickerIcons, children: value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsx("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7312
+ return (jsx("div", { ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: `${styles$4.pickerWrapper} ${timeStyles.field}${showClear ? "" : ` ${timeStyles.narrow}`}`, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required, maxLength: 5 }), showClear && (jsx("div", { className: styles$4.pickerIcons, children: value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsx("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7142
7313
  const isSelected = time === value;
7143
7314
  return (jsx("button", { ref: isSelected ? selectedItemRef : null, type: "button", className: isSelected ? timeStyles.selected : "", onClick: () => handleTimeSelect(time), children: time }, time));
7144
7315
  }) }) }))] })] }) }));
@@ -7804,6 +7975,9 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7804
7975
  const feedbackMessages = feedback
7805
7976
  ? Array.isArray(feedback) ? feedback : [feedback]
7806
7977
  : [];
7978
+ const feedbackId = useId();
7979
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
7980
+ const describedBy = feedbackIds.join(" ") || undefined;
7807
7981
  const wrapperRef = useRef(null);
7808
7982
  const inputRef = useRef(null);
7809
7983
  const prevValueRef = useRef(undefined);
@@ -7910,11 +8084,11 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7910
8084
  const defaultMonthJsDate = defaultMonth
7911
8085
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
7912
8086
  : selectedJsDate;
7913
- return (jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7914
- today: new Date(),
7915
- }, modifiersClassNames: {
7916
- today: "rdp-day-today",
7917
- } }), showTodayButton && (jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
8087
+ return (jsx("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8088
+ today: new Date(),
8089
+ }, modifiersClassNames: {
8090
+ today: "rdp-day-today",
8091
+ } }), showTodayButton && (jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) }));
7918
8092
  }
7919
8093
 
7920
8094
  // DateTimePickerState - immutable domain model for the Temporal date-time picker.
@@ -8652,7 +8826,7 @@ function CwDateRangePickerTemporal({ value, onChange, minDate, maxDate, disabled
8652
8826
  const defaultMonthJsDate = defaultMonth
8653
8827
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
8654
8828
  : (value?.from ? plainDateToJsDate(value.from) : undefined);
8655
- return (jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [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' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [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' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8829
+ return (jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [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, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [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, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8656
8830
  today: new Date(),
8657
8831
  }, modifiersClassNames: {
8658
8832
  today: "rdp-day-today",
@@ -10215,4 +10389,4 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
10215
10389
  }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "person" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
10216
10390
  };
10217
10391
 
10218
- export { CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwButtonSplit, CwButtonSwitch, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNavMenu, CwNote, CwOption, CwPopoverButton, CwProgress, CwRadioGroup, CwReportModal, CwSearchAsync, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSkeleton, CwSortableList, CwSortableTable, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PRESET_LIBRARY_TEMPORAL, PinRowHeader, Scheduler, SchedulerEvent, SuperScheduler, TooltipConstraintContext, UiEvent, Weekdays, configureCwLoading, eventIsVisible, filterNavItems, filterVisibleEvents, getCwLoadingDefaults, getDefaultDivisions, getEventSizes, getPresetsByKeysTemporal, itemsToMultiFilterTags, sortNavItems, useCwMessage, useSortableList, useSortableTable, useTooltipConstraint };
10392
+ export { CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBadge, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwButtonSplit, CwButtonSwitch, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNavMenu, CwNote, CwOption, CwPopoverButton, CwProgress, CwRadioGroup, CwReportModal, CwSearchAsync, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSkeleton, CwSortableList, CwSortableTable, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PRESET_LIBRARY_TEMPORAL, PinRowHeader, Scheduler, SchedulerEvent, SuperScheduler, TooltipConstraintContext, UiEvent, Weekdays, configureCwLoading, eventIsVisible, filterNavItems, filterVisibleEvents, getCwLoadingDefaults, getDefaultDivisions, getEventSizes, getPresetsByKeysTemporal, itemsToMultiFilterTags, sortNavItems, useCwMessage, useSortableList, useSortableTable, useTooltipConstraint };