@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.cjs.js CHANGED
@@ -181,7 +181,7 @@ function getContrastColor(color) {
181
181
  return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
182
182
  }
183
183
 
184
- var styles$x = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
184
+ var styles$y = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
185
185
 
186
186
  // Constants
187
187
  const margin$1 = 16;
@@ -471,7 +471,7 @@ const CwTooltipManager = () => {
471
471
  if (!state.isVisible || !state.content) {
472
472
  return null;
473
473
  }
474
- return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$x["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
474
+ return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$y["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
475
475
  top: `${tooltipPosition.top}px`,
476
476
  left: `${tooltipPosition.left}px`,
477
477
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -552,7 +552,7 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
552
552
  React.useEffect(() => {
553
553
  ensureTooltipManager();
554
554
  }, []);
555
- return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$x["cw-tooltip"], children: children }));
555
+ return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$y["cw-tooltip"], children: children }));
556
556
  };
557
557
 
558
558
  const SVG_ICONS = {
@@ -587,25 +587,31 @@ function CwIcon(props) {
587
587
  /**
588
588
  * CwChip - A simple chip/tag component for displaying labels or categories
589
589
  *
590
+ * The colour comes from `color`; the older `colorScheme` spelling is deprecated but still
591
+ * honoured, and `color` wins when both are passed.
592
+ *
590
593
  * @example
591
- * <CwChip label="Active" colorScheme="success" />
592
- * <CwChip label="High Priority" colorScheme="danger" variant="solid" />
593
- * <CwChip label="Custom" colorScheme="custom" customColor="#8a2be2" />
594
- * <CwChip label="Outlined" colorScheme="info" variant="outline" />
594
+ * <CwChip label="Active" color="success" />
595
+ * <CwChip label="High Priority" color="danger" variant="solid" />
596
+ * <CwChip label="Custom" color="custom" customColor="#8a2be2" />
597
+ * <CwChip label="Outlined" color="info" variant="outline" />
595
598
  * <CwChip label="Removable" closable onClose={() => console.log('closed')} />
596
599
  **/
597
- const CwChip = ({ label, colorScheme = 'info', customColor, variant = 'soft', className = '', closable = false, onClose, icon, style = {}, }) => {
600
+ const CwChip = ({ label, color, colorScheme, customColor, variant = 'soft', className = '', closable = false, onClose, icon, style = {}, }) => {
601
+ const resolvedColor = color ?? colorScheme ?? 'info';
598
602
  // Basic validation
599
603
  if (closable && !onClose) {
600
604
  console.warn('CwChip: onClose prop is required when closable is true');
601
605
  }
602
- // Calculate styles based on colorScheme, customColor and variant
606
+ // One arbitrary colour can only fill two of the four roles, so soft and solid look alike here.
603
607
  const chipStyle = React.useMemo(() => {
604
608
  if (customColor) {
605
- // Simply set the CSS custom properties, CSS handles the rest
609
+ const contrast = getContrastColor(customColor);
606
610
  return {
607
- '--chip-accent': customColor,
608
- '--chip-text': getContrastColor(customColor),
611
+ '--accent-light': customColor,
612
+ '--accent-main': customColor,
613
+ '--accent-dark': contrast,
614
+ '--accent-on-main': contrast,
609
615
  ...style
610
616
  };
611
617
  }
@@ -624,7 +630,79 @@ const CwChip = ({ label, colorScheme = 'info', customColor, variant = 'soft', cl
624
630
  className,
625
631
  closable ? 'cw-chip-closable' : '',
626
632
  ].filter(Boolean).join(' ');
627
- return (jsxRuntime.jsxs("span", { className: chipClassNames, "data-color-scheme": colorScheme, "data-variant": variant, style: chipStyle, children: [icon && jsxRuntime.jsx(CwIcon, { iconId: icon }), label && jsxRuntime.jsx("span", { children: label }), closable && (jsxRuntime.jsx("button", { className: "cw-chip-close-button", onClick: handleClose, "aria-label": "Remove", type: "button", children: jsxRuntime.jsx("span", { className: "cwi-icons cwi-close" }) }))] }));
633
+ return (jsxRuntime.jsxs("span", { className: chipClassNames, "data-color": resolvedColor, "data-variant": variant, "data-icon-only": (Boolean(icon) && !label) || undefined, style: chipStyle, children: [icon && jsxRuntime.jsx(CwIcon, { iconId: icon }), label && jsxRuntime.jsx("span", { children: label }), closable && (jsxRuntime.jsx("button", { className: "cw-chip-close-button", onClick: handleClose, "aria-label": "Remove", type: "button", children: jsxRuntime.jsx("span", { className: "cwi-icons cwi-close" }) }))] }));
634
+ };
635
+
636
+ /**
637
+ * Normalises a raw count into the integer the badge represents: a non-negative whole number.
638
+ * Both the display string and the `showZero` decision derive from this.
639
+ */
640
+ function normalizeBadgeCount(count) {
641
+ return Number.isFinite(count) ? Math.max(0, Math.trunc(count)) : 0;
642
+ }
643
+ /**
644
+ * Formats a badge count into its display string. Both arguments are normalised, `max` with a
645
+ * floor of 1 - below that every non-zero count would overflow.
646
+ *
647
+ * @param count Raw count to display.
648
+ * @param max Highest value shown as a number; anything above renders `"{max}+"`.
649
+ *
650
+ * @example
651
+ * formatBadgeCount(7, 99); // "7"
652
+ * formatBadgeCount(100, 99); // "99+"
653
+ * formatBadgeCount(12, 9); // "9+"
654
+ */
655
+ function formatBadgeCount(count, max) {
656
+ const safeCount = normalizeBadgeCount(count);
657
+ const safeMax = Number.isFinite(max) ? Math.max(1, Math.trunc(max)) : 1;
658
+ return safeCount > safeMax ? `${safeMax}+` : `${safeCount}`;
659
+ }
660
+ /**
661
+ * Resolves the badge's accessibility attributes. A text-less badge with no label is hidden rather
662
+ * than announced as an empty element; the button or tab around it usually names the thing.
663
+ *
664
+ * @param label Caller-supplied accessible name.
665
+ * @param loading Whether the badge is showing its spinner.
666
+ * @param hasText Whether the badge renders a count or content.
667
+ */
668
+ function resolveBadgeAria(label, loading, hasText) {
669
+ if (label) {
670
+ return { role: loading ? 'status' : 'img', 'aria-label': label };
671
+ }
672
+ return hasText ? {} : { 'aria-hidden': 'true' };
673
+ }
674
+
675
+ var styles$x = {"badge":"cw-badge-module__badge__PKlak"};
676
+
677
+ /**
678
+ * CwBadge - the small coloured circle with a number, used for alert and notification counts.
679
+ *
680
+ * Always **in flow** (`inline-flex`); it never positions itself, so overlaying it on an icon
681
+ * button is the caller's job. One digit stays a circle, wider content such as `"99+"` grows into
682
+ * a pill. With neither `count` nor `content` it renders as a dot.
683
+ *
684
+ * Precedence: `loading` > `content` > `count` > dot. While loading the badge renders regardless
685
+ * of `showZero`, and the spinner replaces it - circle, background and padding come off.
686
+ *
687
+ * @example
688
+ * <CwBadge count={3} color="danger" />
689
+ * <CwBadge count={0} showZero={false} />
690
+ * <CwBadge count={128} max={99} color="warning" variant="soft" />
691
+ * <CwBadge color="warning" label="Unresolved findings" />
692
+ * <CwBadge count={0} loading />
693
+ */
694
+ const CwBadge = ({ count, content, color = 'info', variant = 'solid', size = 'small', showZero = true, loading = false, max = 99, label, className = '', style, }) => {
695
+ // null counts as absent, so `content={null}` still renders a dot rather than an empty pill.
696
+ const hasContent = content !== undefined && content !== null;
697
+ if (!loading && !hasContent && count !== undefined && !showZero && normalizeBadgeCount(count) === 0) {
698
+ return null;
699
+ }
700
+ const countText = !hasContent && count !== undefined
701
+ ? formatBadgeCount(count, max)
702
+ : undefined;
703
+ const isDot = !loading && !hasContent && count === undefined;
704
+ const badgeClassNames = ['cw-badge', styles$x.badge, className].filter(Boolean).join(' ');
705
+ return (jsxRuntime.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 ? jsxRuntime.jsx(CwIcon, { iconId: "spinner", size: "small" }) : hasContent ? content : countText }));
628
706
  };
629
707
 
630
708
  const CW_DEFAULT_MESSAGE_DURATION = 2000;
@@ -1078,7 +1156,7 @@ var styles$v = {"progress":"cw-progress-module__progress__d-g2-","value":"cw-pro
1078
1156
  * <CwProgress value={62} label="Import" color="success" />
1079
1157
  * <CwProgress indeterminate label="Uploading" />
1080
1158
  */
1081
- function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'regular', layout = 'row', color = 'primary', monoValue = false, prominent = false }) {
1159
+ function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'regular', layout = 'row', color = 'primary', monoValue = false, prominent = false, className }) {
1082
1160
  const labelId = React.useId();
1083
1161
  // Determinate: a missing or non-finite value is treated as 0 (never NaN), then
1084
1162
  // clamped to [0,100] for aria-valuenow and the fill width. Indeterminate has no value.
@@ -1090,7 +1168,7 @@ function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'r
1090
1168
  const valueText = rightLabel ?? (percent !== undefined ? `${percent}%` : '');
1091
1169
  // The un-hashed cw-progress class carries no styles in the library - a stable
1092
1170
  // public hook for exceptional external overrides only.
1093
- const rootClassName = ['cw-progress', styles$v.progress].filter(Boolean).join(' ');
1171
+ const rootClassName = ['cw-progress', styles$v.progress, className].filter(Boolean).join(' ');
1094
1172
  const labelSpan = label ? jsxRuntime.jsx("span", { className: styles$v.label, id: labelId, children: label }) : null;
1095
1173
  const valueLabel = showValue ? (jsxRuntime.jsx("span", { className: styles$v.value, "data-mono": monoValue || undefined, children: valueText })) : null;
1096
1174
  return (jsxRuntime.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) && (jsxRuntime.jsxs("header", { className: styles$v.header, children: [labelSpan, valueLabel] })), layout === 'row' && labelSpan, jsxRuntime.jsx("div", { className: styles$v.track, role: "progressbar", ...(label && { 'aria-labelledby': labelId }), ...(!indeterminate && percent !== undefined && {
@@ -1246,7 +1324,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1246
1324
  return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1247
1325
  };
1248
1326
 
1249
- const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
1327
+ const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", badge, children, ...buttonProps }, ref) {
1250
1328
  // Build CSS classes based on variant and props
1251
1329
  let buttonClass = `cw-button-${variant}`;
1252
1330
  // Add icon class only for icon variant without children
@@ -1259,13 +1337,19 @@ const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', c
1259
1337
  const tooltipContent = title || (variant === 'icon' && text ? text : undefined);
1260
1338
  const iconElement = icon ? jsxRuntime.jsx(CwIcon, { iconId: icon }) : null;
1261
1339
  const textElement = text ? jsxRuntime.jsx("strong", { children: text }) : null;
1340
+ // Overlaid, not content: the `cwi-` condition above deliberately ignores it, so a badge
1341
+ // never suppresses the button's own icon. Size defaulted explicitly, not by spread order,
1342
+ // so `size: undefined` in the object cannot clobber it.
1343
+ const badgeElement = badge
1344
+ ? jsxRuntime.jsx(CwBadge, { ...badge, size: badge.size ?? (variant === 'icon' ? 'small' : size) })
1345
+ : null;
1262
1346
  // Only emit toggle attributes when `pressed` is defined; otherwise output stays identical to a normal button.
1263
1347
  const pressedProps = pressed !== undefined
1264
1348
  ? { "aria-pressed": pressed, "data-pressed": pressed ? "true" : undefined }
1265
1349
  : {};
1266
- const buttonElement = (jsxRuntime.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'
1267
- ? jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [textElement, iconElement] })
1268
- : jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconElement, textElement] }))) }));
1350
+ const buttonElement = (jsxRuntime.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 : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [children ?? (iconPosition === 'right'
1351
+ ? jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [textElement, iconElement] })
1352
+ : jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconElement, textElement] })), badgeElement] })) }));
1269
1353
  return tooltipContent ? (jsxRuntime.jsx(CwTooltipNew, { content: tooltipContent, position: tooltipPosition, displayInline: true, children: buttonElement })) : (buttonElement);
1270
1354
  });
1271
1355
  CwButton.displayName = "CwButton";
@@ -2654,8 +2738,12 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2654
2738
  }, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2655
2739
  }
2656
2740
 
2657
- 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"};
2741
+ var styles$n = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2658
2742
 
2743
+ const BADGE_COLOR_SCHEMES = ['primary', 'danger', 'warning', 'success', 'info', 'neutral'];
2744
+ function isBadgeColorScheme(value) {
2745
+ return BADGE_COLOR_SCHEMES.includes(value);
2746
+ }
2659
2747
  const TabIcon = ({ icon }) => {
2660
2748
  if (!icon)
2661
2749
  return null;
@@ -2704,7 +2792,11 @@ function CwTabs(CwTabsProps) {
2704
2792
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2705
2793
  ? { minWidth: CwTabsProps.tabsListWidth }
2706
2794
  : undefined;
2707
- return (jsxRuntime.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: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$n['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.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 })] }));
2795
+ return (jsxRuntime.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: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => {
2796
+ const badgeScheme = tab.badgeColor && isBadgeColorScheme(tab.badgeColor) ? tab.badgeColor : undefined;
2797
+ const rawBadgeColor = tab.badgeColor && !badgeScheme ? tab.badgeColor : undefined;
2798
+ return (jsxRuntime.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: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.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));
2799
+ }) }), jsxRuntime.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 })] }));
2708
2800
  }
2709
2801
 
2710
2802
  /**
@@ -3253,14 +3345,16 @@ function CwInput(CwInputProps) {
3253
3345
  * ```
3254
3346
  */
3255
3347
  function CwDigit(props) {
3256
- const { alignProps, buttonProps, iconProps, labelProps, feedback, ...inputProps } = props;
3348
+ const { alignProps, buttonProps, iconProps, labelProps, feedback, feedbackPosition, ...inputProps } = props;
3257
3349
  const feedbackMessages = feedback
3258
3350
  ? Array.isArray(feedback) ? feedback : [feedback]
3259
3351
  : [];
3260
3352
  const feedbackId = React.useId();
3261
3353
  const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
3262
3354
  const describedBy = [inputProps["aria-describedby"], ...feedbackIds].filter(Boolean).join(" ") || undefined;
3263
- return (jsxRuntime.jsxs("div", { className: "cw-input-text", 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: "number", ...inputProps, "aria-describedby": describedBy }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-info", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
3355
+ // data-direction drives the feedback indent, which only makes sense under a label column.
3356
+ const flexDirection = alignProps?.flexDirection ?? "row";
3357
+ return (jsxRuntime.jsxs("div", { className: "cw-input-text", "data-direction": labelProps ? flexDirection : "column", "data-feedback-position": feedbackPosition, 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.jsxs("div", { className: "cw-input-button", children: [jsxRuntime.jsx("input", { type: "number", ...inputProps, "aria-describedby": describedBy }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-info", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
3264
3358
  }
3265
3359
 
3266
3360
  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"};
@@ -4070,15 +4164,37 @@ const CwImageArea = React.forwardRef((props, ref) => {
4070
4164
  });
4071
4165
  CwImageArea.displayName = "CwImageArea";
4072
4166
 
4073
- var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4167
+ var styles$g = {"container":"cw-weekday-selector-module__container__pwcvx","days":"cw-weekday-selector-module__days__Dd3RH"};
4168
+
4169
+ /* 2024-01-01 was a Monday. Formatted in UTC so a negative browser offset cannot shift a day. */
4170
+ const MONDAY_UTC = Date.UTC(2024, 0, 1);
4171
+ const DAY_IN_MS = 86_400_000;
4172
+ const DAY_CODES = ["M", "T", "W", "R", "F", "S", "U"];
4173
+ /**
4174
+ * Day names in the fixed MTWRFSU order the selector renders, resolved through Intl so every
4175
+ * locale gets its own letters (es -> LMXJVSD, de -> MDMDFSS) with no table to maintain.
4176
+ *
4177
+ * @param localeCode BCP-47 tag, e.g. "en-GB" | "es" | "de"
4178
+ */
4179
+ function getWeekdayNames(localeCode) {
4180
+ const narrow = new Intl.DateTimeFormat(localeCode, { weekday: "narrow", timeZone: "UTC" });
4181
+ const full = new Intl.DateTimeFormat(localeCode, { weekday: "long", timeZone: "UTC" });
4182
+ const names = {};
4183
+ DAY_CODES.forEach((code, index) => {
4184
+ const date = new Date(MONDAY_UTC + index * DAY_IN_MS);
4185
+ names[code] = { letter: narrow.format(date), full: full.format(date) };
4186
+ });
4187
+ return names;
4188
+ }
4074
4189
 
4190
+ /* The week model behind CwWeekdaySelector, kept apart from the rendering. */
4075
4191
  /**
4076
4192
  * This class represents a week where days can be selected or unselected
4077
4193
  * @remark Selected days are in UPPERCASE, unselected days are in lowercase
4078
4194
  * ```
4079
4195
  * Monday = "M" | "m"
4080
4196
  * Tuesday = "T" | "t"
4081
- * Wendnesday = "W" | "w"
4197
+ * Wednesday = "W" | "w"
4082
4198
  * thuRsday = "R" | "r"
4083
4199
  * Friday = "F" | "f"
4084
4200
  * Saturday = "S" | "s"
@@ -4090,15 +4206,6 @@ class Weekdays {
4090
4206
  static WEEKDAYS_STANDARD_ARRAY_EMPTY = ["m", "t", "w", "r", "f", "s", "u"];
4091
4207
  static WEEKDAYS_STANDARD_STRING_FULL = "MTWRFSU";
4092
4208
  static WEEKDAYS_STANDARD_STRING_EMPTY = "mtwrfsu";
4093
- static WEEKDAYS_TO_USA_LETTER_FORMAT = new Map([
4094
- ["M", "M"],
4095
- ["T", "T"],
4096
- ["W", "W"],
4097
- ["R", "T"],
4098
- ["F", "F"],
4099
- ["S", "S"],
4100
- ["U", "S"]
4101
- ]);
4102
4209
  static WEEKDAYS_TO_USA_SHORT_FORMAT = new Map([
4103
4210
  ["M", "Mon"],
4104
4211
  ["T", "Tue"],
@@ -4117,6 +4224,7 @@ class Weekdays {
4117
4224
  5: "F",
4118
4225
  6: "S"
4119
4226
  };
4227
+ static DAY_NUMBER_BY_CODE = Object.fromEntries(Object.entries(Weekdays.WEEKDAY_MAP).map(([dayNumber, code]) => [code, Number(dayNumber)]));
4120
4228
  days;
4121
4229
  constructor(days = Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL) {
4122
4230
  if (typeof days === "string")
@@ -4160,11 +4268,11 @@ class Weekdays {
4160
4268
  toString() {
4161
4269
  return this.days.join("").trim();
4162
4270
  }
4163
- toStringFormatted(limiters = { startExistingDay: "{", endExsitingDay: "}", startMissingDay: "(", endMissingDay: ")", separator: " " }, format = Weekdays.WEEKDAYS_TO_USA_SHORT_FORMAT) {
4271
+ toStringFormatted(limiters = { startExistingDay: "{", endExistingDay: "}", startMissingDay: "(", endMissingDay: ")", separator: " " }, format = Weekdays.WEEKDAYS_TO_USA_SHORT_FORMAT) {
4164
4272
  const result = new Array();
4165
4273
  [...this.days].forEach((letter, index) => {
4166
4274
  if (letter === letter.toUpperCase()) {
4167
- result.push(limiters.startExistingDay + format.get(letter) + limiters.endExsitingDay);
4275
+ result.push(limiters.startExistingDay + format.get(letter) + limiters.endExistingDay);
4168
4276
  }
4169
4277
  else if (letter === letter.toLowerCase()) {
4170
4278
  result.push(limiters.startMissingDay +
@@ -4184,33 +4292,77 @@ class Weekdays {
4184
4292
  return this.toString() === Weekdays.WEEKDAYS_STANDARD_STRING_FULL;
4185
4293
  }
4186
4294
  static getFullWeek() {
4187
- return Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL;
4295
+ return [...Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL];
4188
4296
  }
4189
4297
  static getEmptyWeek() {
4190
- return Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY;
4298
+ return [...Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY];
4191
4299
  }
4192
- }
4193
- const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4194
- const [selectedDays, setSelectedDays] = React.useState(Weekdays.fromString(value));
4195
- React.useEffect(() => {
4196
- setSelectedDays(Weekdays.fromString(value));
4197
- }, [value]);
4198
- const handleChange = (day, checked) => {
4199
- const currentDays = selectedDays.toArray();
4200
- let updated;
4201
- if (checked) {
4202
- updated = currentDays.filter(d => d !== day.toLowerCase());
4203
- updated.push(day);
4300
+ /** A week with nothing selected. */
4301
+ static empty() {
4302
+ return new Weekdays(Weekdays.WEEKDAYS_STANDARD_ARRAY_EMPTY);
4303
+ }
4304
+ /**
4305
+ * Like {@link fromString}, but yields an empty week instead of throwing on anything invalid.
4306
+ * For UI fed straight from a backend field that can arrive null, empty or partial.
4307
+ */
4308
+ static tryFromString(value) {
4309
+ if (!value)
4310
+ return Weekdays.empty();
4311
+ try {
4312
+ return Weekdays.fromString(value);
4204
4313
  }
4205
- else {
4206
- updated = currentDays.filter(d => d !== day);
4207
- updated.push(day.toLowerCase());
4314
+ catch {
4315
+ return Weekdays.empty();
4208
4316
  }
4209
- const newWeekdays = new Weekdays(updated);
4210
- setSelectedDays(newWeekdays);
4211
- onChange?.(newWeekdays.toString());
4317
+ }
4318
+ /** Selected flags in MTWRFSU order (Monday first). */
4319
+ toBooleans() {
4320
+ return this.days.map(day => day === day.toUpperCase());
4321
+ }
4322
+ /** @param flags selected flags in MTWRFSU order; missing entries count as unselected */
4323
+ static fromBooleans(flags) {
4324
+ return new Weekdays(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map((day, index) => flags[index] ? day : day.toLowerCase()));
4325
+ }
4326
+ /** 7-character mask in MTWRFSU order where "1" means selected, e.g. "1100100". */
4327
+ toMask() {
4328
+ return this.toBooleans().map(selected => (selected ? "1" : "0")).join("");
4329
+ }
4330
+ /** @param mask 7-character mask in MTWRFSU order where "1" means selected; a shorter, empty or
4331
+ * missing mask counts the absent days as unselected */
4332
+ static fromMask(mask) {
4333
+ return Weekdays.fromBooleans(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map((_, index) => mask?.[index] === "1"));
4334
+ }
4335
+ /** Selected days as Date.getDay() numbers (0 = Sunday), in MTWRFSU order. */
4336
+ toDayNumbers() {
4337
+ return this.days
4338
+ .filter(day => day === day.toUpperCase())
4339
+ .map(day => Weekdays.DAY_NUMBER_BY_CODE[day]);
4340
+ }
4341
+ /** @param days Date.getDay() numbers (0 = Sunday) */
4342
+ static fromDayNumbers(days) {
4343
+ const selected = new Set(days);
4344
+ return Weekdays.fromBooleans(Weekdays.WEEKDAYS_STANDARD_ARRAY_FULL.map(day => selected.has(Weekdays.DAY_NUMBER_BY_CODE[day])));
4345
+ }
4346
+ }
4347
+
4348
+ const CwWeekdaySelector = ({ value = "mtwrfsu", onChange, disabled = false, labelProps, layout, feedback, locale = "en-GB", className }) => {
4349
+ const selectedDays = Weekdays.tryFromString(value).toArray();
4350
+ const dayNames = React.useMemo(() => getWeekdayNames(locale), [locale]);
4351
+ const handleChange = (day, checked) => {
4352
+ const updated = selectedDays.filter(d => d !== day && d !== day.toLowerCase());
4353
+ updated.push(checked ? day : day.toLowerCase());
4354
+ onChange?.(new Weekdays(updated).toString());
4212
4355
  };
4213
- return (jsxRuntime.jsx("div", { className: styles$g["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4356
+ const feedbackMessages = feedback
4357
+ ? Array.isArray(feedback) ? feedback : [feedback]
4358
+ : [];
4359
+ const feedbackId = React.useId();
4360
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4361
+ const describedBy = feedbackIds.join(" ") || undefined;
4362
+ // Points at the label element rather than copying its text, which also covers a labelProps that
4363
+ // carries children instead of `text`.
4364
+ const labelId = labelProps?.id ?? `${feedbackId}-label`;
4365
+ return (jsxRuntime.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 && jsxRuntime.jsx(CwLabel, { id: labelId, ...labelProps }), jsxRuntime.jsx("div", { role: "group", className: styles$g.days, "aria-labelledby": labelProps ? labelId : undefined, "aria-describedby": describedBy, children: Weekdays.getFullWeek().map(day => (jsxRuntime.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) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4214
4366
  };
4215
4367
 
4216
4368
  var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
@@ -4258,6 +4410,9 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4258
4410
  const feedbackMessages = feedback
4259
4411
  ? Array.isArray(feedback) ? feedback : [feedback]
4260
4412
  : [];
4413
+ const feedbackId = React.useId();
4414
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4415
+ const describedBy = feedbackIds.join(" ") || undefined;
4261
4416
  // Effective layout — precedence: new `groupLayout`/`itemLayout` > legacy-derived > default.
4262
4417
  // Legacy `alignProps.flexDirection` drove the label-vs-options axis (default "row" = label
4263
4418
  // beside the options); map it to `groupLayout.direction`.
@@ -4270,7 +4425,7 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4270
4425
  ?? (optionsAlignment === "column" ? "row" : "column");
4271
4426
  // Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
4272
4427
  const checkDirection = itemDirection === "row" ? "column" : "row";
4273
- return (jsxRuntime.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 && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.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) => (jsxRuntime.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) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4428
+ return (jsxRuntime.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 && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.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) => (jsxRuntime.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) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4274
4429
  }
4275
4430
 
4276
4431
  var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
@@ -4297,11 +4452,14 @@ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemL
4297
4452
  const feedbackMessages = feedback
4298
4453
  ? Array.isArray(feedback) ? feedback : [feedback]
4299
4454
  : [];
4455
+ const feedbackId = React.useId();
4456
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4457
+ const describedBy = feedbackIds.join(" ") || undefined;
4300
4458
  // Each radio's circle-to-text layout is the opposite of the options flow: a stacked list
4301
4459
  // (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
4302
4460
  // best with the circle above the text.
4303
4461
  const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
4304
- return (jsxRuntime.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 && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.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) => (jsxRuntime.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) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4462
+ return (jsxRuntime.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 && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.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) => (jsxRuntime.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) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4305
4463
  }
4306
4464
 
4307
4465
  function CwToggle(props) {
@@ -4481,6 +4639,13 @@ function CwDropdown({ options, value, onChange, labelProps, alignProps, placehol
4481
4639
  const feedbackMessages = feedback
4482
4640
  ? Array.isArray(feedback) ? feedback : [feedback]
4483
4641
  : [];
4642
+ const feedbackId = React.useId();
4643
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
4644
+ const describedBy = feedbackIds.join(" ") || undefined;
4645
+ // The trigger is named by reference - the label for the field, the content for the current
4646
+ // value - so neither has to be copied into a string.
4647
+ const labelId = labelProps?.id ?? `${feedbackId}-label`;
4648
+ const valueId = `${feedbackId}-value`;
4484
4649
  // Scroll highlighted item into view
4485
4650
  React.useEffect(() => {
4486
4651
  if (isOpen && highlightedItemRef.current) {
@@ -4549,12 +4714,12 @@ function CwDropdown({ options, value, onChange, labelProps, alignProps, placehol
4549
4714
  }
4550
4715
  }, [isOpen, highlightedIndex, filteredOptions, handleOptionSelect]);
4551
4716
  const flexDirection = alignProps?.flexDirection ?? "row";
4552
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxRuntime.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: jsxRuntime.jsx("div", { className: "cw-dropdown-trigger-content", children: selectedOption ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [selectedOption.color && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsxRuntime.jsx("span", { children: selectedOption.label })] })) : (jsxRuntime.jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }) }), jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", paddingRight: "0.5rem", flexShrink: 0, cursor: disabled ? "not-allowed" : "pointer" }, onClick: handleTriggerClick, children: jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small" }) }), renderPanel(jsxRuntime.jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsxRuntime.jsx("div", { className: dropdownStyles.searchBox, children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsxRuntime.jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxRuntime.jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4553
- dropdownStyles.option,
4554
- value === option.value ? dropdownStyles.optionSelected : "",
4555
- highlightedIndex === index ? dropdownStyles.optionFocused : "",
4556
- option.disabled ? dropdownStyles.optionDisabled : "",
4557
- ].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 && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsxRuntime.jsx("span", { children: option.label })] }, option.value)))) : (jsxRuntime.jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] })] }), feedbackMessages.map((item, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": item.type, children: item.message }, index)))] }));
4717
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && jsxRuntime.jsx(CwLabel, { id: labelId, ...labelProps }), jsxRuntime.jsxs("div", { className: dropdownStyles.value, children: [jsxRuntime.jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxRuntime.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: [jsxRuntime.jsx("div", { className: "cw-dropdown-trigger-content", id: valueId, children: selectedOption ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [selectedOption.color && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsxRuntime.jsx("span", { children: selectedOption.label })] })) : (jsxRuntime.jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }), jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small" })] }), renderPanel(jsxRuntime.jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsxRuntime.jsx("div", { className: dropdownStyles.searchBox, children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsxRuntime.jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxRuntime.jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4718
+ dropdownStyles.option,
4719
+ value === option.value ? dropdownStyles.optionSelected : "",
4720
+ highlightedIndex === index ? dropdownStyles.optionFocused : "",
4721
+ option.disabled ? dropdownStyles.optionDisabled : "",
4722
+ ].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 && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsxRuntime.jsx("span", { children: option.label })] }, option.value)))) : (jsxRuntime.jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] }), feedbackMessages.map((item, index) => (jsxRuntime.jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": item.type, "aria-live": "polite", children: item.message }, index)))] })] }) }));
4558
4723
  }
4559
4724
 
4560
4725
  function CwDropdownFilter(props) {
@@ -4962,7 +5127,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4962
5127
  } }, props.ID))) })] }))] }));
4963
5128
  };
4964
5129
 
4965
- 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"};
5130
+ 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"};
4966
5131
 
4967
5132
  /**
4968
5133
  * Multi-select input with chip tags and searchable dropdown.
@@ -5097,8 +5262,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5097
5262
  // Keeping containerRef for any other potential use
5098
5263
  const direction = alignProps?.flexDirection ?? "row";
5099
5264
  const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
5100
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5101
- inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.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 && (jsxRuntime.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) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.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 && jsxRuntime.jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5265
+ const feedbackId = React.useId();
5266
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
5267
+ const describedBy = feedbackIds.join(" ") || undefined;
5268
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: styles$a.value, children: [jsxRuntime.jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5269
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.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 && (jsxRuntime.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) => (jsxRuntime.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) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.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 && jsxRuntime.jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5102
5270
  }
5103
5271
 
5104
5272
  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"};
@@ -6109,7 +6277,7 @@ function CwBtnCancel({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...res
6109
6277
  return (jsxRuntime.jsx(CwButton, { ...rest, variant: "icon", icon: "cancel", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Cancel" }));
6110
6278
  }
6111
6279
 
6112
- var styles$4 = {"pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
6280
+ 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"};
6113
6281
 
6114
6282
  /**
6115
6283
  * Renders a picker popup in a portal so it escapes overflow containers.
@@ -6166,6 +6334,9 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
6166
6334
  const feedbackMessages = feedback
6167
6335
  ? Array.isArray(feedback) ? feedback : [feedback]
6168
6336
  : [];
6337
+ const feedbackId = React.useId();
6338
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
6339
+ const describedBy = feedbackIds.join(" ") || undefined;
6169
6340
  const wrapperRef = React.useRef(null);
6170
6341
  const inputRef = React.useRef(null);
6171
6342
  const prevValueRef = React.useRef(undefined);
@@ -6346,11 +6517,11 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
6346
6517
  ...(maxDate ? [{ after: maxDate }] : []),
6347
6518
  ...(disabledMatcher ? [disabledMatcher] : []),
6348
6519
  ], [disabledDates, minDate, maxDate, disabledMatcher]);
6349
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6350
- today: new Date(),
6351
- }, modifiersClassNames: {
6352
- today: "rdp-day-today",
6353
- } }), 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)))] }));
6520
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: styles$4.value, children: [jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6521
+ today: new Date(),
6522
+ }, modifiersClassNames: {
6523
+ today: "rdp-day-today",
6524
+ } }), 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", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) }));
6354
6525
  }
6355
6526
 
6356
6527
  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"};
@@ -6989,14 +7160,14 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
6989
7160
  }
6990
7161
  return undefined;
6991
7162
  }, [value]);
6992
- 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: {
7163
+ 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, size: displayFormat.length, "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, size: displayFormat.length, "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: {
6993
7164
  today: new Date(),
6994
7165
  }, modifiersClassNames: {
6995
7166
  today: "rdp-day-today",
6996
7167
  } })] }), jsxRuntime.jsx("div", { role: "alert", "aria-live": "polite", className: rangeStyles.rangeError, children: rangeErrorMessage })] }))] })] }) }));
6997
7168
  }
6998
7169
 
6999
- 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"};
7170
+ 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"};
7000
7171
 
7001
7172
  const isMobileDevice = () => {
7002
7173
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
@@ -7158,7 +7329,7 @@ function CwTimePicker({ value, onChange, interval = 15, minTime, maxTime, labelP
7158
7329
  return (jsxRuntime.jsx("div", { className: `cw-timepicker cw-timepicker-native ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$4.pickerWrapper, children: jsxRuntime.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" }) })] }) }));
7159
7330
  }
7160
7331
  // Custom time picker
7161
- return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required, maxLength: 5, className: showClear ? timeStyles.hasIcons : timeStyles.notIcons }), showClear && (jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsxRuntime.jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsxRuntime.jsx("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsxRuntime.jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7332
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: `${styles$4.pickerWrapper} ${timeStyles.field}${showClear ? "" : ` ${timeStyles.narrow}`}`, children: [jsxRuntime.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 && (jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsxRuntime.jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsxRuntime.jsx("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsxRuntime.jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7162
7333
  const isSelected = time === value;
7163
7334
  return (jsxRuntime.jsx("button", { ref: isSelected ? selectedItemRef : null, type: "button", className: isSelected ? timeStyles.selected : "", onClick: () => handleTimeSelect(time), children: time }, time));
7164
7335
  }) }) }))] })] }) }));
@@ -7824,6 +7995,9 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7824
7995
  const feedbackMessages = feedback
7825
7996
  ? Array.isArray(feedback) ? feedback : [feedback]
7826
7997
  : [];
7998
+ const feedbackId = React.useId();
7999
+ const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
8000
+ const describedBy = feedbackIds.join(" ") || undefined;
7827
8001
  const wrapperRef = React.useRef(null);
7828
8002
  const inputRef = React.useRef(null);
7829
8003
  const prevValueRef = React.useRef(undefined);
@@ -7930,11 +8104,11 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7930
8104
  const defaultMonthJsDate = defaultMonth
7931
8105
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
7932
8106
  : selectedJsDate;
7933
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, required: required }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7934
- today: new Date(),
7935
- }, modifiersClassNames: {
7936
- today: "rdp-day-today",
7937
- } }), 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)))] }));
8107
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: styles$4.value, children: [jsxRuntime.jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8108
+ today: new Date(),
8109
+ }, modifiersClassNames: {
8110
+ today: "rdp-day-today",
8111
+ } }), 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", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) }));
7938
8112
  }
7939
8113
 
7940
8114
  // DateTimePickerState - immutable domain model for the Temporal date-time picker.
@@ -8672,7 +8846,7 @@ function CwDateRangePickerTemporal({ value, onChange, minDate, maxDate, disabled
8672
8846
  const defaultMonthJsDate = defaultMonth
8673
8847
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
8674
8848
  : (value?.from ? plainDateToJsDate(value.from) : undefined);
8675
- return (jsxRuntime.jsx("div", { ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxRuntime.jsxs("div", { className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, required: required, "data-focused": focusedInput === 'from' }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) })] }), jsxRuntime.jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxRuntime.jsxs("div", { className: styles$4.pickerWrapper, children: [jsxRuntime.jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, required: required, "data-focused": focusedInput === 'to' }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxRuntime.jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsxRuntime.jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsxRuntime.jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8849
+ 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, size: displayFormat.length, "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, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsxRuntime.jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsxRuntime.jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxRuntime.jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxRuntime.jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsxRuntime.jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsxRuntime.jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsxRuntime.jsx(reactDayPicker.DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale$1, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8676
8850
  today: new Date(),
8677
8851
  }, modifiersClassNames: {
8678
8852
  today: "rdp-day-today",
@@ -10238,6 +10412,7 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
10238
10412
  exports.CwAccordionContainer = CwAccordionContainer;
10239
10413
  exports.CwAlign = CwAlign;
10240
10414
  exports.CwAnchoredMenu = CwAnchoredMenu;
10415
+ exports.CwBadge = CwBadge;
10241
10416
  exports.CwBtnApprove = CwBtnApprove;
10242
10417
  exports.CwBtnCancel = CwBtnCancel;
10243
10418
  exports.CwBtnDelete = CwBtnDelete;