@cwellt_software/cwellt-reactjs-lib 1.4.14 → 1.5.0

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 (85) hide show
  1. package/dist/content/icons/new-cw-icons/NewCwIcons.json +1 -1
  2. package/dist/content/icons/new-cw-icons/css/new-cw-icons.css +260 -824
  3. package/dist/content/icons/new-cw-icons/fonts/NewCwIcons.woff +0 -0
  4. package/dist/index.cjs.js +564 -217
  5. package/dist/index.css +2 -2
  6. package/dist/index.d.ts +358 -66
  7. package/dist/index.es.js +558 -217
  8. package/dist/src/common/hooks/useRovingSingleSelect.d.ts +28 -0
  9. package/dist/src/common/hooks/useRovingSingleSelect.d.ts.map +1 -0
  10. package/dist/src/components/control/action/button/CwButton.d.ts +14 -4
  11. package/dist/src/components/control/action/button/CwButton.d.ts.map +1 -1
  12. package/dist/src/components/control/action/button/CwButtonSplit.d.ts +52 -0
  13. package/dist/src/components/control/action/button/CwButtonSplit.d.ts.map +1 -0
  14. package/dist/src/components/control/action/button/CwButtonSwitch.d.ts +65 -0
  15. package/dist/src/components/control/action/button/CwButtonSwitch.d.ts.map +1 -0
  16. package/dist/src/components/control/action/search/CwSearch.d.ts +2 -0
  17. package/dist/src/components/control/action/search/CwSearch.d.ts.map +1 -1
  18. package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts +35 -0
  19. package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts.map +1 -0
  20. package/dist/src/components/control/choice/checkbox/CwCheck.d.ts +6 -5
  21. package/dist/src/components/control/choice/checkbox/CwCheck.d.ts.map +1 -1
  22. package/dist/src/components/control/choice/checkbox/CwCheckboxGroup.d.ts +30 -7
  23. package/dist/src/components/control/choice/checkbox/CwCheckboxGroup.d.ts.map +1 -1
  24. package/dist/src/components/control/choice/checkbox/CwRadio.d.ts +10 -0
  25. package/dist/src/components/control/choice/checkbox/CwRadio.d.ts.map +1 -0
  26. package/dist/src/components/control/choice/checkbox/CwRadioGroup.d.ts +58 -0
  27. package/dist/src/components/control/choice/checkbox/CwRadioGroup.d.ts.map +1 -0
  28. package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts +78 -0
  29. package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts.map +1 -0
  30. package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts +9 -0
  31. package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts.map +1 -0
  32. package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts +9 -0
  33. package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts.map +1 -0
  34. package/dist/src/components/control/choice/toggle/CwToggle.d.ts +6 -5
  35. package/dist/src/components/control/choice/toggle/CwToggle.d.ts.map +1 -1
  36. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +12 -0
  37. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -1
  38. package/dist/src/components/control/input/image/CwInputImage.d.ts +17 -2
  39. package/dist/src/components/control/input/image/CwInputImage.d.ts.map +1 -1
  40. package/dist/src/components/display/graphics/icon/CwIcon.d.ts +1 -1
  41. package/dist/src/components/display/graphics/icon/CwIcon.d.ts.map +1 -1
  42. package/dist/src/components/display/graphics/loading/CwLoading.d.ts +3 -14
  43. package/dist/src/components/display/graphics/loading/CwLoading.d.ts.map +1 -1
  44. package/dist/src/components/display/graphics/loading/loadingConfig.d.ts +16 -0
  45. package/dist/src/components/display/graphics/loading/loadingConfig.d.ts.map +1 -0
  46. package/dist/src/index.d.ts +7 -2
  47. package/dist/src/index.d.ts.map +1 -1
  48. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  49. package/dist/src/playground/PlaygroundSection.d.ts +13 -0
  50. package/dist/src/playground/PlaygroundSection.d.ts.map +1 -0
  51. package/dist/src/playground/pages/CwButtonPage.d.ts +3 -0
  52. package/dist/src/playground/pages/CwButtonPage.d.ts.map +1 -0
  53. package/dist/src/playground/pages/CwButtonSplitPage.d.ts +3 -0
  54. package/dist/src/playground/pages/CwButtonSplitPage.d.ts.map +1 -0
  55. package/dist/src/playground/pages/CwButtonSwitchPage.d.ts +3 -0
  56. package/dist/src/playground/pages/CwButtonSwitchPage.d.ts.map +1 -0
  57. package/dist/src/playground/pages/CwCheckboxGroupPage.d.ts +3 -0
  58. package/dist/src/playground/pages/CwCheckboxGroupPage.d.ts.map +1 -0
  59. package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts +3 -0
  60. package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts.map +1 -0
  61. package/dist/src/playground/pages/CwInputImagePage.d.ts.map +1 -1
  62. package/dist/src/playground/pages/CwNavMenuPage.d.ts +3 -0
  63. package/dist/src/playground/pages/CwNavMenuPage.d.ts.map +1 -0
  64. package/dist/src/playground/pages/CwRadioGroupPage.d.ts +3 -0
  65. package/dist/src/playground/pages/CwRadioGroupPage.d.ts.map +1 -0
  66. package/dist/src/playground/pages/IconLibraryPage.d.ts +3 -0
  67. package/dist/src/playground/pages/IconLibraryPage.d.ts.map +1 -0
  68. package/dist/src/playground/pages/LoadingPage.d.ts +3 -0
  69. package/dist/src/playground/pages/LoadingPage.d.ts.map +1 -0
  70. package/dist/src/playground/pages/SelectorsPage.d.ts.map +1 -1
  71. package/dist/test/common/hooks/useRovingSingleSelect.test.d.ts +2 -0
  72. package/dist/test/common/hooks/useRovingSingleSelect.test.d.ts.map +1 -0
  73. package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts +2 -0
  74. package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts.map +1 -0
  75. package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts +2 -0
  76. package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts.map +1 -0
  77. package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts +2 -0
  78. package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts.map +1 -0
  79. package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts +2 -0
  80. package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts.map +1 -0
  81. package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts +2 -0
  82. package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts.map +1 -0
  83. package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts +2 -0
  84. package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts.map +1 -0
  85. package/package.json +1 -2
package/dist/index.cjs.js CHANGED
@@ -181,12 +181,7 @@ function getContrastColor(color) {
181
181
  return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
182
182
  }
183
183
 
184
- const SVG_ICONS = {
185
- 'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
186
- 'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
187
- };
188
-
189
- var styles$r = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
184
+ var styles$v = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
190
185
 
191
186
  // Constants
192
187
  const margin$1 = 16;
@@ -476,7 +471,7 @@ const CwTooltipManager = () => {
476
471
  if (!state.isVisible || !state.content) {
477
472
  return null;
478
473
  }
479
- return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$r["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$v["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
480
475
  top: `${tooltipPosition.top}px`,
481
476
  left: `${tooltipPosition.left}px`,
482
477
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -557,16 +552,22 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
557
552
  React.useEffect(() => {
558
553
  ensureTooltipManager();
559
554
  }, []);
560
- return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$r["cw-tooltip"], children: children }));
555
+ return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$v["cw-tooltip"], children: children }));
556
+ };
557
+
558
+ const SVG_ICONS = {
559
+ 'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
560
+ 'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
561
561
  };
562
562
 
563
563
  function CwIcon(props) {
564
- const { iconId, color, size, title, tooltipPosition = 'bottom', ...iconProps } = props;
564
+ const { iconId, color, size, className, title, tooltipPosition = 'bottom', ...iconProps } = props;
565
565
  const getClassName = (baseClass) => {
566
566
  return [
567
567
  baseClass,
568
568
  color && `cw-color-${color}`,
569
- size && `cw-font-size-${size}`
569
+ size && `cw-font-size-${size}`,
570
+ className
570
571
  ].filter(Boolean).join(' ');
571
572
  };
572
573
  let iconElement;
@@ -978,49 +979,39 @@ function CwImageZoom(image) {
978
979
  } }), jsxRuntime.jsx("div", { style: { color: "#fff", fontSize: "1rem", textAlign: "center" }, children: selectedImage.filename && jsxRuntime.jsx("div", { children: selectedImage.filename }) })] }))] }));
979
980
  }
980
981
 
982
+ let defaults = {};
981
983
  /**
982
- * CwLoading
983
- *
984
- * A versatile loading component that shows a spinner with optional text
985
- * and disables the wrapped content while in loading state.
986
- *
987
- * @example
988
- * // Basic usage
989
- * <CwLoading isLoading={isSubmitting}>
990
- * <form>...</form>
991
- * </CwLoading>
992
- *
993
- * // With custom text and size
994
- * <CwLoading
995
- * isLoading={isLoading}
996
- * text="Please wait..."
997
- * size="large"
998
- * >
999
- * <UserProfile />
1000
- * </CwLoading>
984
+ * Register global CwLoading defaults. Call once at app init, before the first render.
985
+ * Merges into any previously configured defaults.
1001
986
  */
1002
- function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName = 'cwi-plane-solid', animation = 'spin', children }) {
1003
- const iconClasses = `cwi-icons ${iconName || ''}`;
1004
- return (jsxRuntime.jsxs("div", { "aria-busy": isLoading, className: isLoading ? 'cw-loading-container' : '', "data-children": !!children, children: [isLoading && (jsxRuntime.jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, children: [jsxRuntime.jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, children: jsxRuntime.jsx("span", { className: iconClasses }) }), text && (jsxRuntime.jsx("p", { children: text }))] })), jsxRuntime.jsx("div", { className: isLoading ? 'cw-loading-disabled-content' : '', children: children })] }));
987
+ function configureCwLoading(next) {
988
+ defaults = { ...defaults, ...next };
989
+ }
990
+ /** Read the currently configured CwLoading defaults. */
991
+ function getCwLoadingDefaults() {
992
+ return defaults;
1005
993
  }
1006
994
 
1007
995
  /**
1008
- * @deprecated since may 2025. Use <CwLoading size="small"> instead.
996
+ * CwLoading — a spinner with optional text that dims the wrapped content while loading.
1009
997
  *
1010
- * This component will be removed in a future release.
998
+ * Icon resolves as `iconName` prop → `getCwLoadingDefaults().icon` → none (neutral ring).
1011
999
  *
1012
1000
  * @example
1013
- * // Instead of:
1014
- * <CwLoadingSmall />
1015
- *
1016
- * // Use:
1017
- * <CwLoading size="small" />
1001
+ * <CwLoading isLoading={isSubmitting}>
1002
+ * <form>...</form>
1003
+ * </CwLoading>
1018
1004
  */
1019
- function CwLoadingSmall(CwelltLoadingAppointements) {
1020
- return (jsxRuntime.jsx("div", { children: CwelltLoadingAppointements.isLoading === true ? (jsxRuntime.jsx("div", { className: "cw-loading-container", children: jsxRuntime.jsx("div", { className: "cw-loading" }) })) : (jsxRuntime.jsx("div", {})) }));
1005
+ function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName, animation = 'spin', children }) {
1006
+ let overlay = null;
1007
+ if (isLoading) {
1008
+ const resolvedIcon = iconName ?? getCwLoadingDefaults().icon;
1009
+ overlay = (jsxRuntime.jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, role: "status", "aria-label": text || 'Loading', children: [jsxRuntime.jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, "data-has-icon": !!resolvedIcon, children: resolvedIcon && jsxRuntime.jsx("span", { className: `cwi-icons ${resolvedIcon}` }) }), text && (jsxRuntime.jsx("p", { children: text }))] }));
1010
+ }
1011
+ return (jsxRuntime.jsxs("div", { "aria-busy": isLoading, className: "cw-loading-container", "data-children": !!children, children: [overlay, jsxRuntime.jsx("div", { className: "cw-loading-disabled-content", children: children })] }));
1021
1012
  }
1022
1013
 
1023
- var styles$q = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
1014
+ var styles$u = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
1024
1015
 
1025
1016
  // Constants moved outside to prevent recreation
1026
1017
  const margin = 16;
@@ -1143,12 +1134,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1143
1134
  const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
1144
1135
  setIsVisible(true);
1145
1136
  }, showDelay);
1146
- const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$q["cw-generic-tooltip-content"]);
1137
+ const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$u["cw-generic-tooltip-content"]);
1147
1138
  // Memoize tooltip content creation
1148
1139
  const tooltipContent = React.useMemo(() => {
1149
1140
  if (hide || !isVisible || !content)
1150
1141
  return null;
1151
- return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$q["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1142
+ return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$u["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1152
1143
  position: 'fixed',
1153
1144
  top: `${tooltipPosition.top}px`,
1154
1145
  left: `${tooltipPosition.left}px`,
@@ -1163,10 +1154,10 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1163
1154
  clearTooltipTimeout();
1164
1155
  setIsVisible(false);
1165
1156
  }, [clearTooltipTimeout]);
1166
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$q["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1157
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1167
1158
  };
1168
1159
 
1169
- function CwButton({ text, variant = 'solid', color = 'primary', className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }) {
1160
+ const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
1170
1161
  // Build CSS classes based on variant and props
1171
1162
  let buttonClass = `cw-button-${variant}`;
1172
1163
  // Add icon class only for icon variant without children
@@ -1177,9 +1168,18 @@ function CwButton({ text, variant = 'solid', color = 'primary', className = '',
1177
1168
  buttonClass += ` ${className}`;
1178
1169
  }
1179
1170
  const tooltipContent = title || (variant === 'icon' && text ? text : undefined);
1180
- const buttonElement = (jsxRuntime.jsx("button", { type: "button", className: buttonClass, ...buttonProps, "data-color": color, "aria-label": tooltipContent, children: variant === 'icon' ? null : (children ?? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [icon && jsxRuntime.jsx(CwIcon, { iconId: icon }), text && jsxRuntime.jsx("strong", { children: text })] }))) }));
1171
+ const iconElement = icon ? jsxRuntime.jsx(CwIcon, { iconId: icon }) : null;
1172
+ const textElement = text ? jsxRuntime.jsx("strong", { children: text }) : null;
1173
+ // Only emit toggle attributes when `pressed` is defined; otherwise output stays identical to a normal button.
1174
+ const pressedProps = pressed !== undefined
1175
+ ? { "aria-pressed": pressed, "data-pressed": pressed ? "true" : undefined }
1176
+ : {};
1177
+ 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'
1178
+ ? jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [textElement, iconElement] })
1179
+ : jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconElement, textElement] }))) }));
1181
1180
  return tooltipContent ? (jsxRuntime.jsx(CwTooltipNew, { content: tooltipContent, position: tooltipPosition, displayInline: true, children: buttonElement })) : (buttonElement);
1182
- }
1181
+ });
1182
+ CwButton.displayName = "CwButton";
1183
1183
 
1184
1184
  // Reference for draggable modal
1185
1185
  /**
@@ -1216,7 +1216,7 @@ function CwModal(custModalProps) {
1216
1216
  return (jsxRuntime.jsx("div", { children: custModalProps.modalState && (jsxRuntime.jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsxRuntime.jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsxRuntime.jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxRuntime.jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxRuntime.jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsxRuntime.jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsxRuntime.jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsxRuntime.jsx("span", { className: "cwelltCloseIcon" }) })] }), jsxRuntime.jsx("div", { className: "cwelltModalBody", children: jsxRuntime.jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsxRuntime.jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsxRuntime.jsx("div", { style: { display: "none" } }))] }) })] })) }));
1217
1217
  }
1218
1218
 
1219
- var styles$p = {"overlayPositioned":"CwConfirmationPopup-module__overlayPositioned__11qYB","popup":"CwConfirmationPopup-module__popup__ahPjM","message":"CwConfirmationPopup-module__message__MnNL4","buttons":"CwConfirmationPopup-module__buttons__fGYYE","button":"CwConfirmationPopup-module__button__ugYQE","confirmButton":"CwConfirmationPopup-module__confirmButton__rTP4S","cancelButton":"CwConfirmationPopup-module__cancelButton__Ry694"};
1219
+ var styles$t = {"overlayPositioned":"CwConfirmationPopup-module__overlayPositioned__11qYB","popup":"CwConfirmationPopup-module__popup__ahPjM","message":"CwConfirmationPopup-module__message__MnNL4","buttons":"CwConfirmationPopup-module__buttons__fGYYE","button":"CwConfirmationPopup-module__button__ugYQE","confirmButton":"CwConfirmationPopup-module__confirmButton__rTP4S","cancelButton":"CwConfirmationPopup-module__cancelButton__Ry694"};
1220
1220
 
1221
1221
  function CwConfirmationPopup(props) {
1222
1222
  const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
@@ -1280,15 +1280,15 @@ function CwConfirmationPopup(props) {
1280
1280
  onCancel();
1281
1281
  }
1282
1282
  };
1283
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$p.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$p.popup, style: {
1283
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$t.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$t.popup, style: {
1284
1284
  position: 'absolute',
1285
1285
  top: `${position.top}px`,
1286
1286
  left: `${position.left}px`,
1287
1287
  transform: 'none'
1288
- }, children: [jsxRuntime.jsx("p", { className: styles$p.message, children: message }), jsxRuntime.jsxs("div", { className: styles$p.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$p.button} ${styles$p.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$p.button} ${styles$p.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1288
+ }, children: [jsxRuntime.jsx("p", { className: styles$t.message, children: message }), jsxRuntime.jsxs("div", { className: styles$t.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1289
1289
  }
1290
1290
 
1291
- var styles$o = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1291
+ var styles$s = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1292
1292
 
1293
1293
  // Helper function to parse size values
1294
1294
  const parseSize = (size) => {
@@ -1561,7 +1561,7 @@ const CwDialog = props => {
1561
1561
  }
1562
1562
  }
1563
1563
  }, [open]);
1564
- const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$o["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1564
+ const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$s["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1565
1565
  const content = React.useMemo(() => (jsxRuntime.jsx("section", { children: children })), [children]);
1566
1566
  const footer = React.useMemo(() => (jsxRuntime.jsx("footer", { children: customFooter || (jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
1567
1567
  const resizeHandles = React.useMemo(() => size.autoHeight
@@ -1588,7 +1588,7 @@ const CwDialog = props => {
1588
1588
  : `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
1589
1589
  return { displayWidth, displayHeight };
1590
1590
  }, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
1591
- const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$o["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1591
+ const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$s["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1592
1592
  left: `${position.x}px`,
1593
1593
  top: `${position.y}px`,
1594
1594
  width: displayDimensions.displayWidth,
@@ -1749,7 +1749,7 @@ function CwAlign(props) {
1749
1749
  }, children: props.children }));
1750
1750
  }
1751
1751
 
1752
- var styles$n = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
1752
+ var styles$r = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
1753
1753
 
1754
1754
  /**
1755
1755
  * CwCard - A simple card component for displaying content in a contained format
@@ -1775,11 +1775,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1775
1775
  // Construct class names using CSS modules
1776
1776
  const cardClassNames = [
1777
1777
  'cw-card',
1778
- styles$n.card,
1778
+ styles$r.card,
1779
1779
  className,
1780
- clickable ? styles$n.clickable : '',
1781
- disabled ? styles$n.disabled : '',
1782
- isLoading ? styles$n.loading : '',
1780
+ clickable ? styles$r.clickable : '',
1781
+ disabled ? styles$r.disabled : '',
1782
+ isLoading ? styles$r.loading : '',
1783
1783
  ].filter(Boolean).join(' ');
1784
1784
  // Handle click event when card is clickable
1785
1785
  const handleClick = () => {
@@ -1796,15 +1796,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1796
1796
  // Determine if footer should be rendered
1797
1797
  const hasFooter = hasChips || footer || (hasActions && resolvedDirection === "row");
1798
1798
  // Actions component to reuse
1799
- const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$n.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1799
+ const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$r.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1800
1800
  return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
1801
1801
  role: 'button',
1802
1802
  tabIndex: 0,
1803
1803
  onClick: handleClick,
1804
- }), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$n.headerContent, "data-align": resolvedAlign, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$n.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$n.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$n.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$n.footerContent, children: footer }))] })), resolvedDirection === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$n.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1804
+ }), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$r.headerContent, "data-align": resolvedAlign, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$r.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$r.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$r.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$r.footerContent, children: footer }))] })), resolvedDirection === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$r.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1805
1805
  };
1806
1806
 
1807
- var styles$m = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1807
+ var styles$q = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1808
1808
 
1809
1809
  /**
1810
1810
  * Option to display in the CwSelect
@@ -1899,10 +1899,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
1899
1899
  icon: sortDirection === 'asc' ? 'arrow-up' : 'arrow-down',
1900
1900
  onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'),
1901
1901
  title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}`,
1902
- }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: styles$m.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$m.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$m.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$m.pagination, children: [jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxRuntime.jsxs("span", { className: styles$m.pageInfo, children: [currentPage, " / ", totalPages] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
1902
+ }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: styles$q.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$q.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$q.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$q.pagination, children: [jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxRuntime.jsxs("span", { className: styles$q.pageInfo, children: [currentPage, " / ", totalPages] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
1903
1903
  }
1904
1904
 
1905
- var styles$l = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1905
+ var styles$p = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1906
1906
 
1907
1907
  /**
1908
1908
  *
@@ -1919,7 +1919,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
1919
1919
  setVisible_accordionBody(!isVisible_accordionBody);
1920
1920
  };
1921
1921
  // #endregion
1922
- return (jsxRuntime.jsxs("div", { className: styles$l["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$l["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1922
+ return (jsxRuntime.jsxs("div", { className: styles$p["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$p["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1923
1923
  }
1924
1924
 
1925
1925
  /**
@@ -2177,7 +2177,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2177
2177
  }, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2178
2178
  }
2179
2179
 
2180
- var styles$k = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2180
+ var styles$o = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2181
2181
 
2182
2182
  /**
2183
2183
  * Hook that provides state management for CwSortableTable.
@@ -2240,9 +2240,9 @@ function useSortableTable(initialItems) {
2240
2240
  }
2241
2241
 
2242
2242
  // ─── Drop indicator row ───────────────────────────────────────────────────────
2243
- const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$k.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2243
+ const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$o.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2244
2244
  // ─── Loading skeleton ─────────────────────────────────────────────────────────
2245
- const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$k.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$k.skeleton }) }) }, i))) }));
2245
+ const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$o.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$o.skeleton }) }) }, i))) }));
2246
2246
  // ─── Component ────────────────────────────────────────────────────────────────
2247
2247
  /**
2248
2248
  * CwSortableTable
@@ -2329,11 +2329,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2329
2329
  return items.map((item, index) => {
2330
2330
  const key = item[rowKey];
2331
2331
  const isDragging = draggedItem?.[rowKey] === key;
2332
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$k.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2332
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$o.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2333
2333
  });
2334
2334
  };
2335
2335
  // ── Render ──────────────────────────────────────────────────────────────
2336
- return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$k.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2336
+ return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$o.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2337
2337
  }
2338
2338
 
2339
2339
  /**
@@ -2532,7 +2532,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2532
2532
  }, 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" })] })] }))] }));
2533
2533
  }
2534
2534
 
2535
- var styles$j = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2535
+ 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"};
2536
2536
 
2537
2537
  const TabIcon = ({ icon }) => {
2538
2538
  if (!icon)
@@ -2582,7 +2582,7 @@ function CwTabs(CwTabsProps) {
2582
2582
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2583
2583
  ? { minWidth: CwTabsProps.tabsListWidth }
2584
2584
  : undefined;
2585
- return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$j['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$j['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$j['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2585
+ 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, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2586
2586
  }
2587
2587
 
2588
2588
  /**
@@ -2609,7 +2609,7 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
2609
2609
  return (jsxRuntime.jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsxRuntime.jsx("summary", { children: briefing }), children && jsxRuntime.jsx("section", { children: children })] }));
2610
2610
  };
2611
2611
 
2612
- var styles$i = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2612
+ var styles$m = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2613
2613
 
2614
2614
  const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, detailContent, emptyDetail, searchPlaceholder = 'Search...', onSearch, masterHeader, masterFooter, masterWidth: initialWidth = 320, minMasterWidth = 240, maxMasterWidth = 500, resizable = true, showSearch = true, }) => {
2615
2615
  const [masterWidth, setMasterWidth] = React.useState(initialWidth);
@@ -2645,10 +2645,10 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2645
2645
  document.body.style.userSelect = '';
2646
2646
  };
2647
2647
  }, [isResizing, minMasterWidth, maxMasterWidth]);
2648
- const rootClassName = [styles$i['cw-master-detail'], className].filter(Boolean).join(' ');
2649
- return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$i.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$i.detail, children: selectedKey && detailContent
2648
+ const rootClassName = [styles$m['cw-master-detail'], className].filter(Boolean).join(' ');
2649
+ return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$m.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$m.detail, children: selectedKey && detailContent
2650
2650
  ? detailContent
2651
- : (jsxRuntime.jsx("div", { className: styles$i['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2651
+ : (jsxRuntime.jsx("div", { className: styles$m['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2652
2652
  };
2653
2653
 
2654
2654
  /**
@@ -2673,7 +2673,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
2673
2673
  : emptyValue })] }, item.key))) }));
2674
2674
  };
2675
2675
 
2676
- var styles$h = {"sortableList":"cw-sortable-list-module__sortableList__PyLO-","sortableItem":"cw-sortable-list-module__sortableItem__FAnn2","readOnly":"cw-sortable-list-module__readOnly__r7GcH","dragging":"cw-sortable-list-module__dragging__MD715","moved":"cw-sortable-list-module__moved__sE6-N","expandedContent":"cw-sortable-list-module__expandedContent__Kocna","sortableHandle":"cw-sortable-list-module__sortableHandle__HvYBK","sortableContent":"cw-sortable-list-module__sortableContent__C6JhR","sortableTitle":"cw-sortable-list-module__sortableTitle__EgWXr","sortableExtraContent":"cw-sortable-list-module__sortableExtraContent__s4LSv","sortableActions":"cw-sortable-list-module__sortableActions__gwQOU","dropIndicator":"cw-sortable-list-module__dropIndicator__MNSF-","emptyMessage":"cw-sortable-list-module__emptyMessage__gMpaL"};
2676
+ var styles$l = {"sortableList":"cw-sortable-list-module__sortableList__PyLO-","sortableItem":"cw-sortable-list-module__sortableItem__FAnn2","readOnly":"cw-sortable-list-module__readOnly__r7GcH","dragging":"cw-sortable-list-module__dragging__MD715","moved":"cw-sortable-list-module__moved__sE6-N","expandedContent":"cw-sortable-list-module__expandedContent__Kocna","sortableHandle":"cw-sortable-list-module__sortableHandle__HvYBK","sortableContent":"cw-sortable-list-module__sortableContent__C6JhR","sortableTitle":"cw-sortable-list-module__sortableTitle__EgWXr","sortableExtraContent":"cw-sortable-list-module__sortableExtraContent__s4LSv","sortableActions":"cw-sortable-list-module__sortableActions__gwQOU","dropIndicator":"cw-sortable-list-module__dropIndicator__MNSF-","emptyMessage":"cw-sortable-list-module__emptyMessage__gMpaL"};
2677
2677
 
2678
2678
  function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
2679
2679
  const [draggedItem, setDraggedItem] = React.useState(null);
@@ -2736,15 +2736,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
2736
2736
  }
2737
2737
  };
2738
2738
  if (items.length === 0) {
2739
- return (jsxRuntime.jsx("div", { className: `${styles$h.sortableList} ${styles$h.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$h.emptyMessage, children: emptyMessage }) }));
2739
+ return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${styles$l.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$l.emptyMessage, children: emptyMessage }) }));
2740
2740
  }
2741
- return (jsxRuntime.jsx("div", { className: `${styles$h.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2741
+ return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2742
2742
  const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
2743
2743
  const isDragging = draggedItem?.id === item.id;
2744
2744
  const isMoved = movedItems.has(item.id);
2745
2745
  const canExpand = Boolean(expandedContent);
2746
2746
  const isExpanded = expandedItems.has(item.id);
2747
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$h.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$h.sortableItem} ${isDragging ? styles$h.dragging : ''} ${isMoved ? styles$h.moved : ''} ${readOnly ? styles$h.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$h.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$h.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$h.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$h.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$h.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$h.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$h.dropIndicator }))] }, item.id));
2747
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$l.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$l.sortableItem} ${isDragging ? styles$l.dragging : ''} ${isMoved ? styles$l.moved : ''} ${readOnly ? styles$l.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$l.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$l.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$l.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$l.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$l.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$l.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$l.dropIndicator }))] }, item.id));
2748
2748
  }) }));
2749
2749
  }
2750
2750
 
@@ -2870,60 +2870,9 @@ const CwTableGrouped = props => {
2870
2870
  group.rows.map((child, j) => (jsxRuntime.jsx("tr", { "data-row": true, "data-row-last-of-group": j == group.rows.length - 1, children: child.cells.map((cell, k) => (jsxRuntime.jsx("td", { children: cell.content }, k))) }, j)))] }, i))) }), jsxRuntime.jsx("tfoot", {})] }) }));
2871
2871
  };
2872
2872
 
2873
- function CwFileUpload(fileUploadProps) {
2874
- const [previewURL, setPreviewURL] = React.useState("");
2875
- const [error, setError] = React.useState(null);
2876
- const [_selectedFileName, setSelectedFileName] = React.useState("");
2877
- const [_currentHexContent, setCurrentHexContent] = React.useState("");
2878
- React.useEffect(() => {
2879
- // If there is hexadecimal preview content, set the Preview URL
2880
- if (fileUploadProps.file?.Bindata) {
2881
- setPreviewURL(`data:image/png;base64,${fileUploadProps.file.Bindata}`);
2882
- }
2883
- }, [fileUploadProps.file?.Bindata]);
2884
- const handleFileChange = (event) => {
2885
- const file = event.target.files?.[0];
2886
- setSelectedFileName(file?.name ?? "");
2887
- if (file) {
2888
- const allowedExts = fileUploadProps.accept.split(',').map(ext => ext.trim().replace('.', '').toLowerCase());
2889
- const fileExt = file.name.split('.').pop()?.toLowerCase() ?? "";
2890
- if (!allowedExts.includes(fileExt)) {
2891
- setError(`Invalid file type. Only ${fileUploadProps.acceptString} files are allowed.`);
2892
- setPreviewURL("");
2893
- return;
2894
- }
2895
- setError(null);
2896
- const reader = new FileReader();
2897
- reader.onloadend = () => {
2898
- if (typeof reader.result === "string") {
2899
- const hexContent = arrayBufferToHex(reader.result);
2900
- setCurrentHexContent(hexContent);
2901
- setPreviewURL(reader.result);
2902
- setCurrentHexContent(arrayBufferToHex(reader.result));
2903
- // Call function to store hexadecimal content
2904
- fileUploadProps.onSaveHexContent(arrayBufferToHex(reader.result));
2905
- }
2906
- };
2907
- reader.readAsDataURL(file);
2908
- }
2909
- };
2910
- // Function to convert the image buffer into hexadecimal content
2911
- const arrayBufferToHex = (dataUrl) => {
2912
- // Decodes the base64 of the URL data
2913
- const base64 = dataUrl.split(",")[1];
2914
- const binary = atob(base64);
2915
- let hex = "";
2916
- for (let i = 0; i < binary.length; i++) {
2917
- hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
2918
- }
2919
- return hex;
2920
- };
2921
- return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "row", children: [jsxRuntime.jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsxRuntime.jsx("div", { className: "row error", children: error }), jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
2922
- }
2923
-
2924
- var styles$g = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
2873
+ var styles$k = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
2925
2874
 
2926
- const DEFAULT_LABELS = {
2875
+ const DEFAULT_LABELS$1 = {
2927
2876
  uploadDisabled: 'Upload disabled',
2928
2877
  clickToUpload: 'Click to upload or drag and drop',
2929
2878
  acceptedFiles: (accept) => `Accepted files: ${accept}`,
@@ -2931,6 +2880,7 @@ const DEFAULT_LABELS = {
2931
2880
  allTypesAccepted: 'All file types accepted',
2932
2881
  changeFile: 'Change File',
2933
2882
  clearAll: 'Clear all',
2883
+ upload: 'Upload',
2934
2884
  addMoreFiles: 'Add More Files',
2935
2885
  filesSelected: (count) => `${count} file${count !== 1 ? 's' : ''} selected`,
2936
2886
  fileTooLarge: (name, maxSize) => `File "${name}" is too large. Maximum size allowed is ${maxSize}MB.`,
@@ -2938,11 +2888,38 @@ const DEFAULT_LABELS = {
2938
2888
  invalidMimeType: (name, types) => `File "${name}" has an invalid MIME type. Allowed types: ${types}`,
2939
2889
  alreadySelected: (name) => `File "${name}" is already selected.`,
2940
2890
  };
2891
+ /**
2892
+ * Checks a file against an `accept` string (comma-separated tokens). A token can be a dotted
2893
+ * extension (".pdf"), an exact MIME type ("application/pdf"), a wildcard MIME ("image" + slash + "star"),
2894
+ * or a bare "star" / "star-slash-star" for anything. Returns true if the file matches ANY token
2895
+ * (or if `accept` is empty).
2896
+ */
2897
+ function fileMatchesAccept(fileName, fileType, accept) {
2898
+ const tokens = accept.split(',').map(token => token.trim().toLowerCase()).filter(Boolean);
2899
+ if (tokens.length === 0) {
2900
+ return true;
2901
+ }
2902
+ const fileExtension = '.' + (fileName.split('.').pop()?.toLowerCase() ?? '');
2903
+ const mimeType = fileType.toLowerCase();
2904
+ return tokens.some(token => {
2905
+ if (token === '*' || token === '*/*') {
2906
+ return true;
2907
+ }
2908
+ if (token.startsWith('.')) {
2909
+ return token === fileExtension;
2910
+ }
2911
+ if (token.endsWith('/*')) {
2912
+ const prefix = token.slice(0, token.indexOf('/') + 1);
2913
+ return mimeType.startsWith(prefix);
2914
+ }
2915
+ return token === mimeType;
2916
+ });
2917
+ }
2941
2918
  function CwFileUploadMultiple(fileUploadProps) {
2942
2919
  const fileInputRef = React.useRef(null);
2943
2920
  const [selectedFiles, setSelectedFiles] = React.useState([]);
2944
2921
  const [existingFile, setExistingFile] = React.useState(fileUploadProps.initialFileName);
2945
- const labels = { ...DEFAULT_LABELS, ...fileUploadProps.labels };
2922
+ const labels = { ...DEFAULT_LABELS$1, ...fileUploadProps.labels };
2946
2923
  React.useEffect(() => {
2947
2924
  setExistingFile(fileUploadProps.initialFileName);
2948
2925
  }, [fileUploadProps.initialFileName]);
@@ -2960,17 +2937,9 @@ function CwFileUploadMultiple(fileUploadProps) {
2960
2937
  };
2961
2938
  }
2962
2939
  }
2963
- // Validate file type by extension (based in accept)
2940
+ // Validate file type against accept (dotted extensions, exact MIME, wildcard MIME, or *)
2964
2941
  if (fileUploadProps.accept) {
2965
- const acceptedExtensions = fileUploadProps.accept.split(',').map(ext => ext.trim().toLowerCase());
2966
- const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
2967
- const isExtensionValid = acceptedExtensions.some(ext => {
2968
- if (ext.startsWith('.')) {
2969
- return ext === fileExtension;
2970
- }
2971
- return false;
2972
- });
2973
- if (!isExtensionValid) {
2942
+ if (!fileMatchesAccept(file.name, file.type, fileUploadProps.accept)) {
2974
2943
  return {
2975
2944
  isValid: false,
2976
2945
  error: labels.invalidFormat(file.name, fileUploadProps.accept)
@@ -2995,7 +2964,7 @@ function CwFileUploadMultiple(fileUploadProps) {
2995
2964
  const errors = [];
2996
2965
  for (const file of fileArray) {
2997
2966
  // Check if the file already exists (by name and size)
2998
- const isDuplicate = existingFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
2967
+ const isDuplicate = validFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
2999
2968
  if (isDuplicate) {
3000
2969
  errors.push(labels.alreadySelected(file.name));
3001
2970
  continue;
@@ -3013,8 +2982,7 @@ function CwFileUploadMultiple(fileUploadProps) {
3013
2982
  fileUploadProps.onError(errors.join('\n'));
3014
2983
  }
3015
2984
  else {
3016
- console.error(errors.join('\n'));
3017
- alert(errors.join('\n')); // Fallback if there is no onError
2985
+ CwDisplayMessage(errors.join('\n'), exports.CwMessageType.ERROR);
3018
2986
  }
3019
2987
  }
3020
2988
  // If not multiple, only take the first valid file (replace)
@@ -3088,12 +3056,20 @@ function CwFileUploadMultiple(fileUploadProps) {
3088
3056
  }
3089
3057
  }
3090
3058
  };
3091
- return (jsxRuntime.jsxs("div", { className: `${styles$g.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$g.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$g.uploadArea} ${fileUploadProps.disabled ? styles$g.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$g.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$g.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$g.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$g.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$g.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$g.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$g.fileInfo, children: jsxRuntime.jsx("p", { className: styles$g.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3059
+ return (jsxRuntime.jsxs("div", { className: `${styles$k.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$k.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$k.uploadArea} ${fileUploadProps.disabled ? styles$k.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$k.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$k.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$k.fileInfo, children: jsxRuntime.jsx("p", { className: styles$k.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3092
3060
  setExistingFile(undefined);
3093
3061
  if (fileUploadProps.onSelect) {
3094
3062
  fileUploadProps.onSelect(null);
3095
3063
  }
3096
- }, disabled: fileUploadProps.disabled, className: styles$g.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$g.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("small", { className: styles$g.filesCount, children: labels.filesSelected(selectedFiles.length) }), !fileUploadProps.hideClearAll && (jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$g.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$g.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$g.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$g.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$g.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$g.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$g.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3064
+ }, disabled: fileUploadProps.disabled, className: styles$k.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsxRuntime.jsx("small", { className: styles$k.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsxRuntime.jsx(CwButton, { onClick: () => {
3065
+ let files = fileInputRef.current?.files ?? null;
3066
+ if (!files) {
3067
+ const dataTransfer = new DataTransfer();
3068
+ selectedFiles.forEach(file => dataTransfer.items.add(file));
3069
+ files = dataTransfer.files;
3070
+ }
3071
+ fileUploadProps.onConfirm?.(files);
3072
+ }, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$k.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$k.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$k.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$k.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3097
3073
  }
3098
3074
 
3099
3075
  function CwInput(CwInputProps) {
@@ -3134,7 +3110,7 @@ function CwDigit(props) {
3134
3110
  return (jsxRuntime.jsx("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 }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3135
3111
  }
3136
3112
 
3137
- var styles$f = {"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"};
3113
+ 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"};
3138
3114
 
3139
3115
  const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
3140
3116
  const [rgb, setRgb] = React.useState({ r: 255, g: 255, b: 255 });
@@ -3337,13 +3313,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
3337
3313
  // Calculate background color for the main area based on current hue
3338
3314
  const hueColor = hsvToRgb(hsv.h, 100, 100);
3339
3315
  const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
3340
- return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$f.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$f.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$f.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$f.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$f.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$f.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$f.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$f.whiteGradient }), jsxRuntime.jsx("div", { className: styles$f.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$f.colorAreaCursor, style: {
3316
+ return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$j.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$j.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$j.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$j.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$j.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$j.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$j.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$j.whiteGradient }), jsxRuntime.jsx("div", { className: styles$j.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$j.colorAreaCursor, style: {
3341
3317
  left: `${hsv.s}%`,
3342
3318
  top: `${100 - hsv.v}%`
3343
3319
  } })] })] })] }));
3344
3320
  };
3345
3321
 
3346
- var styles$e = {"container":"cw-input-color-module__container__x7gpk","selectColor":"cw-input-color-module__selectColor__DTo3V","disabled":"cw-input-color-module__disabled__O1fK5","readOnly":"cw-input-color-module__readOnly__HL-Bz","colorDropdown":"cw-input-color-module__colorDropdown__pX2bc"};
3322
+ var styles$i = {"container":"cw-input-color-module__container__x7gpk","selectColor":"cw-input-color-module__selectColor__DTo3V","disabled":"cw-input-color-module__disabled__O1fK5","readOnly":"cw-input-color-module__readOnly__HL-Bz","colorDropdown":"cw-input-color-module__colorDropdown__pX2bc"};
3347
3323
 
3348
3324
  const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
3349
3325
  const [isOpen, setIsOpen] = React.useState(false);
@@ -3476,11 +3452,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
3476
3452
  break;
3477
3453
  }
3478
3454
  };
3479
- return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$e.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$e.selectColor} ${disabled ? styles$e.disabled : ''} ${readOnly ? styles$e.readOnly : ''}`, style: {
3455
+ return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$i.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$i.selectColor} ${disabled ? styles$i.disabled : ''} ${readOnly ? styles$i.readOnly : ''}`, style: {
3480
3456
  width,
3481
3457
  height,
3482
3458
  backgroundColor: value,
3483
- }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$e.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3459
+ }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$i.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3484
3460
  };
3485
3461
 
3486
3462
  /**
@@ -3730,31 +3706,63 @@ function CwInputDateText(props) {
3730
3706
  return (jsxRuntime.jsx("div", { className: "cw-input-date-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("input", { type: "text", disabled: disabled, maxLength: 10, onChange: onChangeInputText, pattern: "^$ --|[.0-9\\/\\-]{10}", placeholder: format.toLowerCase(), readOnly: readOnly, ref: textInputRef, required: required, size: width, tabIndex: tabIndex, value: displayedDate }), jsxRuntime.jsxs("span", { children: [jsxRuntime.jsx(CwIcon, { iconId: "calendar" }), jsxRuntime.jsx("input", { type: "date", disabled: disabled, onChange: onChangeInputDate, readOnly: readOnly, ref: dateInputRef, tabIndex: -1, value: date, ...inputProps })] })] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3731
3707
  }
3732
3708
 
3733
- var styles$d = {"dropZone":"cw-input-image-module__dropZone__ygrGu"};
3709
+ var styles$h = {"hiddenInput":"cw-input-image-module__hiddenInput__pS7hb","dropZone":"cw-input-image-module__dropZone__ygrGu","title":"cw-input-image-module__title__Rji5M","subtitle":"cw-input-image-module__subtitle__djYYu","container":"cw-input-image-module__container__qh7Tm"};
3734
3710
 
3711
+ const DEFAULT_LABELS = {
3712
+ dropImageHere: "Drop image here",
3713
+ paste: "Paste",
3714
+ browse: "Browse",
3715
+ acceptedFormats: (formats) => `(${formats})`,
3716
+ clipboardError: "Failed to read from clipboard. Ensure the app has permission to access the clipboard.",
3717
+ invalidType: (formats) => `Unsupported file type. Allowed: ${formats}`,
3718
+ readError: "Could not read the image file.",
3719
+ };
3720
+ /** Reads a file/blob into a base64 data URL (persistable, no blob URL to revoke). */
3721
+ function readImageFileAsDataUrl(file) {
3722
+ return new Promise((resolve, reject) => {
3723
+ const reader = new FileReader();
3724
+ reader.onload = () => resolve(reader.result);
3725
+ reader.onerror = () => reject(reader.error ?? new Error("Failed to read file"));
3726
+ reader.readAsDataURL(file);
3727
+ });
3728
+ }
3735
3729
  function CwInputImage(props) {
3736
3730
  const [_uploadedImage, setUploadedImage] = React.useState(null);
3737
3731
  const inputRef = React.useRef(null);
3738
- const { allowedImageFormats, onChange, ...inputProps } = props;
3732
+ const { allowedImageFormats, onChange, onError, labels: labelsProp, size, ...inputProps } = props;
3739
3733
  const allowedFormats = allowedImageFormats || ["image/jpeg", "image/png", "image/gif"];
3734
+ const labels = { ...DEFAULT_LABELS, ...labelsProp };
3740
3735
  const isValidFileType = (type) => allowedFormats.includes(type);
3741
- const handleFile = (file) => {
3742
- if (file && isValidFileType(file.type)) {
3743
- const imgURL = URL.createObjectURL(file);
3744
- setUploadedImage(imgURL);
3745
- if (onChange)
3746
- onChange(imgURL);
3736
+ const reportError = (message) => {
3737
+ if (onError)
3738
+ onError(message);
3739
+ else
3740
+ CwDisplayMessage(message, exports.CwMessageType.ERROR);
3741
+ };
3742
+ const handleFile = async (file) => {
3743
+ if (!file) {
3744
+ onChange?.(null);
3745
+ return;
3747
3746
  }
3748
- else {
3749
- // Optionally handle unsupported file types
3750
- if (onChange)
3751
- onChange(null);
3747
+ if (!isValidFileType(file.type)) {
3748
+ reportError(labels.invalidType(allowedFormats.join(", ").replace(/image\//g, "")));
3749
+ onChange?.(null);
3750
+ return;
3751
+ }
3752
+ try {
3753
+ const dataUrl = await readImageFileAsDataUrl(file);
3754
+ setUploadedImage(dataUrl);
3755
+ onChange?.(dataUrl, file);
3756
+ }
3757
+ catch {
3758
+ reportError(labels.readError);
3759
+ onChange?.(null);
3752
3760
  }
3753
3761
  };
3754
3762
  const handleDrop = (e) => {
3755
3763
  e.preventDefault();
3756
3764
  const file = e.dataTransfer.files[0];
3757
- handleFile(file);
3765
+ void handleFile(file ?? null);
3758
3766
  };
3759
3767
  const onPasteButtonClick = async () => {
3760
3768
  try {
@@ -3764,21 +3772,20 @@ function CwInputImage(props) {
3764
3772
  for (const type of clipboardItem.types) {
3765
3773
  if (type.startsWith("image/")) {
3766
3774
  const blob = await clipboardItem.getType(type);
3767
- handleFile(blob);
3775
+ await handleFile(blob);
3768
3776
  }
3769
3777
  }
3770
3778
  }
3771
3779
  }
3772
- catch (err) {
3773
- console.error("Failed to read clipboard:", err);
3774
- alert("Failed to read from clipboard. Ensure the app has permission to access clipboard.");
3780
+ catch {
3781
+ reportError(labels.clipboardError);
3775
3782
  }
3776
3783
  };
3777
3784
  const handleFileChange = (e) => {
3778
- const file = e.target.files?.[0];
3779
- handleFile(file ?? null);
3785
+ const file = e.currentTarget.files?.[0];
3786
+ void handleFile(file ?? null);
3780
3787
  };
3781
- return (jsxRuntime.jsxs("div", { className: "cw-input-image", children: [jsxRuntime.jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$d.dropZone, children: [jsxRuntime.jsx("p", { children: "Drop image here" }), jsxRuntime.jsxs("small", { children: ["(", allowedFormats.join(", ").replace(/image\//g, ""), ")"] })] }), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsxRuntime.jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: "Paste" }), jsxRuntime.jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: "Browse" })] }), jsxRuntime.jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, style: { display: "none" }, ...inputProps })] }));
3788
+ return (jsxRuntime.jsxs("div", { className: `cw-input-image ${styles$h.container}`, "data-size": size, children: [jsxRuntime.jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$h.dropZone, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsxRuntime.jsx("p", { className: styles$h.title, children: labels.dropImageHere }), jsxRuntime.jsx("p", { className: styles$h.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsxRuntime.jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsxRuntime.jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsxRuntime.jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$h.hiddenInput, ...inputProps })] }));
3782
3789
  }
3783
3790
 
3784
3791
  /**
@@ -3910,7 +3917,7 @@ const CwImageArea = React.forwardRef((props, ref) => {
3910
3917
  });
3911
3918
  CwImageArea.displayName = "CwImageArea";
3912
3919
 
3913
- var styles$c = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
3920
+ var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
3914
3921
 
3915
3922
  /**
3916
3923
  * This class represents a week where days can be selected or unselected
@@ -4050,15 +4057,16 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4050
4057
  setSelectedDays(newWeekdays);
4051
4058
  onChange?.(newWeekdays.toString());
4052
4059
  };
4053
- return (jsxRuntime.jsx("div", { className: styles$c["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))) }));
4060
+ 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))) }));
4054
4061
  };
4055
4062
 
4056
- var styles$b = {"check-container":"cw-check-module__check-container__4nscZ","checkbox-group-container":"cw-check-module__checkbox-group-container__WMNbG"};
4063
+ var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
4057
4064
 
4058
4065
  function CwCheck(props) {
4059
- const { labelProps, labelText, iconProps, alignment = "row", className, ...inputProps } = props;
4060
- const displayText = labelText || labelProps?.text;
4061
- return (jsxRuntime.jsx("div", { className: `cw-check ${styles$b["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": alignment, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsxs("span", { className: "cw-icon-text", children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), displayText] }))] }) }));
4066
+ const { labelProps, labelText, direction, alignment, className, ...inputProps } = props;
4067
+ const resolvedDirection = direction ?? alignment ?? "row";
4068
+ const displayText = labelProps?.text ?? labelText;
4069
+ return (jsxRuntime.jsx("div", { className: `cw-check ${styles$f["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": resolvedDirection, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
4062
4070
  }
4063
4071
 
4064
4072
  function CwCheckbox(CwCheckboxProps) {
@@ -4076,7 +4084,16 @@ function CwCheckbox(CwCheckboxProps) {
4076
4084
  : "cw_checkboxContent cwellt_flex_row" + " " + CwCheckboxProps.classNameContainer, style: CwCheckboxProps.styleContainer, children: [inputElement, CwCheckboxProps.labelName ? (jsxRuntime.jsx("label", { htmlFor: CwCheckboxProps.id, className: CwCheckboxProps.labelClassName, children: CwCheckboxProps.labelName })) : null] }));
4077
4085
  }
4078
4086
 
4079
- function CwCheckboxGroup({ options, value = [], onChange, labelProps, alignProps, required, disabled, optionsAlignment = "row", className, feedback, }) {
4087
+ /**
4088
+ * CwCheckboxGroup - Multi-select group of native checkbox inputs.
4089
+ *
4090
+ * Use for selecting any number of values from a list of options. Layout follows the
4091
+ * CwKeyValueList / CwRadioGroup convention with two nested {@link CwLayoutProps} axes applied as
4092
+ * `data-*` attributes: `groupLayout` positions the label relative to the group block (root grid),
4093
+ * `itemLayout` controls how the checkboxes flow among themselves (options container) and, on the
4094
+ * opposite axis, each checkbox's own box-to-text layout.
4095
+ */
4096
+ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayout, itemLayout, required, disabled, className, feedback, alignProps, optionsAlignment, "data-testid": dataTestId, }) {
4080
4097
  const handleChange = (optionValue, checked) => {
4081
4098
  if (checked) {
4082
4099
  onChange([...value, optionValue]);
@@ -4088,15 +4105,57 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, alignProps
4088
4105
  const feedbackMessages = feedback
4089
4106
  ? Array.isArray(feedback) ? feedback : [feedback]
4090
4107
  : [];
4091
- const flexDirection = alignProps?.flexDirection ?? "row";
4092
- const dataDirection = { 'data-direction': flexDirection };
4093
- return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$b["checkbox-group-container"]}${className ? ` ${className}` : ''}`, ...dataDirection, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: `${optionsAlignment === "row" ? "cw-flex-column cw-gap-small" : "cw-flex-row cw-flex-wrap"}`, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelText: option.label, checked: value.includes(option.value), disabled: disabled || option.disabled, alignment: optionsAlignment, onChange: (e) => handleChange(option.value, e.target.checked) }, option.value))) })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4108
+ // Effective layout — precedence: new `groupLayout`/`itemLayout` > legacy-derived > default.
4109
+ // Legacy `alignProps.flexDirection` drove the label-vs-options axis (default "row" = label
4110
+ // beside the options); map it to `groupLayout.direction`.
4111
+ const groupDirection = groupLayout?.direction
4112
+ ?? (alignProps?.flexDirection === "column" ? "column" : "row");
4113
+ // Legacy `optionsAlignment` is inverted relative to the options flow: "row" stacked the options
4114
+ // (column flow) with each check internally row; "column" laid them inline (row flow) with each
4115
+ // check internally column. Default reproduces the legacy `optionsAlignment="row"` case.
4116
+ const itemDirection = itemLayout?.direction
4117
+ ?? (optionsAlignment === "column" ? "row" : "column");
4118
+ // Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
4119
+ const checkDirection = itemDirection === "row" ? "column" : "row";
4120
+ 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)))] }));
4121
+ }
4122
+
4123
+ var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
4124
+
4125
+ /** Single native radio input. Building block for CwRadioGroup. */
4126
+ function CwRadio({ label, direction = "row", className, ...inputProps }) {
4127
+ return (jsxRuntime.jsxs("label", { className: `cw-radio ${styles$e.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsxRuntime.jsx("input", { type: "radio", ...inputProps }), label && jsxRuntime.jsx("span", { children: label })] }));
4128
+ }
4129
+
4130
+ /**
4131
+ * CwRadioGroup - Single-select group of native radio inputs.
4132
+ *
4133
+ * Built on `<input type="radio">` sharing one `name`, so the browser provides radio-group
4134
+ * semantics (roving tabindex, arrow-key navigation) natively. Use for a single choice from a
4135
+ * list of options; for 2–3 options shown as a strip use CwButtonSwitch.
4136
+ *
4137
+ * Layout follows the CwKeyValueList convention with two nested {@link CwLayoutProps} axes
4138
+ * applied as `data-*` attributes: `groupLayout` positions the label relative to the radiogroup
4139
+ * block (root grid), `itemLayout` controls how the radios flow among themselves (options
4140
+ * container) and, on the opposite axis, each radio's own circle-to-text layout.
4141
+ */
4142
+ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemLayout, required, disabled, className, feedback, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "data-testid": dataTestId, }) {
4143
+ const groupName = React.useId();
4144
+ const feedbackMessages = feedback
4145
+ ? Array.isArray(feedback) ? feedback : [feedback]
4146
+ : [];
4147
+ // Each radio's circle-to-text layout is the opposite of the options flow: a stacked list
4148
+ // (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
4149
+ // best with the circle above the text.
4150
+ const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
4151
+ 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)))] }));
4094
4152
  }
4095
4153
 
4096
4154
  function CwToggle(props) {
4097
- const { labelProps, labelText, iconProps, alignment = "row", className, style, ...inputProps } = props;
4098
- const displayText = labelText || labelProps?.text;
4099
- return (jsxRuntime.jsx("div", { className: `cw-toggle ${className ? ` ${className}` : ''}`, style: style, children: jsxRuntime.jsxs("label", { className: "cw-toggle-label", "data-direction": alignment, children: [displayText && (jsxRuntime.jsxs("span", { className: "cw-icon-text", children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), displayText] })), jsxRuntime.jsx("input", {
4155
+ const { labelProps, labelText, direction, alignment, className, style, ...inputProps } = props;
4156
+ const resolvedDirection = direction ?? alignment ?? "row";
4157
+ const displayText = labelProps?.text ?? labelText;
4158
+ return (jsxRuntime.jsx("div", { className: `cw-toggle ${className ? ` ${className}` : ''}`, style: style, children: jsxRuntime.jsxs("label", { className: "cw-toggle-label", "data-direction": resolvedDirection, children: [displayText && (jsxRuntime.jsx("span", { className: "cw-icon-text", children: displayText })), jsxRuntime.jsx("input", {
4100
4159
  //data-color={color}
4101
4160
  type: "checkbox", ...inputProps })] }) }));
4102
4161
  }
@@ -4355,7 +4414,7 @@ function CwDropdownFilter(props) {
4355
4414
  return (jsxRuntime.jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsxRuntime.jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsxRuntime.jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsxRuntime.jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
4356
4415
  }
4357
4416
 
4358
- var styles$a = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4417
+ var styles$d = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4359
4418
 
4360
4419
  /**
4361
4420
  * Button that toggles a floating panel with arbitrary children.
@@ -4434,7 +4493,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4434
4493
  }
4435
4494
  panel.showPopover();
4436
4495
  }, [placement]);
4437
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$a.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$a.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4496
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$d.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$d.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4438
4497
  }
4439
4498
 
4440
4499
  function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
@@ -4452,13 +4511,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
4452
4511
  return result;
4453
4512
  }
4454
4513
 
4455
- var styles$9 = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4514
+ var styles$c = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4456
4515
 
4457
4516
  const CwMultiFilterTag = props => {
4458
4517
  const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
4459
4518
  const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
4460
4519
  const isOutlineMode = Selected && !Removable;
4461
- return (jsxRuntime.jsx("li", { className: styles$9["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4520
+ return (jsxRuntime.jsx("li", { className: styles$c["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4462
4521
  if (Selectable)
4463
4522
  props.OnSelect?.(props);
4464
4523
  }, children: jsxRuntime.jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
@@ -4468,7 +4527,7 @@ const CwMultiFilterTag = props => {
4468
4527
  } : undefined }) }));
4469
4528
  };
4470
4529
 
4471
- var styles$8 = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
4530
+ var styles$b = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
4472
4531
 
4473
4532
  /**
4474
4533
  * A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
@@ -4695,9 +4754,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4695
4754
  inputRef.current?.focus();
4696
4755
  }
4697
4756
  };
4698
- return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$8["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4757
+ return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$b["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4699
4758
  e.preventDefault();
4700
- }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$8["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4759
+ }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$b["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4701
4760
  switch (e.key) {
4702
4761
  case "Enter":
4703
4762
  case "Tab": {
@@ -4724,7 +4783,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4724
4783
  break;
4725
4784
  }
4726
4785
  }
4727
- } })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$8["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$8["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$8["category-selected"] : undefined, style: {
4786
+ } })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$b["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$b["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$b["category-selected"] : undefined, style: {
4728
4787
  backgroundColor: getColor(category).primary,
4729
4788
  color: getColor(category).onPrimary,
4730
4789
  }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsxRuntime.jsx("ul", { children: displayTags
@@ -4750,7 +4809,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4750
4809
  } }, props.ID))) })] }))] }));
4751
4810
  };
4752
4811
 
4753
- var styles$7 = {"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"};
4812
+ 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"};
4754
4813
 
4755
4814
  /**
4756
4815
  * Multi-select input with chip tags and searchable dropdown.
@@ -4885,11 +4944,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
4885
4944
  // Keeping containerRef for any other potential use
4886
4945
  const direction = alignProps?.flexDirection ?? "row";
4887
4946
  const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
4888
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$7.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$7.inputBox}${disabled ? ` ${styles$7.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
4889
- 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$7.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$7.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$7.option}${idx === focusedIndex ? ` ${styles$7.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsxRuntime.jsx("span", { className: styles$7.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
4947
+ 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)
4948
+ 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)] }));
4890
4949
  }
4891
4950
 
4892
- var styles$6 = {"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"};
4951
+ 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"};
4893
4952
 
4894
4953
  function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
4895
4954
  const [expanded, setExpanded] = React.useState(new Set());
@@ -4956,10 +5015,10 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
4956
5015
  const isLeaf = !hasChildren;
4957
5016
  const isSelected = selectedId?.toString().toLowerCase() === node.id.toString().toLowerCase();
4958
5017
  const selectable = allowParentSelection || isLeaf;
4959
- return (jsxRuntime.jsxs("div", { className: styles$6["tree-item"], children: [jsxRuntime.jsxs("div", { className: [
4960
- styles$6["tree-node"],
4961
- isSelected && styles$6["selected"],
4962
- !selectable && styles$6["non-selectable"]
5018
+ return (jsxRuntime.jsxs("div", { className: styles$9["tree-item"], children: [jsxRuntime.jsxs("div", { className: [
5019
+ styles$9["tree-node"],
5020
+ isSelected && styles$9["selected"],
5021
+ !selectable && styles$9["non-selectable"]
4963
5022
  ].filter(Boolean).join(' '), style: { paddingLeft: `${depth * 24 + 8}px` }, onClick: () => {
4964
5023
  if (selectable) {
4965
5024
  setSelectedId(node.id);
@@ -4968,7 +5027,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
4968
5027
  else {
4969
5028
  toggleExpand(node.id);
4970
5029
  }
4971
- }, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$6["tree-label"]} ${!hasChildren ? styles$6["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsxRuntime.jsx("div", { className: styles$6["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
5030
+ }, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$9["tree-label"]} ${!hasChildren ? styles$9["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsxRuntime.jsx("div", { className: styles$9["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
4972
5031
  };
4973
5032
  // Function to search for nodes that match the search term
4974
5033
  const searchInTree = (nodes, searchTerm) => {
@@ -4992,7 +5051,129 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
4992
5051
  return results;
4993
5052
  };
4994
5053
  const filteredData = searchInTree(data, search);
4995
- return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$6["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$6["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$6["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5054
+ return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$9["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$9["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$9["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5055
+ }
5056
+
5057
+ const EXACT_PHRASE = /"([^"]+)"/g;
5058
+ /**
5059
+ * Quoted phrases are matched against the label only; loose words against label + description + href.
5060
+ * Parsed once instead of per node.
5061
+ */
5062
+ function parseSearch(search) {
5063
+ const phrases = Array.from(search.matchAll(EXACT_PHRASE), match => match[1].toLowerCase());
5064
+ const words = search
5065
+ .replace(EXACT_PHRASE, "")
5066
+ .trim()
5067
+ .toLowerCase()
5068
+ .split(/\s+/)
5069
+ .filter(Boolean);
5070
+ return { phrases, words };
5071
+ }
5072
+ /**
5073
+ * Filters a nav tree by a search string, keeping a group whose descendants match.
5074
+ *
5075
+ * Supports `"quoted phrases"` (must appear in the label) alongside loose words (any field) — this is
5076
+ * behaviour users are told about, so don't simplify it.
5077
+ */
5078
+ function filterNavItems(items, search) {
5079
+ if (!search?.trim())
5080
+ return items;
5081
+ const { phrases, words } = parseSearch(search);
5082
+ if (phrases.length === 0 && words.length === 0)
5083
+ return items;
5084
+ const keep = (item, parentMatchedPhrases) => {
5085
+ const label = item.label.toLowerCase();
5086
+ const haystack = [item.label, item.description, item.href].filter(Boolean).join(" ").toLowerCase();
5087
+ const matchesPhrases = phrases.every(phrase => label.includes(phrase));
5088
+ const matchesWords = words.every(word => haystack.includes(word));
5089
+ const selfMatches = (phrases.length === 0 || matchesPhrases || parentMatchedPhrases) && matchesWords;
5090
+ if (!item.children?.length)
5091
+ return selfMatches ? item : null;
5092
+ let children = item.children
5093
+ .map(child => keep(child, matchesPhrases || parentMatchedPhrases))
5094
+ .filter((child) => child !== null);
5095
+ // A phrase-only search narrows the survivors further: each must carry the phrase itself.
5096
+ if (phrases.length > 0 && words.length === 0 && matchesPhrases) {
5097
+ children = children.filter(child => phrases.every(phrase => child.label.toLowerCase().includes(phrase)));
5098
+ }
5099
+ if (children.length > 0)
5100
+ return { ...item, children };
5101
+ // The group matched but nothing under it did. Returning `children: []` would make it a leaf —
5102
+ // and a leaf with no href — so keep the subtree instead of emptying it.
5103
+ return selfMatches ? item : null;
5104
+ };
5105
+ return items
5106
+ .map(item => keep(item, false))
5107
+ .filter((item) => item !== null);
5108
+ }
5109
+
5110
+ /**
5111
+ * Sorts the top level alphabetically, leaving every nested list in the order the consumer gave.
5112
+ *
5113
+ * Deliberately level 1 only: this exists because a long list of modules is hard to scan, while the
5114
+ * pages inside a module are ordered on purpose. Returns the input untouched when not sorting.
5115
+ */
5116
+ function sortNavItems(items, alphabetically) {
5117
+ if (!alphabetically)
5118
+ return items;
5119
+ return [...items].sort((first, second) => first.label.localeCompare(second.label));
5120
+ }
5121
+
5122
+ var styles$8 = {"menu":"cw-nav-menu-module__menu__LmeQg","expandIndicator":"cw-nav-menu-module__expandIndicator__TBSdQ","favorites":"cw-nav-menu-module__favorites__Esaqd","favoritesContent":"cw-nav-menu-module__favoritesContent__l5DGG","favoriteStar":"cw-nav-menu-module__favoriteStar__J-jzg","emptyMessage":"cw-nav-menu-module__emptyMessage__-CQNd","skeleton":"cw-nav-menu-module__skeleton__INQqF"};
5123
+
5124
+ const SKELETON_ROW_COUNT = 5;
5125
+ const defaultRenderLink = (item, children) => (jsxRuntime.jsx("a", { href: item.href, children: children }));
5126
+ /** Sizes only its own icons — content injected via `renderLink` is styled by the consumer. */
5127
+ function CwNavMenu({ items, loading = false, isActive, renderLink = defaultRenderLink, showExpandIndicator = false, search, emptyMessage, sortAlphabetically = false, favoritesSlot, favoritesLabel = "Favorites", favoritesProps, isFavorite, beforeTreeSlot, className, ...navProps }) {
5128
+ const visibleItems = sortNavItems(filterNavItems(items, search), sortAlphabetically);
5129
+ const showEmptyMessage = !loading && Boolean(emptyMessage) && Boolean(search?.trim()) && visibleItems.length === 0;
5130
+ const hasActiveDescendant = (node) => node.children?.some(child => isActive?.(child) || hasActiveDescendant(child)) ?? false;
5131
+ const renderItem = (item, level) => {
5132
+ const children = item.children;
5133
+ if (children && children.length > 0) {
5134
+ return (jsxRuntime.jsx("li", { children: jsxRuntime.jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxRuntime.jsxs("summary", { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$8.expandIndicator }))] }), jsxRuntime.jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
5135
+ }
5136
+ return (jsxRuntime.jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsxRuntime.jsx(CwIcon, { iconId: "star", size: "small", className: styles$8.favoriteStar })] })) }, item.id));
5137
+ };
5138
+ return (jsxRuntime.jsxs("nav", { ...navProps, className: [styles$8.menu, className].filter(Boolean).join(" "), children: [favoritesSlot && (jsxRuntime.jsxs("details", { open: true, ...favoritesProps, className: [styles$8.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxRuntime.jsxs("summary", { children: [jsxRuntime.jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsxRuntime.jsx("div", { className: styles$8.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsxRuntime.jsx("ul", { children: loading
5139
+ ? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsxRuntime.jsx("li", { className: styles$8.skeleton }, index)))
5140
+ : visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsxRuntime.jsx("p", { className: styles$8.emptyMessage, children: emptyMessage })] }));
5141
+ }
5142
+
5143
+ /**
5144
+ * Pure keyboard-navigation resolver shared by the `CwSearchInput` combobox.
5145
+ * Kept side-effect-free so the arrow/home/end/enter/escape behaviour can be unit
5146
+ * tested without a DOM (the library's vitest runs with `environment: "node"`).
5147
+ */
5148
+ /**
5149
+ * Resolves a key press against the current highlight into a {@link SearchKeyAction}.
5150
+ * Arrow navigation wraps around; `Enter` selects only when a valid row is highlighted.
5151
+ *
5152
+ * @param key `KeyboardEvent.key` value.
5153
+ * @param currentIndex Currently highlighted option index (`-1` = none).
5154
+ * @param optionsLength Number of options currently in the dropdown.
5155
+ */
5156
+ function resolveSearchKeyAction(key, currentIndex, optionsLength) {
5157
+ if (optionsLength <= 0)
5158
+ return { type: "none" };
5159
+ switch (key) {
5160
+ case "ArrowDown":
5161
+ return { type: "move", index: currentIndex < optionsLength - 1 ? currentIndex + 1 : 0 };
5162
+ case "ArrowUp":
5163
+ return { type: "move", index: currentIndex > 0 ? currentIndex - 1 : optionsLength - 1 };
5164
+ case "Home":
5165
+ return { type: "move", index: 0 };
5166
+ case "End":
5167
+ return { type: "move", index: optionsLength - 1 };
5168
+ case "Enter":
5169
+ return currentIndex >= 0 && currentIndex < optionsLength
5170
+ ? { type: "select", index: currentIndex }
5171
+ : { type: "none" };
5172
+ case "Escape":
5173
+ return { type: "close" };
5174
+ default:
5175
+ return { type: "none" };
5176
+ }
4996
5177
  }
4997
5178
 
4998
5179
  /**
@@ -5013,14 +5194,19 @@ function CwSearchInput(optionsProps) {
5013
5194
  const [_selectedOption, setSelectedOption] = React.useState(null);
5014
5195
  const [showDropdown, setShowDropdown] = React.useState(false);
5015
5196
  const [isLoading, setIsLoading] = React.useState(false);
5197
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
5016
5198
  const wrapperRef = React.useRef(null);
5199
+ const inputRef = React.useRef(null);
5200
+ // Stable ids wiring the combobox input to its listbox popup for assistive tech.
5201
+ const listboxId = React.useId();
5202
+ const optionId = (index) => `${listboxId}-opt-${index}`;
5017
5203
  const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5018
5204
  anchorRef: wrapperRef,
5019
5205
  isOpen: showDropdown && filteredOptions.length > 0,
5020
- onClose: () => setShowDropdown(false),
5206
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
5021
5207
  });
5022
5208
  // Extract props
5023
- const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
5209
+ const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, autoFocus, ...otherProps } = optionsProps;
5024
5210
  // Get direction for data attribute
5025
5211
  const direction = alignProps?.flexDirection || "row";
5026
5212
  // Make default value selection when loading the component
@@ -5039,9 +5225,10 @@ function CwSearchInput(optionsProps) {
5039
5225
  }
5040
5226
  }, [defaultValue, selectList]);
5041
5227
  const handleInputChange = (event) => {
5042
- const text = event.target.value;
5228
+ const text = event.currentTarget.value;
5043
5229
  setSearchText(text);
5044
5230
  setShowDropdown(true);
5231
+ setHighlightedIndex(-1);
5045
5232
  if (text === "") {
5046
5233
  setFilteredOptions(selectList);
5047
5234
  setSelectedOption(null);
@@ -5064,10 +5251,30 @@ function CwSearchInput(optionsProps) {
5064
5251
  };
5065
5252
  const handleInputFocus = () => {
5066
5253
  setShowDropdown(true);
5254
+ setHighlightedIndex(-1);
5067
5255
  if (searchText === "") {
5068
5256
  setFilteredOptions(selectList);
5069
5257
  }
5070
5258
  };
5259
+ const handleKeyDown = (event) => {
5260
+ if (!(showDropdown && filteredOptions.length > 0))
5261
+ return;
5262
+ const action = resolveSearchKeyAction(event.key, highlightedIndex, filteredOptions.length);
5263
+ switch (action.type) {
5264
+ case "move":
5265
+ event.preventDefault();
5266
+ setHighlightedIndex(action.index);
5267
+ break;
5268
+ case "select":
5269
+ event.preventDefault();
5270
+ handleOptionSelect(filteredOptions[action.index]);
5271
+ break;
5272
+ case "close":
5273
+ setShowDropdown(false);
5274
+ setHighlightedIndex(-1);
5275
+ break;
5276
+ }
5277
+ };
5071
5278
  const handleInputBlur = () => {
5072
5279
  // Dropdown is closed by useDropdownPortal's outside-click handler.
5073
5280
  // Blur alone must not close it — clicking an option would lose focus before the click fires.
@@ -5079,16 +5286,19 @@ function CwSearchInput(optionsProps) {
5079
5286
  handleChange(option.id);
5080
5287
  }
5081
5288
  setFilteredOptions([]);
5289
+ setHighlightedIndex(-1);
5082
5290
  };
5083
5291
  const handleClearClick = () => {
5084
5292
  setSearchText("");
5085
5293
  setFilteredOptions([]);
5086
5294
  setSelectedOption(null);
5295
+ setHighlightedIndex(-1);
5087
5296
  if (handleChange) {
5088
5297
  handleChange("");
5089
5298
  }
5299
+ inputRef.current?.focus();
5090
5300
  };
5091
- return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option) => (jsxRuntime.jsx("li", { className: dropdownStyles.option, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5301
+ return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, id: id, type: "text", value: searchText, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled, autoFocus: autoFocus, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown && filteredOptions.length > 0, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option, index) => (jsxRuntime.jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5092
5302
  }
5093
5303
 
5094
5304
  /**
@@ -5350,7 +5560,7 @@ const CwSearchAsync = ({ onSearch, onChange, value, onResolveInitial, onResolveS
5350
5560
  }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeholder, disabled: disabled, required: required, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined, title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selection", variant: "icon", icon: "close", color: "neutral" })) : (icon ? jsxRuntime.jsx(CwIcon, { ...icon }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.id), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.subLabel ? (jsxRuntime.jsxs("span", { className: "cw-search-async-option-lines", children: [jsxRuntime.jsx("span", { children: option.label }), jsxRuntime.jsx("span", { className: "cw-search-async-option-sub", children: option.subLabel })] })) : (option.label) }, option.id))) }) }))] }));
5351
5561
  };
5352
5562
 
5353
- var styles$5 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
5563
+ var styles$7 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
5354
5564
 
5355
5565
  const ARROW_SIZE = 8;
5356
5566
  const SAFETY_MARGIN = 8;
@@ -5491,14 +5701,14 @@ const CwAnchoredMenu = ({ children, options, onSelect, placement = 'bottom', ope
5491
5701
  document.removeEventListener("keydown", handleEscape);
5492
5702
  };
5493
5703
  }, [isOpen]);
5494
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && reactDom.createPortal(jsxRuntime.jsxs("div", { ref: menuRef, className: styles$5["menu"], style: {
5704
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && reactDom.createPortal(jsxRuntime.jsxs("div", { ref: menuRef, className: styles$7["menu"], style: {
5495
5705
  top: `${position.y}px`,
5496
5706
  left: `${position.x}px`,
5497
- }, "data-has-arrow": "true", children: [jsxRuntime.jsx("div", { ref: arrowRef, className: styles$5["arrow"], "data-placement": placement }), normalizedOptions.map(option => (jsxRuntime.jsxs("div", { onClick: (e) => {
5707
+ }, "data-has-arrow": "true", children: [jsxRuntime.jsx("div", { ref: arrowRef, className: styles$7["arrow"], "data-placement": placement }), normalizedOptions.map(option => (jsxRuntime.jsxs("div", { onClick: (e) => {
5498
5708
  e.stopPropagation();
5499
5709
  e.preventDefault();
5500
5710
  handleOptionClick(option);
5501
- }, className: `${styles$5["item"]} ${option.disabled ? styles$5["disabled"] : ""}`, "data-disabled": option.disabled, children: [option.icon && jsxRuntime.jsx("span", { className: styles$5["icon"], children: option.icon }), option.label] }, option.key)))] }), document.body)] }));
5711
+ }, className: `${styles$7["item"]} ${option.disabled ? styles$7["disabled"] : ""}`, "data-disabled": option.disabled, children: [option.icon && jsxRuntime.jsx("span", { className: styles$7["icon"], children: option.icon }), option.label] }, option.key)))] }), document.body)] }));
5502
5712
  };
5503
5713
 
5504
5714
  /**
@@ -5571,12 +5781,143 @@ const CwContextMenu = ({ children, options, offset = DEFAULT_OFFSET, onSelect })
5571
5781
  document.removeEventListener("keydown", handleEscape);
5572
5782
  };
5573
5783
  }, [isOpen]);
5574
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: menuRef, className: styles$5["menu"], style: {
5784
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: menuRef, className: styles$7["menu"], style: {
5575
5785
  top: `${position.y}px`,
5576
5786
  left: `${position.x}px`,
5577
- }, children: options.map(option => (jsxRuntime.jsx("div", { onClick: () => handleOptionClick(option), className: styles$5["item"], children: option }, option))) }), document.body)] }));
5787
+ }, children: options.map(option => (jsxRuntime.jsx("div", { onClick: () => handleOptionClick(option), className: styles$7["item"], children: option }, option))) }), document.body)] }));
5578
5788
  };
5579
5789
 
5790
+ var styles$6 = {"split":"cw-button-split-module__split__B2KbU","menu":"cw-button-split-module__menu__mKDlt","item":"cw-button-split-module__item__Aqw6f"};
5791
+
5792
+ /**
5793
+ * CwButtonSplit - A primary action joined to a dropdown of alternative actions.
5794
+ *
5795
+ * Composes a main {@link CwButton} with a {@link CwPopoverButton} chevron whose
5796
+ * panel holds a vertical menu of alternatives (rendered as `variant="ghost"` rows).
5797
+ * Both parts share variant, color and size and read as one joined control.
5798
+ *
5799
+ * @example
5800
+ * <CwButtonSplit
5801
+ * text="Save"
5802
+ * icon="save"
5803
+ * onClick={handleSave}
5804
+ * actions={[
5805
+ * { key: "saveAs", label: "Save as…", icon: "copy" },
5806
+ * { key: "saveAndClose", label: "Save and close" },
5807
+ * ]}
5808
+ * onSelect={handleSelect}
5809
+ * />
5810
+ */
5811
+ function CwButtonSplit({ text, icon, onClick, actions, onSelect, variant = "solid", color = "primary", size = "medium", disabled = false, placement = "bottom-end", "data-testid": dataTestId, }) {
5812
+ const handleSelect = (action) => (event) => {
5813
+ onSelect(action.key);
5814
+ event.currentTarget.closest("[popover]")?.hidePopover();
5815
+ };
5816
+ return (jsxRuntime.jsxs("div", { className: styles$6.split, "data-variant": variant, "data-testid": dataTestId, children: [jsxRuntime.jsx(CwButton, { text: text, icon: icon, variant: variant, color: color, size: size, onClick: onClick, disabled: disabled }), jsxRuntime.jsx(CwPopoverButton, { icon: "chevron-down", title: "More actions", variant: variant, color: color, size: size, disabled: disabled, placement: placement, children: jsxRuntime.jsx("div", { className: styles$6.menu, children: actions.map((action) => (jsxRuntime.jsx(CwButton, { variant: "ghost", color: "neutral", text: action.label, icon: action.icon, disabled: action.disabled, className: styles$6.item, onClick: handleSelect(action) }, action.key))) }) })] }));
5817
+ }
5818
+
5819
+ /**
5820
+ * Roving-tabindex single-select behaviour for a custom radio group (e.g. a segmented
5821
+ * button strip that has no native grouping). The active segment is the selected one,
5822
+ * or the first enabled option when nothing is selected. Arrow keys (Right/Down = next,
5823
+ * Left/Up = previous) move focus and select, wrapping around and skipping disabled
5824
+ * options; Space/Enter selects the focused segment.
5825
+ *
5826
+ * Native form controls (e.g. `<input type="radio">` sharing a name) already get this
5827
+ * behaviour from the browser — use this hook only for non-native custom groups.
5828
+ */
5829
+ function useRovingSingleSelect(options, value, onChange) {
5830
+ const elementRefs = React.useRef([]);
5831
+ const selectedIndex = options.findIndex((option) => option.value === value);
5832
+ const firstEnabledIndex = options.findIndex((option) => !option.disabled);
5833
+ // If the selected option is disabled it cannot hold the tab stop (disabled elements are out of
5834
+ // the tab order), so fall back to the first enabled option to keep the group reachable by Tab.
5835
+ const activeIndex = selectedIndex >= 0 && !options[selectedIndex]?.disabled ? selectedIndex : firstEnabledIndex;
5836
+ const focusAndSelect = React.useCallback((index) => {
5837
+ const option = options[index];
5838
+ if (!option || option.disabled)
5839
+ return;
5840
+ onChange(option.value);
5841
+ elementRefs.current[index]?.focus();
5842
+ }, [options, onChange]);
5843
+ const moveFocus = React.useCallback((fromIndex, direction) => {
5844
+ const count = options.length;
5845
+ if (count === 0)
5846
+ return;
5847
+ let nextIndex = fromIndex;
5848
+ for (let step = 0; step < count; step++) {
5849
+ nextIndex = (nextIndex + direction + count) % count;
5850
+ if (!options[nextIndex]?.disabled) {
5851
+ focusAndSelect(nextIndex);
5852
+ return;
5853
+ }
5854
+ }
5855
+ }, [options, focusAndSelect]);
5856
+ const getSegmentProps = React.useCallback((index) => ({
5857
+ tabIndex: index === activeIndex ? 0 : -1,
5858
+ ref: (element) => {
5859
+ elementRefs.current[index] = element;
5860
+ },
5861
+ onKeyDown: (event) => {
5862
+ switch (event.key) {
5863
+ case "ArrowRight":
5864
+ case "ArrowDown":
5865
+ event.preventDefault();
5866
+ moveFocus(index, 1);
5867
+ break;
5868
+ case "ArrowLeft":
5869
+ case "ArrowUp":
5870
+ event.preventDefault();
5871
+ moveFocus(index, -1);
5872
+ break;
5873
+ case " ":
5874
+ case "Enter":
5875
+ event.preventDefault();
5876
+ focusAndSelect(index);
5877
+ break;
5878
+ }
5879
+ },
5880
+ }), [activeIndex, moveFocus, focusAndSelect]);
5881
+ return { activeIndex, getSegmentProps };
5882
+ }
5883
+
5884
+ var styles$5 = {"switch":"cw-button-switch-module__switch__vdWV-","segment":"cw-button-switch-module__segment__JmVla","iconOnly":"cw-button-switch-module__iconOnly__-kCwj"};
5885
+
5886
+ /**
5887
+ * CwButtonSwitch - Segmented single-select control: a strip of joined CwButtons.
5888
+ *
5889
+ * The selected segment renders `solid`, the others `outline`, both sharing the `color`
5890
+ * theme (`primary` default, `danger`, or `neutral`). It is a proper ARIA radiogroup with
5891
+ * roving tabindex (one tab stop) and arrow-key navigation, provided by
5892
+ * {@link useRovingSingleSelect}. Use for 2–3 mutually-exclusive options that benefit from
5893
+ * being shown side by side; for a longer list use CwRadioGroup.
5894
+ *
5895
+ * `direction="column"` renders the strip vertically (stacked, full-width segments) instead of
5896
+ * the default horizontal `row`; arrow-key navigation handles both orientations.
5897
+ *
5898
+ * Set `iconOnly` to render just each option's icon; the option's `label` is still required
5899
+ * and is passed as the segment title, so it becomes the tooltip and the accessible name.
5900
+ *
5901
+ * It is an inline control with no form label — if a caption is needed, place it next to the
5902
+ * control at the call site, and pass `aria-label` (or `aria-labelledby`) to name the radiogroup
5903
+ * for screen readers.
5904
+ *
5905
+ * @example
5906
+ * <CwButtonSwitch
5907
+ * options={[{ value: "list", label: "List", icon: "list" }, { value: "grid", label: "Grid", icon: "grid" }]}
5908
+ * value={view}
5909
+ * onChange={setView}
5910
+ * />
5911
+ */
5912
+ function CwButtonSwitch({ options, value, onChange, size = "medium", color = "primary", iconOnly = false, direction = "row", disabled = false, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "data-testid": dataTestId, }) {
5913
+ const { getSegmentProps } = useRovingSingleSelect(options, value, onChange);
5914
+ return (jsxRuntime.jsx("div", { className: `cw-button-switch ${styles$5.switch}`, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : ariaLabel, "data-direction": direction, "data-testid": dataTestId, children: options.map((option, index) => {
5915
+ const selected = option.value === value;
5916
+ const segmentProps = getSegmentProps(index);
5917
+ return (jsxRuntime.jsx(CwButton, { text: iconOnly ? undefined : option.label, title: iconOnly ? option.label : undefined, icon: option.icon, size: size, color: color, variant: selected ? "solid" : "outline", role: "radio", "aria-checked": selected, disabled: disabled || option.disabled, onClick: () => onChange(option.value), className: `${styles$5.segment}${iconOnly ? ` ${styles$5.iconOnly}` : ""}`, tabIndex: segmentProps.tabIndex, ref: segmentProps.ref, onKeyDown: segmentProps.onKeyDown }, option.value));
5918
+ }) }));
5919
+ }
5920
+
5580
5921
  /**
5581
5922
  * Save button wrapper (6 uses pending delete)
5582
5923
  * @deprecated Use <CwButton variant="icon" icon="save" onClick={...} /> instead
@@ -11130,6 +11471,8 @@ exports.CwBtnDelete = CwBtnDelete;
11130
11471
  exports.CwBtnEdit = CwBtnEdit;
11131
11472
  exports.CwBtnSave = CwBtnSave;
11132
11473
  exports.CwButton = CwButton;
11474
+ exports.CwButtonSplit = CwButtonSplit;
11475
+ exports.CwButtonSwitch = CwButtonSwitch;
11133
11476
  exports.CwCard = CwCard;
11134
11477
  exports.CwCardList = CwCardList;
11135
11478
  exports.CwCheck = CwCheck;
@@ -11152,7 +11495,6 @@ exports.CwDisplayMessage = CwDisplayMessage;
11152
11495
  exports.CwDropdown = CwDropdown;
11153
11496
  exports.CwDropdownFilter = CwDropdownFilter;
11154
11497
  exports.CwExpandable = CwExpandable;
11155
- exports.CwFileUpload = CwFileUpload;
11156
11498
  exports.CwFileUploadMultiple = CwFileUploadMultiple;
11157
11499
  exports.CwFindAirport = CwFindAirport;
11158
11500
  exports.CwFindCrewmember = CwFindCrewmember;
@@ -11174,7 +11516,6 @@ exports.CwInputText = CwInputText;
11174
11516
  exports.CwKeyValueList = CwKeyValueList;
11175
11517
  exports.CwLabel = CwLabel;
11176
11518
  exports.CwLoading = CwLoading;
11177
- exports.CwLoadingSmall = CwLoadingSmall;
11178
11519
  exports.CwMasterDetail = CwMasterDetail;
11179
11520
  exports.CwMessage = CwMessage;
11180
11521
  exports.CwMessageManager = CwMessageManager;
@@ -11183,9 +11524,11 @@ exports.CwModalHover = CwModalHover;
11183
11524
  exports.CwModalReportFunctional = CwModalReportFunctional;
11184
11525
  exports.CwMultiFilter = CwMultiFilter;
11185
11526
  exports.CwMultiFilterTag = CwMultiFilterTag;
11527
+ exports.CwNavMenu = CwNavMenu;
11186
11528
  exports.CwNote = CwNote;
11187
11529
  exports.CwOption = CwOption;
11188
11530
  exports.CwPopoverButton = CwPopoverButton;
11531
+ exports.CwRadioGroup = CwRadioGroup;
11189
11532
  exports.CwReportModal = CwReportModal;
11190
11533
  exports.CwScheduler = CwScheduler;
11191
11534
  exports.CwSearchAsync = CwSearchAsync;
@@ -11241,12 +11584,16 @@ exports.TooltipConstraintContext = TooltipConstraintContext;
11241
11584
  exports.UiEvent = UiEvent;
11242
11585
  exports.Weekdays = Weekdays;
11243
11586
  exports.cblEvent = cblEvent;
11587
+ exports.configureCwLoading = configureCwLoading;
11244
11588
  exports.eventIsVisible = eventIsVisible;
11589
+ exports.filterNavItems = filterNavItems;
11245
11590
  exports.filterVisibleEvents = filterVisibleEvents;
11591
+ exports.getCwLoadingDefaults = getCwLoadingDefaults;
11246
11592
  exports.getDefaultDivisions = getDefaultDivisions;
11247
11593
  exports.getEventSizes = getEventSizes;
11248
11594
  exports.getPresetsByKeysTemporal = getPresetsByKeysTemporal;
11249
11595
  exports.itemsToMultiFilterTags = itemsToMultiFilterTags;
11596
+ exports.sortNavItems = sortNavItems;
11250
11597
  exports.useCwMessage = useCwMessage;
11251
11598
  exports.useSortableList = useSortableList;
11252
11599
  exports.useSortableTable = useSortableTable;