@cwellt_software/cwellt-reactjs-lib 1.6.2 → 1.7.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 (120) hide show
  1. package/dist/index.cjs.js +2522 -166
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +697 -5
  4. package/dist/index.es.js +2508 -167
  5. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts.map +1 -1
  6. package/dist/src/components/control/choice/tag-selector/CwTagSelector.stories.d.ts +2 -0
  7. package/dist/src/components/control/choice/tag-selector/CwTagSelector.stories.d.ts.map +1 -1
  8. package/dist/src/components/custom/report-viewer/CwReportGauge.d.ts +19 -0
  9. package/dist/src/components/custom/report-viewer/CwReportGauge.d.ts.map +1 -0
  10. package/dist/src/components/custom/report-viewer/CwReportLineChart.d.ts +21 -0
  11. package/dist/src/components/custom/report-viewer/CwReportLineChart.d.ts.map +1 -0
  12. package/dist/src/components/custom/report-viewer/CwReportPage.d.ts +36 -0
  13. package/dist/src/components/custom/report-viewer/CwReportPage.d.ts.map +1 -0
  14. package/dist/src/components/custom/report-viewer/CwReportParameterForm.d.ts +26 -0
  15. package/dist/src/components/custom/report-viewer/CwReportParameterForm.d.ts.map +1 -0
  16. package/dist/src/components/custom/report-viewer/CwReportPieChart.d.ts +13 -0
  17. package/dist/src/components/custom/report-viewer/CwReportPieChart.d.ts.map +1 -0
  18. package/dist/src/components/custom/report-viewer/CwReportToolbar.d.ts +40 -0
  19. package/dist/src/components/custom/report-viewer/CwReportToolbar.d.ts.map +1 -0
  20. package/dist/src/components/custom/report-viewer/CwReportViewer.d.ts +50 -0
  21. package/dist/src/components/custom/report-viewer/CwReportViewer.d.ts.map +1 -0
  22. package/dist/src/components/custom/report-viewer/ReportItem.d.ts +21 -0
  23. package/dist/src/components/custom/report-viewer/ReportItem.d.ts.map +1 -0
  24. package/dist/src/components/custom/report-viewer/ReportTextbox.d.ts +10 -0
  25. package/dist/src/components/custom/report-viewer/ReportTextbox.d.ts.map +1 -0
  26. package/dist/src/components/custom/report-viewer/logic/rdlChartMarkers.d.ts +26 -0
  27. package/dist/src/components/custom/report-viewer/logic/rdlChartMarkers.d.ts.map +1 -0
  28. package/dist/src/components/custom/report-viewer/logic/rdlChartScale.d.ts +75 -0
  29. package/dist/src/components/custom/report-viewer/logic/rdlChartScale.d.ts.map +1 -0
  30. package/dist/src/components/custom/report-viewer/logic/rdlFind.d.ts +38 -0
  31. package/dist/src/components/custom/report-viewer/logic/rdlFind.d.ts.map +1 -0
  32. package/dist/src/components/custom/report-viewer/logic/rdlGauge.d.ts +40 -0
  33. package/dist/src/components/custom/report-viewer/logic/rdlGauge.d.ts.map +1 -0
  34. package/dist/src/components/custom/report-viewer/logic/rdlListMarkers.d.ts +12 -0
  35. package/dist/src/components/custom/report-viewer/logic/rdlListMarkers.d.ts.map +1 -0
  36. package/dist/src/components/custom/report-viewer/logic/rdlNumberFormat.d.ts +8 -0
  37. package/dist/src/components/custom/report-viewer/logic/rdlNumberFormat.d.ts.map +1 -0
  38. package/dist/src/components/custom/report-viewer/logic/rdlPageGeometry.d.ts +38 -0
  39. package/dist/src/components/custom/report-viewer/logic/rdlPageGeometry.d.ts.map +1 -0
  40. package/dist/src/components/custom/report-viewer/logic/rdlParameterValues.d.ts +42 -0
  41. package/dist/src/components/custom/report-viewer/logic/rdlParameterValues.d.ts.map +1 -0
  42. package/dist/src/components/custom/report-viewer/logic/rdlStyle.d.ts +62 -0
  43. package/dist/src/components/custom/report-viewer/logic/rdlStyle.d.ts.map +1 -0
  44. package/dist/src/components/custom/report-viewer/logic/rdlTableLayout.d.ts +33 -0
  45. package/dist/src/components/custom/report-viewer/logic/rdlTableLayout.d.ts.map +1 -0
  46. package/dist/src/components/custom/report-viewer/logic/rdlToggles.d.ts +20 -0
  47. package/dist/src/components/custom/report-viewer/logic/rdlToggles.d.ts.map +1 -0
  48. package/dist/src/components/custom/report-viewer/logic/rdlUnits.d.ts +9 -0
  49. package/dist/src/components/custom/report-viewer/logic/rdlUnits.d.ts.map +1 -0
  50. package/dist/src/components/custom/report-viewer/logic/reportOutputGuard.d.ts +20 -0
  51. package/dist/src/components/custom/report-viewer/logic/reportOutputGuard.d.ts.map +1 -0
  52. package/dist/src/components/custom/report-viewer/logic/reportViewerLayout.d.ts +17 -0
  53. package/dist/src/components/custom/report-viewer/logic/reportViewerLayout.d.ts.map +1 -0
  54. package/dist/src/components/custom/report-viewer/rdlTypes.d.ts +333 -0
  55. package/dist/src/components/custom/report-viewer/rdlTypes.d.ts.map +1 -0
  56. package/dist/src/components/custom/report-viewer/reportChartShared.d.ts +53 -0
  57. package/dist/src/components/custom/report-viewer/reportChartShared.d.ts.map +1 -0
  58. package/dist/src/components/custom/report-viewer/reportRenderContext.d.ts +25 -0
  59. package/dist/src/components/custom/report-viewer/reportRenderContext.d.ts.map +1 -0
  60. package/dist/src/components/custom/report-viewer/useReportParameterForm.d.ts +30 -0
  61. package/dist/src/components/custom/report-viewer/useReportParameterForm.d.ts.map +1 -0
  62. package/dist/src/components/custom/report-viewer/useReportViewerState.d.ts +74 -0
  63. package/dist/src/components/custom/report-viewer/useReportViewerState.d.ts.map +1 -0
  64. package/dist/src/components/custom/report-viewer/useSidebarResize.d.ts +22 -0
  65. package/dist/src/components/custom/report-viewer/useSidebarResize.d.ts.map +1 -0
  66. package/dist/src/components/custom/scheduler-new/presentation/Scheduler.stories.d.ts +18 -1
  67. package/dist/src/components/custom/scheduler-new/presentation/Scheduler.stories.d.ts.map +1 -1
  68. package/dist/src/components/custom/scheduler-new/presentation/components/row/DefaultRowHeader.d.ts +2 -0
  69. package/dist/src/components/custom/scheduler-new/presentation/components/row/DefaultRowHeader.d.ts.map +1 -1
  70. package/dist/src/components/custom/scheduler-new/presentation/components/row/Event.d.ts +15 -0
  71. package/dist/src/components/custom/scheduler-new/presentation/components/row/Event.d.ts.map +1 -1
  72. package/dist/src/components/custom/super-scheduler/PinRowHeader.d.ts +0 -1
  73. package/dist/src/components/custom/super-scheduler/PinRowHeader.d.ts.map +1 -1
  74. package/dist/src/components/display/data/table/CwTable.d.ts.map +1 -1
  75. package/dist/src/components/display/data/table/CwTable.stories.d.ts +2 -0
  76. package/dist/src/components/display/data/table/CwTable.stories.d.ts.map +1 -1
  77. package/dist/src/components/display/data/tooltip_manager/CwTooltipManager.d.ts +1 -1
  78. package/dist/src/components/display/data/tooltip_manager/CwTooltipManager.d.ts.map +1 -1
  79. package/dist/src/components/layout/card/CwCard.d.ts +2 -2
  80. package/dist/src/components/layout/card/CwCard.d.ts.map +1 -1
  81. package/dist/src/components/layout/card/CwCard.stories.d.ts +4 -2
  82. package/dist/src/components/layout/card/CwCard.stories.d.ts.map +1 -1
  83. package/dist/src/index.d.ts +16 -1
  84. package/dist/src/index.d.ts.map +1 -1
  85. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  86. package/dist/src/playground/pages/ReportViewerPage.d.ts +8 -0
  87. package/dist/src/playground/pages/ReportViewerPage.d.ts.map +1 -0
  88. package/dist/src/playground/pages/reportViewerFakeData.d.ts +13 -0
  89. package/dist/src/playground/pages/reportViewerFakeData.d.ts.map +1 -0
  90. package/dist/test/components/custom/report-viewer/rdlChartMarkers.test.d.ts +2 -0
  91. package/dist/test/components/custom/report-viewer/rdlChartMarkers.test.d.ts.map +1 -0
  92. package/dist/test/components/custom/report-viewer/rdlChartScale.test.d.ts +2 -0
  93. package/dist/test/components/custom/report-viewer/rdlChartScale.test.d.ts.map +1 -0
  94. package/dist/test/components/custom/report-viewer/rdlFind.test.d.ts +2 -0
  95. package/dist/test/components/custom/report-viewer/rdlFind.test.d.ts.map +1 -0
  96. package/dist/test/components/custom/report-viewer/rdlGauge.test.d.ts +2 -0
  97. package/dist/test/components/custom/report-viewer/rdlGauge.test.d.ts.map +1 -0
  98. package/dist/test/components/custom/report-viewer/rdlNumberFormat.test.d.ts +2 -0
  99. package/dist/test/components/custom/report-viewer/rdlNumberFormat.test.d.ts.map +1 -0
  100. package/dist/test/components/custom/report-viewer/rdlParameterValues.test.d.ts +2 -0
  101. package/dist/test/components/custom/report-viewer/rdlParameterValues.test.d.ts.map +1 -0
  102. package/dist/test/components/custom/report-viewer/rdlTableLayout.test.d.ts +2 -0
  103. package/dist/test/components/custom/report-viewer/rdlTableLayout.test.d.ts.map +1 -0
  104. package/dist/test/components/custom/report-viewer/rdlText.test.d.ts +2 -0
  105. package/dist/test/components/custom/report-viewer/rdlText.test.d.ts.map +1 -0
  106. package/dist/test/components/custom/report-viewer/rdlToggles.test.d.ts +2 -0
  107. package/dist/test/components/custom/report-viewer/rdlToggles.test.d.ts.map +1 -0
  108. package/dist/test/components/custom/report-viewer/rdlUnits.test.d.ts +2 -0
  109. package/dist/test/components/custom/report-viewer/rdlUnits.test.d.ts.map +1 -0
  110. package/dist/test/components/custom/report-viewer/reportOutputGuard.test.d.ts +2 -0
  111. package/dist/test/components/custom/report-viewer/reportOutputGuard.test.d.ts.map +1 -0
  112. package/dist/test/components/custom/report-viewer/reportViewerLayout.test.d.ts +2 -0
  113. package/dist/test/components/custom/report-viewer/reportViewerLayout.test.d.ts.map +1 -0
  114. package/dist/test/components/custom/report-viewer/useReportParameterForm.test.d.ts +2 -0
  115. package/dist/test/components/custom/report-viewer/useReportParameterForm.test.d.ts.map +1 -0
  116. package/dist/test/components/custom/report-viewer/useReportViewerState.test.d.ts +2 -0
  117. package/dist/test/components/custom/report-viewer/useReportViewerState.test.d.ts.map +1 -0
  118. package/dist/test/helpers/renderHookHeadless.d.ts +8 -0
  119. package/dist/test/helpers/renderHookHeadless.d.ts.map +1 -0
  120. package/package.json +1 -1
package/dist/index.es.js CHANGED
@@ -174,7 +174,7 @@ function getContrastColor(color) {
174
174
  return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
175
175
  }
176
176
 
177
- var styles$A = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
177
+ var styles$D = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
178
178
 
179
179
  // Constants
180
180
  const margin$1 = 16;
@@ -464,7 +464,7 @@ const CwTooltipManager = () => {
464
464
  if (!state.isVisible || !state.content) {
465
465
  return null;
466
466
  }
467
- return createPortal(jsx("div", { ref: tooltipRef, className: styles$A["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
467
+ return createPortal(jsx("div", { ref: tooltipRef, className: styles$D["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
468
468
  top: `${tooltipPosition.top}px`,
469
469
  left: `${tooltipPosition.left}px`,
470
470
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -545,7 +545,7 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
545
545
  useEffect(() => {
546
546
  ensureTooltipManager();
547
547
  }, []);
548
- return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$A["cw-tooltip"], children: children }));
548
+ return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$D["cw-tooltip"], children: children }));
549
549
  };
550
550
 
551
551
  const SVG_ICONS = {
@@ -665,7 +665,7 @@ function resolveBadgeAria(label, loading, hasText) {
665
665
  return hasText ? {} : { 'aria-hidden': 'true' };
666
666
  }
667
667
 
668
- var styles$z = {"badge":"cw-badge-module__badge__PKlak"};
668
+ var styles$C = {"badge":"cw-badge-module__badge__PKlak"};
669
669
 
670
670
  /**
671
671
  * CwBadge - the small coloured circle with a number, used for alert and notification counts.
@@ -701,7 +701,7 @@ const CwBadge = ({ count, content, color = 'info', variant = 'solid', size = 'sm
701
701
  ? formatBadgeCount(count, max)
702
702
  : undefined;
703
703
  const isDot = !loading && !hasContent && count === undefined;
704
- const badgeClassNames = ['cw-badge', styles$z.badge, className].filter(Boolean).join(' ');
704
+ const badgeClassNames = ['cw-badge', styles$C.badge, className].filter(Boolean).join(' ');
705
705
  return (jsx("span", { ...dataAttributes, className: badgeClassNames, "data-color": color, "data-variant": variant, "data-size": size, "data-loading": loading ? 'true' : undefined, "data-dot": isDot ? 'true' : undefined, ...resolveBadgeAria(label, loading, !loading && (hasContent || countText !== undefined)), style: style, children: loading ? jsx(CwIcon, { iconId: "spinner", size: "small" }) : hasContent ? content : countText }));
706
706
  };
707
707
 
@@ -1089,7 +1089,7 @@ function CwLoading({ isLoading = false, text = '', size = 'regular', iconPositio
1089
1089
  return (jsxs("div", { "aria-busy": isLoading, className: "cw-loading-container", "data-children": !!children, children: [overlay, jsx("div", { className: "cw-loading-disabled-content", children: children })] }));
1090
1090
  }
1091
1091
 
1092
- var styles$y = {"skeleton":"cw-skeleton-module__skeleton__Jvx2x","group":"cw-skeleton-module__group__Cm8AU"};
1092
+ var styles$B = {"skeleton":"cw-skeleton-module__skeleton__Jvx2x","group":"cw-skeleton-module__group__Cm8AU"};
1093
1093
 
1094
1094
  /*
1095
1095
  * Internal helper for skeleton allocations (CwSkeleton, tables, cards).
@@ -1131,8 +1131,8 @@ function CwSkeleton({ variant = 'text', width, height, count = 1, radius, gap })
1131
1131
  };
1132
1132
  // The un-hashed cw-skeleton / cw-skeleton-group classes carry no styles in the
1133
1133
  // library - they are stable public hooks for exceptional external overrides.
1134
- const skeletonClassName = ['cw-skeleton', styles$y.skeleton].filter(Boolean).join(' ');
1135
- const groupClassName = ['cw-skeleton-group', styles$y.group].filter(Boolean).join(' ');
1134
+ const skeletonClassName = ['cw-skeleton', styles$B.skeleton].filter(Boolean).join(' ');
1135
+ const groupClassName = ['cw-skeleton-group', styles$B.group].filter(Boolean).join(' ');
1136
1136
  const lineCount = normalizeSkeletonCount(count, 1);
1137
1137
  if (lineCount <= 1) {
1138
1138
  return (jsx("span", { className: skeletonClassName, "data-variant": variant, "aria-hidden": "true", style: style }));
@@ -1144,7 +1144,7 @@ function CwSkeleton({ variant = 'text', width, height, count = 1, radius, gap })
1144
1144
  return (jsx("span", { className: groupClassName, "aria-hidden": "true", style: groupStyle, children: skeletonElements }));
1145
1145
  }
1146
1146
 
1147
- var styles$x = {"progress":"cw-progress-module__progress__d-g2-","value":"cw-progress-module__value__Q-DrH","label":"cw-progress-module__label__jwOWp","track":"cw-progress-module__track__572-3","footer":"cw-progress-module__footer__0Wo4G","header":"cw-progress-module__header__mv5ct","fill":"cw-progress-module__fill__fX1UA"};
1147
+ var styles$A = {"progress":"cw-progress-module__progress__d-g2-","value":"cw-progress-module__value__Q-DrH","label":"cw-progress-module__label__jwOWp","track":"cw-progress-module__track__572-3","footer":"cw-progress-module__footer__0Wo4G","header":"cw-progress-module__header__mv5ct","fill":"cw-progress-module__fill__fX1UA"};
1148
1148
 
1149
1149
  /**
1150
1150
  * CwProgress - a determinate or indeterminate progress bar.
@@ -1168,17 +1168,17 @@ function CwProgress({ value, indeterminate = false, label, rightLabel, footer, s
1168
1168
  const valueContent = rightLabel ?? (percent !== undefined ? `${percent}%` : '');
1169
1169
  // The un-hashed cw-progress class carries no styles in the library - a stable
1170
1170
  // public hook for exceptional external overrides only.
1171
- const rootClassName = ['cw-progress', styles$x.progress, className].filter(Boolean).join(' ');
1172
- const labelSpan = label ? jsx("span", { className: styles$x.label, id: labelId, children: label }) : null;
1173
- const valueLabel = showValue ? (jsx("span", { className: styles$x.value, "data-mono": monoValue || undefined, children: valueContent })) : null;
1174
- return (jsxs("div", { ...dataAttributes, className: rootClassName, style: style, "data-layout": layout, "data-size": size, "data-color": color, "data-prominent": prominent || undefined, "data-indeterminate": indeterminate || undefined, children: [layout === 'column' && (labelSpan || valueLabel) && (jsxs("header", { className: styles$x.header, children: [labelSpan, valueLabel] })), layout === 'row' && labelSpan, jsx("div", { className: styles$x.track, role: "progressbar", ...(label && { 'aria-labelledby': labelId }), ...(!indeterminate && percent !== undefined && {
1171
+ const rootClassName = ['cw-progress', styles$A.progress, className].filter(Boolean).join(' ');
1172
+ const labelSpan = label ? jsx("span", { className: styles$A.label, id: labelId, children: label }) : null;
1173
+ const valueLabel = showValue ? (jsx("span", { className: styles$A.value, "data-mono": monoValue || undefined, children: valueContent })) : null;
1174
+ return (jsxs("div", { ...dataAttributes, className: rootClassName, style: style, "data-layout": layout, "data-size": size, "data-color": color, "data-prominent": prominent || undefined, "data-indeterminate": indeterminate || undefined, children: [layout === 'column' && (labelSpan || valueLabel) && (jsxs("header", { className: styles$A.header, children: [labelSpan, valueLabel] })), layout === 'row' && labelSpan, jsx("div", { className: styles$A.track, role: "progressbar", ...(label && { 'aria-labelledby': labelId }), ...(!indeterminate && percent !== undefined && {
1175
1175
  'aria-valuenow': percent,
1176
1176
  'aria-valuemin': 0,
1177
1177
  'aria-valuemax': 100
1178
- }), children: jsx("div", { className: styles$x.fill, style: !indeterminate && clamped !== undefined ? { width: `${clamped}%` } : undefined }) }), layout === 'row' && valueLabel, footer != null && jsx("footer", { className: styles$x.footer, children: footer })] }));
1178
+ }), children: jsx("div", { className: styles$A.fill, style: !indeterminate && clamped !== undefined ? { width: `${clamped}%` } : undefined }) }), layout === 'row' && valueLabel, footer != null && jsx("footer", { className: styles$A.footer, children: footer })] }));
1179
1179
  }
1180
1180
 
1181
- var styles$w = {"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"};
1181
+ var styles$z = {"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"};
1182
1182
 
1183
1183
  // Constants moved outside to prevent recreation
1184
1184
  const margin = 16;
@@ -1305,12 +1305,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1305
1305
  const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
1306
1306
  setIsVisible(true);
1307
1307
  }, showDelay);
1308
- const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$w["cw-generic-tooltip-content"]);
1308
+ const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$z["cw-generic-tooltip-content"]);
1309
1309
  // Memoize tooltip content creation
1310
1310
  const tooltipContent = useMemo(() => {
1311
1311
  if (hide || !isVisible || !content)
1312
1312
  return null;
1313
- return createPortal(jsx("div", { className: styles$w["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1313
+ return createPortal(jsx("div", { className: styles$z["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1314
1314
  position: 'fixed',
1315
1315
  top: `${tooltipPosition.top}px`,
1316
1316
  left: `${tooltipPosition.left}px`,
@@ -1325,7 +1325,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1325
1325
  clearTooltipTimeout();
1326
1326
  setIsVisible(false);
1327
1327
  }, [clearTooltipTimeout]);
1328
- return (jsxs("div", { ref: containerRef, className: styles$w["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1328
+ return (jsxs("div", { ref: containerRef, className: styles$z["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1329
1329
  };
1330
1330
 
1331
1331
  const CwButton = React__default.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", badge, children, ...buttonProps }, ref) {
@@ -1393,7 +1393,7 @@ function CwModal(custModalProps) {
1393
1393
  return (jsx("div", { children: custModalProps.modalState && (jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsx("span", { className: "cwelltCloseIcon" }) })] }), jsx("div", { className: "cwelltModalBody", children: jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsx("div", { style: { display: "none" } }))] }) })] })) }));
1394
1394
  }
1395
1395
 
1396
- var styles$v = {"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"};
1396
+ var styles$y = {"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"};
1397
1397
 
1398
1398
  /**
1399
1399
  * Small anchored confirmation for a destructive action.
@@ -1462,15 +1462,15 @@ function CwConfirmationPopup(props) {
1462
1462
  onCancel();
1463
1463
  }
1464
1464
  };
1465
- return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$v.overlayPositioned, onClick: handleOverlayClick, children: jsxs("div", { ref: popupRef, className: styles$v.popup, style: {
1465
+ return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$y.overlayPositioned, onClick: handleOverlayClick, children: jsxs("div", { ref: popupRef, className: styles$y.popup, style: {
1466
1466
  position: 'absolute',
1467
1467
  top: `${position.top}px`,
1468
1468
  left: `${position.left}px`,
1469
1469
  transform: 'none'
1470
- }, children: [jsx("p", { className: styles$v.message, children: message }), jsxs("div", { className: styles$v.buttons, children: [jsx("button", { className: `${styles$v.button} ${styles$v.confirmButton}`, onClick: onConfirm, children: confirmText }), jsx("button", { className: `${styles$v.button} ${styles$v.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1470
+ }, children: [jsx("p", { className: styles$y.message, children: message }), jsxs("div", { className: styles$y.buttons, children: [jsx("button", { className: `${styles$y.button} ${styles$y.confirmButton}`, onClick: onConfirm, children: confirmText }), jsx("button", { className: `${styles$y.button} ${styles$y.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1471
1471
  }
1472
1472
 
1473
- var styles$u = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1473
+ var styles$x = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1474
1474
 
1475
1475
  // Helper function to parse size values
1476
1476
  const parseSize = (size) => {
@@ -1743,7 +1743,7 @@ const CwDialog = props => {
1743
1743
  }
1744
1744
  }
1745
1745
  }, [open]);
1746
- const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$u["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1746
+ const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$x["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1747
1747
  const content = useMemo(() => (jsx("section", { children: children })), [children]);
1748
1748
  const footer = useMemo(() => (jsx("footer", { children: customFooter || (jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
1749
1749
  const resizeHandles = useMemo(() => size.autoHeight
@@ -1770,7 +1770,7 @@ const CwDialog = props => {
1770
1770
  : `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
1771
1771
  return { displayWidth, displayHeight };
1772
1772
  }, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
1773
- const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$u["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1773
+ const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$x["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1774
1774
  left: `${position.x}px`,
1775
1775
  top: `${position.y}px`,
1776
1776
  width: displayDimensions.displayWidth,
@@ -1932,7 +1932,7 @@ function CwAlign(props) {
1932
1932
  }, children: props.children }));
1933
1933
  }
1934
1934
 
1935
- var styles$t = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW"};
1935
+ var styles$w = {"card":"cw-card-module__card__HJUT0","content":"cw-card-module__content__ma9qy","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW"};
1936
1936
 
1937
1937
  /**
1938
1938
  * CwCard - A simple card component for displaying content in a contained format
@@ -1945,8 +1945,8 @@ var styles$t = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module
1945
1945
  * onDelete={confirmDeletion}
1946
1946
  * footer="Last updated: 2 days ago"
1947
1947
  * chips={[
1948
- * { label: 'Important', colorScheme: 'danger' },
1949
- * { label: 'Custom', colorScheme: 'custom', customColor: '#8a2be2' }
1948
+ * { label: 'Important', color: 'danger' },
1949
+ * { label: 'Custom', color: 'custom', customColor: '#8a2be2' }
1950
1950
  * ]}
1951
1951
  * >
1952
1952
  * <p>This is the main content of the card.</p>
@@ -1958,10 +1958,10 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1958
1958
  // Construct class names using CSS modules
1959
1959
  const cardClassNames = [
1960
1960
  'cw-card',
1961
- styles$t.card,
1961
+ styles$w.card,
1962
1962
  className,
1963
- clickable ? styles$t.clickable : '',
1964
- disabled ? styles$t.disabled : '',
1963
+ clickable ? styles$w.clickable : '',
1964
+ disabled ? styles$w.disabled : '',
1965
1965
  ].filter(Boolean).join(' ');
1966
1966
  // Handle click event when card is clickable
1967
1967
  const handleClick = () => {
@@ -1979,15 +1979,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1979
1979
  const hasFooter = hasChips || footer || (hasActions && resolvedDirection === "row");
1980
1980
  // Actions component to reuse. While loading, each provided action renders a circular
1981
1981
  // ghost sized to the CwButton icon footprint (2rem) - no interactive buttons.
1982
- const ActionsComponent = hasActions && !disabled ? (jsx("div", { className: styles$t.actions, children: isLoading ? (jsxs(Fragment, { children: [extraActions && jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onEdit && jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onDelete && jsx(CwSkeleton, { variant: "circle", height: "2rem" })] })) : (jsxs(Fragment, { children: [extraActions ?? null, onEdit && jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) })) : null;
1982
+ const ActionsComponent = hasActions && !disabled ? (jsx("div", { className: styles$w.actions, children: isLoading ? (jsxs(Fragment, { children: [extraActions && jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onEdit && jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onDelete && jsx(CwSkeleton, { variant: "circle", height: "2rem" })] })) : (jsxs(Fragment, { children: [extraActions ?? null, onEdit && jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) })) : null;
1983
1983
  return (jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && !isLoading && {
1984
1984
  role: 'button',
1985
1985
  tabIndex: 0,
1986
1986
  onClick: handleClick,
1987
- }), "data-variant": variant, "data-direction": resolvedDirection, "aria-busy": isLoading || undefined, children: [isLoading ? (jsxs("header", { children: [jsx("div", { className: styles$t.headerContent, "data-align": resolvedAlign, children: jsx(CwSkeleton, { width: "8rem", height: "1.5em" }) }), resolvedDirection === "column" && ActionsComponent] })) : (hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$t.headerContent, "data-align": resolvedAlign, children: [title && jsx("h5", { children: title }), subtitle && jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] }))), jsx("div", { className: styles$t.content, children: isLoading ? jsx(CwSkeleton, { count: normalizeSkeletonCount(skeletonLines, 3) }) : children }), hasFooter && (isLoading ? (jsx("footer", { children: jsx("div", { className: styles$t.footerTags, children: jsx(CwSkeleton, { variant: "rect", width: "4rem", height: "1.5em", radius: "1rem" }) }) })) : (jsxs("footer", { children: [hasChips && (jsx("div", { className: styles$t.footerTags, children: chips.map((chip, index) => (jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$t.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsx("div", { className: styles$t.footerContent, children: footer }))] }))), resolvedDirection === "row" && ActionsComponent] }));
1987
+ }), "data-variant": variant, "data-direction": resolvedDirection, "aria-busy": isLoading || undefined, children: [isLoading ? (jsxs("header", { children: [jsx("div", { className: styles$w.headerContent, "data-align": resolvedAlign, children: jsx(CwSkeleton, { width: "8rem", height: "1.5em" }) }), resolvedDirection === "column" && ActionsComponent] })) : (hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$w.headerContent, "data-align": resolvedAlign, children: [title && jsx("h5", { children: title }), subtitle && jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] }))), jsx("div", { className: styles$w.content, children: isLoading ? jsx(CwSkeleton, { count: normalizeSkeletonCount(skeletonLines, 3) }) : children }), hasFooter && (isLoading ? (jsx("footer", { children: jsx("div", { className: styles$w.footerTags, children: jsx(CwSkeleton, { variant: "rect", width: "4rem", height: "1.5em", radius: "1rem" }) }) })) : (jsxs("footer", { children: [hasChips && (jsx("div", { className: styles$w.footerTags, children: chips.map((chip, index) => (jsx(CwChip, { label: chip.label, color: chip.color, colorScheme: chip.colorScheme, className: styles$w.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsx("div", { className: styles$w.footerContent, children: footer }))] }))), resolvedDirection === "row" && ActionsComponent] }));
1988
1988
  };
1989
1989
 
1990
- var styles$s = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1990
+ var styles$v = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1991
1991
 
1992
1992
  /**
1993
1993
  * Option to display in the CwSelect
@@ -2082,10 +2082,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
2082
2082
  icon: sortDirection === 'asc' ? 'arrow-up' : 'arrow-down',
2083
2083
  onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'),
2084
2084
  title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}`,
2085
- }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsx("div", { className: `${styles$s.cardContainer}`, "data-layout": layout, style: gridStyle, "aria-busy": true, children: Array.from({ length: normalizeSkeletonCount(skeletonCards, 6) }, (_, index) => (jsx(CwCard, { isLoading: true, children: null }, `skeleton_${index}`))) })) : sortedItems.length === 0 ? (jsx("div", { className: styles$s.emptyState, children: emptyState || jsx("p", { children: "No items to display" }) })) : (jsxs(Fragment, { children: [jsx("div", { className: `${styles$s.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsx(React__default.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxs("div", { className: styles$s.pagination, children: [jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxs("span", { className: styles$s.pageInfo, children: [currentPage, " / ", totalPages] }), jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
2085
+ }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsx("div", { className: `${styles$v.cardContainer}`, "data-layout": layout, style: gridStyle, "aria-busy": true, children: Array.from({ length: normalizeSkeletonCount(skeletonCards, 6) }, (_, index) => (jsx(CwCard, { isLoading: true, children: null }, `skeleton_${index}`))) })) : sortedItems.length === 0 ? (jsx("div", { className: styles$v.emptyState, children: emptyState || jsx("p", { children: "No items to display" }) })) : (jsxs(Fragment, { children: [jsx("div", { className: `${styles$v.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsx(React__default.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxs("div", { className: styles$v.pagination, children: [jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxs("span", { className: styles$v.pageInfo, children: [currentPage, " / ", totalPages] }), jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
2086
2086
  }
2087
2087
 
2088
- var styles$r = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
2088
+ var styles$u = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
2089
2089
 
2090
2090
  /**
2091
2091
  * Legacy collapsible section with its own header markup.
@@ -2100,7 +2100,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
2100
2100
  setVisible_accordionBody(!isVisible_accordionBody);
2101
2101
  };
2102
2102
  // #endregion
2103
- return (jsxs("div", { className: styles$r["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxs("header", { onClick: () => showAccordionBody(), children: [jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsx("button", { className: "cw-button-icon" })] }), jsx("div", { className: styles$r["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
2103
+ return (jsxs("div", { className: styles$u["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxs("header", { onClick: () => showAccordionBody(), children: [jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsx("button", { className: "cw-button-icon" })] }), jsx("div", { className: styles$u["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
2104
2104
  }
2105
2105
 
2106
2106
  /*
@@ -2201,9 +2201,6 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2201
2201
  return acc;
2202
2202
  }, {}));
2203
2203
  const [selectedKeys, setSelectedKeys] = useState(new Set(rowSelection?.selectedRowKeys || []));
2204
- useEffect(() => {
2205
- setCurrentPage(1);
2206
- }, [data]);
2207
2204
  useEffect(() => {
2208
2205
  setSelectedKeys(new Set(rowSelection?.selectedRowKeys || []));
2209
2206
  }, [rowSelection?.selectedRowKeys]);
@@ -2289,20 +2286,27 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2289
2286
  return newSet;
2290
2287
  });
2291
2288
  }, [rowSelection, rowKey, sortedData]);
2289
+ const totalPages = useMemo(() => {
2290
+ return pagination ? Math.ceil(sortedData.length / localItemsPerPage) : 1;
2291
+ }, [sortedData, localItemsPerPage, pagination]);
2292
+ // Keep the page when data changes (e.g. a row was edited); only clamp it when it no longer exists.
2293
+ // Derived in render so a shrunk data set never shows an empty page for a frame.
2294
+ const page = Math.min(currentPage, Math.max(1, totalPages));
2295
+ useEffect(() => {
2296
+ if (page !== currentPage)
2297
+ setCurrentPage(page);
2298
+ }, [page, currentPage]);
2292
2299
  const paginatedData = useMemo(() => {
2293
2300
  if (!sortedData)
2294
2301
  return [];
2295
2302
  if (!pagination)
2296
2303
  return sortedData;
2297
- const start = (currentPage - 1) * localItemsPerPage;
2304
+ const start = (page - 1) * localItemsPerPage;
2298
2305
  return sortedData.slice(start, start + localItemsPerPage);
2299
- }, [sortedData, currentPage, localItemsPerPage, pagination]);
2300
- const totalPages = useMemo(() => {
2301
- return pagination ? Math.ceil(sortedData.length / localItemsPerPage) : 1;
2302
- }, [sortedData, localItemsPerPage, pagination]);
2303
- const handlePageChange = (page) => {
2304
- if (page >= 1 && page <= totalPages)
2305
- setCurrentPage(page);
2306
+ }, [sortedData, page, localItemsPerPage, pagination]);
2307
+ const handlePageChange = (target) => {
2308
+ if (target >= 1 && target <= totalPages)
2309
+ setCurrentPage(target);
2306
2310
  };
2307
2311
  const startResize = (e, key) => {
2308
2312
  e.preventDefault();
@@ -2363,7 +2367,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2363
2367
  ? "sortable"
2364
2368
  : sortConfig.direction === "asc"
2365
2369
  ? "sortable-asc"
2366
- : "sortable-desc" }))] }), jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsx("tbody", { children: renderTableBody() })] }), pagination && data.length > pageSizeOptions[0] && (jsxs("footer", { className: "cw-table-pagination", children: [jsxs("div", { className: "cw-table-pagination-size", children: [jsx(CwIcon, { iconId: "list" }), jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxs("div", { className: "cw-table-pagination-nav", children: [jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages <= 1, variant: "icon", icon: "chevron-left-double" }), jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages <= 1, variant: "icon", icon: "chevron-left" }), jsx("input", { type: "text", inputMode: "numeric", value: totalPages === 0 ? 0 : currentPage, disabled: totalPages === 0, onChange: (e) => {
2370
+ : "sortable-desc" }))] }), jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsx("tbody", { children: renderTableBody() })] }), pagination && data.length > pageSizeOptions[0] && (jsxs("footer", { className: "cw-table-pagination", children: [jsxs("div", { className: "cw-table-pagination-size", children: [jsx(CwIcon, { iconId: "list" }), jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxs("div", { className: "cw-table-pagination-nav", children: [jsx(CwButton, { onClick: () => handlePageChange(1), disabled: page === 1 || totalPages <= 1, variant: "icon", icon: "chevron-left-double" }), jsx(CwButton, { onClick: () => handlePageChange(page - 1), disabled: page === 1 || totalPages <= 1, variant: "icon", icon: "chevron-left" }), jsx("input", { type: "text", inputMode: "numeric", value: totalPages === 0 ? 0 : page, disabled: totalPages === 0, onChange: (e) => {
2367
2371
  const value = parseInt(e.target.value, 10);
2368
2372
  if (!isNaN(value))
2369
2373
  handlePageChange(value);
@@ -2372,10 +2376,10 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2372
2376
  if (isNaN(value) || value < 1 || value > totalPages) {
2373
2377
  handlePageChange(1);
2374
2378
  }
2375
- }, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2379
+ }, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(page + 1), disabled: page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2376
2380
  }
2377
2381
 
2378
- var styles$q = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2382
+ var styles$t = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2379
2383
 
2380
2384
  /**
2381
2385
  * Hook that provides state management for CwSortableTable.
@@ -2438,7 +2442,7 @@ function useSortableTable(initialItems) {
2438
2442
  }
2439
2443
 
2440
2444
  // ─── Drop indicator row ───────────────────────────────────────────────────────
2441
- const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$q.dropIndicator, "aria-hidden": true, children: jsx("td", { colSpan: colSpan, children: jsx("div", {}) }) }));
2445
+ const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$t.dropIndicator, "aria-hidden": true, children: jsx("td", { colSpan: colSpan, children: jsx("div", {}) }) }));
2442
2446
  // ─── Loading skeleton ─────────────────────────────────────────────────────────
2443
2447
  // Plain td cells (no local class): the ghost cells get the same global cw-table
2444
2448
  // padding as real body cells, so row heights match the loaded rows exactly.
@@ -2541,11 +2545,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2541
2545
  return items.map((item, index) => {
2542
2546
  const key = item[rowKey];
2543
2547
  const isDragging = draggedItem?.[rowKey] === key;
2544
- return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$q.dragging : "", children: [showHandle && (jsx("td", { className: "cw-table-col-action", children: jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (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 && (jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2548
+ return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$t.dragging : "", children: [showHandle && (jsx("td", { className: "cw-table-col-action", children: jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (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 && (jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2545
2549
  });
2546
2550
  };
2547
2551
  // ── Render ──────────────────────────────────────────────────────────────
2548
- return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, "aria-busy": loading || undefined, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), !loading && hasChanges && (jsxs("footer", { className: styles$q.saveBar, children: [jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2552
+ return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, "aria-busy": loading || undefined, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), !loading && hasChanges && (jsxs("footer", { className: styles$t.saveBar, children: [jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2549
2553
  }
2550
2554
 
2551
2555
  /**
@@ -2746,7 +2750,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2746
2750
  }, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2747
2751
  }
2748
2752
 
2749
- var styles$p = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2753
+ var styles$s = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2750
2754
 
2751
2755
  const BADGE_COLOR_SCHEMES = ['primary', 'danger', 'warning', 'success', 'info', 'neutral'];
2752
2756
  function isBadgeColorScheme(value) {
@@ -2800,11 +2804,11 @@ function CwTabs(CwTabsProps) {
2800
2804
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2801
2805
  ? { minWidth: CwTabsProps.tabsListWidth }
2802
2806
  : undefined;
2803
- return (jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$p['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => {
2807
+ return (jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$s['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => {
2804
2808
  const badgeScheme = tab.badgeColor && isBadgeColorScheme(tab.badgeColor) ? tab.badgeColor : undefined;
2805
2809
  const rawBadgeColor = tab.badgeColor && !badgeScheme ? tab.badgeColor : undefined;
2806
2810
  return (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, "data-badge-themed": tab.badgeColor ? "true" : undefined, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx(CwBadge, { count: typeof tab.badge === 'number' ? tab.badge : undefined, content: typeof tab.badge === 'string' ? tab.badge : undefined, size: "medium", color: badgeScheme ?? 'primary', variant: badgeScheme ? 'solid' : 'soft', style: rawBadgeColor ? { backgroundColor: rawBadgeColor, color: getContrastColor(rawBadgeColor) } : undefined }))] }, tab.key));
2807
- }) }), jsx("div", { className: styles$p['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, style: CwTabsProps.contentHeight ? { '--tabs-height': CwTabsProps.contentHeight } : undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2811
+ }) }), jsx("div", { className: styles$s['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, style: CwTabsProps.contentHeight ? { '--tabs-height': CwTabsProps.contentHeight } : undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2808
2812
  }
2809
2813
 
2810
2814
  /**
@@ -2832,7 +2836,7 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
2832
2836
  return (jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsx("summary", { children: briefing }), children && jsx("section", { children: children })] }));
2833
2837
  };
2834
2838
 
2835
- var styles$o = {"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","skeletonRow":"cw-master-detail-module__skeletonRow__6BUgt","detailSkeleton":"cw-master-detail-module__detailSkeleton__GcDS4","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2839
+ var styles$r = {"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","skeletonRow":"cw-master-detail-module__skeletonRow__6BUgt","detailSkeleton":"cw-master-detail-module__detailSkeleton__GcDS4","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2836
2840
 
2837
2841
  /*
2838
2842
  * Fixed rem widths for the ghosts: the master rows and detail panel size their
@@ -2876,12 +2880,12 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2876
2880
  document.body.style.userSelect = '';
2877
2881
  };
2878
2882
  }, [isResizing, minMasterWidth, maxMasterWidth]);
2879
- const rootClassName = [styles$o['cw-master-detail'], className].filter(Boolean).join(' ');
2883
+ const rootClassName = [styles$r['cw-master-detail'], className].filter(Boolean).join(' ');
2880
2884
  return (jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, "aria-busy": loading || undefined, children: [jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsx("search", { children: jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsx("header", { children: masterHeader })), jsx("ul", { children: loading
2881
- ? Array.from({ length: skeletonRows }, (_unused, rowIndex) => (jsxs("li", { "aria-hidden": "true", children: [jsx(CwSkeleton, { variant: "circle", height: "2rem" }), jsxs("div", { className: styles$o.skeletonRow, children: [jsx(CwSkeleton, { variant: "text", width: MASTER_TITLE_WIDTHS[rowIndex % MASTER_TITLE_WIDTHS.length] }), jsx(CwSkeleton, { variant: "text", width: MASTER_SUBTITLE_WIDTH })] })] }, `skeleton_${rowIndex}`)))
2882
- : items.map((item) => (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 && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$o.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsx("section", { className: styles$o.detail, children: loading ? (jsxs("div", { className: styles$o.detailSkeleton, "aria-hidden": "true", children: [jsx(CwSkeleton, { variant: "text", width: "14rem", height: "1.5em" }), jsx(CwSkeleton, { variant: "text", width: "22rem" }), jsx(CwSkeleton, { variant: "text", width: "18rem" }), jsx(CwSkeleton, { variant: "text", width: "20rem" })] })) : selectedKey && detailContent
2885
+ ? Array.from({ length: skeletonRows }, (_unused, rowIndex) => (jsxs("li", { "aria-hidden": "true", children: [jsx(CwSkeleton, { variant: "circle", height: "2rem" }), jsxs("div", { className: styles$r.skeletonRow, children: [jsx(CwSkeleton, { variant: "text", width: MASTER_TITLE_WIDTHS[rowIndex % MASTER_TITLE_WIDTHS.length] }), jsx(CwSkeleton, { variant: "text", width: MASTER_SUBTITLE_WIDTH })] })] }, `skeleton_${rowIndex}`)))
2886
+ : items.map((item) => (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 && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$r.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsx("section", { className: styles$r.detail, children: loading ? (jsxs("div", { className: styles$r.detailSkeleton, "aria-hidden": "true", children: [jsx(CwSkeleton, { variant: "text", width: "14rem", height: "1.5em" }), jsx(CwSkeleton, { variant: "text", width: "22rem" }), jsx(CwSkeleton, { variant: "text", width: "18rem" }), jsx(CwSkeleton, { variant: "text", width: "20rem" })] })) : selectedKey && detailContent
2883
2887
  ? detailContent
2884
- : (jsx("div", { className: styles$o['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2888
+ : (jsx("div", { className: styles$r['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2885
2889
  };
2886
2890
 
2887
2891
  /*
@@ -2921,7 +2925,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
2921
2925
  return (jsx("dl", { className: `cw-keyvalue-list ${className}`, "data-direction": groupLayout?.direction, "data-align": groupLayout?.align, "data-justify": groupLayout?.justify, "data-gap": groupLayout?.gap, "aria-busy": loading || undefined, ...htmlProps, children: renderItems() }));
2922
2926
  };
2923
2927
 
2924
- var styles$n = {"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"};
2928
+ var styles$q = {"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"};
2925
2929
 
2926
2930
  function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
2927
2931
  const [draggedItem, setDraggedItem] = useState(null);
@@ -2984,15 +2988,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
2984
2988
  }
2985
2989
  };
2986
2990
  if (items.length === 0) {
2987
- return (jsx("div", { className: `${styles$n.sortableList} ${styles$n.emptyState} ${className}`, children: jsx("div", { className: styles$n.emptyMessage, children: emptyMessage }) }));
2991
+ return (jsx("div", { className: `${styles$q.sortableList} ${styles$q.emptyState} ${className}`, children: jsx("div", { className: styles$q.emptyMessage, children: emptyMessage }) }));
2988
2992
  }
2989
- return (jsx("div", { className: `${styles$n.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2993
+ return (jsx("div", { className: `${styles$q.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2990
2994
  const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
2991
2995
  const isDragging = draggedItem?.id === item.id;
2992
2996
  const isMoved = movedItems.has(item.id);
2993
2997
  const canExpand = Boolean(expandedContent);
2994
2998
  const isExpanded = expandedItems.has(item.id);
2995
- return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$n.dropIndicator }), jsxs("div", { className: `${styles$n.sortableItem} ${isDragging ? styles$n.dragging : ''} ${isMoved ? styles$n.moved : ''} ${readOnly ? styles$n.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxs("header", { children: [canExpand ? (jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsx("div", { className: styles$n.sortableHandle, children: jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxs("div", { className: styles$n.sortableContent, children: [jsx("div", { className: styles$n.sortableTitle, children: title }), extraContent && jsx("div", { className: styles$n.sortableExtraContent, children: extraContent })] }), jsx("div", { className: styles$n.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsx("div", { className: styles$n.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsx("div", { className: styles$n.dropIndicator }))] }, item.id));
2999
+ return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$q.dropIndicator }), jsxs("div", { className: `${styles$q.sortableItem} ${isDragging ? styles$q.dragging : ''} ${isMoved ? styles$q.moved : ''} ${readOnly ? styles$q.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxs("header", { children: [canExpand ? (jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsx("div", { className: styles$q.sortableHandle, children: jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxs("div", { className: styles$q.sortableContent, children: [jsx("div", { className: styles$q.sortableTitle, children: title }), extraContent && jsx("div", { className: styles$q.sortableExtraContent, children: extraContent })] }), jsx("div", { className: styles$q.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsx("div", { className: styles$q.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsx("div", { className: styles$q.dropIndicator }))] }, item.id));
2996
3000
  }) }));
2997
3001
  }
2998
3002
 
@@ -3119,7 +3123,7 @@ const CwTableGrouped = props => {
3119
3123
  group.rows.map((child, j) => (jsx("tr", { "data-row": true, "data-row-last-of-group": j == group.rows.length - 1, children: child.cells.map((cell, k) => (jsx("td", { children: cell.content }, k))) }, j)))] }, i))) }), jsx("tfoot", {})] }) }));
3120
3124
  };
3121
3125
 
3122
- var styles$m = {"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"};
3126
+ var styles$p = {"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"};
3123
3127
 
3124
3128
  const DEFAULT_LABELS$1 = {
3125
3129
  uploadDisabled: 'Upload disabled',
@@ -3305,12 +3309,12 @@ function CwFileUploadMultiple(fileUploadProps) {
3305
3309
  }
3306
3310
  }
3307
3311
  };
3308
- return (jsxs("div", { className: `${styles$m.fileUploadContainer} ${fileUploadProps.className}`, children: [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$m.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxs("div", { className: `${styles$m.uploadArea} ${fileUploadProps.disabled ? styles$m.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsx(CwIcon, { iconId: "upload" }), jsx("p", { className: `${styles$m.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxs("p", { className: `${styles$m.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxs("div", { className: styles$m.filesContainer, children: [jsxs("div", { className: styles$m.fileItem, children: [jsxs("div", { className: styles$m.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$m.fileExtension, children: getFileExtension(existingFile) })] }), jsx("div", { className: styles$m.fileInfo, children: jsx("p", { className: styles$m.fileName, children: existingFile }) }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3312
+ return (jsxs("div", { className: `${styles$p.fileUploadContainer} ${fileUploadProps.className}`, children: [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$p.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxs("div", { className: `${styles$p.uploadArea} ${fileUploadProps.disabled ? styles$p.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsx(CwIcon, { iconId: "upload" }), jsx("p", { className: `${styles$p.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxs("p", { className: `${styles$p.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxs("div", { className: styles$p.filesContainer, children: [jsxs("div", { className: styles$p.fileItem, children: [jsxs("div", { className: styles$p.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$p.fileExtension, children: getFileExtension(existingFile) })] }), jsx("div", { className: styles$p.fileInfo, children: jsx("p", { className: styles$p.fileName, children: existingFile }) }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3309
3313
  setExistingFile(undefined);
3310
3314
  if (fileUploadProps.onSelect) {
3311
3315
  fileUploadProps.onSelect(null);
3312
3316
  }
3313
- }, disabled: fileUploadProps.disabled, className: styles$m.smallButton })] }), jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxs("div", { className: styles$m.filesContainer, children: [jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsx("small", { className: styles$m.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsx(CwButton, { onClick: () => {
3317
+ }, disabled: fileUploadProps.disabled, className: styles$p.smallButton })] }), jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxs("div", { className: styles$p.filesContainer, children: [jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsx("small", { className: styles$p.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsx(CwButton, { onClick: () => {
3314
3318
  let files = fileInputRef.current?.files ?? null;
3315
3319
  if (!files) {
3316
3320
  const dataTransfer = new DataTransfer();
@@ -3318,7 +3322,7 @@ function CwFileUploadMultiple(fileUploadProps) {
3318
3322
  files = dataTransfer.files;
3319
3323
  }
3320
3324
  fileUploadProps.onConfirm?.(files);
3321
- }, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxs("div", { className: styles$m.fileItem, children: [jsxs("div", { className: styles$m.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$m.fileExtension, children: getFileExtension(file.name) })] }), jsxs("div", { className: styles$m.fileInfo, children: [jsx("p", { className: styles$m.fileName, children: file.name }), jsxs("p", { className: styles$m.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$m.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3325
+ }, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxs("div", { className: styles$p.fileItem, children: [jsxs("div", { className: styles$p.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$p.fileExtension, children: getFileExtension(file.name) })] }), jsxs("div", { className: styles$p.fileInfo, children: [jsx("p", { className: styles$p.fileName, children: file.name }), jsxs("p", { className: styles$p.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$p.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3322
3326
  }
3323
3327
 
3324
3328
  /**
@@ -3371,7 +3375,7 @@ function CwDigit(props) {
3371
3375
  return (jsxs("div", { className: "cw-input-text", "data-direction": labelProps ? flexDirection : "column", "data-feedback-position": feedbackPosition, children: [jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: "cw-input-button", children: [jsx("input", { type: "number", ...inputProps, "aria-describedby": describedBy }), buttonProps && jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-info", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
3372
3376
  }
3373
3377
 
3374
- var styles$l = {"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"};
3378
+ var styles$o = {"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"};
3375
3379
 
3376
3380
  const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
3377
3381
  const [rgb, setRgb] = useState({ r: 255, g: 255, b: 255 });
@@ -3574,13 +3578,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
3574
3578
  // Calculate background color for the main area based on current hue
3575
3579
  const hueColor = hsvToRgb(hsv.h, 100, 100);
3576
3580
  const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
3577
- return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$l.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxs("div", { children: [jsx("label", { children: "R:" }), jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "G:" }), jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "B:" }), jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxs("div", { className: styles$l.colorPickerInteractiveArea, children: [jsx("div", { className: styles$l.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsx("div", { className: styles$l.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxs("div", { className: styles$l.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxs("div", { className: styles$l.colorAreaOverlay, children: [jsx("div", { className: styles$l.hueBackground, style: { backgroundColor: hueHex } }), jsx("div", { className: styles$l.whiteGradient }), jsx("div", { className: styles$l.blackGradient })] }), jsx("div", { className: styles$l.colorAreaCursor, style: {
3581
+ return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$o.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxs("div", { children: [jsx("label", { children: "R:" }), jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "G:" }), jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "B:" }), jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxs("div", { className: styles$o.colorPickerInteractiveArea, children: [jsx("div", { className: styles$o.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsx("div", { className: styles$o.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxs("div", { className: styles$o.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxs("div", { className: styles$o.colorAreaOverlay, children: [jsx("div", { className: styles$o.hueBackground, style: { backgroundColor: hueHex } }), jsx("div", { className: styles$o.whiteGradient }), jsx("div", { className: styles$o.blackGradient })] }), jsx("div", { className: styles$o.colorAreaCursor, style: {
3578
3582
  left: `${hsv.s}%`,
3579
3583
  top: `${100 - hsv.v}%`
3580
3584
  } })] })] })] }));
3581
3585
  };
3582
3586
 
3583
- var styles$k = {"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"};
3587
+ var styles$n = {"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"};
3584
3588
 
3585
3589
  const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, className, style, }) => {
3586
3590
  const [isOpen, setIsOpen] = useState(false);
@@ -3713,11 +3717,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
3713
3717
  break;
3714
3718
  }
3715
3719
  };
3716
- return (jsxs("div", { className: `cw-input-color ${styles$k.container}${className ? ` ${className}` : ''}`, style: style, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsx(CwLabel, { ...labelProps })), jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$k.selectColor} ${disabled ? styles$k.disabled : ''} ${readOnly ? styles$k.readOnly : ''}`, style: {
3720
+ return (jsxs("div", { className: `cw-input-color ${styles$n.container}${className ? ` ${className}` : ''}`, style: style, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsx(CwLabel, { ...labelProps })), jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$n.selectColor} ${disabled ? styles$n.disabled : ''} ${readOnly ? styles$n.readOnly : ''}`, style: {
3717
3721
  width,
3718
3722
  height,
3719
3723
  backgroundColor: value,
3720
- }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$k.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3724
+ }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$n.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3721
3725
  };
3722
3726
 
3723
3727
  /**
@@ -3972,7 +3976,7 @@ function CwInputDateText(props) {
3972
3976
  return (jsx("div", { className: "cw-input-date-text", children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { children: [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 }), jsxs("span", { children: [jsx(CwIcon, { iconId: "calendar" }), jsx("input", { type: "date", disabled: disabled, onChange: onChangeInputDate, readOnly: readOnly, ref: dateInputRef, tabIndex: -1, value: date, ...inputProps })] })] }), buttonProps && jsx(CwButton, { ...buttonProps })] }) }));
3973
3977
  }
3974
3978
 
3975
- var styles$j = {"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"};
3979
+ var styles$m = {"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"};
3976
3980
 
3977
3981
  const DEFAULT_LABELS = {
3978
3982
  dropImageHere: "Drop image here",
@@ -4051,7 +4055,7 @@ function CwInputImage(props) {
4051
4055
  const file = e.currentTarget.files?.[0];
4052
4056
  void handleFile(file ?? null);
4053
4057
  };
4054
- return (jsxs("div", { className: `cw-input-image ${styles$j.container}`, "data-size": size, children: [jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$j.dropZone, children: [jsx(CwIcon, { iconId: "upload" }), jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsx("p", { className: styles$j.title, children: labels.dropImageHere }), jsx("p", { className: styles$j.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$j.hiddenInput, ...inputProps })] }));
4058
+ return (jsxs("div", { className: `cw-input-image ${styles$m.container}`, "data-size": size, children: [jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$m.dropZone, children: [jsx(CwIcon, { iconId: "upload" }), jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsx("p", { className: styles$m.title, children: labels.dropImageHere }), jsx("p", { className: styles$m.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$m.hiddenInput, ...inputProps })] }));
4055
4059
  }
4056
4060
 
4057
4061
  /**
@@ -4183,7 +4187,7 @@ const CwImageArea = forwardRef((props, ref) => {
4183
4187
  });
4184
4188
  CwImageArea.displayName = "CwImageArea";
4185
4189
 
4186
- var styles$i = {"container":"cw-weekday-selector-module__container__pwcvx","days":"cw-weekday-selector-module__days__Dd3RH"};
4190
+ var styles$l = {"container":"cw-weekday-selector-module__container__pwcvx","days":"cw-weekday-selector-module__days__Dd3RH"};
4187
4191
 
4188
4192
  /* 2024-01-01 was a Monday. Formatted in UTC so a negative browser offset cannot shift a day. */
4189
4193
  const MONDAY_UTC = Date.UTC(2024, 0, 1);
@@ -4381,16 +4385,16 @@ const CwWeekdaySelector = ({ value = "mtwrfsu", onChange, disabled = false, labe
4381
4385
  // Points at the label element rather than copying its text, which also covers a labelProps that
4382
4386
  // carries children instead of `text`.
4383
4387
  const labelId = labelProps?.id ?? `${feedbackId}-label`;
4384
- return (jsxs("div", { ...dataAttributes, className: `cw-weekday-selector ${styles$i.container}${className ? ` ${className}` : ""}`, "data-direction": labelProps ? layout?.direction ?? "row" : "column", "data-align": layout?.align, "data-gap": layout?.gap, children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsx("div", { role: "group", className: styles$i.days, "aria-labelledby": labelProps ? labelId : undefined, "aria-describedby": describedBy, children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, "data-letter": dayNames[day].letter, "aria-label": dayNames[day].full, title: dayNames[day].full, checked: selectedDays.includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4388
+ return (jsxs("div", { ...dataAttributes, className: `cw-weekday-selector ${styles$l.container}${className ? ` ${className}` : ""}`, "data-direction": labelProps ? layout?.direction ?? "row" : "column", "data-align": layout?.align, "data-gap": layout?.gap, children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsx("div", { role: "group", className: styles$l.days, "aria-labelledby": labelProps ? labelId : undefined, "aria-describedby": describedBy, children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, "data-letter": dayNames[day].letter, "aria-label": dayNames[day].full, title: dayNames[day].full, checked: selectedDays.includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4385
4389
  };
4386
4390
 
4387
- var styles$h = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
4391
+ var styles$k = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
4388
4392
 
4389
4393
  function CwCheck(props) {
4390
4394
  const { labelProps, labelText, direction, alignment, className, ...inputProps } = props;
4391
4395
  const resolvedDirection = direction ?? alignment ?? "row";
4392
4396
  const displayText = labelProps?.text ?? labelText;
4393
- return (jsx("div", { className: `cw-check ${styles$h["check-container"]}${className ? ` ${className}` : ''}`, children: jsxs("label", { "data-direction": resolvedDirection, children: [jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
4397
+ return (jsx("div", { className: `cw-check ${styles$k["check-container"]}${className ? ` ${className}` : ''}`, children: jsxs("label", { "data-direction": resolvedDirection, children: [jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
4394
4398
  }
4395
4399
 
4396
4400
  function CwCheckbox(CwCheckboxProps) {
@@ -4444,14 +4448,14 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4444
4448
  ?? (optionsAlignment === "column" ? "row" : "column");
4445
4449
  // Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
4446
4450
  const checkDirection = itemDirection === "row" ? "column" : "row";
4447
- return (jsxs("div", { className: `cw-checkbox-group ${styles$h.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$h.options, role: "group", "aria-label": labelProps?.text, "aria-describedby": describedBy, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4451
+ return (jsxs("div", { className: `cw-checkbox-group ${styles$k.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$k.options, role: "group", "aria-label": labelProps?.text, "aria-describedby": describedBy, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4448
4452
  }
4449
4453
 
4450
- var styles$g = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
4454
+ var styles$j = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
4451
4455
 
4452
4456
  /** Single native radio input. Building block for CwRadioGroup. */
4453
4457
  function CwRadio({ label, direction = "row", className, ...inputProps }) {
4454
- return (jsxs("label", { className: `cw-radio ${styles$g.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsx("input", { type: "radio", ...inputProps }), label && jsx("span", { children: label })] }));
4458
+ return (jsxs("label", { className: `cw-radio ${styles$j.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsx("input", { type: "radio", ...inputProps }), label && jsx("span", { children: label })] }));
4455
4459
  }
4456
4460
 
4457
4461
  /**
@@ -4478,7 +4482,7 @@ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemL
4478
4482
  // (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
4479
4483
  // best with the circle above the text.
4480
4484
  const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
4481
- return (jsxs("div", { className: `cw-radio-group ${styles$g.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$g.options, role: "radiogroup", "aria-describedby": describedBy, "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4485
+ return (jsxs("div", { className: `cw-radio-group ${styles$j.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: styles$j.options, role: "radiogroup", "aria-describedby": describedBy, "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] }));
4482
4486
  }
4483
4487
 
4484
4488
  function CwToggle(props) {
@@ -4619,7 +4623,7 @@ function useDropdownPortal({ anchorRef, isOpen, onClose, positionStrategy = defa
4619
4623
  return { panelRef, panelStyle: style, renderPanel };
4620
4624
  }
4621
4625
 
4622
- var styles$f = {"dropdown":"cw-dropdown-module__dropdown__EFZ9M cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-dropdown-module__option__TuMdI cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-dropdown-module__optionFocused__7LGaC cw-choice-dropdown-module__optionFocused__BYMxj","optionSelected":"cw-dropdown-module__optionSelected__OiXIc cw-choice-dropdown-module__optionSelected__Lt8Xg","optionDisabled":"cw-dropdown-module__optionDisabled__lYM6w cw-choice-dropdown-module__optionDisabled__n3scM","emptyState":"cw-dropdown-module__emptyState__gp8KT cw-choice-dropdown-module__emptyState__HO0Y7","searchBox":"cw-dropdown-module__searchBox__Bx0JE cw-choice-dropdown-module__searchBox__0gox7","searchInput":"cw-dropdown-module__searchInput__JrxCK cw-choice-dropdown-module__searchInput__G5oRs","value":"cw-dropdown-module__value__i-7IN","colorCircle":"cw-dropdown-module__colorCircle__5kgiT cw-choice-dropdown-module__colorCircle__x7mI9"};
4626
+ var styles$i = {"dropdown":"cw-dropdown-module__dropdown__EFZ9M cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-dropdown-module__option__TuMdI cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-dropdown-module__optionFocused__7LGaC cw-choice-dropdown-module__optionFocused__BYMxj","optionSelected":"cw-dropdown-module__optionSelected__OiXIc cw-choice-dropdown-module__optionSelected__Lt8Xg","optionDisabled":"cw-dropdown-module__optionDisabled__lYM6w cw-choice-dropdown-module__optionDisabled__n3scM","emptyState":"cw-dropdown-module__emptyState__gp8KT cw-choice-dropdown-module__emptyState__HO0Y7","searchBox":"cw-dropdown-module__searchBox__Bx0JE cw-choice-dropdown-module__searchBox__0gox7","searchInput":"cw-dropdown-module__searchInput__JrxCK cw-choice-dropdown-module__searchInput__G5oRs","value":"cw-dropdown-module__value__i-7IN","colorCircle":"cw-dropdown-module__colorCircle__5kgiT cw-choice-dropdown-module__colorCircle__x7mI9"};
4623
4627
 
4624
4628
  /**
4625
4629
  * Custom dropdown component with colour-coded options, optional search filter, and full
@@ -4733,12 +4737,12 @@ function CwDropdown({ options, value, onChange, labelProps, alignProps, placehol
4733
4737
  }
4734
4738
  }, [isOpen, highlightedIndex, filteredOptions, handleOptionSelect]);
4735
4739
  const flexDirection = alignProps?.flexDirection ?? "row";
4736
- return (jsx("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsxs("div", { className: styles$f.value, children: [jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxs("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-labelledby": labelProps ? `${labelId} ${valueId}` : undefined, "aria-label": labelProps ? undefined : (selectedOption?.label || placeholder), "aria-describedby": describedBy, children: [jsx("div", { className: "cw-dropdown-trigger-content", id: valueId, children: selectedOption ? (jsxs(Fragment, { children: [selectedOption.color && (jsx("span", { className: styles$f.colorCircle, style: { backgroundColor: selectedOption.color } })), jsx("span", { children: selectedOption.label })] })) : (jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }), jsx(CwIcon, { iconId: "chevron-down", size: "small" })] }), renderPanel(jsxs("div", { ref: panelRef, className: styles$f.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsx("div", { className: styles$f.searchBox, children: jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: styles$f.searchInput, autoComplete: "off" }) })), jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4737
- styles$f.option,
4738
- value === option.value ? styles$f.optionSelected : "",
4739
- highlightedIndex === index ? styles$f.optionFocused : "",
4740
- option.disabled ? styles$f.optionDisabled : "",
4741
- ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsx("span", { className: styles$f.colorCircle, style: { backgroundColor: option.color } })), jsx("span", { children: option.label })] }, option.value)))) : (jsx("li", { className: styles$f.emptyState, children: "No options available" })) })] }))] }), feedbackMessages.map((item, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": item.type, "aria-live": "polite", children: item.message }, index)))] })] }) }));
4740
+ return (jsx("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && jsx(CwLabel, { id: labelId, ...labelProps }), jsxs("div", { className: styles$i.value, children: [jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxs("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-labelledby": labelProps ? `${labelId} ${valueId}` : undefined, "aria-label": labelProps ? undefined : (selectedOption?.label || placeholder), "aria-describedby": describedBy, children: [jsx("div", { className: "cw-dropdown-trigger-content", id: valueId, children: selectedOption ? (jsxs(Fragment, { children: [selectedOption.color && (jsx("span", { className: styles$i.colorCircle, style: { backgroundColor: selectedOption.color } })), jsx("span", { children: selectedOption.label })] })) : (jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }), jsx(CwIcon, { iconId: "chevron-down", size: "small" })] }), renderPanel(jsxs("div", { ref: panelRef, className: styles$i.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsx("div", { className: styles$i.searchBox, children: jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: styles$i.searchInput, autoComplete: "off" }) })), jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4741
+ styles$i.option,
4742
+ value === option.value ? styles$i.optionSelected : "",
4743
+ highlightedIndex === index ? styles$i.optionFocused : "",
4744
+ option.disabled ? styles$i.optionDisabled : "",
4745
+ ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsx("span", { className: styles$i.colorCircle, style: { backgroundColor: option.color } })), jsx("span", { children: option.label })] }, option.value)))) : (jsx("li", { className: styles$i.emptyState, children: "No options available" })) })] }))] }), feedbackMessages.map((item, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": item.type, "aria-live": "polite", children: item.message }, index)))] })] }) }));
4742
4746
  }
4743
4747
 
4744
4748
  /**
@@ -4755,7 +4759,7 @@ function CwDropdownFilter(props) {
4755
4759
  return (jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
4756
4760
  }
4757
4761
 
4758
- var styles$e = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4762
+ var styles$h = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4759
4763
 
4760
4764
  /**
4761
4765
  * Button that toggles a floating panel with arbitrary children.
@@ -4834,7 +4838,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4834
4838
  }
4835
4839
  panel.showPopover();
4836
4840
  }, [placement]);
4837
- return (jsxs("div", { ref: containerRef, className: styles$e.container, children: [jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsx("div", { ref: panelCallbackRef, className: `${styles$e.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4841
+ return (jsxs("div", { ref: containerRef, className: styles$h.container, children: [jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsx("div", { ref: panelCallbackRef, className: `${styles$h.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4838
4842
  }
4839
4843
 
4840
4844
  function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
@@ -4852,13 +4856,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
4852
4856
  return result;
4853
4857
  }
4854
4858
 
4855
- var styles$d = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4859
+ var styles$g = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4856
4860
 
4857
4861
  const CwMultiFilterTag = props => {
4858
4862
  const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
4859
4863
  const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
4860
4864
  const isOutlineMode = Selected && !Removable;
4861
- return (jsx("li", { className: styles$d["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4865
+ return (jsx("li", { className: styles$g["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4862
4866
  if (Selectable)
4863
4867
  props.OnSelect?.(props);
4864
4868
  }, children: jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
@@ -4868,7 +4872,7 @@ const CwMultiFilterTag = props => {
4868
4872
  } : undefined }) }));
4869
4873
  };
4870
4874
 
4871
- var styles$c = {"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"};
4875
+ var styles$f = {"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"};
4872
4876
 
4873
4877
  /**
4874
4878
  * A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
@@ -5109,9 +5113,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
5109
5113
  inputRef.current?.focus();
5110
5114
  }
5111
5115
  };
5112
- return (jsxs("form", { ref: componentRef, id: id, "data-testid": testId, className: `${styles$c["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
5116
+ return (jsxs("form", { ref: componentRef, id: id, "data-testid": testId, className: `${styles$f["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
5113
5117
  e.preventDefault();
5114
- }, children: [jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$c["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-outline-variant)" } : {}, children: [jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), 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 => {
5118
+ }, children: [jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$f["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-outline-variant)" } : {}, children: [jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), 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 => {
5115
5119
  switch (e.key) {
5116
5120
  case "Enter":
5117
5121
  case "Tab": {
@@ -5138,7 +5142,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
5138
5142
  break;
5139
5143
  }
5140
5144
  }
5141
- } })] }), selectedTags.size > 0 && (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(jsxs("section", { ref: panelRef, className: styles$c["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxs("nav", { children: [jsx("button", { className: selectedCategory === "All" ? styles$c["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsx("button", { className: selectedCategory === category ? styles$c["category-selected"] : undefined, style: {
5145
+ } })] }), selectedTags.size > 0 && (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(jsxs("section", { ref: panelRef, className: styles$f["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxs("nav", { children: [jsx("button", { className: selectedCategory === "All" ? styles$f["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsx("button", { className: selectedCategory === category ? styles$f["category-selected"] : undefined, style: {
5142
5146
  backgroundColor: getColor(category).primary,
5143
5147
  color: getColor(category).onPrimary,
5144
5148
  }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsx("ul", { children: displayTags
@@ -5164,7 +5168,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
5164
5168
  } }, props.ID))) })] }))] }));
5165
5169
  };
5166
5170
 
5167
- var styles$b = {"container":"cw-tag-selector-module__container__-do8i","value":"cw-tag-selector-module__value__TDAy3","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
5171
+ var styles$e = {"container":"cw-tag-selector-module__container__-do8i","value":"cw-tag-selector-module__value__TDAy3","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
5168
5172
 
5169
5173
  /**
5170
5174
  * Multi-select input with chip tags and searchable dropdown.
@@ -5202,6 +5206,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5202
5206
  isOpen: open,
5203
5207
  onClose: () => { setOpen(false); setFocusedIndex(-1); },
5204
5208
  });
5209
+ // Disabling while the panel is open closes it (state adjusted during render, no effect pass).
5210
+ if (disabled && open) {
5211
+ setOpen(false);
5212
+ setFocusedIndex(-1);
5213
+ }
5205
5214
  const selectedSet = useMemo(() => new Set(value), [value]);
5206
5215
  const filtered = useMemo(() => {
5207
5216
  if (!search)
@@ -5211,17 +5220,23 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5211
5220
  }, [options, selectedSet, search]);
5212
5221
  const selectedOptions = useMemo(() => value.map(v => options.find(o => o.value === v)).filter(Boolean), [value, options]);
5213
5222
  const handleSelect = useCallback((optionValue) => {
5223
+ if (disabled)
5224
+ return;
5214
5225
  onChange([...value, optionValue]);
5215
5226
  setSearch("");
5216
5227
  setFocusedIndex(-1);
5217
5228
  inputRef.current?.focus();
5218
- }, [value, onChange]);
5229
+ }, [disabled, value, onChange]);
5219
5230
  const handleRemove = useCallback((optionValue) => {
5231
+ if (disabled)
5232
+ return;
5220
5233
  onChange(value.filter(v => v !== optionValue));
5221
5234
  inputRef.current?.focus();
5222
- }, [value, onChange]);
5235
+ }, [disabled, value, onChange]);
5223
5236
  const allSelected = options.length > 0 && options.every(o => selectedSet.has(o.value));
5224
5237
  const handleToggleAll = useCallback(() => {
5238
+ if (disabled)
5239
+ return;
5225
5240
  if (allSelected) {
5226
5241
  onChange([]);
5227
5242
  }
@@ -5231,7 +5246,7 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5231
5246
  setSearch("");
5232
5247
  setFocusedIndex(-1);
5233
5248
  inputRef.current?.focus();
5234
- }, [allSelected, options, onChange]);
5249
+ }, [disabled, allSelected, options, onChange]);
5235
5250
  const handleInputChange = useCallback((e) => {
5236
5251
  setSearch(e.currentTarget.value);
5237
5252
  if (!open)
@@ -5243,6 +5258,8 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5243
5258
  setOpen(true);
5244
5259
  }, [disabled]);
5245
5260
  const handleKeyDown = useCallback((e) => {
5261
+ if (disabled)
5262
+ return;
5246
5263
  if (e.key === "Backspace" && !search && value.length > 0) {
5247
5264
  onChange(value.slice(0, -1));
5248
5265
  return;
@@ -5287,7 +5304,7 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5287
5304
  e.preventDefault();
5288
5305
  setFocusedIndex(prev => (prev > 0 ? prev - 1 : 0));
5289
5306
  }
5290
- }, [open, search, value, filtered, focusedIndex, onChange, handleSelect]);
5307
+ }, [disabled, open, search, value, filtered, focusedIndex, onChange, handleSelect]);
5291
5308
  // Scroll focused item into view
5292
5309
  useEffect(() => {
5293
5310
  if (focusedIndex >= 0 && listRef.current) {
@@ -5302,11 +5319,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
5302
5319
  const feedbackId = useId();
5303
5320
  const feedbackIds = feedbackMessages.map((_, index) => `${feedbackId}-${index}`);
5304
5321
  const describedBy = feedbackIds.join(" ") || undefined;
5305
- return (jsxs("div", { ref: containerRef, className: `${styles$b.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: styles$b.value, children: [jsxs("div", { className: `${styles$b.inputBox}${disabled ? ` ${styles$b.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5306
- inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off", "aria-describedby": describedBy }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), feedbackMessages.map((fb, i) => (jsx("p", { id: feedbackIds[i], className: "cw-input-feedback", "data-color": fb.type, "aria-live": "polite", children: fb.message }, i)))] })] }), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$b.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$b.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$b.option}${idx === focusedIndex ? ` ${styles$b.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$b.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5322
+ return (jsxs("div", { ref: containerRef, className: `${styles$e.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: styles$e.value, children: [jsxs("div", { className: `${styles$e.inputBox}${disabled ? ` ${styles$e.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5323
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off", "aria-describedby": describedBy }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), feedbackMessages.map((fb, i) => (jsx("p", { id: feedbackIds[i], className: "cw-input-feedback", "data-color": fb.type, "aria-live": "polite", children: fb.message }, i)))] })] }), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$e.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$e.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$e.option}${idx === focusedIndex ? ` ${styles$e.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$e.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5307
5324
  }
5308
5325
 
5309
- var styles$a = {"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"};
5326
+ var styles$d = {"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"};
5310
5327
 
5311
5328
  function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null, ...dataAttributes }) {
5312
5329
  const [expanded, setExpanded] = useState(new Set());
@@ -5373,10 +5390,10 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5373
5390
  const isLeaf = !hasChildren;
5374
5391
  const isSelected = selectedId?.toString().toLowerCase() === node.id.toString().toLowerCase();
5375
5392
  const selectable = allowParentSelection || isLeaf;
5376
- return (jsxs("div", { className: styles$a["tree-item"], children: [jsxs("div", { className: [
5377
- styles$a["tree-node"],
5378
- isSelected && styles$a["selected"],
5379
- !selectable && styles$a["non-selectable"]
5393
+ return (jsxs("div", { className: styles$d["tree-item"], children: [jsxs("div", { className: [
5394
+ styles$d["tree-node"],
5395
+ isSelected && styles$d["selected"],
5396
+ !selectable && styles$d["non-selectable"]
5380
5397
  ].filter(Boolean).join(' '), style: { paddingLeft: `${depth * 24 + 8}px` }, onClick: () => {
5381
5398
  if (selectable) {
5382
5399
  setSelectedId(node.id);
@@ -5388,7 +5405,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5388
5405
  }, children: [hasChildren && (jsx(CwButton, { variant: "icon", color: "neutral", icon: isExpanded ? "chevron-down" : "chevron-right", "aria-expanded": isExpanded, "aria-label": `${isExpanded ? "Collapse" : "Expand"} ${node.label}`, onClick: (event) => {
5389
5406
  event.stopPropagation();
5390
5407
  toggleExpand(node.id);
5391
- } })), jsx("div", { className: `${styles$a["tree-label"]} ${!hasChildren ? styles$a["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsx("div", { className: styles$a["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
5408
+ } })), jsx("div", { className: `${styles$d["tree-label"]} ${!hasChildren ? styles$d["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsx("div", { className: styles$d["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
5392
5409
  };
5393
5410
  // Function to search for nodes that match the search term
5394
5411
  const searchInTree = (nodes, searchTerm) => {
@@ -5412,7 +5429,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5412
5429
  return results;
5413
5430
  };
5414
5431
  const filteredData = searchInTree(data, search);
5415
- return (jsxs("div", { ...dataAttributes, className: `cw-tree-view ${styles$a["tree-container"]}`, children: [jsxs("header", { children: [jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsx("div", { className: styles$a["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxs("div", { className: styles$a["empty-state"], children: [jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5432
+ return (jsxs("div", { ...dataAttributes, className: `cw-tree-view ${styles$d["tree-container"]}`, children: [jsxs("header", { children: [jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsx("div", { className: styles$d["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxs("div", { className: styles$d["empty-state"], children: [jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5416
5433
  }
5417
5434
 
5418
5435
  const EXACT_PHRASE = /"([^"]+)"/g;
@@ -5480,7 +5497,7 @@ function sortNavItems(items, alphabetically) {
5480
5497
  return [...items].sort((first, second) => first.label.localeCompare(second.label));
5481
5498
  }
5482
5499
 
5483
- var styles$9 = {"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"};
5500
+ var styles$c = {"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"};
5484
5501
 
5485
5502
  const SKELETON_ROW_COUNT = 5;
5486
5503
  const defaultRenderLink = (item, children) => (jsx("a", { href: item.href, children: children }));
@@ -5492,13 +5509,13 @@ function CwNavMenu({ items, loading = false, isActive, renderLink = defaultRende
5492
5509
  const renderItem = (item, level) => {
5493
5510
  const children = item.children;
5494
5511
  if (children && children.length > 0) {
5495
- return (jsx("li", { children: jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxs("summary", { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$9.expandIndicator }))] }), jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
5512
+ return (jsx("li", { children: jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxs("summary", { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$c.expandIndicator }))] }), jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
5496
5513
  }
5497
- return (jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxs(Fragment, { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsx(CwIcon, { iconId: "star", size: "small", className: styles$9.favoriteStar })] })) }, item.id));
5514
+ return (jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxs(Fragment, { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsx(CwIcon, { iconId: "star", size: "small", className: styles$c.favoriteStar })] })) }, item.id));
5498
5515
  };
5499
- return (jsxs("nav", { ...navProps, className: [styles$9.menu, className].filter(Boolean).join(" "), "aria-busy": loading || undefined, children: [favoritesSlot && (jsxs("details", { open: true, ...favoritesProps, className: [styles$9.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxs("summary", { children: [jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsx("div", { className: styles$9.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsx("ul", { children: loading
5500
- ? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsx("li", { className: styles$9.skeleton, children: jsx(CwSkeleton, { height: "var(--cw-size-small)", radius: "var(--cw-border-radius-small)" }) }, index)))
5501
- : visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsx("p", { className: styles$9.emptyMessage, children: emptyMessage })] }));
5516
+ return (jsxs("nav", { ...navProps, className: [styles$c.menu, className].filter(Boolean).join(" "), "aria-busy": loading || undefined, children: [favoritesSlot && (jsxs("details", { open: true, ...favoritesProps, className: [styles$c.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxs("summary", { children: [jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsx("div", { className: styles$c.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsx("ul", { children: loading
5517
+ ? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsx("li", { className: styles$c.skeleton, children: jsx(CwSkeleton, { height: "var(--cw-size-small)", radius: "var(--cw-border-radius-small)" }) }, index)))
5518
+ : visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsx("p", { className: styles$c.emptyMessage, children: emptyMessage })] }));
5502
5519
  }
5503
5520
 
5504
5521
  var dropdownStyles = {"dropdown":"cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-choice-dropdown-module__optionFocused__BYMxj"};
@@ -5664,7 +5681,7 @@ function CwSearchInput(optionsProps) {
5664
5681
  return (jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, ...otherProps, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [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 && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsx(CwIcon, { ...iconProps }) : jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: filteredOptions.map((option, index) => (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))) }) }))] }));
5665
5682
  }
5666
5683
 
5667
- var styles$8 = {"value":"cw-search-async-module__value__z53xT"};
5684
+ var styles$b = {"value":"cw-search-async-module__value__z53xT"};
5668
5685
 
5669
5686
  /**
5670
5687
  * Generic API-backed search input. Fetches matching options from a caller-supplied `onSearch`
@@ -5928,10 +5945,10 @@ const CwSearchAsync = ({ onSearch, onChange, value, onResolveInitial, onResolveS
5928
5945
  return (jsxs("div", { ...dataAttributes, className: `cw-search-input ${className}`, style: {
5929
5946
  ...(width ? { width } : {}),
5930
5947
  ...(labelProps?.labelWidth ? { "--label-width": labelProps.labelWidth } : {}),
5931
- }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$8.value, children: [jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeholder, disabled: disabled, required: required, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined, "aria-describedby": describedBy, title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selection", variant: "icon", icon: "close", color: "neutral" })) : (icon ? jsx(CwIcon, { ...icon }) : jsx(CwIcon, { iconId: "search" })) })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }), renderPanel(jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (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 ? (jsxs("span", { className: "cw-search-async-option-lines", children: [jsx("span", { children: option.label }), jsx("span", { className: "cw-search-async-option-sub", children: option.subLabel })] })) : (option.label) }, option.id))) }) }))] }));
5948
+ }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$b.value, children: [jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeholder, disabled: disabled, required: required, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined, "aria-describedby": describedBy, title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selection", variant: "icon", icon: "close", color: "neutral" })) : (icon ? jsx(CwIcon, { ...icon }) : jsx(CwIcon, { iconId: "search" })) })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }), renderPanel(jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (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 ? (jsxs("span", { className: "cw-search-async-option-lines", children: [jsx("span", { children: option.label }), jsx("span", { className: "cw-search-async-option-sub", children: option.subLabel })] })) : (option.label) }, option.id))) }) }))] }));
5932
5949
  };
5933
5950
 
5934
- var styles$7 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
5951
+ var styles$a = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
5935
5952
 
5936
5953
  const ARROW_SIZE = 8;
5937
5954
  const SAFETY_MARGIN = 8;
@@ -6072,14 +6089,14 @@ const CwAnchoredMenu = ({ children, options, onSelect, placement = 'bottom', ope
6072
6089
  document.removeEventListener("keydown", handleEscape);
6073
6090
  };
6074
6091
  }, [isOpen]);
6075
- return (jsxs(Fragment, { children: [jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && createPortal(jsxs("div", { ref: menuRef, className: styles$7["menu"], style: {
6092
+ return (jsxs(Fragment, { children: [jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && createPortal(jsxs("div", { ref: menuRef, className: styles$a["menu"], style: {
6076
6093
  top: `${position.y}px`,
6077
6094
  left: `${position.x}px`,
6078
- }, "data-has-arrow": "true", children: [jsx("div", { ref: arrowRef, className: styles$7["arrow"], "data-placement": placement }), normalizedOptions.map(option => (jsxs("div", { onClick: (e) => {
6095
+ }, "data-has-arrow": "true", children: [jsx("div", { ref: arrowRef, className: styles$a["arrow"], "data-placement": placement }), normalizedOptions.map(option => (jsxs("div", { onClick: (e) => {
6079
6096
  e.stopPropagation();
6080
6097
  e.preventDefault();
6081
6098
  handleOptionClick(option);
6082
- }, className: `${styles$7["item"]} ${option.disabled ? styles$7["disabled"] : ""}`, "data-disabled": option.disabled, children: [option.icon && jsx("span", { className: styles$7["icon"], children: option.icon }), option.label] }, option.key)))] }), document.body)] }));
6099
+ }, className: `${styles$a["item"]} ${option.disabled ? styles$a["disabled"] : ""}`, "data-disabled": option.disabled, children: [option.icon && jsx("span", { className: styles$a["icon"], children: option.icon }), option.label] }, option.key)))] }), document.body)] }));
6083
6100
  };
6084
6101
 
6085
6102
  /**
@@ -6152,13 +6169,13 @@ const CwContextMenu = ({ children, options, offset = DEFAULT_OFFSET, onSelect })
6152
6169
  document.removeEventListener("keydown", handleEscape);
6153
6170
  };
6154
6171
  }, [isOpen]);
6155
- return (jsxs(Fragment, { children: [jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && createPortal(jsx("div", { ref: menuRef, className: styles$7["menu"], style: {
6172
+ return (jsxs(Fragment, { children: [jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && createPortal(jsx("div", { ref: menuRef, className: styles$a["menu"], style: {
6156
6173
  top: `${position.y}px`,
6157
6174
  left: `${position.x}px`,
6158
- }, children: options.map(option => (jsx("div", { onClick: () => handleOptionClick(option), className: styles$7["item"], children: option }, option))) }), document.body)] }));
6175
+ }, children: options.map(option => (jsx("div", { onClick: () => handleOptionClick(option), className: styles$a["item"], children: option }, option))) }), document.body)] }));
6159
6176
  };
6160
6177
 
6161
- var styles$6 = {"split":"cw-button-split-module__split__B2KbU","menu":"cw-button-split-module__menu__mKDlt","item":"cw-button-split-module__item__Aqw6f"};
6178
+ var styles$9 = {"split":"cw-button-split-module__split__B2KbU","menu":"cw-button-split-module__menu__mKDlt","item":"cw-button-split-module__item__Aqw6f"};
6162
6179
 
6163
6180
  /**
6164
6181
  * CwButtonSplit - A primary action joined to a dropdown of alternative actions.
@@ -6184,7 +6201,7 @@ function CwButtonSplit({ text, icon, onClick, actions, onSelect, variant = "soli
6184
6201
  onSelect(action.key);
6185
6202
  event.currentTarget.closest("[popover]")?.hidePopover();
6186
6203
  };
6187
- return (jsxs("div", { className: styles$6.split, "data-variant": variant, "data-testid": dataTestId, children: [jsx(CwButton, { text: text, icon: icon, variant: variant, color: color, size: size, onClick: onClick, disabled: disabled }), jsx(CwPopoverButton, { icon: "chevron-down", title: "More actions", variant: variant, color: color, size: size, disabled: disabled, placement: placement, children: jsx("div", { className: styles$6.menu, children: actions.map((action) => (jsx(CwButton, { variant: "ghost", color: "neutral", text: action.label, icon: action.icon, disabled: action.disabled, className: styles$6.item, onClick: handleSelect(action) }, action.key))) }) })] }));
6204
+ return (jsxs("div", { className: styles$9.split, "data-variant": variant, "data-testid": dataTestId, children: [jsx(CwButton, { text: text, icon: icon, variant: variant, color: color, size: size, onClick: onClick, disabled: disabled }), jsx(CwPopoverButton, { icon: "chevron-down", title: "More actions", variant: variant, color: color, size: size, disabled: disabled, placement: placement, children: jsx("div", { className: styles$9.menu, children: actions.map((action) => (jsx(CwButton, { variant: "ghost", color: "neutral", text: action.label, icon: action.icon, disabled: action.disabled, className: styles$9.item, onClick: handleSelect(action) }, action.key))) }) })] }));
6188
6205
  }
6189
6206
 
6190
6207
  /**
@@ -6252,7 +6269,7 @@ function useRovingSingleSelect(options, value, onChange) {
6252
6269
  return { activeIndex, getSegmentProps };
6253
6270
  }
6254
6271
 
6255
- var styles$5 = {"switch":"cw-button-switch-module__switch__vdWV-","segment":"cw-button-switch-module__segment__JmVla","iconOnly":"cw-button-switch-module__iconOnly__-kCwj"};
6272
+ var styles$8 = {"switch":"cw-button-switch-module__switch__vdWV-","segment":"cw-button-switch-module__segment__JmVla","iconOnly":"cw-button-switch-module__iconOnly__-kCwj"};
6256
6273
 
6257
6274
  /**
6258
6275
  * CwButtonSwitch - Segmented single-select control: a strip of joined CwButtons.
@@ -6282,10 +6299,10 @@ var styles$5 = {"switch":"cw-button-switch-module__switch__vdWV-","segment":"cw-
6282
6299
  */
6283
6300
  function CwButtonSwitch({ options, value, onChange, size = "medium", color = "primary", iconOnly = false, direction = "row", disabled = false, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...dataAttributes }) {
6284
6301
  const { getSegmentProps } = useRovingSingleSelect(options, value, onChange);
6285
- return (jsx("div", { ...dataAttributes, className: `cw-button-switch ${styles$5.switch}`, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : ariaLabel, "data-direction": direction, children: options.map((option, index) => {
6302
+ return (jsx("div", { ...dataAttributes, className: `cw-button-switch ${styles$8.switch}`, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : ariaLabel, "data-direction": direction, children: options.map((option, index) => {
6286
6303
  const selected = option.value === value;
6287
6304
  const segmentProps = getSegmentProps(index);
6288
- return (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));
6305
+ return (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$8.segment}${iconOnly ? ` ${styles$8.iconOnly}` : ""}`, tabIndex: segmentProps.tabIndex, ref: segmentProps.ref, onKeyDown: segmentProps.onKeyDown }, option.value));
6289
6306
  }) }));
6290
6307
  }
6291
6308
 
@@ -6327,7 +6344,7 @@ function CwBtnCancel({ cw_btnOnclick, cw_btn_disabled, onClick, disabled, ...res
6327
6344
  return (jsx(CwButton, { ...rest, variant: "icon", icon: "cancel", color: "danger", onClick: onClick ?? cw_btnOnclick, disabled: disabled ?? cw_btn_disabled, title: "Cancel" }));
6328
6345
  }
6329
6346
 
6330
- var styles$4 = {"value":"cw-pickers-base-module__value__BR67P","pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
6347
+ var styles$7 = {"value":"cw-pickers-base-module__value__BR67P","pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","pickerIcons":"cw-pickers-base-module__pickerIcons__dyd2-","pickerPopup":"cw-pickers-base-module__pickerPopup__dkxJo"};
6331
6348
 
6332
6349
  /**
6333
6350
  * Renders a picker popup in a portal so it escapes overflow containers.
@@ -6567,7 +6584,7 @@ function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabl
6567
6584
  ...(maxDate ? [{ after: maxDate }] : []),
6568
6585
  ...(disabledMatcher ? [disabledMatcher] : []),
6569
6586
  ], [disabledDates, minDate, maxDate, disabledMatcher]);
6570
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6587
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$7.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: value || undefined, defaultMonth: defaultMonth || value || undefined, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
6571
6588
  today: new Date(),
6572
6589
  }, modifiersClassNames: {
6573
6590
  today: "rdp-day-today",
@@ -7216,7 +7233,7 @@ function CwDateRangePicker({ value, onChange, minDate, maxDate, disabledDates, d
7216
7233
  }
7217
7234
  return undefined;
7218
7235
  }, [value]);
7219
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonth || value?.from || undefined, modifiers: {
7236
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$7.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonth || value?.from || undefined, modifiers: {
7220
7237
  today: new Date(),
7221
7238
  }, modifiersClassNames: {
7222
7239
  today: "rdp-day-today",
@@ -7389,10 +7406,10 @@ function CwTimePicker({ value, onChange, interval = 15, minTime, maxTime, labelP
7389
7406
  const displayValue = inputValue;
7390
7407
  // If using native time input
7391
7408
  if (useNative) {
7392
- return (jsx("div", { ...dataAttributes, className: `cw-timepicker cw-timepicker-native ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsx("div", { className: styles$4.pickerWrapper, children: jsx("input", { type: "time", value: displayValue, onChange: handleNativeChange, min: minTime, max: maxTime, step: interval * 60, disabled: disabled, required: required, placeholder: placeholder, "aria-describedby": describedBy, className: "cw-timepicker-native" }) }), feedbackElements] })] }) }));
7409
+ return (jsx("div", { ...dataAttributes, className: `cw-timepicker cw-timepicker-native ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsx("div", { className: styles$7.pickerWrapper, children: jsx("input", { type: "time", value: displayValue, onChange: handleNativeChange, min: minTime, max: maxTime, step: interval * 60, disabled: disabled, required: required, placeholder: placeholder, "aria-describedby": describedBy, className: "cw-timepicker-native" }) }), feedbackElements] })] }) }));
7393
7410
  }
7394
7411
  // Custom time picker
7395
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: `${styles$4.pickerWrapper} ${timeStyles.field}${showClear ? "" : ` ${timeStyles.narrow}`}`, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, maxLength: 5 }), showClear && (jsx("div", { className: styles$4.pickerIcons, children: value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsx("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7412
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-timepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: `${styles$7.pickerWrapper} ${timeStyles.field}${showClear ? "" : ` ${timeStyles.narrow}`}`, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, maxLength: 5 }), showClear && (jsx("div", { className: styles$7.pickerIcons, children: value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", icon: "close", color: "neutral", onClick: handleClear, tabIndex: -1, "aria-label": "Clear time" })) : (jsx(CwIcon, { iconId: "clock" })) })), renderPopup(jsx("div", { ref: popupRef, className: `${styles$7.pickerPopup} ${timeStyles.timePickerPopup}`, style: popupStyle, children: jsx("div", { className: timeStyles.timePickerList, children: timeOptions.map((time) => {
7396
7413
  const isSelected = time === value;
7397
7414
  return (jsx("button", { ref: isSelected ? selectedItemRef : null, type: "button", className: isSelected ? timeStyles.selected : "", onClick: () => handleTimeSelect(time), children: time }, time));
7398
7415
  }) }) }))] }), feedbackElements] })] }) }));
@@ -7700,7 +7717,7 @@ function CwDateTimePicker({ value, onChange, minDateTime, maxDateTime, disabledD
7700
7717
  const displayMaxDate = useMemo(() => normalizedMaxDateTime && timezoneOffset !== undefined
7701
7718
  ? getDateInOffset(normalizedMaxDateTime, timezoneOffset)
7702
7719
  : normalizedMaxDateTime, [normalizedMaxDateTime, timezoneOffset]);
7703
- return jsx("div", { ...dataAttributes, className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsx(CwDatePicker, { value: selectedDate, onChange: handleDateChange, minDate: displayMinDate, maxDate: displayMaxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale }), jsx(CwTimePicker, { value: selectedTime, onChange: handleTimeChange, interval: timeInterval, minTime: timeRestrictions.minTime, maxTime: timeRestrictions.maxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsx(CwButton, { type: "button", variant: "outline", onClick: handleNowClick, disabled: disabled, text: nowLabel }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) });
7720
+ return jsx("div", { ...dataAttributes, className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsx(CwDatePicker, { value: selectedDate, onChange: handleDateChange, minDate: displayMinDate, maxDate: displayMaxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale }), jsx(CwTimePicker, { value: selectedTime, onChange: handleTimeChange, interval: timeInterval, minTime: timeRestrictions.minTime, maxTime: timeRestrictions.maxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsx(CwButton, { type: "button", variant: "outline", onClick: handleNowClick, disabled: disabled, text: nowLabel }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) });
7704
7721
  }
7705
7722
 
7706
7723
  var compactStyles = {"compactPopup":"cw-datetime-compact-module__compactPopup__GiuNY","calendarWrapper":"cw-datetime-compact-module__calendarWrapper__P4Nlq","timeWrapper":"cw-datetime-compact-module__timeWrapper__uMe-A","compactTimeList":"cw-datetime-compact-module__compactTimeList__MzSQT"};
@@ -7956,7 +7973,7 @@ function CwDateTimePickerCompact({ value, onChange, minDateTime, maxDateTime, di
7956
7973
  ...(maxDateTime ? [{ after: maxDateTime }] : []),
7957
7974
  ...(disabledMatcher ? [disabledMatcher] : []),
7958
7975
  ], [disabledDates, minDateTime, maxDateTime, disabledMatcher]);
7959
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datetimepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, maxLength: 16 }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear datetime" })) : (jsx(CwIcon, { iconId: "calendar-time" })) }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${compactStyles.compactPopup}`, style: popupStyle, children: [jsxs("div", { className: compactStyles.calendarWrapper, children: [jsx(DayPicker, { mode: "single", selected: selectedDate, onSelect: handleDaySelect, defaultMonth: selectedDate, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7976
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datetimepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, maxLength: 16 }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear datetime" })) : (jsx(CwIcon, { iconId: "calendar-time" })) }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$7.pickerPopup} ${compactStyles.compactPopup}`, style: popupStyle, children: [jsxs("div", { className: compactStyles.calendarWrapper, children: [jsx(DayPicker, { mode: "single", selected: selectedDate, onSelect: handleDaySelect, defaultMonth: selectedDate, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
7960
7977
  today: new Date(),
7961
7978
  }, modifiersClassNames: {
7962
7979
  today: "rdp-day-today",
@@ -8191,7 +8208,7 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
8191
8208
  const defaultMonthJsDate = defaultMonth
8192
8209
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
8193
8210
  : selectedJsDate;
8194
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$4.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8211
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-datepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, placeholder: placeholder, onChange: handleInputChange, onBlur: handleInputBlur, onClick: handleInputClick, onKeyDown: handleInputKeyDown, disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClear, tabIndex: -1, "aria-label": "Clear date" })) : (jsx(CwIcon, { iconId: "calendar" })) }), renderPopup(jsxs("div", { ref: popupRef, className: styles$7.pickerPopup, style: popupStyle, children: [jsx(DayPicker, { mode: "single", selected: selectedJsDate, defaultMonth: defaultMonthJsDate, onSelect: handleDaySelect, disabled: disabledDays, numberOfMonths: numberOfMonths, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8195
8212
  today: new Date(),
8196
8213
  }, modifiersClassNames: {
8197
8214
  today: "rdp-day-today",
@@ -8492,7 +8509,7 @@ function CwDateTimePickerTemporal({ value, onChange, minDateTime, maxDateTime, d
8492
8509
  minTime,
8493
8510
  maxTime,
8494
8511
  });
8495
- return jsx("div", { ...dataAttributes, className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsx(CwDatePickerTemporal, { value: picker.date, onChange: picker.selectDate, minDate: picker.minDate, maxDate: picker.maxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale }), jsx(CwTimePicker, { value: picker.time, onChange: picker.selectTime, interval: timeInterval, minTime: picker.effectiveMinTime, maxTime: picker.effectiveMaxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsx(CwButton, { type: "button", variant: "outline", onClick: picker.selectNow, disabled: disabled, text: nowLabel }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) });
8512
+ return jsx("div", { ...dataAttributes, className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsx(CwDatePickerTemporal, { value: picker.date, onChange: picker.selectDate, minDate: picker.minDate, maxDate: picker.maxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale }), jsx(CwTimePicker, { value: picker.time, onChange: picker.selectTime, interval: timeInterval, minTime: picker.effectiveMinTime, maxTime: picker.effectiveMaxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsx(CwButton, { type: "button", variant: "outline", onClick: picker.selectNow, disabled: disabled, text: nowLabel }))] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { id: feedbackIds[index], className: "cw-input-feedback", "data-color": feedbackItem.type, "aria-live": "polite", children: feedbackItem.message }, index)))] })] }) });
8496
8513
  }
8497
8514
 
8498
8515
  // dateRangePresetsTemporal.ts
@@ -8944,7 +8961,7 @@ function CwDateRangePickerTemporal({ value, onChange, minDate, maxDate, disabled
8944
8961
  const defaultMonthJsDate = defaultMonth
8945
8962
  ? new Date(defaultMonth.year, defaultMonth.month - 1, 1)
8946
8963
  : (value?.from ? plainDateToJsDate(value.from) : undefined);
8947
- return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$4.value, children: [jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$4.pickerWrapper, children: [jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$4.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$4.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8964
+ return (jsx("div", { ...dataAttributes, ref: containerRef, className: `cw-rangepicker ${className || ""}`, children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: styles$7.value, children: [jsxs("div", { ref: wrapperRef, className: rangeStyles.rangeWrapper, children: [jsxs("div", { className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputFromRef, type: "text", value: inputFromValue, placeholder: placeholderFrom, onChange: handleInputFromChange, onBlur: () => handleInputBlur('from'), onClick: handleInputFromClick, onKeyDown: (e) => handleInputKeyDown(e, 'from'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'from' }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value?.from && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearFrom, tabIndex: -1, "aria-label": "Clear from date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), jsx(CwIcon, { iconId: "arrow-right", size: "medium" }), jsxs("div", { className: styles$7.pickerWrapper, children: [jsx("input", { ref: inputToRef, type: "text", value: inputToValue, placeholder: placeholderTo, onChange: handleInputToChange, onBlur: () => handleInputBlur('to'), onClick: handleInputToClick, onKeyDown: (e) => handleInputKeyDown(e, 'to'), disabled: disabled, "aria-describedby": describedBy, required: required, size: displayFormat.length, "data-focused": focusedInput === 'to' }), jsx("div", { className: styles$7.pickerIcons, children: showClear && value?.to && !disabled ? (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onClick: handleClearTo, tabIndex: -1, "aria-label": "Clear to date" })) : (jsx(CwIcon, { iconId: "calendar" })) })] }), renderPopup(jsxs("div", { ref: popupRef, className: `${styles$7.pickerPopup} ${rangeStyles.rangePopup}`, style: popupStyle, children: [jsxs("div", { className: rangeStyles.rangeCalendarRow, children: [showPresets && presetsToRender.length > 0 && (jsx("div", { className: rangeStyles.presetList, children: presetsToRender.map((preset) => (jsx("button", { type: "button", onClick: (e) => handlePresetClick(preset, e), children: preset.label }, preset.key))) })), jsx(DayPicker, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, numberOfMonths: numberOfMonths, defaultMonth: defaultMonthJsDate, locale: locale, captionLayout: "dropdown", startMonth: dropdownStartMonth, endMonth: dropdownEndMonth, modifiers: {
8948
8965
  today: new Date(),
8949
8966
  }, modifiersClassNames: {
8950
8967
  today: "rdp-day-today",
@@ -9091,7 +9108,7 @@ class OnClickContextMenu {
9091
9108
  }
9092
9109
  }
9093
9110
 
9094
- var styles$3 = {"scheduler-header":"scheduler-header-module__scheduler-header__Y7SNV","scheduler-header-divisions":"scheduler-header-module__scheduler-header-divisions__1JrNe","scheduler-timeline-now":"scheduler-header-module__scheduler-timeline-now__naREv","scheduler-timeline-label":"scheduler-header-module__scheduler-timeline-label__mLVAp","scheduler-header-title":"scheduler-header-module__scheduler-header-title__Jzy94","title-cell":"scheduler-header-module__title-cell__mz7Ki","title":"scheduler-header-module__title__TuJVn","scheduler-dates":"scheduler-header-module__scheduler-dates__O7ePQ","current-day":"scheduler-header-module__current-day__FpHiv","scheduler-hours":"scheduler-header-module__scheduler-hours__ZDCVj"};
9111
+ var styles$6 = {"scheduler-header":"scheduler-header-module__scheduler-header__Y7SNV","scheduler-header-divisions":"scheduler-header-module__scheduler-header-divisions__1JrNe","scheduler-timeline-now":"scheduler-header-module__scheduler-timeline-now__naREv","scheduler-timeline-label":"scheduler-header-module__scheduler-timeline-label__mLVAp","scheduler-header-title":"scheduler-header-module__scheduler-header-title__Jzy94","title-cell":"scheduler-header-module__title-cell__mz7Ki","title":"scheduler-header-module__title__TuJVn","scheduler-dates":"scheduler-header-module__scheduler-dates__O7ePQ","current-day":"scheduler-header-module__current-day__FpHiv","scheduler-hours":"scheduler-header-module__scheduler-hours__ZDCVj"};
9095
9112
 
9096
9113
  const getNow$1 = (isUtc) => {
9097
9114
  let now = new Date();
@@ -9120,9 +9137,9 @@ const TimeLine = ({ left, top = "0px", height, color, width = "2px", zIndexNumbe
9120
9137
  background: color,
9121
9138
  pointerEvents: "none",
9122
9139
  zIndex: zIndexNumber,
9123
- }, className: styles$3["scheduler-timeline-now"], children: isHeader && (jsx("span", { style: {
9140
+ }, className: styles$6["scheduler-timeline-now"], children: isHeader && (jsx("span", { style: {
9124
9141
  color: color,
9125
- }, className: styles$3["scheduler-timeline-label"], children: currentTime.toLocaleTimeString([], {
9142
+ }, className: styles$6["scheduler-timeline-label"], children: currentTime.toLocaleTimeString([], {
9126
9143
  hour: '2-digit',
9127
9144
  minute: '2-digit',
9128
9145
  hour12: false
@@ -9149,17 +9166,17 @@ const SchedulerHeaderDivision = ({ topDivisions, bottomDivisions, classification
9149
9166
  return (jsxs("div", { style: {
9150
9167
  width: topWidth,
9151
9168
  cursor: "pointer"
9152
- }, children: [jsx("div", { className: `${styles$3["scheduler-dates"]} ${isToday(startDate, endDate) ? styles$3["current-day"] : ""}`, children: jsx("span", { children: topDivisions }) }), jsx("div", { style: { display: "flex", justifyContent: "space-between", flex: 1 }, children: bottomDivisions.map((element) => (jsx("div", { className: styles$3["scheduler-hours"], children: jsx("span", { children: element }) }, classification + element + topDivisions))) })] }));
9169
+ }, children: [jsx("div", { className: `${styles$6["scheduler-dates"]} ${isToday(startDate, endDate) ? styles$6["current-day"] : ""}`, children: jsx("span", { children: topDivisions }) }), jsx("div", { style: { display: "flex", justifyContent: "space-between", flex: 1 }, children: bottomDivisions.map((element) => (jsx("div", { className: styles$6["scheduler-hours"], children: jsx("span", { children: element }) }, classification + element + topDivisions))) })] }));
9153
9170
  };
9154
9171
 
9155
9172
  const HeaderTitle = ({ title, dividerText, width }) => {
9156
- return (jsxs("div", { className: styles$3["scheduler-header-title"], style: { width: width }, children: [jsx("div", { className: styles$3["title-cell"], children: jsx("span", { className: styles$3.title, children: title }) }), jsx("div", { children: jsx("span", { children: dividerText }) })] }));
9173
+ return (jsxs("div", { className: styles$6["scheduler-header-title"], style: { width: width }, children: [jsx("div", { className: styles$6["title-cell"], children: jsx("span", { className: styles$6.title, children: title }) }), jsx("div", { children: jsx("span", { children: dividerText }) })] }));
9157
9174
  };
9158
9175
 
9159
9176
  const SchedulerHeader = ({ content, divisions, visibleDays, selectedDate, width, onEvent, timeLinePercentage, isUtc }) => {
9160
9177
  const topWidth = (100 / visibleDays);
9161
9178
  const { title, classification } = content;
9162
- return (jsxs("div", { className: styles$3["scheduler-header"], children: [jsx(HeaderTitle, { title: title, dividerText: classification, width: width }), jsxs("div", { className: styles$3["scheduler-header-divisions"], style: { flex: 1, display: "flex", position: "relative" }, onMouseDown: (e) => {
9179
+ return (jsxs("div", { className: styles$6["scheduler-header"], children: [jsx(HeaderTitle, { title: title, dividerText: classification, width: width }), jsxs("div", { className: styles$6["scheduler-header-divisions"], style: { flex: 1, display: "flex", position: "relative" }, onMouseDown: (e) => {
9163
9180
  e.preventDefault();
9164
9181
  const clickPercentage = getPercentageFromMouseEvent(e);
9165
9182
  const date = dateFromPercentage(selectedDate, visibleDays, clickPercentage);
@@ -9191,7 +9208,7 @@ function getStartEnd(day) {
9191
9208
  };
9192
9209
  }
9193
9210
 
9194
- var styles$2 = {"hide-scrollbar":"new-scheduler-module__hide-scrollbar__33GG9","scheduler-event":"new-scheduler-module__scheduler-event__gphwn","scheduler-event-container":"new-scheduler-module__scheduler-event-container__-h1xm","time-marker":"new-scheduler-module__time-marker__2BejU","color-bars":"new-scheduler-module__color-bars__MhMF7","scheduler-event-text":"new-scheduler-module__scheduler-event-text__zjvd7"};
9211
+ var styles$5 = {"hide-scrollbar":"new-scheduler-module__hide-scrollbar__33GG9","scheduler-event":"new-scheduler-module__scheduler-event__gphwn","scheduler-event-container":"new-scheduler-module__scheduler-event-container__-h1xm","time-marker":"new-scheduler-module__time-marker__2BejU","underlay":"new-scheduler-module__underlay__RVCnV","label-halo":"new-scheduler-module__label-halo__84c7e","corner-marker":"new-scheduler-module__corner-marker__w7o90","color-bars":"new-scheduler-module__color-bars__MhMF7","scheduler-event-text":"new-scheduler-module__scheduler-event-text__zjvd7"};
9195
9212
 
9196
9213
  const BackgroundEvent = ({ value, heightRem }) => {
9197
9214
  const backColor = getHSLColor(value.color, value.alpha ?? 0.5);
@@ -9218,13 +9235,13 @@ const BackgroundEvent = ({ value, heightRem }) => {
9218
9235
  padding: "0.25rem",
9219
9236
  color: textColor,
9220
9237
  alignItems: value.contentAlign ?? "center"
9221
- }, className: styles$2["scheduler-event-container"], children: [value.icons ? jsx("div", { style: {
9238
+ }, className: styles$5["scheduler-event-container"], children: [value.icons ? jsx("div", { style: {
9222
9239
  display: "flex",
9223
9240
  flexDirection: "row",
9224
9241
  alignItems: "center",
9225
9242
  whiteSpace: "nowrap",
9226
9243
  color: textColor,
9227
- }, children: value.icons }) : null, jsx("span", { className: styles$2["scheduler-event-text"], children: value.name })] }) }) }) }) })) : null;
9244
+ }, children: value.icons }) : null, jsx("span", { className: styles$5["scheduler-event-text"], children: value.name })] }) }) }) }) })) : null;
9228
9245
  };
9229
9246
 
9230
9247
  const eventIsVisible = (startDate, endDate, selectedDate, visibleDays) => {
@@ -9386,16 +9403,16 @@ const WeekEndLine = ({ left, top = "0px", height, widthPercentage }) => {
9386
9403
  } }));
9387
9404
  };
9388
9405
 
9389
- var styles$1 = {"scheduler-row-header":"scheduler-row-module__scheduler-row-header__S-iv4"};
9406
+ var styles$4 = {"scheduler-row-header":"scheduler-row-module__scheduler-row-header__S-iv4"};
9390
9407
 
9391
9408
  const DefaultRowHeader = ({ value, width, onEvent }) => {
9392
9409
  return (jsxs("div", { style: {
9393
9410
  width: width,
9394
9411
  flexShrink: 0,
9395
- // background: color,
9412
+ background: value.highlightColor,
9396
9413
  }, onClick: (_) => {
9397
9414
  onEvent(new OnClickRowHeader(value.rowId));
9398
- }, className: styles$1["scheduler-row-header"], children: [jsxs("div", { children: [jsx("strong", { children: value.title }), value.title2 && jsxs("span", { children: ["-", value.title2] }), " ", jsx("strong", { children: value.subtitle })] }), value.subtitle && jsxs("div", { style: { opacity: 0.5 }, children: [value.title3 && jsxs("span", { className: styles$1["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxs("span", { children: ["-", value.subtitle2] })] })] }));
9415
+ }, className: styles$4["scheduler-row-header"], children: [jsxs("div", { children: [jsx("strong", { children: value.title }), value.title2 && jsxs("span", { children: ["-", value.title2] }), " ", jsx("strong", { children: value.subtitle })] }), value.subtitle && jsxs("div", { style: { opacity: 0.5 }, children: [value.title3 && jsxs("span", { className: styles$4["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxs("span", { children: ["-", value.subtitle2] })] })] }));
9399
9416
  };
9400
9417
 
9401
9418
  const EventSideDrag = ({ left = false, heightRem, onStartEvent }) => {
@@ -9485,7 +9502,7 @@ const SchedulerEvent = ({ value, heightRem, onEvent, maxEventHeightRem }) => {
9485
9502
  height: `calc(${effectiveHeight}rem - 4px)`,
9486
9503
  opacity: eventTransparent ? 0.5 : 1,
9487
9504
  ...value.style,
9488
- }, className: styles$2["scheduler-event"], children: [jsxs("div", { style: {
9505
+ }, className: styles$5["scheduler-event"], "data-underlay": value.underlay ? true : undefined, children: [value.underlay && jsx("div", { className: styles$5["underlay"], children: value.underlay }), jsxs("div", { style: {
9489
9506
  display: "flex",
9490
9507
  flexDirection: "row",
9491
9508
  alignItems: "stretch",
@@ -9496,26 +9513,32 @@ const SchedulerEvent = ({ value, heightRem, onEvent, maxEventHeightRem }) => {
9496
9513
  height: "100%",
9497
9514
  }, children: [value.isResizable && (jsx(EventSideDrag, { left: true, heightRem: effectiveHeight * 0.7, onStartEvent: () => {
9498
9515
  onEvent(new OnLeftDragStart(value.id));
9499
- } })), jsxs("div", { className: styles$2["scheduler-event-container"], children: [jsx("div", { style: {
9516
+ } })), jsxs("div", { className: styles$5["scheduler-event-container"], children: [jsx("div", { style: {
9500
9517
  display: "flex",
9501
9518
  flexDirection: "row",
9502
9519
  alignItems: "center",
9503
9520
  whiteSpace: "nowrap",
9504
9521
  color: textColor,
9505
- }, children: value.icons }), jsx("span", { style: {
9522
+ }, children: value.icons }), jsx("span", { className: value.underlay ? styles$5["label-halo"] : undefined, style: {
9506
9523
  padding: "0.1rem",
9507
9524
  color: textColor,
9508
9525
  display: "flex",
9509
9526
  flex: 1,
9510
9527
  alignItems: "center",
9511
9528
  width: "100%",
9512
- }, children: value.rectangleColors && value.rectangleColors.length > 0 ? (jsx("div", { className: styles$2["color-bars"], children: value.rectangleColors.map((item, i) => (jsx("div", { style: { backgroundColor: item } }, value.id + "_" + i))) })) : (value.name) })] }), value.isResizable && (jsx(EventSideDrag, { heightRem: effectiveHeight * 0.7, onStartEvent: () => {
9529
+ ...(value.underlay && { "--label-halo-color": backColor }),
9530
+ }, children: value.rectangleColors && value.rectangleColors.length > 0 ? (jsx("div", { className: styles$5["color-bars"], children: value.rectangleColors.map((item, i) => (jsx("div", { style: { backgroundColor: item } }, value.id + "_" + i))) })) : (value.label ?? value.name) })] }), value.isResizable && (jsx(EventSideDrag, { heightRem: effectiveHeight * 0.7, onStartEvent: () => {
9513
9531
  onEvent(new OnRightDragStart(value.id));
9514
- } }))] }), value.primaryTimeMarkerColor && (jsx("div", { className: styles$2["time-marker"], style: {
9532
+ } }))] }), value.primaryTimeMarkerColor && (jsx("div", { className: styles$5["time-marker"], style: {
9515
9533
  backgroundColor: value.primaryTimeMarkerColor,
9516
- } })), value.secondaryTimeMarkerColor && (jsx("div", { className: styles$2["time-marker"], style: {
9534
+ } })), value.secondaryTimeMarkerColor && (jsx("div", { className: styles$5["time-marker"], style: {
9517
9535
  backgroundColor: value.secondaryTimeMarkerColor,
9518
- } }))] }) }) }, value.id) })] }));
9536
+ } }))] }) }) }, value.id) }), value.cornerMarker && (jsx("div", { className: styles$5["corner-marker"], style: {
9537
+ top: `${topOffsetPx}px`,
9538
+ left: `${value.left}%`,
9539
+ width: `${value.width}%`,
9540
+ height: `calc(${effectiveHeight}rem - 4px)`,
9541
+ }, children: jsx("span", { "data-interactive": value.cornerMarker.tooltip ? true : undefined, "data-pulse": value.cornerMarker.pulse ? true : undefined, children: value.cornerMarker.tooltip ? (jsx(CwTooltipNew, { content: value.cornerMarker.tooltip, position: "top", showDelay: 200, hide: isOnDrag, displayInline: true, children: jsx(CwBadge, { color: value.cornerMarker.color, size: "medium" }) })) : (jsx(CwBadge, { color: value.cornerMarker.color, size: "medium" })) }) }))] }));
9519
9542
  };
9520
9543
 
9521
9544
  const SchedulerRow = memo((props) => {
@@ -10044,13 +10067,13 @@ const Scheduler = (props) => {
10044
10067
  position: "sticky",
10045
10068
  top: 0,
10046
10069
  zIndex: 1,
10047
- }, children: jsx(SchedulerHeader, { ...header }) })), jsx(VariableSizeList, { height: schedulerContentHeight * 16, itemCount: rows.length, itemSize: getItemSize, itemData: itemData, width: "100%", style: { overflowX: "hidden" }, ref: instanceRef, className: styles$2["hide-scrollbar"], children: Row })] }) }));
10070
+ }, children: jsx(SchedulerHeader, { ...header }) })), jsx(VariableSizeList, { height: schedulerContentHeight * 16, itemCount: rows.length, itemSize: getItemSize, itemData: itemData, width: "100%", style: { overflowX: "hidden" }, ref: instanceRef, className: styles$5["hide-scrollbar"], children: Row })] }) }));
10048
10071
  };
10049
10072
 
10050
10073
  class UiEvent {
10051
10074
  }
10052
10075
 
10053
- var styles = {"super-scheduler-row-header":"super-scheduler-module__super-scheduler-row-header__TTs4e","indicators":"super-scheduler-module__indicators__f4lIT","scheduler-crewmember-functions":"super-scheduler-module__scheduler-crewmember-functions__BS2hs"};
10076
+ var styles$3 = {"super-scheduler-row-header":"super-scheduler-module__super-scheduler-row-header__TTs4e","indicators":"super-scheduler-module__indicators__f4lIT","scheduler-crewmember-functions":"super-scheduler-module__scheduler-crewmember-functions__BS2hs"};
10054
10077
 
10055
10078
  class OnPinRow {
10056
10079
  id;
@@ -10078,15 +10101,15 @@ const PinRowHeader = ({ value, width, onEvent }) => {
10078
10101
  flexShrink: 0,
10079
10102
  height: "100%",
10080
10103
  background: highlightColor
10081
- }, className: styles["super-scheduler-row-header"], children: [jsx("button", { className: "cw-button-icon cwi-pin", "data-pinned": value.isPinned, onClick: (_) => {
10104
+ }, className: styles$3["super-scheduler-row-header"], children: [jsx("button", { className: "cw-button-icon cwi-pin", "data-pinned": value.isPinned, onClick: (_) => {
10082
10105
  onEvent(value.isPinned ? new OnUnpinRow(value.rowId) : new OnPinRow(value.rowId));
10083
- } }), jsx("div", { className: styles["indicators"], children: value.indicators ?? undefined }), jsxs("div", { style: {
10106
+ } }), jsx("div", { className: styles$3["indicators"], children: value.indicators ?? undefined }), jsxs("div", { style: {
10084
10107
  display: "flex",
10085
10108
  flexDirection: "column",
10086
10109
  justifyContent: "center",
10087
10110
  alignItems: "flex-start",
10088
10111
  }, children: [jsxs("div", { children: [jsx("strong", { children: value.title }), value.title2 && jsxs("span", { children: ["-", value.title2] }), " ", jsx("strong", { children: value.subtitle })] }), value.subtitle && jsxs("div", { style: { opacity: 0.5 }, children: [value.title3 &&
10089
- jsxs("span", { className: styles["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxs("span", { children: ["-", value.subtitle2] })] })] }), isLoading ? jsx("span", { className: "cwi-icons cwi-spinner" }) : undefined] }) }, value.rowId) }, value.rowId);
10112
+ jsxs("span", { className: styles$3["scheduler-crewmember-functions"], children: ["(", value.title3, ")"] }), value.subtitle2 && jsxs("span", { children: ["-", value.subtitle2] })] })] }), isLoading ? jsx("span", { className: "cwi-icons cwi-spinner" }) : undefined] }) }, value.rowId) }, value.rowId);
10090
10113
  };
10091
10114
 
10092
10115
  const SuperScheduler = ({ id, state, header, rows, events, headerColumnComp, pinnedOrderCategory, unPinnedOrderCategory, backgroundEvents, indicatorRows = [], contextMenuItems, onEvent, rowHeightRem = 1.75, rowHeaderWidth, maxEventHeightRem, EventComp = SchedulerEvent, }) => {
@@ -10098,6 +10121,2324 @@ const SuperScheduler = ({ id, state, header, rows, events, headerColumnComp, pin
10098
10121
  }, children: "Clear pinned" }) })] })), jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: EventComp, RowTitleComp: headerColumnComp, rowHeightRem: rowHeightRem, rowHeaderWidth: rowHeaderWidth, maxEventHeightRem: maxEventHeightRem })] }));
10099
10122
  };
10100
10123
 
10124
+ /** A toggle ref hides its item while `InitiallyHidden` XOR "flipped" is true. */
10125
+ function isToggleRefHidden(ref, flipped) {
10126
+ return ref.InitiallyHidden !== flipped.has(ref.Id);
10127
+ }
10128
+ /** An item, row or cell is visible only when every toggle it depends on is in its visible state. */
10129
+ function isRdlVisible(toggles, flipped) {
10130
+ if (!toggles || toggles.length === 0)
10131
+ return true;
10132
+ return toggles.every(ref => !isToggleRefHidden(ref, flipped));
10133
+ }
10134
+ /** The +/- state of a toggle textbox: the initial state inverted when its id was flipped. */
10135
+ function isToggleExpanded(textbox, flipped) {
10136
+ const initial = textbox.ToggleExpanded ?? false;
10137
+ return textbox.ToggleId ? initial !== flipped.has(textbox.ToggleId) : initial;
10138
+ }
10139
+ /**
10140
+ * The toggle ids an export or print sends so the file shows the drilldown state of the screen: the
10141
+ * ids flipped relative to the render's initial state (a toggle clicked twice is back to its initial
10142
+ * state and not sent), sorted for a stable request.
10143
+ */
10144
+ function flippedToggleIds(flipped) {
10145
+ return [...flipped].sort();
10146
+ }
10147
+ /** The toggle ids to ask the server for after a click on toggle `id`: the flipped ids with `id` flipped once more. */
10148
+ function toggledIds(flipped, id) {
10149
+ return flippedToggleIds(flipToggle(flipped, id));
10150
+ }
10151
+ /** Returns a new set with `id` flipped (added when absent, removed when present). */
10152
+ function flipToggle(flipped, id) {
10153
+ const next = new Set(flipped);
10154
+ if (next.has(id)) {
10155
+ next.delete(id);
10156
+ }
10157
+ else {
10158
+ next.add(id);
10159
+ }
10160
+ return next;
10161
+ }
10162
+
10163
+ /** Number of visible rows among `span` rows starting at `start`, at least 1. */
10164
+ function visibleRowSpan(rowVisible, start, span) {
10165
+ const end = Math.min(rowVisible.length, start + Math.max(1, span));
10166
+ let count = 0;
10167
+ for (let i = start; i < end; i++) {
10168
+ if (rowVisible[i])
10169
+ count++;
10170
+ }
10171
+ return Math.max(1, count);
10172
+ }
10173
+ function sum(values, from, to) {
10174
+ let total = 0;
10175
+ for (let i = Math.max(0, from); i < Math.min(values.length, to); i++)
10176
+ total += values[i];
10177
+ return total;
10178
+ }
10179
+ function visibleHeight(rows, rowVisible, start, span) {
10180
+ const end = Math.min(rows.length, start + Math.max(1, span));
10181
+ let height = 0;
10182
+ for (let i = start; i < end; i++) {
10183
+ if (rowVisible[i])
10184
+ height += rows[i].Height;
10185
+ }
10186
+ return height;
10187
+ }
10188
+ /**
10189
+ * Lays a table out for the current toggle state: hidden rows take no space, cells are placed at
10190
+ * their column with ColSpan/RowSpan and a header cell's RowSpan is recounted over the visible rows.
10191
+ * Cells that start in a hidden row are not drawn.
10192
+ */
10193
+ function layoutRdlTable(table, flipped) {
10194
+ const rows = table.Rows;
10195
+ const widths = table.ColumnWidths;
10196
+ const rowVisible = rows.map(row => isRdlVisible(row.Toggles, flipped));
10197
+ const rowTops = [];
10198
+ let top = 0;
10199
+ rows.forEach((row, index) => {
10200
+ rowTops.push(top);
10201
+ if (rowVisible[index])
10202
+ top += row.Height;
10203
+ });
10204
+ const cells = [];
10205
+ rows.forEach((row, rowIndex) => {
10206
+ if (!rowVisible[rowIndex])
10207
+ return;
10208
+ row.Cells.forEach((cell, cellIndex) => {
10209
+ const colSpan = Math.max(1, cell.ColSpan);
10210
+ cells.push({
10211
+ cell,
10212
+ rowIndex,
10213
+ cellIndex,
10214
+ left: sum(widths, 0, cell.Column),
10215
+ top: rowTops[rowIndex],
10216
+ width: sum(widths, cell.Column, cell.Column + colSpan),
10217
+ height: visibleHeight(rows, rowVisible, rowIndex, cell.RowSpan),
10218
+ rowSpan: visibleRowSpan(rowVisible, rowIndex, cell.RowSpan),
10219
+ hidden: !isRdlVisible(cell.Toggles, flipped)
10220
+ });
10221
+ });
10222
+ });
10223
+ return {
10224
+ width: sum(widths, 0, widths.length),
10225
+ height: top,
10226
+ rowTops,
10227
+ rowVisible,
10228
+ cells
10229
+ };
10230
+ }
10231
+
10232
+ /*
10233
+ * Find over the text of one page. Every run gets a key from its position in the render tree; the
10234
+ * renderer builds the same keys, so a match can be highlighted where the run is drawn.
10235
+ */
10236
+ /** Key prefixes of the three page sections. */
10237
+ const RDL_SECTION_KEYS = { header: "h", body: "b", footer: "f" };
10238
+ function rdlItemKey(parentKey, index) {
10239
+ return `${parentKey}.${index}`;
10240
+ }
10241
+ function rdlCellKey(tableKey, rowIndex, cellIndex) {
10242
+ return `${tableKey}.r${rowIndex}c${cellIndex}`;
10243
+ }
10244
+ function rdlRunKey(textboxKey, paragraphIndex, runIndex) {
10245
+ return `${textboxKey}.p${paragraphIndex}r${runIndex}`;
10246
+ }
10247
+ function collectTextbox(textbox, key, out) {
10248
+ textbox.Paragraphs.forEach((paragraph, p) => {
10249
+ paragraph.Runs.forEach((run, r) => {
10250
+ if (run.Text)
10251
+ out.push({ key: rdlRunKey(key, p, r), text: run.Text });
10252
+ });
10253
+ });
10254
+ }
10255
+ function collectItem(item, key, flipped, out) {
10256
+ if (!isRdlVisible(item.Toggles, flipped))
10257
+ return;
10258
+ switch (item.Kind) {
10259
+ case "textbox":
10260
+ collectTextbox(item, key, out);
10261
+ break;
10262
+ case "rectangle":
10263
+ collectItems(item.Items, key, flipped, out);
10264
+ break;
10265
+ case "table": {
10266
+ const layout = layoutRdlTable(item, flipped);
10267
+ for (const box of layout.cells) {
10268
+ if (box.hidden || !box.cell.Content)
10269
+ continue;
10270
+ collectItem(box.cell.Content, rdlCellKey(key, box.rowIndex, box.cellIndex), flipped, out);
10271
+ }
10272
+ break;
10273
+ }
10274
+ }
10275
+ }
10276
+ function collectItems(items, parentKey, flipped, out) {
10277
+ items.forEach((item, index) => collectItem(item, rdlItemKey(parentKey, index), flipped, out));
10278
+ }
10279
+ /** Every visible text run of a page in document order: header, body, footer. */
10280
+ function collectPageText(page, flipped) {
10281
+ const out = [];
10282
+ if (page.Header)
10283
+ collectItems(page.Header.Items, RDL_SECTION_KEYS.header, flipped, out);
10284
+ collectItems(page.Items, RDL_SECTION_KEYS.body, flipped, out);
10285
+ if (page.Footer)
10286
+ collectItems(page.Footer.Items, RDL_SECTION_KEYS.footer, flipped, out);
10287
+ return out;
10288
+ }
10289
+ /**
10290
+ * The text lower-cased one character at a time, with each code unit of the result pointing back to the
10291
+ * original character it came from: lower-casing can change the length ("İ" becomes two code units outside
10292
+ * Turkish), and the highlights slice the original text.
10293
+ */
10294
+ function lowerWithOffsets(text, locale) {
10295
+ let lower = "";
10296
+ const starts = [];
10297
+ const ends = [];
10298
+ let index = 0;
10299
+ for (const character of text) {
10300
+ const lowered = character.toLocaleLowerCase(locale);
10301
+ for (let unit = 0; unit < lowered.length; unit++) {
10302
+ starts.push(index);
10303
+ ends.push(index + character.length);
10304
+ }
10305
+ lower += lowered;
10306
+ index += character.length;
10307
+ }
10308
+ return { lower, starts, ends };
10309
+ }
10310
+ /**
10311
+ * Case-insensitive, non-overlapping matches of `query` in the runs, in run order, with the casing rules of
10312
+ * `locale` (default: the browser's, so "istanbul" finds "İSTANBUL" in Turkish). A match does not span two runs.
10313
+ */
10314
+ function findInRuns(runs, query, locale) {
10315
+ const needle = query.trim().toLocaleLowerCase(locale);
10316
+ if (needle === "")
10317
+ return [];
10318
+ const matches = [];
10319
+ for (const run of runs) {
10320
+ const { lower, starts, ends } = lowerWithOffsets(run.text, locale);
10321
+ let from = 0;
10322
+ for (;;) {
10323
+ const at = lower.indexOf(needle, from);
10324
+ if (at < 0)
10325
+ break;
10326
+ const start = starts[at];
10327
+ matches.push({ key: run.key, start, length: ends[at + needle.length - 1] - start });
10328
+ from = at + needle.length;
10329
+ }
10330
+ }
10331
+ return matches;
10332
+ }
10333
+ /** Find over the visible text of one page. */
10334
+ function findInPage(page, query, flipped) {
10335
+ return findInRuns(collectPageText(page, flipped), query);
10336
+ }
10337
+ /**
10338
+ * The active match index: -1 without matches; the stored index clamped into the matches when it belongs to the
10339
+ * current page and query (a stored -1 from an empty search becomes 0 once a drilldown reveals matches); else 0.
10340
+ */
10341
+ function activeMatchIndex(storedIndex, storedForCurrentSearch, count) {
10342
+ if (count <= 0)
10343
+ return -1;
10344
+ return storedForCurrentSearch ? Math.min(Math.max(0, storedIndex), count - 1) : 0;
10345
+ }
10346
+ /** The next match index after `current`, cycling; -1 when there are no matches. */
10347
+ function nextMatchIndex(current, count) {
10348
+ if (count <= 0)
10349
+ return -1;
10350
+ return current < 0 ? 0 : (current + 1) % count;
10351
+ }
10352
+
10353
+ /** CSS pixels per point: 96 px per inch, 72 pt per inch. */
10354
+ const PX_PER_PT = 96 / 72;
10355
+ /** Converts points to CSS pixels at a zoom factor (1 = 100%). */
10356
+ function ptToPx(pt, zoom = 1) {
10357
+ return pt * PX_PER_PT * zoom;
10358
+ }
10359
+ const POINTS_PER_UNIT = {
10360
+ pt: 1,
10361
+ px: 72 / 96,
10362
+ in: 72,
10363
+ cm: 72 / 2.54,
10364
+ mm: 72 / 25.4,
10365
+ pc: 12
10366
+ };
10367
+ // Linear: one digit run either side of the point, so a long non-matching value cannot backtrack quadratically.
10368
+ const SIZE_PATTERN = /^\s*(-?(?:\d+(?:\.\d*)?|\.\d+))\s*(pt|px|in|cm|mm|pc)?\s*$/i;
10369
+ /** No real RDL size comes near this; longer report-supplied strings are rejected before matching. */
10370
+ const MAX_SIZE_LENGTH = 32;
10371
+ /** Parses an RDL size ("10pt", "2.5mm", "1in", ...) into points; a bare number is points. Null when unparsable. */
10372
+ function parseRdlSize(value) {
10373
+ if (!value || value.length > MAX_SIZE_LENGTH)
10374
+ return null;
10375
+ const match = SIZE_PATTERN.exec(value);
10376
+ if (!match)
10377
+ return null;
10378
+ const unit = (match[2] ?? "pt").toLowerCase();
10379
+ return parseFloat(match[1]) * POINTS_PER_UNIT[unit];
10380
+ }
10381
+ /** An RDL size as CSS pixels at a zoom factor, or undefined when the size is missing or unparsable. */
10382
+ function rdlSizeToPx(value, zoom) {
10383
+ const pt = parseRdlSize(value);
10384
+ return pt === null ? undefined : ptToPx(pt, zoom);
10385
+ }
10386
+
10387
+ /** The zoom steps of the toolbar, 50% to 200%. */
10388
+ const REPORT_ZOOM_STEPS = [0.5, 0.75, 1, 1.25, 1.5, 2];
10389
+ const MIN_ZOOM = 0.1;
10390
+ const MAX_ZOOM = 4;
10391
+ /** Default margins of a standalone CwReportPage: a quarter inch, so content never touches the paper edge. */
10392
+ const DEFAULT_PAGE_MARGIN_PT = 18;
10393
+ /**
10394
+ * Margins of the sheet in the viewer: none. Like the old ReportViewer, the screen shows the content
10395
+ * (header, body, footer) without the RDL page margins; PDF and print come from the server with them.
10396
+ */
10397
+ const SCREEN_PAGE_MARGINS = { top: 0, right: 0, bottom: 0, left: 0 };
10398
+ /** Width of the page content in points: the page's own `Width` (body plus items reaching past it) when the server sends it, else the body width. */
10399
+ function pageContentWidthPt(page, bodyWidth) {
10400
+ return page.Width && Number.isFinite(page.Width) && page.Width > 0 ? Math.max(page.Width, bodyWidth) : bodyWidth;
10401
+ }
10402
+ /** Size of the drawn sheet in points: margins + header + body + footer, as wide as the content so every item lies on it. */
10403
+ function pageSheetSizePt(page, bodyWidth, margins) {
10404
+ return {
10405
+ width: margins.left + pageContentWidthPt(page, bodyWidth) + margins.right,
10406
+ height: margins.top + (page.Header?.Height ?? 0) + page.Height + (page.Footer?.Height ?? 0) + margins.bottom
10407
+ };
10408
+ }
10409
+ /**
10410
+ * The zoom factor to draw with. "pageWidth" fits the sheet width into the available width,
10411
+ * "wholePage" fits the whole sheet; available sizes are CSS pixels. Clamped to 10%..400%.
10412
+ */
10413
+ function resolveZoomFactor(zoom, sheetPt, available) {
10414
+ if (typeof zoom === "number")
10415
+ return clamp(zoom);
10416
+ const widthPx = ptToPx(sheetPt.width);
10417
+ const heightPx = ptToPx(sheetPt.height);
10418
+ if (widthPx <= 0 || available.width <= 0)
10419
+ return 1;
10420
+ const byWidth = available.width / widthPx;
10421
+ if (zoom === "pageWidth" || heightPx <= 0 || available.height <= 0)
10422
+ return clamp(byWidth);
10423
+ return clamp(Math.min(byWidth, available.height / heightPx));
10424
+ }
10425
+ function clamp(value) {
10426
+ return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, value));
10427
+ }
10428
+
10429
+ /*
10430
+ * Maps the RDL style vocabulary to CSS. Everything here is report CONTENT: colors, fonts and borders
10431
+ * come from the report definition and are applied as given, not from the design system.
10432
+ */
10433
+ const RDL_DEFAULT_FONT_FAMILY = "Arial";
10434
+ const RDL_DEFAULT_FONT_SIZE = "10pt";
10435
+ const RDL_DEFAULT_COLOR = "black";
10436
+ const FONT_WEIGHTS = {
10437
+ thin: 100,
10438
+ extralight: 200,
10439
+ light: 300,
10440
+ normal: 400,
10441
+ medium: 500,
10442
+ semibold: 600,
10443
+ bold: 700,
10444
+ extrabold: 800,
10445
+ heavy: 900
10446
+ };
10447
+ const BORDER_STYLES = {
10448
+ solid: "solid",
10449
+ dotted: "dotted",
10450
+ dashed: "dashed",
10451
+ double: "double",
10452
+ none: "none"
10453
+ };
10454
+ /** An RDL color as CSS: "Transparent" = transparent, names and #RRGGBB pass through, empty = undefined. */
10455
+ function rdlColor(value) {
10456
+ if (!value)
10457
+ return undefined;
10458
+ const trimmed = value.trim();
10459
+ if (trimmed === "")
10460
+ return undefined;
10461
+ return trimmed.toLowerCase() === "transparent" ? "transparent" : trimmed;
10462
+ }
10463
+ /** Thin..Heavy to 100..900; unknown values fall back to normal. */
10464
+ function rdlFontWeight(value) {
10465
+ if (!value)
10466
+ return 400;
10467
+ return FONT_WEIGHTS[value.toLowerCase()] ?? (/^\d{3}$/.test(value) ? parseInt(value, 10) : 400);
10468
+ }
10469
+ /** A border side as a CSS shorthand; Style None or missing = none. Width defaults to 1pt, color to black. */
10470
+ function rdlBorder(border, zoom) {
10471
+ if (!border)
10472
+ return undefined;
10473
+ const style = BORDER_STYLES[(border.Style ?? "none").toLowerCase()] ?? "solid";
10474
+ if (style === "none")
10475
+ return "none";
10476
+ const widthPt = parseRdlSize(border.Width) ?? 1;
10477
+ const widthPx = Math.max(1, ptToPx(widthPt, zoom));
10478
+ return `${widthPx}px ${style} ${rdlColor(border.Color) ?? RDL_DEFAULT_COLOR}`;
10479
+ }
10480
+ /**
10481
+ * The four borders of an item box as the custom properties its border overlay draws
10482
+ * (`--rdl-border-top` ... in cw-report-page.module.css). Like the report server, borders sit on
10483
+ * the box edge and take no space from the content, so text laid out by the server to just fit
10484
+ * still fits. Always all four sides, "none" when unset: custom properties inherit, and a nested
10485
+ * item must not draw its container's borders.
10486
+ */
10487
+ function rdlBorderVars(style, zoom) {
10488
+ return {
10489
+ "--rdl-border-top": rdlBorder(style?.BorderTop, zoom) ?? "none",
10490
+ "--rdl-border-right": rdlBorder(style?.BorderRight, zoom) ?? "none",
10491
+ "--rdl-border-bottom": rdlBorder(style?.BorderBottom, zoom) ?? "none",
10492
+ "--rdl-border-left": rdlBorder(style?.BorderLeft, zoom) ?? "none"
10493
+ };
10494
+ }
10495
+ /** Background, borders (as overlay custom properties, see `rdlBorderVars`) and padding of an item box. */
10496
+ function rdlBoxStyle(style, zoom) {
10497
+ if (!style)
10498
+ return rdlBorderVars(null, zoom);
10499
+ return {
10500
+ ...rdlBorderVars(style, zoom),
10501
+ backgroundColor: rdlColor(style.BackgroundColor),
10502
+ paddingTop: rdlSizeToPx(style.PaddingTop, zoom),
10503
+ paddingRight: rdlSizeToPx(style.PaddingRight, zoom),
10504
+ paddingBottom: rdlSizeToPx(style.PaddingBottom, zoom),
10505
+ paddingLeft: rdlSizeToPx(style.PaddingLeft, zoom)
10506
+ };
10507
+ }
10508
+ function pick(key, styles) {
10509
+ for (const style of styles) {
10510
+ const value = style?.[key];
10511
+ if (value)
10512
+ return value;
10513
+ }
10514
+ return null;
10515
+ }
10516
+ function resolveRdlTextStyle(run, paragraph, textbox) {
10517
+ const chain = [run, paragraph, textbox];
10518
+ return {
10519
+ color: pick("Color", chain) ?? RDL_DEFAULT_COLOR,
10520
+ fontFamily: pick("FontFamily", chain) ?? RDL_DEFAULT_FONT_FAMILY,
10521
+ fontSize: pick("FontSize", chain) ?? RDL_DEFAULT_FONT_SIZE,
10522
+ fontStyle: pick("FontStyle", chain),
10523
+ fontWeight: pick("FontWeight", chain),
10524
+ textDecoration: pick("TextDecoration", chain),
10525
+ lineHeight: pick("LineHeight", chain)
10526
+ };
10527
+ }
10528
+ /**
10529
+ * The text style of a paragraph element. Its font sets the strut every line box gets, so it takes
10530
+ * the font of its runs (they usually share one; when they differ, the first run's): a paragraph
10531
+ * left at the textbox default (Arial 10pt) around Segoe UI 8pt runs would make every line taller
10532
+ * than the server measured and the text would overflow its box. An RDL LineHeight on the paragraph
10533
+ * or textbox still wins; otherwise the run's LineHeight, if any, applies.
10534
+ */
10535
+ function resolveParagraphTextStyle(runStyles, paragraph, textbox) {
10536
+ const own = resolveRdlTextStyle(null, paragraph, textbox);
10537
+ if (runStyles.length === 0)
10538
+ return own;
10539
+ const run = resolveRdlTextStyle(runStyles[0], paragraph, textbox);
10540
+ return {
10541
+ ...own,
10542
+ fontFamily: run.fontFamily,
10543
+ fontSize: run.fontSize,
10544
+ fontStyle: run.fontStyle,
10545
+ fontWeight: run.fontWeight,
10546
+ lineHeight: own.lineHeight ?? run.lineHeight
10547
+ };
10548
+ }
10549
+ function textDecoration(value) {
10550
+ switch ((value ?? "").toLowerCase()) {
10551
+ case "underline": return "underline";
10552
+ case "linethrough": return "line-through";
10553
+ case "overline": return "overline";
10554
+ default: return undefined;
10555
+ }
10556
+ }
10557
+ /** An RDL LineHeight in pixels, else "normal"; an unparsable value also falls back to normal. */
10558
+ function rdlLineHeight(value, zoom) {
10559
+ const px = rdlSizeToPx(value, zoom);
10560
+ return px === undefined ? "normal" : `${px}px`;
10561
+ }
10562
+ /**
10563
+ * CSS of a resolved text style at a zoom factor. Without an RDL LineHeight the line height is the
10564
+ * font's natural one ("normal"), the spacing the server measures text with; set inline so no app
10565
+ * or base rule on p / span (125%, 1.15) can shrink the line box and clip large glyphs.
10566
+ */
10567
+ function rdlTextCss(text, zoom) {
10568
+ return {
10569
+ // Transparent text is invisible, as in Reporting Services (reports use it to hide values).
10570
+ color: rdlColor(text.color),
10571
+ fontFamily: text.fontFamily,
10572
+ fontSize: rdlSizeToPx(text.fontSize, zoom) ?? ptToPx(10, zoom),
10573
+ fontStyle: (text.fontStyle ?? "").toLowerCase() === "italic" ? "italic" : undefined,
10574
+ fontWeight: text.fontWeight ? rdlFontWeight(text.fontWeight) : undefined,
10575
+ textDecoration: textDecoration(text.textDecoration),
10576
+ lineHeight: rdlLineHeight(text.lineHeight, zoom)
10577
+ };
10578
+ }
10579
+ /** TextAlign Left/Center/Right/General (General = left). */
10580
+ function rdlTextAlign(value) {
10581
+ switch ((value ?? "").toLowerCase()) {
10582
+ case "center": return "center";
10583
+ case "right": return "right";
10584
+ case "justify": return "justify";
10585
+ default: return "left";
10586
+ }
10587
+ }
10588
+ /**
10589
+ * VerticalAlign Top/Middle/Bottom as the justify-content of a column flex box. "safe": when the
10590
+ * text is taller than its box it falls back to the top, so the first line is never cut off.
10591
+ */
10592
+ function rdlVerticalAlign(value) {
10593
+ switch ((value ?? "").toLowerCase()) {
10594
+ case "middle": return "safe center";
10595
+ case "bottom": return "safe flex-end";
10596
+ default: return "flex-start";
10597
+ }
10598
+ }
10599
+ /** The stroke of a line item: BorderTop, else BorderLeft, default 1pt solid black. */
10600
+ function rdlLineStroke(style, zoom) {
10601
+ const border = style?.BorderTop ?? style?.BorderLeft ?? null;
10602
+ const width = Math.max(1, ptToPx(parseRdlSize(border?.Width) ?? 1, zoom));
10603
+ const kind = (border?.Style ?? "solid").toLowerCase();
10604
+ const color = rdlColor(border?.Color) ?? RDL_DEFAULT_COLOR;
10605
+ if (kind === "none")
10606
+ return { color: "transparent", width };
10607
+ if (kind === "dotted")
10608
+ return { color, width, dash: `${width} ${width * 2}` };
10609
+ if (kind === "dashed")
10610
+ return { color, width, dash: `${width * 4} ${width * 2}` };
10611
+ return { color, width };
10612
+ }
10613
+
10614
+ /*
10615
+ * Pure chart math for the report charts. The hex values below are the report's chart palettes:
10616
+ * content colors (like the colors a report carries), not UI chrome, so no design tokens.
10617
+ */
10618
+ /**
10619
+ * The Microsoft chart palettes by name, with the exact colors of the old ReportViewer engine.
10620
+ * The engine's semi-transparent palettes are #AARRGGBB; here they are CSS #RRGGBBAA.
10621
+ */
10622
+ const PALETTES = {
10623
+ Default: [
10624
+ "#008000", "#0000FF", "#800080", "#00FF00", "#FF00FF", "#008080", "#FFFF00", "#808080",
10625
+ "#00FFFF", "#000080", "#800000", "#FF0000", "#808000", "#C0C0C0", "#FF6347", "#FFE4B5"
10626
+ ],
10627
+ Grayscale: [
10628
+ "#C8C8C8", "#BDBDBD", "#B2B2B2", "#A7A7A7", "#9C9C9C", "#919191", "#868686", "#7B7B7B",
10629
+ "#707070", "#656565", "#5A5A5A", "#4F4F4F", "#444444", "#393939", "#2E2E2E", "#232323"
10630
+ ],
10631
+ Excel: [
10632
+ "#9999FF", "#993366", "#FFFFCC", "#CCFFFF", "#660066", "#FF8080", "#0066CC", "#CCCCFF",
10633
+ "#000080", "#FF00FF", "#FFFF00", "#00FFFF", "#800080", "#800000", "#008080", "#0000FF"
10634
+ ],
10635
+ Light: ["#E6E6FA", "#FFF0F5", "#FFDAB9", "#FFFACD", "#FFE4E1", "#F0FFF0", "#F0F8FF", "#F5F5F5", "#FAEBD7", "#E0FFFF"],
10636
+ Pastel: [
10637
+ "#87CEEB", "#32CD32", "#BA55D3", "#F08080", "#4682B4", "#9ACD32", "#40E0D0", "#FF69B4",
10638
+ "#F0E68C", "#D2B48C", "#8FBC8B", "#6495ED", "#DDA0DD", "#5F9EA0", "#FFDAB9", "#FFA07A"
10639
+ ],
10640
+ EarthTones: [
10641
+ "#FF8000", "#B8860B", "#C04000", "#6B8E23", "#CD853F", "#C0C000", "#228B22", "#D2691E",
10642
+ "#808000", "#20B2AA", "#F4A460", "#00C000", "#8FBC8B", "#B22222", "#8B4513", "#C00000"
10643
+ ],
10644
+ SemiTransparent: [
10645
+ "#FF000096", "#00FF0096", "#0000FF96", "#FFFF0096", "#00FFFF96", "#FF00FF96", "#AA781496", "#FF000050",
10646
+ "#00FF0050", "#0000FF50", "#FFFF0050", "#00FFFF50", "#FF00FF50", "#AA781450", "#64783296", "#285A9696"
10647
+ ],
10648
+ Berry: ["#8A2BE2", "#BA55D3", "#4169E1", "#C71585", "#0000FF", "#8A2BE2", "#DA70D6", "#7B68EE", "#C000C0", "#0000CD", "#800080"],
10649
+ Chocolate: ["#A0522D", "#D2691E", "#8B0000", "#CD853F", "#A52A2A", "#F4A460", "#8B4513", "#C04000", "#B22222", "#B65C3A"],
10650
+ Fire: ["#FFD700", "#FF0000", "#FF1493", "#DC143C", "#FF8C00", "#FF00FF", "#FFFF00", "#FF4500", "#C71585", "#DDE221"],
10651
+ SeaGreen: ["#2E8B57", "#66CDAA", "#4682B4", "#008B8B", "#5F9EA0", "#3CB371", "#48D1CC", "#B0C4DE", "#8FBC8B", "#87CEEB"],
10652
+ BrightPastel: [
10653
+ "#418CF0", "#FCB441", "#E0400A", "#056492", "#BFBFBF", "#1A3B69", "#FFE382", "#129CDD",
10654
+ "#CA6B4B", "#005CDB", "#F3D288", "#506381", "#F1B9A8", "#E0830A", "#7893BE"
10655
+ ],
10656
+ Pacific: [
10657
+ "#01B8AA", "#374649", "#FD625E", "#F2C80F", "#5F6B6D", "#8AD4EB", "#FE9666", "#A66999", "#3599B8", "#DFBFBF",
10658
+ "#4AC5BB", "#5F6B6D", "#FB8281", "#F4D25A", "#7F898A", "#A4DDEE", "#FDAB89", "#B687AC", "#28738A", "#A78F8F"
10659
+ ],
10660
+ PacificLight: ["#4AC5BB", "#5F6B6D", "#FB8281", "#F4D25A", "#7F898A", "#A4DDEE", "#FDAB89", "#B687AC", "#28738A", "#A78F8F"],
10661
+ PacificSemiTransparent: [
10662
+ "#01B8AA99", "#37464999", "#FD625E99", "#F2C80F99", "#5F6B6D99", "#8AD4EB99", "#FE966699", "#A6699999", "#3599B899", "#DFBFBF99",
10663
+ "#4AC5BB99", "#5F6B6D99", "#FB828199", "#F4D25A99", "#7F898A99", "#A4DDEE99", "#FDAB8999", "#B687AC99", "#28738A99", "#A78F8F99"
10664
+ ]
10665
+ };
10666
+ const PALETTES_BY_NAME = new Map(Object.entries(PALETTES).map(([name, colors]) => [name.toLowerCase(), colors]));
10667
+ /** The palette for an RDL palette name (any case); a missing or unknown name is "Default", the RDL default. */
10668
+ function chartPalette(name) {
10669
+ return PALETTES_BY_NAME.get((name ?? "").trim().toLowerCase()) ?? PALETTES.Default;
10670
+ }
10671
+ /** The color of series `index`: its own color, else the palette entry. */
10672
+ function seriesColor(series, index, palette) {
10673
+ return series.Color && series.Color.toLowerCase() !== "automatic" ? series.Color : palette[index % palette.length];
10674
+ }
10675
+ /** Steps of a value axis: about five, rounded to 1, 2, 5 or 10 times a power of ten. */
10676
+ const VALUE_AXIS_STEPS = 5;
10677
+ /** Drops the binary noise of step multiples (0.6000000000000001 -> 0.6). */
10678
+ function tidy$1(value) {
10679
+ return Number(value.toPrecision(12));
10680
+ }
10681
+ /**
10682
+ * bound / step, snapped to the nearest integer only when it is within a few ulps of it: 0.07 / 0.01 is
10683
+ * 7.000000000000001 in binary floating point and would otherwise add an axis step. Genuine non-multiples
10684
+ * (0.37 / 0.05) keep their fraction so the bounds still round outwards.
10685
+ */
10686
+ function axisQuotient(bound, step) {
10687
+ const quotient = bound / step;
10688
+ const nearest = Math.round(quotient);
10689
+ const reconstructed = nearest * step;
10690
+ const tolerance = Number.EPSILON * 4 * Math.max(1, Math.abs(bound), Math.abs(reconstructed));
10691
+ return Math.abs(reconstructed - bound) <= tolerance ? nearest : quotient;
10692
+ }
10693
+ /** The nice step for a value range (> 0): range / 5 rounded to 1, 2, 5 or 10 times its magnitude. */
10694
+ function niceAxisStep(range) {
10695
+ const raw = range / VALUE_AXIS_STEPS;
10696
+ const magnitude = Math.pow(10, Math.floor(Math.log10(raw)));
10697
+ const residual = raw / magnitude;
10698
+ const nice = residual < 1.5 ? 1 : residual < 3.5 ? 2 : residual < 7.5 ? 5 : 10;
10699
+ return tidy$1(nice * magnitude);
10700
+ }
10701
+ /**
10702
+ * A value axis over the given values, the same rule as the server's PDF: the range always includes
10703
+ * 0, nulls are ignored, the step is `niceAxisStep(range)` and the bounds are rounded out to whole
10704
+ * steps (data max 113 gives 0..120 in steps of 20). All-null or all-zero data gives 0..1.
10705
+ */
10706
+ function computeValueScale(values) {
10707
+ let min = 0;
10708
+ let max = 0;
10709
+ for (const value of values) {
10710
+ if (value === null || value === undefined || !Number.isFinite(value))
10711
+ continue;
10712
+ if (value < min)
10713
+ min = value;
10714
+ if (value > max)
10715
+ max = value;
10716
+ }
10717
+ if (min === max)
10718
+ max = min + 1;
10719
+ const step = niceAxisStep(max - min);
10720
+ const first = Math.floor(axisQuotient(min, step));
10721
+ const last = Math.ceil(axisQuotient(max, step));
10722
+ const ticks = [];
10723
+ for (let index = first; index <= last; index++)
10724
+ ticks.push(tidy$1(index * step));
10725
+ return { min: tidy$1(first * step), max: tidy$1(last * step), ticks };
10726
+ }
10727
+ /**
10728
+ * The server's category axis labels (`RdlRenderChart.CategoryAxisLabels`) along an axis that starts
10729
+ * at `start` with `band` pixels per category: position 0 is the first category's point (the middle
10730
+ * of its band), fractions fall between two categories. Labels outside the categories are dropped.
10731
+ */
10732
+ function categoryAxisLabels(labels, categoryCount, start, band) {
10733
+ return labels
10734
+ .filter(label => Number.isFinite(label.Position) && label.Position >= -0.5 && label.Position <= categoryCount - 0.5)
10735
+ .map(label => ({ at: start + band * (label.Position + 0.5), text: label.Text }));
10736
+ }
10737
+ /**
10738
+ * Centers a label of `width` on `center`, moved inside [min, max] when it would cross an end: a
10739
+ * category label never runs past the value axis (and its origin label) or the plot's right edge.
10740
+ */
10741
+ function placeAxisLabel(center, width, min, max) {
10742
+ if (center - width / 2 < min)
10743
+ return { x: min, anchor: "start" };
10744
+ if (center + width / 2 > max)
10745
+ return { x: max, anchor: "end" };
10746
+ return { x: center, anchor: "middle" };
10747
+ }
10748
+ /** Maps a value of the scale to a pixel coordinate between `from` (scale min) and `to` (scale max). */
10749
+ function scaleValue(value, scale, from, to) {
10750
+ const span = scale.max - scale.min;
10751
+ if (span === 0)
10752
+ return from;
10753
+ return from + ((value - scale.min) / span) * (to - from);
10754
+ }
10755
+ /** Splits a series into runs of consecutive non-null points: a null value leaves a gap in the line. */
10756
+ function lineSegments(values, x, y) {
10757
+ const segments = [];
10758
+ let current = [];
10759
+ values.forEach((value, index) => {
10760
+ if (value === null || value === undefined || !Number.isFinite(value)) {
10761
+ if (current.length > 0)
10762
+ segments.push(current);
10763
+ current = [];
10764
+ return;
10765
+ }
10766
+ current.push({ index, value, x: x(index), y: y(value) });
10767
+ });
10768
+ if (current.length > 0)
10769
+ segments.push(current);
10770
+ return segments;
10771
+ }
10772
+ /** SVG path of one segment: straight, stepped (horizontal then vertical) or smooth (Catmull-Rom as cubic Beziers). */
10773
+ function segmentPath(points, subtype) {
10774
+ if (points.length === 0)
10775
+ return "";
10776
+ const kind = (subtype ?? "").toLowerCase();
10777
+ let path = `M${points[0].x},${points[0].y}`;
10778
+ for (let i = 1; i < points.length; i++) {
10779
+ const prev = points[i - 1];
10780
+ const point = points[i];
10781
+ if (kind === "stepped") {
10782
+ path += ` H${point.x} V${point.y}`;
10783
+ }
10784
+ else if (kind === "smooth") {
10785
+ const before = points[i - 2] ?? prev;
10786
+ const after = points[i + 1] ?? point;
10787
+ const c1x = prev.x + (point.x - before.x) / 6;
10788
+ const c1y = prev.y + (point.y - before.y) / 6;
10789
+ const c2x = point.x - (after.x - prev.x) / 6;
10790
+ const c2y = point.y - (after.y - prev.y) / 6;
10791
+ path += ` C${c1x},${c1y} ${c2x},${c2y} ${point.x},${point.y}`;
10792
+ }
10793
+ else {
10794
+ path += ` L${point.x},${point.y}`;
10795
+ }
10796
+ }
10797
+ return path;
10798
+ }
10799
+ /** Pie slices of positive values (null, zero and negative values get no slice); angles in radians from 12 o'clock, clockwise. */
10800
+ function pieSlices(values) {
10801
+ const total = values.reduce((acc, value) => acc + (value !== null && value > 0 ? value : 0), 0);
10802
+ if (total <= 0)
10803
+ return [];
10804
+ const slices = [];
10805
+ let angle = 0;
10806
+ values.forEach((value, index) => {
10807
+ if (value === null || value <= 0)
10808
+ return;
10809
+ const fraction = value / total;
10810
+ const end = angle + fraction * Math.PI * 2;
10811
+ slices.push({ index, value, fraction, startAngle: angle, endAngle: end });
10812
+ angle = end;
10813
+ });
10814
+ return slices;
10815
+ }
10816
+ /** A point on a circle; angle in radians from 12 o'clock, clockwise. */
10817
+ function polar(cx, cy, radius, angle) {
10818
+ return { x: cx + radius * Math.sin(angle), y: cy - radius * Math.cos(angle) };
10819
+ }
10820
+ /** SVG path of an arc band (or a pie wedge when innerRadius is 0) between two angles. */
10821
+ function arcPath(cx, cy, outerRadius, innerRadius, start, end) {
10822
+ const sweep = end - start;
10823
+ if (sweep >= Math.PI * 2 - 1e-9) {
10824
+ const mid = start + Math.PI;
10825
+ return arcPath(cx, cy, outerRadius, innerRadius, start, mid) + " " + arcPath(cx, cy, outerRadius, innerRadius, mid, end);
10826
+ }
10827
+ const large = sweep > Math.PI ? 1 : 0;
10828
+ const o1 = polar(cx, cy, outerRadius, start);
10829
+ const o2 = polar(cx, cy, outerRadius, end);
10830
+ if (innerRadius <= 0) {
10831
+ return `M${cx},${cy} L${o1.x},${o1.y} A${outerRadius},${outerRadius} 0 ${large} 1 ${o2.x},${o2.y} Z`;
10832
+ }
10833
+ const i2 = polar(cx, cy, innerRadius, end);
10834
+ const i1 = polar(cx, cy, innerRadius, start);
10835
+ return `M${o1.x},${o1.y} A${outerRadius},${outerRadius} 0 ${large} 1 ${o2.x},${o2.y} L${i2.x},${i2.y} A${innerRadius},${innerRadius} 0 ${large} 0 ${i1.x},${i1.y} Z`;
10836
+ }
10837
+ /** Clamps a gauge value into the scale; null stays at the minimum. */
10838
+ function clampGaugeValue(value, minimum, maximum) {
10839
+ if (value === null || value === undefined || !Number.isFinite(value))
10840
+ return minimum;
10841
+ const low = Math.min(minimum, maximum);
10842
+ const high = Math.max(minimum, maximum);
10843
+ return Math.min(high, Math.max(low, value));
10844
+ }
10845
+ /** Formats an axis or data value compactly: integers without decimals, else up to 2 decimals. */
10846
+ function formatChartValue(value) {
10847
+ if (Number.isInteger(value))
10848
+ return value.toString();
10849
+ return (Math.round(value * 100) / 100).toString();
10850
+ }
10851
+
10852
+ /** More ticks than this on one scale is a broken interval, not a scale anyone can read. */
10853
+ const MAX_GAUGE_TICKS = 200;
10854
+ /**
10855
+ * The ellipse a state indicator fills: its percent box of the panel, stretched to an oval in a box
10856
+ * that is not square, like the old viewer. Null when the active state has no color or the box is empty.
10857
+ */
10858
+ function stateIndicatorEllipse(indicator, panelWidth, panelHeight) {
10859
+ if (!indicator.Color)
10860
+ return null;
10861
+ const width = (Math.max(0, indicator.Width) / 100) * panelWidth;
10862
+ const height = (Math.max(0, indicator.Height) / 100) * panelHeight;
10863
+ if (width <= 0 || height <= 0)
10864
+ return null;
10865
+ const left = (indicator.Left / 100) * panelWidth;
10866
+ const top = (indicator.Top / 100) * panelHeight;
10867
+ return { cx: left + width / 2, cy: top + height / 2, rx: width / 2, ry: height / 2 };
10868
+ }
10869
+ /** The value span a Bar pointer covers: from the scale minimum to the value clamped into the scale. */
10870
+ function gaugeBarSpan(value, minimum, maximum) {
10871
+ return { from: minimum, to: clampGaugeValue(value, minimum, maximum) };
10872
+ }
10873
+ function tidy(value) {
10874
+ return Number(value.toPrecision(12));
10875
+ }
10876
+ /**
10877
+ * The major tick values of a gauge scale: every `interval` from the minimum up to the maximum (the
10878
+ * server computes it); without a usable interval the chart axis' nice step of the range is used.
10879
+ */
10880
+ function gaugeTicks(minimum, maximum, interval) {
10881
+ const low = Math.min(minimum, maximum);
10882
+ const high = Math.max(minimum, maximum);
10883
+ if (!Number.isFinite(low) || !Number.isFinite(high))
10884
+ return [];
10885
+ if (high === low)
10886
+ return [tidy(low)];
10887
+ const step = interval !== null && interval !== undefined && Number.isFinite(interval) && interval > 0
10888
+ ? interval
10889
+ : niceAxisStep(high - low);
10890
+ const count = Math.floor(tidy((high - low) / step));
10891
+ if (count > MAX_GAUGE_TICKS)
10892
+ return [tidy(low), tidy(high)];
10893
+ const ticks = [];
10894
+ for (let index = 0; index <= count; index++)
10895
+ ticks.push(tidy(low + index * step));
10896
+ return ticks;
10897
+ }
10898
+ /**
10899
+ * A thickness given in percent of the gauge's own size (for a horizontal linear gauge its height, as
10900
+ * the chart engine measures range and pointer widths), or the default fraction when it is missing.
10901
+ */
10902
+ function gaugeThickness(percent, gaugeSize, defaultFraction) {
10903
+ const fraction = percent !== null && percent !== undefined && Number.isFinite(percent) && percent > 0 ? percent / 100 : defaultFraction;
10904
+ return gaugeSize * Math.min(1, fraction);
10905
+ }
10906
+ /** Cross (or none) is centred on the scale line, Inside lies above it, Outside below it. */
10907
+ function gaugeBandExtent(placement, thickness) {
10908
+ switch ((placement ?? "").toLowerCase()) {
10909
+ case "inside": return { up: thickness, down: 0 };
10910
+ case "outside": return { up: 0, down: thickness };
10911
+ default: return { up: thickness / 2, down: thickness / 2 };
10912
+ }
10913
+ }
10914
+ /**
10915
+ * The y of the scale line of a horizontal linear gauge `height` tall: the bands (ranges and pointers)
10916
+ * and the tick labels below them (`labelSpace`) are centred as one block.
10917
+ */
10918
+ function linearGaugeScaleY(height, bands, labelSpace) {
10919
+ const up = Math.max(0, ...bands.map(band => band.up));
10920
+ const down = Math.max(0, ...bands.map(band => band.down));
10921
+ return Math.max(up, (height - (up + down + labelSpace)) / 2 + up);
10922
+ }
10923
+
10924
+ /** The order an "Auto" marker takes per series, as the chart engine cycles it. */
10925
+ const AUTO_SHAPES = ["square", "circle", "diamond", "triangle", "cross", "star4", "star5", "star6", "star10"];
10926
+ const SHAPES = {
10927
+ square: "square",
10928
+ circle: "circle",
10929
+ diamond: "diamond",
10930
+ triangle: "triangle",
10931
+ cross: "cross",
10932
+ star4: "star4",
10933
+ star5: "star5",
10934
+ star6: "star6",
10935
+ star10: "star10"
10936
+ };
10937
+ /** The marker size when the series sets none, as the server uses it. */
10938
+ const RDL_DEFAULT_MARKER_SIZE_PT = 5;
10939
+ /**
10940
+ * The marker a series draws, or null for none. The server resolves Auto to a shape, so a missing type
10941
+ * or None means no marker. Should an Auto (or an unknown name) still arrive, a scatter series cycles
10942
+ * the shapes per series, so its points stay visible; a line series then draws none.
10943
+ */
10944
+ function seriesMarker(markerType, scatter, seriesIndex) {
10945
+ if (!markerType)
10946
+ return null;
10947
+ const name = markerType.trim().toLowerCase();
10948
+ if (name === "none" || name === "")
10949
+ return null;
10950
+ const shape = SHAPES[name];
10951
+ if (shape)
10952
+ return shape;
10953
+ return scatter ? AUTO_SHAPES[seriesIndex % AUTO_SHAPES.length] : null;
10954
+ }
10955
+ /** The marker size in pixels at a zoom (RDL size, default 5pt), at least 3 px so it stays visible. */
10956
+ function markerSizePx(markerSize, zoom) {
10957
+ return Math.max(3, ptToPx(parseRdlSize(markerSize) ?? RDL_DEFAULT_MARKER_SIZE_PT, zoom));
10958
+ }
10959
+ function round(value) {
10960
+ return Math.round(value * 100) / 100;
10961
+ }
10962
+ function polygon(points) {
10963
+ return `M${points.map(([x, y]) => `${round(x)},${round(y)}`).join(" L")} Z`;
10964
+ }
10965
+ function star(cx, cy, outer, points) {
10966
+ const inner = outer * (points <= 4 ? 0.35 : 0.45);
10967
+ const corners = [];
10968
+ for (let index = 0; index < points * 2; index++) {
10969
+ const radius = index % 2 === 0 ? outer : inner;
10970
+ const angle = -Math.PI / 2 + (index * Math.PI) / points;
10971
+ corners.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
10972
+ }
10973
+ return polygon(corners);
10974
+ }
10975
+ /** SVG path of a marker of `size` (its width; an X has arms of that length along its diagonals) centered on (cx, cy); every shape is filled. */
10976
+ function markerPath(shape, cx, cy, size) {
10977
+ const r = size / 2;
10978
+ switch (shape) {
10979
+ case "square":
10980
+ return polygon([[cx - r, cy - r], [cx + r, cy - r], [cx + r, cy + r], [cx - r, cy + r]]);
10981
+ case "circle":
10982
+ return `M${round(cx - r)},${round(cy)} A${round(r)},${round(r)} 0 1 0 ${round(cx + r)},${round(cy)} A${round(r)},${round(r)} 0 1 0 ${round(cx - r)},${round(cy)} Z`;
10983
+ case "diamond":
10984
+ return polygon([[cx, cy - r], [cx + r, cy], [cx, cy + r], [cx - r, cy]]);
10985
+ case "triangle":
10986
+ return polygon([[cx, cy - r], [cx + r, cy + r], [cx - r, cy + r]]);
10987
+ case "cross": {
10988
+ // The chart engine's Cross is an X: a filled plus sign, its arms a third of the size thick, turned by 45 degrees.
10989
+ const t = size / 6;
10990
+ const plus = [
10991
+ [-t, -r], [t, -r], [t, -t], [r, -t], [r, t], [t, t],
10992
+ [t, r], [-t, r], [-t, t], [-r, t], [-r, -t], [-t, -t]
10993
+ ];
10994
+ const turn = Math.SQRT1_2;
10995
+ return polygon(plus.map(([dx, dy]) => [cx + (dx - dy) * turn, cy + (dx + dy) * turn]));
10996
+ }
10997
+ case "star4": return star(cx, cy, r, 4);
10998
+ case "star5": return star(cx, cy, r, 5);
10999
+ case "star6": return star(cx, cy, r, 6);
11000
+ case "star10": return star(cx, cy, r, 10);
11001
+ }
11002
+ }
11003
+ const ALIGN = {
11004
+ left: "start",
11005
+ top: "start",
11006
+ center: "center",
11007
+ right: "end",
11008
+ bottom: "end"
11009
+ };
11010
+ /** The RDL default legend position: a column on the right, vertically centered (RightCenter). */
11011
+ const DEFAULT_LEGEND = { edge: "right", align: "center" };
11012
+ /**
11013
+ * The RDL ChartLegend Position as an edge and an alignment: the first word is the edge, the second
11014
+ * the alignment along it (TopLeft = top edge, left aligned; LeftTop = left edge, top aligned).
11015
+ * Missing or unknown = RightCenter, the RDL default.
11016
+ */
11017
+ function legendPlacement(position) {
11018
+ const match = /^(top|bottom|left|right)(left|right|top|bottom|center)$/i.exec((position ?? "").trim());
11019
+ if (!match)
11020
+ return DEFAULT_LEGEND;
11021
+ const edge = match[1].toLowerCase();
11022
+ const along = match[2].toLowerCase();
11023
+ const horizontalEdge = edge === "top" || edge === "bottom";
11024
+ // "TopTop" or "LeftLeft" make no sense: the alignment must run along the edge.
11025
+ const valid = horizontalEdge ? ["left", "center", "right"].includes(along) : ["top", "center", "bottom"].includes(along);
11026
+ return { edge, align: valid ? ALIGN[along] : "center" };
11027
+ }
11028
+
11029
+ var styles$2 = {"chart":"cw-report-chart-module__chart__HEwvf","title":"cw-report-chart-module__title__zvCfx","axis":"cw-report-chart-module__axis__qwHaL","grid":"cw-report-chart-module__grid__xJMG8","tick":"cw-report-chart-module__tick__uQJeQ","muted":"cw-report-chart-module__muted__Nj1-j","hit":"cw-report-chart-module__hit__-u6vf","point":"cw-report-chart-module__point__M-GuI","slice":"cw-report-chart-module__slice__DEbOB","track":"cw-report-chart-module__track__NAVBX","needle":"cw-report-chart-module__needle__m5fJK","cap":"cw-report-chart-module__cap__zL7KT"};
11030
+
11031
+ /** Chart text size in points (scaled with the zoom). */
11032
+ const CHART_FONT_PT = 8;
11033
+ /** Rough width of one character of the chart font, as a share of the font size. */
11034
+ const CHAR_WIDTH = 0.6;
11035
+ function chartFontPx(zoom) {
11036
+ return ptToPx(CHART_FONT_PT, zoom);
11037
+ }
11038
+ function estimateTextWidth(text, fontPx) {
11039
+ return text.length * fontPx * CHAR_WIDTH;
11040
+ }
11041
+ /** Hover handlers that show the shared CwTooltipManager tooltip over an SVG element. */
11042
+ function useChartTooltip() {
11043
+ useEffect(() => {
11044
+ ensureTooltipManager();
11045
+ }, []);
11046
+ const show = useCallback((content) => (event) => {
11047
+ showTooltip(content, event.currentTarget, "top");
11048
+ }, []);
11049
+ const hide = useCallback(() => hideTooltip(), []);
11050
+ return { show, hide };
11051
+ }
11052
+ function tooltipContent(title, label, value) {
11053
+ return (jsxs("span", { children: [jsx("strong", { children: title }), jsx("br", {}), label, ": ", value] }));
11054
+ }
11055
+ /** Lays legend entries out in rows that wrap at `width`, each row aligned within `width` (centered by default). */
11056
+ function layoutLegend(entries, width, fontPx, align = "center") {
11057
+ if (entries.length === 0)
11058
+ return { height: 0, width: 0, items: [] };
11059
+ const swatch = fontPx;
11060
+ const gap = fontPx;
11061
+ const lineHeight = fontPx * 1.6;
11062
+ const rows = [[]];
11063
+ let rowWidth = 0;
11064
+ for (const entry of entries) {
11065
+ const itemWidth = swatch + fontPx * 0.4 + estimateTextWidth(entry.label, fontPx);
11066
+ if (rowWidth > 0 && rowWidth + gap + itemWidth > width) {
11067
+ rows.push([]);
11068
+ rowWidth = 0;
11069
+ }
11070
+ rowWidth += (rowWidth > 0 ? gap : 0) + itemWidth;
11071
+ rows[rows.length - 1].push({ entry, width: itemWidth });
11072
+ }
11073
+ const items = [];
11074
+ let widest = 0;
11075
+ rows.forEach((row, rowIndex) => {
11076
+ const total = row.reduce((acc, item) => acc + item.width, 0) + gap * (row.length - 1);
11077
+ widest = Math.max(widest, total);
11078
+ const free = Math.max(0, width - total);
11079
+ let x = align === "start" ? 0 : align === "end" ? free : free / 2;
11080
+ for (const item of row) {
11081
+ items.push({ entry: item.entry, x, y: rowIndex * lineHeight + lineHeight / 2 });
11082
+ x += item.width + gap;
11083
+ }
11084
+ });
11085
+ return { height: rows.length * lineHeight, width: widest, items };
11086
+ }
11087
+ function ChartLegend({ layout, top, left = 0, fontPx }) {
11088
+ return (jsx("g", { transform: `translate(${left}, ${top})`, children: layout.items.map((item, index) => (jsxs("g", { transform: `translate(${item.x}, ${item.y})`, children: [item.entry.marker
11089
+ ? jsx("path", { d: markerPath(item.entry.marker, fontPx / 2, 0, fontPx), fill: item.entry.color })
11090
+ : jsx("rect", { x: 0, y: -fontPx / 2, width: fontPx, height: fontPx, fill: item.entry.color }), jsx("text", { x: fontPx * 1.4, dominantBaseline: "central", fontSize: fontPx, children: item.entry.label })] }, index))) }));
11091
+ }
11092
+ /** The chart titles, one line each, centered. Returns the height they take. */
11093
+ function ChartTitles({ titles, width, fontPx }) {
11094
+ return (jsx(Fragment, { children: titles.map((title, index) => (jsx("text", { className: styles$2.title, x: width / 2, y: fontPx * 1.5 * (index + 1), textAnchor: "middle", fontSize: fontPx * 1.25, children: title }, index))) }));
11095
+ }
11096
+ function titlesHeight(titles, fontPx) {
11097
+ return titles.length === 0 ? 0 : fontPx * 1.5 * titles.length + fontPx * 0.5;
11098
+ }
11099
+ /** A centered message instead of the plot (dataset error or no rows). */
11100
+ function ChartMessage({ text, width, height, fontPx }) {
11101
+ return (jsx("text", { className: styles$2.muted, x: width / 2, y: height / 2, textAnchor: "middle", dominantBaseline: "central", fontSize: fontPx * 1.2, children: text }));
11102
+ }
11103
+
11104
+ /** 270 degree dial: from 7:30 to 4:30 on a clock face, in radians from 12 o'clock. */
11105
+ const DIAL_START = -Math.PI * 0.75;
11106
+ const DIAL_END = Math.PI * 0.75;
11107
+ /** Report content defaults, as the old viewer drew them: black pointers, the Default palette for ranges. */
11108
+ const POINTER_FALLBACK = "black";
11109
+ const RANGE_PALETTE = chartPalette(null);
11110
+ /** Thickness of a range / pointer without a Width, as a fraction of the gauge height (the chart engine defaults). */
11111
+ const RANGE_DEFAULT_WIDTH = 0.3;
11112
+ const POINTER_DEFAULT_WIDTH = 0.1;
11113
+ const EMPTY_SCALE = { Minimum: 0, Maximum: 100, Pointers: [], Ranges: [] };
11114
+ function isBarPointer(type) {
11115
+ return (type ?? "").toLowerCase() === "bar";
11116
+ }
11117
+ function rangeColor(range, index) {
11118
+ return range.Color || RANGE_PALETTE[index % RANGE_PALETTE.length];
11119
+ }
11120
+ function pointerColor(pointer) {
11121
+ return pointer.Color || POINTER_FALLBACK;
11122
+ }
11123
+ function RadialGauge({ gauge, width, height, fontPx, zoom }) {
11124
+ const scale = gauge.Scales[0] ?? EMPTY_SCALE;
11125
+ const { Minimum: min, Maximum: max } = scale;
11126
+ const radius = Math.max(0, Math.min(width / 2, height / 1.75) - fontPx * 0.5);
11127
+ const cx = width / 2;
11128
+ const cy = fontPx * 0.5 + radius;
11129
+ const band = radius * 0.15;
11130
+ const angle = (value) => scaleValue(clampGaugeValue(value, min, max), { min, max }, DIAL_START, DIAL_END);
11131
+ const minLabel = polar(cx, cy, radius - band * 2.5, DIAL_START);
11132
+ const maxLabel = polar(cx, cy, radius - band * 2.5, DIAL_END);
11133
+ const showLabels = scale.ShowLabels !== false;
11134
+ return (jsxs("g", { children: [jsx("path", { className: styles$2.track, d: arcPath(cx, cy, radius, radius - band, DIAL_START, DIAL_END) }), scale.Ranges.map((range, index) => (jsx("path", { d: arcPath(cx, cy, radius, radius - band, angle(range.Start ?? min), angle(range.End ?? max)), fill: rangeColor(range, index) }, `r${index}`))), scale.Pointers.map((pointer, index) => {
11135
+ if (isBarPointer(pointer.Type)) {
11136
+ const span = gaugeBarSpan(pointer.Value, min, max);
11137
+ return (jsx("path", { d: arcPath(cx, cy, radius - band * 1.2, radius - band * 1.9, angle(span.from), angle(span.to)), fill: pointerColor(pointer) }, `p${index}`));
11138
+ }
11139
+ const tip = polar(cx, cy, radius * 0.8, angle(pointer.Value ?? min));
11140
+ return (jsx("line", { className: styles$2.needle, x1: cx, y1: cy, x2: tip.x, y2: tip.y, style: pointer.Color ? { stroke: pointer.Color } : undefined, strokeWidth: Math.max(1.5, 2.5 * zoom) }, `p${index}`));
11141
+ }), jsx("circle", { className: styles$2.cap, cx: cx, cy: cy, r: Math.max(2, radius * 0.06) }), showLabels && (jsxs(Fragment, { children: [jsx("text", { className: styles$2.tick, x: minLabel.x, y: minLabel.y, textAnchor: "middle", fontSize: fontPx, children: formatChartValue(min) }), jsx("text", { className: styles$2.tick, x: maxLabel.x, y: maxLabel.y, textAnchor: "middle", fontSize: fontPx, children: formatChartValue(max) })] }))] }));
11142
+ }
11143
+ /**
11144
+ * A horizontal linear gauge as the chart engine draws it: range bands and pointers are as thick as
11145
+ * their Width percent of the gauge height (ranges 30%, pointers 10% by default) around the scale line
11146
+ * (Cross centred, Inside above, Outside below), the ranges in their own colour at full opacity, a Bar
11147
+ * pointer on top of them from the minimum to the value, and the major ticks with labels below.
11148
+ */
11149
+ function LinearGauge({ gauge, width, height, fontPx }) {
11150
+ const scale = gauge.Scales[0] ?? EMPTY_SCALE;
11151
+ const { Minimum: min, Maximum: max } = scale;
11152
+ const showLabels = scale.ShowLabels !== false;
11153
+ const left = fontPx;
11154
+ const right = width - fontPx;
11155
+ const labelSpace = showLabels ? fontPx * 2 : 0;
11156
+ const x = (value) => scaleValue(clampGaugeValue(value, min, max), { min, max }, left, right);
11157
+ const ticks = showLabels ? gaugeTicks(min, max, scale.Interval) : [];
11158
+ const ranges = scale.Ranges.map(range => {
11159
+ const thickness = gaugeThickness(range.Width, height, RANGE_DEFAULT_WIDTH);
11160
+ return { range, thickness, extent: gaugeBandExtent(range.Placement, thickness) };
11161
+ });
11162
+ const pointers = scale.Pointers.map(pointer => {
11163
+ const thickness = gaugeThickness(pointer.Width, height, POINTER_DEFAULT_WIDTH);
11164
+ return { pointer, thickness, extent: gaugeBandExtent(pointer.Placement, thickness) };
11165
+ });
11166
+ const extents = [...ranges, ...pointers].map(band => band.extent);
11167
+ const scaleY = linearGaugeScaleY(height, extents, labelSpace);
11168
+ const bandsBottom = scaleY + Math.max(0, ...extents.map(extent => extent.down));
11169
+ return (jsxs("g", { children: [ranges.map(({ range, thickness, extent }, index) => {
11170
+ const from = x(range.Start ?? min);
11171
+ const to = x(range.End ?? max);
11172
+ return (jsx("rect", { x: Math.min(from, to), y: scaleY - extent.up, width: Math.abs(to - from), height: thickness, fill: rangeColor(range, index) }, `r${index}`));
11173
+ }), jsx("line", { className: styles$2.axis, x1: left, x2: right, y1: scaleY, y2: scaleY }), pointers.map(({ pointer, thickness, extent }, index) => {
11174
+ if (isBarPointer(pointer.Type)) {
11175
+ const span = gaugeBarSpan(pointer.Value, min, max);
11176
+ const from = x(span.from);
11177
+ const to = x(span.to);
11178
+ return (jsx("rect", { x: Math.min(from, to), y: scaleY - extent.up, width: Math.abs(to - from), height: thickness, fill: pointerColor(pointer) }, `p${index}`));
11179
+ }
11180
+ // A marker: a triangle pointing at the scale line from below.
11181
+ const at = x(pointer.Value ?? min);
11182
+ const size = Math.max(thickness, fontPx * 0.6);
11183
+ return (jsx("path", { d: `M${at},${scaleY} l${-size / 2},${size} h${size} Z`, fill: pointerColor(pointer) }, `p${index}`));
11184
+ }), ticks.map(tick => (jsxs("g", { children: [jsx("line", { className: styles$2.axis, x1: x(tick), x2: x(tick), y1: bandsBottom, y2: bandsBottom + fontPx * 0.4 }), jsx("text", { className: styles$2.tick, x: x(tick), y: bandsBottom + fontPx * 1.5, textAnchor: "middle", fontSize: fontPx, children: formatChartValue(tick) })] }, tick)))] }));
11185
+ }
11186
+ /**
11187
+ * A gauge panel: its gauges side by side (RadialGauge = 270 degree dial with colored ranges and a
11188
+ * needle or bar per pointer, LinearGauge = horizontal track with range bands, a bar or marker per
11189
+ * pointer and the major ticks), the state indicators at their percent boxes and the panel labels
11190
+ * below. The pointer value is not printed; only the report's own labels are. Only the first scale of
11191
+ * a gauge is drawn.
11192
+ */
11193
+ function CwReportGauge({ panel, width, height, zoom = 1 }) {
11194
+ const fontPx = chartFontPx(zoom);
11195
+ const lineHeight = fontPx * 1.5;
11196
+ const labelsHeight = panel.Labels.length * lineHeight;
11197
+ const gaugeHeight = Math.max(0, height - labelsHeight);
11198
+ const cellWidth = panel.Gauges.length > 0 ? width / panel.Gauges.length : width;
11199
+ return (jsxs("svg", { className: styles$2.chart, width: width, height: height, role: "img", "aria-label": panel.Name, children: [panel.Error ? (jsx(ChartMessage, { text: panel.Error, width: width, height: height, fontPx: fontPx })) : (jsxs(Fragment, { children: [panel.Gauges.map((gauge, index) => {
11200
+ const drawProps = { gauge, width: cellWidth, height: gaugeHeight, fontPx, zoom };
11201
+ return (jsx("g", { transform: `translate(${cellWidth * index}, 0)`, children: gauge.Kind.toLowerCase() === "lineargauge" ? jsx(LinearGauge, { ...drawProps }) : jsx(RadialGauge, { ...drawProps }) }, index));
11202
+ }), (panel.StateIndicators ?? []).map((indicator, index) => {
11203
+ const ellipse = stateIndicatorEllipse(indicator, width, height);
11204
+ return ellipse && jsx("ellipse", { ...ellipse, fill: indicator.Color ?? undefined }, `s${index}`);
11205
+ })] })), panel.Labels.map((label, index) => (jsx("text", { x: width / 2, y: gaugeHeight + lineHeight * (index + 0.7), textAnchor: "middle", fontSize: fontPx, children: label }, index)))] }));
11206
+ }
11207
+
11208
+ /*
11209
+ * The .NET numeric format strings a report puts on a chart's value axis (<Format>), applied with the
11210
+ * report culture so the screen shows the same tick text as the server's PDF. Only the formats reports
11211
+ * actually use are covered; anything else returns null and the caller keeps its own formatting.
11212
+ */
11213
+ /** .NET's default decimals of the N, F and P standard formats without a precision. */
11214
+ const STANDARD_DEFAULT_DECIMALS = 2;
11215
+ const STANDARD_FORMAT = /^([NnFfPp])(\d{1,2})?$/;
11216
+ /** 0, 0.00, 0.0#, #,##0, #,0.00, 0%, 0.0% ... (integer part of 0, # and one optional grouping comma). */
11217
+ const CUSTOM_FORMAT = /^(#*,?#*0+)(?:\.(0*)(#*))?(%?)$/;
11218
+ /**
11219
+ * Formats longer than this are not matched (the custom pattern backtracks quadratically on a long
11220
+ * non-matching string), and more decimals than this are left to the caller: Intl.NumberFormat throws
11221
+ * above 100 fraction digits (above 20 on older browsers), which would break the chart render.
11222
+ */
11223
+ const MAX_FORMAT_LENGTH = 64;
11224
+ const MAX_FRACTION_DIGITS = 20;
11225
+ function parseFormat(format) {
11226
+ if (format.length > MAX_FORMAT_LENGTH)
11227
+ return null;
11228
+ const standard = STANDARD_FORMAT.exec(format);
11229
+ if (standard) {
11230
+ const kind = standard[1].toUpperCase();
11231
+ const digits = standard[2] === undefined ? STANDARD_DEFAULT_DECIMALS : parseInt(standard[2], 10);
11232
+ return {
11233
+ minimumFractionDigits: digits,
11234
+ maximumFractionDigits: digits,
11235
+ grouping: kind !== "F",
11236
+ percent: kind === "P" ? "standard" : null
11237
+ };
11238
+ }
11239
+ const custom = CUSTOM_FORMAT.exec(format);
11240
+ if (custom) {
11241
+ const required = custom[2]?.length ?? 0;
11242
+ const optional = custom[3]?.length ?? 0;
11243
+ return {
11244
+ minimumFractionDigits: required,
11245
+ maximumFractionDigits: required + optional,
11246
+ grouping: custom[1].includes(","),
11247
+ percent: custom[4] === "%" ? "custom" : null
11248
+ };
11249
+ }
11250
+ return null;
11251
+ }
11252
+ function numberFormat(locale, options) {
11253
+ try {
11254
+ return new Intl.NumberFormat(locale || "en-US", options);
11255
+ }
11256
+ catch {
11257
+ return new Intl.NumberFormat("en-US", options);
11258
+ }
11259
+ }
11260
+ /**
11261
+ * A value in a .NET numeric format ("N0", "F1", "P0", "0", "0.0", "#,##0.00", "0%", ...) and a culture
11262
+ * ("de-CH"; missing or unknown = invariant-like en-US). Null for a missing or unsupported format.
11263
+ * The standard "P" uses the culture's percent pattern (e.g. "12 %" in de-DE); a custom "%" appends the
11264
+ * sign directly, as .NET does.
11265
+ */
11266
+ function formatRdlNumber(value, format, culture) {
11267
+ if (!format || !Number.isFinite(value))
11268
+ return null;
11269
+ const spec = parseFormat(format.trim());
11270
+ if (!spec || spec.maximumFractionDigits > MAX_FRACTION_DIGITS)
11271
+ return null;
11272
+ const digits = {
11273
+ minimumFractionDigits: spec.minimumFractionDigits,
11274
+ maximumFractionDigits: spec.maximumFractionDigits,
11275
+ useGrouping: spec.grouping
11276
+ };
11277
+ const locale = culture ?? undefined;
11278
+ if (spec.percent === "standard")
11279
+ return numberFormat(locale, { ...digits, style: "percent" }).format(value);
11280
+ if (spec.percent === "custom") {
11281
+ // The percent style scales by 100 without float noise (0.145 -> 14.5, not 14.499...); its own
11282
+ // sign and spacing are dropped for the plain "%" a custom format appends.
11283
+ const parts = numberFormat(locale, { ...digits, style: "percent" }).formatToParts(value);
11284
+ return `${parts.filter(part => part.type !== "percentSign" && part.type !== "literal").map(part => part.value).join("")}%`;
11285
+ }
11286
+ return numberFormat(locale, digits).format(value);
11287
+ }
11288
+
11289
+ function seriesKind(series) {
11290
+ switch (series.Type.toLowerCase()) {
11291
+ case "column": return "column";
11292
+ case "bar": return "bar";
11293
+ case "area": return "area";
11294
+ case "scatter": return "scatter";
11295
+ default: return "line";
11296
+ }
11297
+ }
11298
+ function truncate(text, maxWidth, fontPx) {
11299
+ if (estimateTextWidth(text, fontPx) <= maxWidth)
11300
+ return text;
11301
+ const chars = Math.max(1, Math.floor(maxWidth / (fontPx * 0.6)) - 1);
11302
+ return text.slice(0, chars) + "…";
11303
+ }
11304
+ /** Categories along the x axis, values up: lines, areas, columns and scatter points. */
11305
+ function VerticalPlot({ chart, colors, scale, fontPx, left, top, right, bottom, strokeWidth, zoom, tickLabel }) {
11306
+ const tooltip = useChartTooltip();
11307
+ const count = Math.max(1, chart.Categories.length);
11308
+ const band = (right - left) / count;
11309
+ const x = (index) => left + band * (index + 0.5);
11310
+ const y = (value) => scaleValue(value, scale, bottom, top);
11311
+ const baseline = y(Math.min(scale.max, Math.max(scale.min, 0)));
11312
+ const columns = chart.Series.map((series, index) => ({ series, index })).filter(({ series }) => {
11313
+ const kind = seriesKind(series);
11314
+ return kind === "column" || kind === "bar";
11315
+ });
11316
+ const groupWidth = band * 0.75;
11317
+ const columnWidth = columns.length > 0 ? groupWidth / columns.length : 0;
11318
+ const labelWidth = Math.max(...chart.Categories.map(label => estimateTextWidth(label, fontPx)), 0) + fontPx;
11319
+ const labelStep = Math.max(1, Math.ceil(Math.min(labelWidth, fontPx * 12) / band));
11320
+ const marks = [];
11321
+ const hits = [];
11322
+ columns.forEach(({ series, index }, columnIndex) => {
11323
+ series.Values.forEach((value, category) => {
11324
+ if (value === null || !Number.isFinite(value))
11325
+ return;
11326
+ const columnX = left + band * category + (band - groupWidth) / 2 + columnWidth * columnIndex;
11327
+ const valueY = y(value);
11328
+ const content = tooltipContent(series.Name, chart.Categories[category] ?? "", formatChartValue(value));
11329
+ marks.push(jsx("rect", { x: columnX, y: Math.min(valueY, baseline), width: Math.max(1, columnWidth - 1), height: Math.max(0, Math.abs(baseline - valueY)), fill: colors[index], onMouseEnter: tooltip.show(content), onMouseLeave: tooltip.hide }, `c${index}-${category}`));
11330
+ if (series.ShowDataLabels) {
11331
+ marks.push(jsx("text", { x: columnX + columnWidth / 2, y: valueY - fontPx * 0.4, textAnchor: "middle", fontSize: fontPx, children: formatChartValue(value) }, `cl${index}-${category}`));
11332
+ }
11333
+ });
11334
+ });
11335
+ chart.Series.forEach((series, index) => {
11336
+ const kind = seriesKind(series);
11337
+ if (kind !== "line" && kind !== "area" && kind !== "scatter")
11338
+ return;
11339
+ const marker = seriesMarker(series.MarkerType, kind === "scatter", index);
11340
+ const markerSize = markerSizePx(series.MarkerSize, zoom);
11341
+ const segments = lineSegments(series.Values, x, y);
11342
+ segments.forEach((segment, segmentIndex) => {
11343
+ if (kind !== "scatter")
11344
+ drawLine(segment, segmentIndex);
11345
+ for (const point of segment) {
11346
+ if (marker) {
11347
+ marks.push(jsx("path", { d: markerPath(marker, point.x, point.y, markerSize), fill: colors[index] }, `m${index}-${point.index}`));
11348
+ }
11349
+ if (series.ShowDataLabels) {
11350
+ marks.push(jsx("text", { x: point.x, y: point.y - Math.max(fontPx * 0.6, markerSize), textAnchor: "middle", fontSize: fontPx, children: formatChartValue(point.value) }, `ll${index}-${point.index}`));
11351
+ }
11352
+ const content = tooltipContent(series.Name, chart.Categories[point.index] ?? "", formatChartValue(point.value));
11353
+ hits.push(jsx("circle", { className: styles$2.hit, cx: point.x, cy: point.y, r: Math.max(4, Math.min(8, band / 3), markerSize / 2), onMouseEnter: tooltip.show(content), onMouseLeave: tooltip.hide }, `h${index}-${point.index}`));
11354
+ }
11355
+ });
11356
+ function drawLine(segment, segmentIndex) {
11357
+ const path = segmentPath(segment, series.Subtype);
11358
+ if (kind === "area") {
11359
+ const first = segment[0];
11360
+ const last = segment[segment.length - 1];
11361
+ marks.push(jsx("path", { d: `${path} L${last.x},${baseline} L${first.x},${baseline} Z`, fill: colors[index], fillOpacity: 0.45, stroke: "none" }, `a${index}-${segmentIndex}`));
11362
+ }
11363
+ marks.push(jsx("path", { d: path, fill: "none", stroke: colors[index], strokeWidth: strokeWidth }, `l${index}-${segmentIndex}`));
11364
+ // A lone point between gaps has no line to show it: a dot, unless the series draws markers.
11365
+ if (segment.length === 1 && !marker) {
11366
+ marks.push(jsx("circle", { className: styles$2.point, cx: segment[0].x, cy: segment[0].y, r: strokeWidth * 1.5, fill: colors[index] }, `p${index}-${segmentIndex}`));
11367
+ }
11368
+ }
11369
+ });
11370
+ const serverLabels = chart.CategoryAxisLabels ? categoryAxisLabels(chart.CategoryAxisLabels, count, left, band) : null;
11371
+ // Category gridlines run through the labelled categories: the server's labels, else every labelStep-th category.
11372
+ const categoryGrid = chart.CategoryAxisGridLines === false
11373
+ ? []
11374
+ : serverLabels?.map(label => label.at) ?? chart.Categories.map((_label, index) => index).filter(index => index % labelStep === 0).map(x);
11375
+ return (jsxs(Fragment, { children: [categoryGrid.map((at, index) => jsx("line", { className: styles$2.grid, x1: at, x2: at, y1: top, y2: bottom }, `cg${index}`)), scale.ticks.map(tick => (jsxs("g", { children: [chart.ValueAxisGridLines !== false && jsx("line", { className: styles$2.grid, x1: left, x2: right, y1: y(tick), y2: y(tick) }), jsx("text", { className: styles$2.tick, x: left - fontPx * 0.4, y: y(tick), textAnchor: "end", dominantBaseline: "central", fontSize: fontPx, children: tickLabel(tick) })] }, tick))), jsx("line", { className: styles$2.axis, x1: left, x2: left, y1: top, y2: bottom }), jsx("line", { className: styles$2.axis, x1: left, x2: right, y1: baseline, y2: baseline }), serverLabels
11376
+ ? serverLabels.map((label, index) => {
11377
+ const placement = placeAxisLabel(label.at, estimateTextWidth(label.text, fontPx), left, right);
11378
+ return (jsxs("g", { children: [jsx("line", { className: styles$2.axis, x1: label.at, x2: label.at, y1: bottom, y2: bottom + fontPx * 0.3 }), jsx("text", { className: styles$2.tick, x: placement.x, y: bottom + fontPx * 1.3, textAnchor: placement.anchor, fontSize: fontPx, children: label.text })] }, `c${index}`));
11379
+ })
11380
+ : chart.Categories.map((label, index) => {
11381
+ if (index % labelStep !== 0)
11382
+ return null;
11383
+ const text = truncate(label, band * labelStep - fontPx * 0.4, fontPx);
11384
+ const placement = placeAxisLabel(x(index), estimateTextWidth(text, fontPx), left, right);
11385
+ return (jsx("text", { className: styles$2.tick, x: placement.x, y: bottom + fontPx * 1.1, textAnchor: placement.anchor, fontSize: fontPx, children: text }, index));
11386
+ }), marks, hits] }));
11387
+ }
11388
+ /** Categories down the y axis, values to the right: horizontal bars. */
11389
+ function HorizontalPlot({ chart, colors, scale, fontPx, left, top, right, bottom, tickLabel }) {
11390
+ const tooltip = useChartTooltip();
11391
+ const count = Math.max(1, chart.Categories.length);
11392
+ const band = (bottom - top) / count;
11393
+ const x = (value) => scaleValue(value, scale, left, right);
11394
+ const baseline = x(Math.min(scale.max, Math.max(scale.min, 0)));
11395
+ const groupHeight = band * 0.75;
11396
+ const barHeight = chart.Series.length > 0 ? groupHeight / chart.Series.length : 0;
11397
+ const serverLabels = chart.CategoryAxisLabels ? categoryAxisLabels(chart.CategoryAxisLabels, count, top, band) : null;
11398
+ const categoryGrid = chart.CategoryAxisGridLines === false
11399
+ ? []
11400
+ : serverLabels?.map(label => label.at) ?? chart.Categories.map((_label, index) => top + band * (index + 0.5));
11401
+ return (jsxs(Fragment, { children: [categoryGrid.map((at, index) => jsx("line", { className: styles$2.grid, x1: left, x2: right, y1: at, y2: at }, `cg${index}`)), scale.ticks.map(tick => (jsxs("g", { children: [chart.ValueAxisGridLines !== false && jsx("line", { className: styles$2.grid, x1: x(tick), x2: x(tick), y1: top, y2: bottom }), jsx("text", { className: styles$2.tick, x: x(tick), y: bottom + fontPx * 1.1, textAnchor: "middle", fontSize: fontPx, children: tickLabel(tick) })] }, tick))), jsx("line", { className: styles$2.axis, x1: baseline, x2: baseline, y1: top, y2: bottom }), jsx("line", { className: styles$2.axis, x1: left, x2: right, y1: bottom, y2: bottom }), serverLabels
11402
+ ? serverLabels.map((label, index) => (jsxs("g", { children: [jsx("line", { className: styles$2.axis, x1: left - fontPx * 0.3, x2: left, y1: label.at, y2: label.at }), jsx("text", { className: styles$2.tick, x: left - fontPx * 0.4, y: label.at, textAnchor: "end", dominantBaseline: "central", fontSize: fontPx, children: truncate(label.text, left - fontPx, fontPx) })] }, `c${index}`)))
11403
+ : chart.Categories.map((label, index) => (jsx("text", { className: styles$2.tick, x: left - fontPx * 0.4, y: top + band * (index + 0.5), textAnchor: "end", dominantBaseline: "central", fontSize: fontPx, children: truncate(label, left - fontPx, fontPx) }, index))), chart.Series.map((series, index) => series.Values.map((value, category) => {
11404
+ if (value === null || !Number.isFinite(value))
11405
+ return null;
11406
+ const barY = top + band * category + (band - groupHeight) / 2 + barHeight * index;
11407
+ const valueX = x(value);
11408
+ const content = tooltipContent(series.Name, chart.Categories[category] ?? "", formatChartValue(value));
11409
+ return (jsxs("g", { children: [jsx("rect", { x: Math.min(valueX, baseline), y: barY, width: Math.max(0, Math.abs(valueX - baseline)), height: Math.max(1, barHeight - 1), fill: colors[index], onMouseEnter: tooltip.show(content), onMouseLeave: tooltip.hide }), series.ShowDataLabels && (jsx("text", { x: Math.max(valueX, baseline) + fontPx * 0.3, y: barY + barHeight / 2, dominantBaseline: "central", fontSize: fontPx, children: formatChartValue(value) }))] }, `${index}-${category}`));
11410
+ }))] }));
11411
+ }
11412
+ /**
11413
+ * A report chart over categories: Line (Smooth / Stepped), Area, Column and Scatter series share one
11414
+ * value axis; a chart made only of Bar series is drawn horizontally. Scatter series draw only their
11415
+ * markers, line series draw markers too when the report sets a marker type. Null values leave gaps.
11416
+ * The legend sits where the RDL legend Position says. Own SVG, no chart library; hover shows
11417
+ * category, series and value.
11418
+ */
11419
+ function CwReportLineChart({ chart, width, height, zoom = 1, culture }) {
11420
+ const fontPx = chartFontPx(zoom);
11421
+ const palette = chartPalette(chart.Palette);
11422
+ const colors = chart.Series.map((series, index) => seriesColor(series, index, palette));
11423
+ const titleHeight = titlesHeight(chart.Titles, fontPx);
11424
+ // The legend on the side its RDL Position names: a side legend is a column at most 30% wide.
11425
+ const placement = legendPlacement(chart.LegendPosition);
11426
+ const sideLegend = placement.edge === "left" || placement.edge === "right";
11427
+ const legend = layoutLegend(chart.LegendHidden ? [] : chart.Series.map((series, index) => ({
11428
+ label: series.Name,
11429
+ color: colors[index],
11430
+ marker: seriesMarker(series.MarkerType, seriesKind(series) === "scatter", index)
11431
+ })), sideLegend ? width * 0.3 : width, fontPx, sideLegend ? "start" : placement.align);
11432
+ const legendHeight = legend.height > 0 ? legend.height + fontPx * 0.5 : 0;
11433
+ const legendWidth = legend.width > 0 ? legend.width + fontPx : 0;
11434
+ const legendSpace = {
11435
+ top: placement.edge === "top" ? legendHeight : 0,
11436
+ bottom: placement.edge === "bottom" ? legendHeight : 0,
11437
+ left: placement.edge === "left" ? legendWidth : 0,
11438
+ right: placement.edge === "right" ? legendWidth : 0
11439
+ };
11440
+ const message = chart.Error
11441
+ ?? (chart.Categories.length === 0 || chart.Series.length === 0 ? (chart.NoRowsMessage ?? "No data") : null);
11442
+ if (message) {
11443
+ return (jsxs("svg", { className: styles$2.chart, width: width, height: height, role: "img", "aria-label": chart.Titles.join(" ") || chart.Name, children: [jsx(ChartTitles, { titles: chart.Titles, width: width, fontPx: fontPx }), jsx(ChartMessage, { text: message, width: width, height: height, fontPx: fontPx })] }));
11444
+ }
11445
+ const horizontal = chart.Series.every(series => seriesKind(series) === "bar");
11446
+ const scale = computeValueScale(chart.Series.flatMap(series => series.Values));
11447
+ // The axis <Format> with the report culture, as the server's PDF prints it; an unsupported format keeps the compact default.
11448
+ const tickLabel = (tick) => formatRdlNumber(tick, chart.ValueAxisFormat, culture) ?? formatChartValue(tick);
11449
+ const tickWidth = Math.max(...scale.ticks.map(tick => estimateTextWidth(tickLabel(tick), fontPx)));
11450
+ const categoryWidth = Math.min(width * 0.35, Math.max(...chart.Categories.map(label => estimateTextWidth(label, fontPx)), 0));
11451
+ const lineHeight = fontPx * 1.6;
11452
+ const valueTitleSpace = chart.ValueAxisTitle ? lineHeight : 0;
11453
+ const categoryTitleSpace = chart.CategoryAxisTitle ? lineHeight : 0;
11454
+ const left = legendSpace.left + (horizontal ? categoryTitleSpace + categoryWidth : valueTitleSpace + tickWidth) + fontPx * 0.8;
11455
+ const right = width - fontPx - legendSpace.right;
11456
+ const top = titleHeight + legendSpace.top + fontPx * 0.8;
11457
+ const bottom = height - legendSpace.bottom - lineHeight - (horizontal ? valueTitleSpace : categoryTitleSpace);
11458
+ const strokeWidth = Math.max(1, 1.5 * zoom);
11459
+ const plotProps = { chart, colors, scale, fontPx, left, top, right, bottom, strokeWidth, zoom, tickLabel };
11460
+ const verticalTitle = horizontal ? chart.CategoryAxisTitle : chart.ValueAxisTitle;
11461
+ const horizontalTitle = horizontal ? chart.ValueAxisTitle : chart.CategoryAxisTitle;
11462
+ const titleX = legendSpace.left + fontPx;
11463
+ const legendLeft = placement.edge === "left" ? fontPx * 0.4 : placement.edge === "right" ? width - legendWidth + fontPx * 0.4 : 0;
11464
+ const legendTop = (() => {
11465
+ switch (placement.edge) {
11466
+ case "top": return titleHeight;
11467
+ case "bottom": return height - legend.height;
11468
+ default:
11469
+ if (placement.align === "start")
11470
+ return top;
11471
+ if (placement.align === "end")
11472
+ return Math.max(top, bottom - legend.height);
11473
+ return Math.max(top, (top + bottom - legend.height) / 2);
11474
+ }
11475
+ })();
11476
+ return (jsxs("svg", { className: styles$2.chart, width: width, height: height, role: "img", "aria-label": chart.Titles.join(" ") || chart.Name, children: [jsx(ChartTitles, { titles: chart.Titles, width: width, fontPx: fontPx }), right - left > 10 && bottom - top > 10 && (horizontal ? jsx(HorizontalPlot, { ...plotProps }) : jsx(VerticalPlot, { ...plotProps })), verticalTitle && (jsx("text", { x: titleX, y: (top + bottom) / 2, textAnchor: "middle", dominantBaseline: "central", fontSize: fontPx, transform: `rotate(-90 ${titleX} ${(top + bottom) / 2})`, children: verticalTitle })), horizontalTitle && (jsx("text", { x: (left + right) / 2, y: bottom + lineHeight * 1.6, textAnchor: "middle", fontSize: fontPx, children: horizontalTitle })), jsx(ChartLegend, { layout: legend, top: legendTop, left: legendLeft, fontPx: fontPx })] }));
11477
+ }
11478
+
11479
+ /** A pie of the chart's first series over its categories (RDL series Type "Shape"). Own SVG. */
11480
+ function CwReportPieChart({ chart, width, height, zoom = 1 }) {
11481
+ const tooltip = useChartTooltip();
11482
+ const fontPx = chartFontPx(zoom);
11483
+ const palette = chartPalette(chart.Palette);
11484
+ const series = chart.Series[0];
11485
+ const colorOf = (index) => palette[index % palette.length];
11486
+ const titleHeight = titlesHeight(chart.Titles, fontPx);
11487
+ const legend = layoutLegend(chart.LegendHidden ? [] : chart.Categories.map((label, index) => ({ label, color: colorOf(index) })), width, fontPx);
11488
+ const legendHeight = legend.height > 0 ? legend.height + fontPx * 0.5 : 0;
11489
+ const slices = series ? pieSlices(series.Values) : [];
11490
+ const message = chart.Error ?? (slices.length === 0 ? (chart.NoRowsMessage ?? "No data") : null);
11491
+ const plotTop = titleHeight + fontPx * 0.5;
11492
+ const plotHeight = height - plotTop - legendHeight;
11493
+ const radius = Math.max(0, Math.min(width, plotHeight) / 2 - fontPx * 0.5);
11494
+ const cx = width / 2;
11495
+ const cy = plotTop + plotHeight / 2;
11496
+ return (jsxs("svg", { className: styles$2.chart, width: width, height: height, role: "img", "aria-label": chart.Titles.join(" ") || chart.Name, children: [jsx(ChartTitles, { titles: chart.Titles, width: width, fontPx: fontPx }), message ? (jsx(ChartMessage, { text: message, width: width, height: height, fontPx: fontPx })) : (slices.map(slice => {
11497
+ const category = chart.Categories[slice.index] ?? "";
11498
+ const percent = `${formatChartValue(slice.fraction * 100)}%`;
11499
+ const labelAt = polar(cx, cy, radius * 0.65, (slice.startAngle + slice.endAngle) / 2);
11500
+ return (jsxs("g", { children: [jsx("path", { className: styles$2.slice, d: arcPath(cx, cy, radius, 0, slice.startAngle, slice.endAngle), fill: colorOf(slice.index), onMouseEnter: tooltip.show(tooltipContent(series.Name, category, `${formatChartValue(slice.value)} (${percent})`)), onMouseLeave: tooltip.hide }), series.ShowDataLabels && slice.fraction >= 0.03 && (jsx("text", { x: labelAt.x, y: labelAt.y, textAnchor: "middle", dominantBaseline: "central", fontSize: fontPx, pointerEvents: "none", children: formatChartValue(slice.value) }))] }, slice.index));
11501
+ })), jsx(ChartLegend, { layout: legend, top: height - legend.height, fontPx: fontPx })] }));
11502
+ }
11503
+
11504
+ /** Indent of one list level, in points. */
11505
+ const RDL_LIST_INDENT_PT = 18;
11506
+ const BULLETS = ["•", "◦", "▪"];
11507
+ function listKind(paragraph) {
11508
+ switch ((paragraph.ListStyle ?? "").toLowerCase()) {
11509
+ case "bulleted": return "bulleted";
11510
+ case "numbered": return "numbered";
11511
+ default: return null;
11512
+ }
11513
+ }
11514
+ /**
11515
+ * The list marker of every paragraph (null = no list). Numbering counts consecutive numbered
11516
+ * paragraphs of the same level: a non-list paragraph resets every level, a paragraph at a level
11517
+ * resets the levels below it, and a bulleted paragraph resets the numbering of its own level.
11518
+ */
11519
+ function computeListMarkers(paragraphs) {
11520
+ const counters = [];
11521
+ return paragraphs.map(paragraph => {
11522
+ const kind = listKind(paragraph);
11523
+ if (!kind) {
11524
+ counters.length = 0;
11525
+ return null;
11526
+ }
11527
+ const level = Math.max(1, paragraph.ListLevel);
11528
+ counters.length = Math.min(counters.length, level);
11529
+ if (kind === "bulleted") {
11530
+ counters[level - 1] = 0;
11531
+ return BULLETS[(level - 1) % BULLETS.length];
11532
+ }
11533
+ counters[level - 1] = (counters[level - 1] ?? 0) + 1;
11534
+ return `${counters[level - 1]}.`;
11535
+ });
11536
+ }
11537
+ /** Left indent of a paragraph in points: one list indent per level (a list paragraph has at least level 1). */
11538
+ function paragraphIndentPt(paragraph) {
11539
+ const level = listKind(paragraph) ? Math.max(1, paragraph.ListLevel) : Math.max(0, paragraph.ListLevel);
11540
+ return level * RDL_LIST_INDENT_PT;
11541
+ }
11542
+
11543
+ const EMPTY_FLIPPED = new Set();
11544
+ const EMPTY_HIGHLIGHTS = new Map();
11545
+ const ReportRenderContext = createContext({
11546
+ zoom: 1,
11547
+ flipped: EMPTY_FLIPPED,
11548
+ highlights: EMPTY_HIGHLIGHTS,
11549
+ activeMatchIndex: -1
11550
+ });
11551
+ function useReportRender() {
11552
+ return useContext(ReportRenderContext);
11553
+ }
11554
+ /** Groups the page's matches by run key. */
11555
+ function highlightsByRun(matches) {
11556
+ const map = new Map();
11557
+ matches.forEach((match, matchIndex) => {
11558
+ const list = map.get(match.key) ?? [];
11559
+ list.push({ start: match.start, length: match.length, matchIndex });
11560
+ map.set(match.key, list);
11561
+ });
11562
+ return map;
11563
+ }
11564
+
11565
+ var styles$1 = {"sheet":"cw-report-page-module__sheet__MAL8a","section":"cw-report-page-module__section__rN7A3","item":"cw-report-page-module__item__VZFw8","table":"cw-report-page-module__table__SAZVC","textbox":"cw-report-page-module__textbox__iwVwk cw-report-page-module__item__VZFw8","textRow":"cw-report-page-module__textRow__3WIRX","textBody":"cw-report-page-module__textBody__Jp1-1","paragraph":"cw-report-page-module__paragraph__d6dYI","marker":"cw-report-page-module__marker__geRQt","link":"cw-report-page-module__link__YFX1h","match":"cw-report-page-module__match__sWdSD","inlineButton":"cw-report-page-module__inlineButton__m05OC","rectangle":"cw-report-page-module__rectangle__2PYyK cw-report-page-module__item__VZFw8","line":"cw-report-page-module__line__Vfus-","image":"cw-report-page-module__image__VEp5H cw-report-page-module__item__VZFw8","tableMessage":"cw-report-page-module__tableMessage__kWsAj","chart":"cw-report-page-module__chart__PP9oM cw-report-page-module__item__VZFw8","placeholder":"cw-report-page-module__placeholder__FK8kO cw-report-page-module__item__VZFw8"};
11566
+
11567
+ /** Size of the drilldown / sort icons, in points: a little below the default 10pt text. */
11568
+ const INLINE_ICON_PT = 9;
11569
+ const SAFE_LINK = /^(https?:|mailto:)/i;
11570
+ function highlightedText(text, highlights, activeMatchIndex) {
11571
+ if (!highlights || highlights.length === 0)
11572
+ return text;
11573
+ const parts = [];
11574
+ let cursor = 0;
11575
+ for (const highlight of highlights) {
11576
+ if (highlight.start > cursor)
11577
+ parts.push(text.slice(cursor, highlight.start));
11578
+ const active = highlight.matchIndex === activeMatchIndex;
11579
+ parts.push(jsx("mark", { className: styles$1.match, "data-active": active ? "true" : undefined, "data-active-match": active ? "true" : undefined, children: text.slice(highlight.start, highlight.start + highlight.length) }, highlight.matchIndex));
11580
+ cursor = highlight.start + highlight.length;
11581
+ }
11582
+ if (cursor < text.length)
11583
+ parts.push(text.slice(cursor));
11584
+ return parts;
11585
+ }
11586
+ function ReportRun({ run, runKey, paragraphStyle, textboxStyle }) {
11587
+ const { zoom, highlights, activeMatchIndex } = useReportRender();
11588
+ const css = rdlTextCss(resolveRdlTextStyle(run.Style, paragraphStyle, textboxStyle), zoom);
11589
+ const content = highlightedText(run.Text, highlights.get(runKey), activeMatchIndex);
11590
+ if (run.Href && SAFE_LINK.test(run.Href)) {
11591
+ return (jsx("a", { className: styles$1.link, href: run.Href, target: "_blank", rel: "noopener noreferrer", style: css, children: content }));
11592
+ }
11593
+ return jsx("span", { style: css, children: content });
11594
+ }
11595
+ function iconSizeStyle(zoom) {
11596
+ return { "--btn-size": `${ptToPx(INLINE_ICON_PT, zoom)}px` };
11597
+ }
11598
+ function sortIcon(direction) {
11599
+ switch ((direction ?? "").toLowerCase()) {
11600
+ case "ascending": return "sort-asc";
11601
+ case "descending": return "sort-desc";
11602
+ default: return "sortable";
11603
+ }
11604
+ }
11605
+ /** A textbox: paragraphs as blocks, runs as inline spans, plain text only (never HTML). */
11606
+ function ReportTextbox({ textbox, itemKey, frameStyle }) {
11607
+ const { zoom, flipped, onToggle, onSort } = useReportRender();
11608
+ const markers = computeListMarkers(textbox.Paragraphs);
11609
+ const paragraphs = textbox.Paragraphs.map((paragraph, p) => {
11610
+ const indent = ptToPx(paragraphIndentPt(paragraph), zoom);
11611
+ const marker = markers[p];
11612
+ const firstRun = paragraph.Runs[0];
11613
+ const paragraphCss = {
11614
+ ...rdlTextCss(resolveParagraphTextStyle(paragraph.Runs.map(run => run.Style), paragraph.Style, textbox.Style), zoom),
11615
+ textAlign: rdlTextAlign(paragraph.Style?.TextAlign ?? textbox.Style?.TextAlign),
11616
+ paddingLeft: indent || undefined
11617
+ };
11618
+ return (jsxs("p", { className: styles$1.paragraph, style: paragraphCss, children: [marker !== null && (jsx("span", { className: styles$1.marker, style: {
11619
+ ...rdlTextCss(resolveRdlTextStyle(firstRun?.Style, paragraph.Style, textbox.Style), zoom),
11620
+ left: indent - ptToPx(RDL_LIST_INDENT_PT, zoom),
11621
+ width: ptToPx(RDL_LIST_INDENT_PT, zoom)
11622
+ }, children: marker })), paragraph.Runs.map((run, r) => (jsx(ReportRun, { run: run, runKey: rdlRunKey(itemKey, p, r), paragraphStyle: paragraph.Style, textboxStyle: textbox.Style }, r)))] }, p));
11623
+ });
11624
+ const boxCss = {
11625
+ ...frameStyle,
11626
+ ...rdlBoxStyle(textbox.Style, zoom),
11627
+ color: rdlColor(textbox.Style?.Color),
11628
+ justifyContent: rdlVerticalAlign(textbox.Style?.VerticalAlign)
11629
+ };
11630
+ const toggleId = textbox.ToggleId;
11631
+ const sortId = textbox.SortId;
11632
+ if (!toggleId && !sortId) {
11633
+ return jsx("div", { className: styles$1.textbox, style: boxCss, children: paragraphs });
11634
+ }
11635
+ const expanded = isToggleExpanded(textbox, flipped);
11636
+ return (jsx("div", { className: styles$1.textbox, style: boxCss, children: jsxs("div", { className: styles$1.textRow, children: [toggleId && (jsx(CwButton, { variant: "icon", size: "small", icon: expanded ? "minus" : "plus", className: styles$1.inlineButton, style: iconSizeStyle(zoom), "aria-label": expanded ? "Collapse" : "Expand", "aria-expanded": expanded, "data-toggle-id": toggleId, onClick: () => onToggle?.(toggleId) })), jsx("div", { className: styles$1.textBody, children: paragraphs }), sortId && (jsx(CwButton, { variant: "icon", size: "small", icon: sortIcon(textbox.SortDirection), className: styles$1.inlineButton, style: iconSizeStyle(zoom), "aria-label": "Sort", onClick: () => onSort?.(sortId) }))] }) }));
11637
+ }
11638
+
11639
+ function frameOf(item) {
11640
+ return { top: item.Top, left: item.Left, width: item.Width, height: item.Height };
11641
+ }
11642
+ function frameCss(frame, zoom) {
11643
+ return {
11644
+ top: ptToPx(frame.top, zoom),
11645
+ left: ptToPx(frame.left, zoom),
11646
+ width: ptToPx(frame.width, zoom),
11647
+ height: ptToPx(frame.height, zoom)
11648
+ };
11649
+ }
11650
+ const SAFE_IMAGE_URL = /^https?:/i;
11651
+ function ReportRectangle({ item, itemKey, frame }) {
11652
+ const { zoom } = useReportRender();
11653
+ return (jsx("div", { className: styles$1.rectangle, style: { ...frameCss(frame, zoom), ...rdlBoxStyle(item.Style, zoom) }, children: jsx(ReportItems, { items: item.Items, parentKey: itemKey }) }));
11654
+ }
11655
+ function ReportLine({ item, frame }) {
11656
+ const { zoom } = useReportRender();
11657
+ const stroke = rdlLineStroke(item.Style, zoom);
11658
+ const x1 = ptToPx(frame.left, zoom);
11659
+ const y1 = ptToPx(frame.top, zoom);
11660
+ const x2 = ptToPx(frame.left + frame.width, zoom);
11661
+ const y2 = ptToPx(frame.top + frame.height, zoom);
11662
+ const pad = stroke.width;
11663
+ const left = Math.min(x1, x2) - pad;
11664
+ const top = Math.min(y1, y2) - pad;
11665
+ const width = Math.abs(x2 - x1) + pad * 2;
11666
+ const height = Math.abs(y2 - y1) + pad * 2;
11667
+ return (jsx("svg", { className: styles$1.line, style: { left, top, width, height }, width: width, height: height, "aria-hidden": "true", children: jsx("line", { x1: x1 - left, y1: y1 - top, x2: x2 - left, y2: y2 - top, stroke: stroke.color, strokeWidth: stroke.width, strokeDasharray: stroke.dash }) }));
11668
+ }
11669
+ function imageSizing(sizing) {
11670
+ switch (sizing.toLowerCase()) {
11671
+ case "fit": return "fit";
11672
+ case "fitproportional": return "proportional";
11673
+ default: return "natural";
11674
+ }
11675
+ }
11676
+ function ReportImage({ item, frame }) {
11677
+ const { zoom, getImageUrl } = useReportRender();
11678
+ const src = item.Url && SAFE_IMAGE_URL.test(item.Url)
11679
+ ? item.Url
11680
+ : item.ImageId && getImageUrl ? getImageUrl(item.ImageId) : null;
11681
+ const sizing = imageSizing(item.Sizing);
11682
+ return (jsx("div", { className: styles$1.image, style: { ...frameCss(frame, zoom), ...rdlBoxStyle(item.Style, zoom) }, children: src && (jsx("img", { src: src, alt: item.Name, referrerPolicy: "no-referrer", "data-sizing": sizing, style: sizing === "natural" ? { transform: `scale(${zoom})` } : undefined })) }));
11683
+ }
11684
+ function ReportTable({ item, itemKey, frame }) {
11685
+ const { zoom, flipped } = useReportRender();
11686
+ const message = item.Error ?? (item.Rows.length === 0 ? item.NoRowsMessage : null);
11687
+ if (message) {
11688
+ const textCss = rdlTextCss(resolveRdlTextStyle(null, null, item.Style), zoom);
11689
+ return (jsx("div", { className: styles$1.table, style: { ...frameCss(frame, zoom), height: undefined, ...rdlBoxStyle(item.Style, zoom) }, children: item.Error
11690
+ ? jsx(CwNote, { color: "danger", variant: "soft", fontSize: "small", content: item.Error })
11691
+ : jsx("p", { className: `${styles$1.tableMessage} cw-margin-none`, style: textCss, children: message }) }));
11692
+ }
11693
+ const layout = layoutRdlTable(item, flipped);
11694
+ return (jsx("div", { className: styles$1.table, style: { ...frameCss({ ...frame, width: layout.width, height: layout.height }, zoom), ...rdlBoxStyle(item.Style, zoom) }, children: layout.cells.map(box => {
11695
+ const content = box.cell.Content;
11696
+ if (!content)
11697
+ return null;
11698
+ const cellFrame = { top: box.top, left: box.left, width: box.width, height: box.height };
11699
+ const key = `${box.rowIndex}-${box.cellIndex}`;
11700
+ if (box.hidden) {
11701
+ // Drawn empty: the cell keeps its borders and background so the grid stays closed.
11702
+ return jsx("div", { className: styles$1.item, style: { ...frameCss(cellFrame, zoom), ...rdlBoxStyle(content.Style, zoom) } }, key);
11703
+ }
11704
+ return jsx(ReportItem, { item: content, itemKey: rdlCellKey(itemKey, box.rowIndex, box.cellIndex), frame: cellFrame }, key);
11705
+ }) }));
11706
+ }
11707
+ function ReportChart({ item, frame }) {
11708
+ const { zoom, culture } = useReportRender();
11709
+ const width = ptToPx(frame.width, zoom);
11710
+ const height = ptToPx(frame.height, zoom);
11711
+ const pie = item.Series[0]?.Type.toLowerCase() === "shape";
11712
+ return (jsx("div", { className: styles$1.chart, style: { ...frameCss(frame, zoom), ...rdlBoxStyle(item.Style, zoom) }, children: pie
11713
+ ? jsx(CwReportPieChart, { chart: item, width: width, height: height, zoom: zoom })
11714
+ : jsx(CwReportLineChart, { chart: item, width: width, height: height, zoom: zoom, culture: culture }) }));
11715
+ }
11716
+ function ReportGauge({ item, frame }) {
11717
+ const { zoom } = useReportRender();
11718
+ return (jsx("div", { className: styles$1.chart, style: { ...frameCss(frame, zoom), ...rdlBoxStyle(item.Style, zoom) }, children: jsx(CwReportGauge, { panel: item, width: ptToPx(frame.width, zoom), height: ptToPx(frame.height, zoom), zoom: zoom }) }));
11719
+ }
11720
+ function ReportPlaceholder({ item, frame }) {
11721
+ const { zoom } = useReportRender();
11722
+ return (jsx(CwTooltipNew, { content: `${item.Element}: ${item.Reason}`, position: "top", children: jsx("div", { className: styles$1.placeholder, style: frameCss(frame, zoom), "aria-label": `${item.Element}: ${item.Reason}`, children: item.Element }) }));
11723
+ }
11724
+ /** One render-tree item, absolutely positioned in its container; nothing when its toggles hide it. */
11725
+ function ReportItem({ item, itemKey, frame }) {
11726
+ const { zoom, flipped } = useReportRender();
11727
+ if (!isRdlVisible(item.Toggles, flipped))
11728
+ return null;
11729
+ const box = frame ?? frameOf(item);
11730
+ switch (item.Kind) {
11731
+ case "textbox": return jsx(ReportTextbox, { textbox: item, itemKey: itemKey, frameStyle: frameCss(box, zoom) });
11732
+ case "rectangle": return jsx(ReportRectangle, { item: item, itemKey: itemKey, frame: box });
11733
+ case "line": return jsx(ReportLine, { item: item, frame: box });
11734
+ case "image": return jsx(ReportImage, { item: item, frame: box });
11735
+ case "table": return jsx(ReportTable, { item: item, itemKey: itemKey, frame: box });
11736
+ case "chart": return jsx(ReportChart, { item: item, frame: box });
11737
+ case "gauge": return jsx(ReportGauge, { item: item, frame: box });
11738
+ case "placeholder": return jsx(ReportPlaceholder, { item: item, frame: box });
11739
+ default: return null;
11740
+ }
11741
+ }
11742
+ function ReportItems({ items, parentKey }) {
11743
+ return (jsx(Fragment, { children: items.map((item, index) => (jsx(ReportItem, { item: item, itemKey: rdlItemKey(parentKey, index) }, index))) }));
11744
+ }
11745
+
11746
+ const NO_FLIPS$1 = new Set();
11747
+ const NO_MATCHES = [];
11748
+ const DEFAULT_MARGINS = {
11749
+ top: DEFAULT_PAGE_MARGIN_PT,
11750
+ right: DEFAULT_PAGE_MARGIN_PT,
11751
+ bottom: DEFAULT_PAGE_MARGIN_PT,
11752
+ left: DEFAULT_PAGE_MARGIN_PT
11753
+ };
11754
+ function Band({ section, sectionKey, zoom, bodyWidth, as: Element }) {
11755
+ return (jsx(Element, { className: styles$1.section, style: { ...rdlBoxStyle(section.Style, zoom), width: ptToPx(bodyWidth, zoom), height: ptToPx(section.Height, zoom) }, children: jsx(ReportItems, { items: section.Items, parentKey: sectionKey }) }));
11756
+ }
11757
+ /**
11758
+ * One page of a rendered RDL report drawn as a sheet of paper: page header, body and page footer,
11759
+ * every item absolutely positioned in points scaled by the zoom. Presentational: toggle state,
11760
+ * sorting, images and find matches come from the host.
11761
+ */
11762
+ function CwReportPage({ page, bodyWidth, zoom = 1, culture, margins = DEFAULT_MARGINS, flippedToggles = NO_FLIPS$1, onToggle, onSort, getImageUrl, findMatches = NO_MATCHES, activeMatchIndex = -1, className }) {
11763
+ const sheetRef = useRef(null);
11764
+ const highlights = useMemo(() => highlightsByRun(findMatches), [findMatches]);
11765
+ const context = useMemo(() => ({
11766
+ zoom,
11767
+ culture,
11768
+ flipped: flippedToggles,
11769
+ onToggle,
11770
+ onSort,
11771
+ getImageUrl,
11772
+ highlights,
11773
+ activeMatchIndex
11774
+ }), [zoom, culture, flippedToggles, onToggle, onSort, getImageUrl, highlights, activeMatchIndex]);
11775
+ useEffect(() => {
11776
+ if (activeMatchIndex < 0)
11777
+ return;
11778
+ const active = sheetRef.current?.querySelector("[data-active-match='true']");
11779
+ active?.scrollIntoView?.({ block: "center", inline: "nearest" });
11780
+ }, [activeMatchIndex, findMatches]);
11781
+ const sheet = pageSheetSizePt(page, bodyWidth, margins);
11782
+ return (jsx(ReportRenderContext.Provider, { value: context, children: jsxs("div", { ref: sheetRef, className: `${styles$1.sheet}${className ? ` ${className}` : ""}`, style: {
11783
+ width: ptToPx(sheet.width, zoom),
11784
+ height: ptToPx(sheet.height, zoom),
11785
+ padding: `${ptToPx(margins.top, zoom)}px ${ptToPx(margins.right, zoom)}px ${ptToPx(margins.bottom, zoom)}px ${ptToPx(margins.left, zoom)}px`
11786
+ }, "data-page": page.Number, children: [page.Header && jsx(Band, { section: page.Header, sectionKey: RDL_SECTION_KEYS.header, zoom: zoom, bodyWidth: bodyWidth, as: "header" }), jsx("div", { className: styles$1.section, style: { width: ptToPx(bodyWidth, zoom), height: ptToPx(page.Height, zoom) }, children: jsx(ReportItems, { items: page.Items, parentKey: RDL_SECTION_KEYS.body }) }), page.Footer && jsx(Band, { section: page.Footer, sectionKey: RDL_SECTION_KEYS.footer, zoom: zoom, bodyWidth: bodyWidth, as: "footer" })] }) }));
11787
+ }
11788
+
11789
+ const DATE_PREFIX = /^(\d{4}-\d{2}-\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2}))?)?/;
11790
+ /** Reads the date and time of an ISO 8601 text (any offset is ignored, the wall clock is kept). Null when it is not a date. */
11791
+ function parseRdlDateTime(text) {
11792
+ const match = DATE_PREFIX.exec(text.trim());
11793
+ if (!match)
11794
+ return null;
11795
+ try {
11796
+ return Temporal.PlainDateTime.from(`${match[1]}T${match[2] ?? "00"}:${match[3] ?? "00"}:${match[4] ?? "00"}`);
11797
+ }
11798
+ catch {
11799
+ return null;
11800
+ }
11801
+ }
11802
+ /** A date-time as invariant text "YYYY-MM-DDTHH:mm:ss". */
11803
+ function formatRdlDateTime(value) {
11804
+ return value.toString({ smallestUnit: "second", calendarName: "never" });
11805
+ }
11806
+ /** A typed API value as the text of an option or an editor (null stays null). */
11807
+ function rdlValueToText(value) {
11808
+ if (value === null || value === undefined)
11809
+ return null;
11810
+ if (typeof value === "boolean")
11811
+ return value ? "true" : "false";
11812
+ if (typeof value === "number")
11813
+ return numberToInvariant(value);
11814
+ return value;
11815
+ }
11816
+ function numberToInvariant(value) {
11817
+ return Number.isFinite(value) ? value.toString() : "";
11818
+ }
11819
+ function isDateTime(parameter) {
11820
+ return parameter.DataType.toLowerCase() === "datetime" || parameter.InputType.toLowerCase() === "datetime";
11821
+ }
11822
+ function isBoolean(parameter) {
11823
+ return parameter.DataType.toLowerCase() === "boolean" || parameter.InputType.toLowerCase() === "boolean";
11824
+ }
11825
+ function isTextInput(parameter) {
11826
+ return parameter.InputType.toLowerCase() === "textbox";
11827
+ }
11828
+ function isNumeric(parameter) {
11829
+ const type = parameter.DataType.toLowerCase();
11830
+ return type === "integer" || type === "float";
11831
+ }
11832
+ function toEditorScalar(parameter, value) {
11833
+ if (isDateTime(parameter) && parameter.InputType.toLowerCase() !== "dropdownlist") {
11834
+ const text = String(value);
11835
+ return parseRdlDateTime(text) ?? text;
11836
+ }
11837
+ if (isBoolean(parameter) && parameter.InputType.toLowerCase() !== "dropdownlist") {
11838
+ return typeof value === "boolean" ? value : String(value).toLowerCase() === "true";
11839
+ }
11840
+ return rdlValueToText(value) ?? "";
11841
+ }
11842
+ /** The editor state of one parameter from the values the server sent; a NULL value is an empty field. */
11843
+ function initialParameterEdit(parameter) {
11844
+ const scalars = (parameter.Values ?? [])
11845
+ .filter((value) => value !== null && value !== undefined)
11846
+ .map(value => toEditorScalar(parameter, value));
11847
+ return { values: parameter.MultiValue ? scalars : scalars.slice(0, 1) };
11848
+ }
11849
+ /** The values that count: a multi-value text drops its empty lines, a single value keeps only the first. */
11850
+ function enteredValues(parameter, edit) {
11851
+ const values = edit.values.filter(value => value !== "");
11852
+ return parameter.MultiValue ? values : values.slice(0, 1);
11853
+ }
11854
+ /** The editor state of a whole form. */
11855
+ function initialParameterEdits(parameters) {
11856
+ const edits = {};
11857
+ for (const parameter of parameters)
11858
+ edits[parameter.Name] = initialParameterEdit(parameter);
11859
+ return edits;
11860
+ }
11861
+ /** One editor value as invariant text. */
11862
+ function editorScalarToInvariant(parameter, value) {
11863
+ if (typeof value === "boolean")
11864
+ return value ? "true" : "false";
11865
+ if (typeof value !== "string")
11866
+ return formatRdlDateTime(value);
11867
+ if (isNumeric(parameter))
11868
+ return value.trim().replace(",", ".");
11869
+ return value;
11870
+ }
11871
+ /**
11872
+ * The values the API takes (RdlParameterValuesRequest.Values): every parameter, each as an array of
11873
+ * invariant text. An empty field is [null] when the parameter is nullable, [""] for a single text,
11874
+ * else []. A parameter without an edit sends the values the server gave it.
11875
+ *
11876
+ * A nullable boolean whose value is NULL shows neither True nor False and keeps sending NULL until
11877
+ * the user picks one; from then on it sends "true" / "false" (a radio group cannot be emptied again).
11878
+ */
11879
+ function toRdlParameterValues(parameters, edits) {
11880
+ const result = {};
11881
+ for (const parameter of parameters) {
11882
+ const edit = edits[parameter.Name] ?? initialParameterEdit(parameter);
11883
+ const texts = enteredValues(parameter, edit).map(value => editorScalarToInvariant(parameter, value));
11884
+ if (texts.length > 0) {
11885
+ result[parameter.Name] = texts;
11886
+ }
11887
+ else if (parameter.Nullable) {
11888
+ result[parameter.Name] = [null];
11889
+ }
11890
+ else {
11891
+ result[parameter.Name] = !parameter.MultiValue && isTextInput(parameter) ? [""] : [];
11892
+ }
11893
+ }
11894
+ return result;
11895
+ }
11896
+ /** True when any other parameter lists `name` in its DependsOn: a change must re-resolve the form. */
11897
+ function hasDependentParameters(parameters, name) {
11898
+ return parameters.some(parameter => parameter.Name !== name && parameter.DependsOn.includes(name));
11899
+ }
11900
+ /** Whether the user edits the parameter (hidden and server-filled parameters are not editable). */
11901
+ function isEditableParameter(parameter) {
11902
+ return !parameter.Hidden && !parameter.ServerValue;
11903
+ }
11904
+ /** Whether the form has anything for the user to fill in (some parameter is neither hidden nor server-filled). */
11905
+ function hasEditableParameters(parameters) {
11906
+ return parameters.some(isEditableParameter);
11907
+ }
11908
+ /**
11909
+ * Client-side checks before "View report": a value is required unless the parameter is nullable
11910
+ * (empty = NULL) or allows blank text (AllowBlank), and numbers / dates must parse. Hidden and
11911
+ * server-filled parameters are the server's business. Returns parameter name to message.
11912
+ */
11913
+ function validateParameterEdits(parameters, edits) {
11914
+ const errors = {};
11915
+ for (const parameter of parameters) {
11916
+ if (!isEditableParameter(parameter))
11917
+ continue;
11918
+ const edit = edits[parameter.Name] ?? initialParameterEdit(parameter);
11919
+ const values = enteredValues(parameter, edit);
11920
+ if (values.length === 0) {
11921
+ const blankAllowed = parameter.Nullable
11922
+ || (parameter.AllowBlank && !parameter.MultiValue && isTextInput(parameter) && !isNumeric(parameter));
11923
+ if (!blankAllowed)
11924
+ errors[parameter.Name] = parameter.MultiValue ? "Select at least one value." : "A value is required.";
11925
+ continue;
11926
+ }
11927
+ if (isNumeric(parameter) && parameter.InputType.toLowerCase() !== "dropdownlist") {
11928
+ const integer = parameter.DataType.toLowerCase() === "integer";
11929
+ const invalid = values.some(value => {
11930
+ const text = editorScalarToInvariant(parameter, value);
11931
+ return integer ? !/^-?\d+$/.test(text) : !/^-?(\d+\.?\d*|\.\d+)$/.test(text);
11932
+ });
11933
+ if (invalid)
11934
+ errors[parameter.Name] = integer ? "Enter a whole number." : "Enter a number.";
11935
+ continue;
11936
+ }
11937
+ if (isDateTime(parameter) && parameter.InputType.toLowerCase() !== "dropdownlist"
11938
+ && values.some(value => typeof value === "string")) {
11939
+ errors[parameter.Name] = "Enter a valid date.";
11940
+ }
11941
+ }
11942
+ return errors;
11943
+ }
11944
+
11945
+ var styles = {"viewer":"cw-report-viewer-module__viewer__SYHSE","sidebar":"cw-report-viewer-module__sidebar__1ZSM2","resizer":"cw-report-viewer-module__resizer__JdnQI","main":"cw-report-viewer-module__main__qsPXX","parameterForm":"cw-report-viewer-module__parameterForm__H01sS","parameterFields":"cw-report-viewer-module__parameterFields__D2BuK","parameterActions":"cw-report-viewer-module__parameterActions__01RD4","viewButton":"cw-report-viewer-module__viewButton__1CMHL","parameterGrid":"cw-report-viewer-module__parameterGrid__Jyn0M","toolbar":"cw-report-viewer-module__toolbar__9gKXV","reportName":"cw-report-viewer-module__reportName__g5nsm","findStatus":"cw-report-viewer-module__findStatus__4gLGb","warningsButton":"cw-report-viewer-module__warningsButton__GIKjH","warningsPanel":"cw-report-viewer-module__warningsPanel__rFHBP","warningList":"cw-report-viewer-module__warningList__Ouk7x","menu":"cw-report-viewer-module__menu__ufxUU","menuItem":"cw-report-viewer-module__menuItem__hBmdD","canvas":"cw-report-viewer-module__canvas__9KuUT","canvasNote":"cw-report-viewer-module__canvasNote__K9XP0","sheetSkeleton":"cw-report-viewer-module__sheetSkeleton__DsSaA","emptyState":"cw-report-viewer-module__emptyState__pJyQ1"};
11946
+
11947
+ /** Above this many options a single-select dropdown gets a search box. */
11948
+ const SEARCH_THRESHOLD = 10;
11949
+ const LABEL_LAYOUT = { flexDirection: "column" };
11950
+ const BOOLEAN_OPTIONS = [
11951
+ { value: "true", label: "True" },
11952
+ { value: "false", label: "False" }
11953
+ ];
11954
+ function scalarText(value) {
11955
+ if (value === undefined)
11956
+ return "";
11957
+ if (typeof value === "boolean")
11958
+ return value ? "true" : "false";
11959
+ return typeof value === "string" ? value : value.toString();
11960
+ }
11961
+ function feedbackFor(parameter, clientError) {
11962
+ const messages = [];
11963
+ if (parameter.ValidValuesError)
11964
+ messages.push({ type: "danger", message: parameter.ValidValuesError });
11965
+ if (parameter.ValueError)
11966
+ messages.push({ type: "danger", message: parameter.ValueError });
11967
+ if (clientError)
11968
+ messages.push({ type: "danger", message: clientError });
11969
+ return messages.length > 0 ? messages : undefined;
11970
+ }
11971
+ function ParameterField({ parameter, edit, error, disabled, setEdit, commit }) {
11972
+ const label = { text: parameter.Prompt || parameter.Name };
11973
+ const feedback = feedbackFor(parameter, error);
11974
+ const testId = `report-parameter-${parameter.Name}`;
11975
+ // A NULL valid value is no option of its own: leaving the field empty is NULL.
11976
+ const options = parameter.ValidValues
11977
+ .filter(option => option.Value !== null && option.Value !== undefined)
11978
+ .map(option => ({ value: rdlValueToText(option.Value) ?? "", label: option.Label }));
11979
+ switch (parameter.InputType.toLowerCase()) {
11980
+ case "dropdownlist":
11981
+ if (parameter.MultiValue) {
11982
+ return (jsx(CwTagSelector, { id: testId, labelProps: label, alignProps: LABEL_LAYOUT, options: options, value: edit.values.map(scalarText), onChange: values => setEdit({ values }, true), showSelectAll: true, disabled: disabled, feedback: feedback }));
11983
+ }
11984
+ return (jsx(CwDropdown, { "data-testid": testId, labelProps: label, alignProps: LABEL_LAYOUT, options: options, value: scalarText(edit.values[0]), onChange: value => setEdit({ values: value === undefined ? [] : [String(value)] }, true), allowSearch: options.length > SEARCH_THRESHOLD, disabled: disabled, feedback: feedback }));
11985
+ case "datetime": {
11986
+ const value = edit.values[0];
11987
+ return (jsx(CwDateTimePickerTemporal, { "data-testid": testId, labelProps: label, alignProps: LABEL_LAYOUT, value: value instanceof Temporal.PlainDateTime ? value : undefined, onChange: dateTime => setEdit({ values: dateTime ? [dateTime] : [] }, true), disabled: disabled, feedback: feedback }));
11988
+ }
11989
+ case "boolean":
11990
+ return (jsx(CwRadioGroup, { "data-testid": testId, labelProps: label, groupLayout: { direction: "row" }, options: BOOLEAN_OPTIONS, value: edit.values.length > 0 ? scalarText(edit.values[0]) : undefined, onChange: value => setEdit({ values: [value === "true"] }, true), disabled: disabled, feedback: feedback }));
11991
+ case "integer":
11992
+ case "float":
11993
+ return (jsx(CwDigit, { "data-testid": testId, labelProps: label, alignProps: LABEL_LAYOUT, step: parameter.InputType.toLowerCase() === "integer" ? 1 : "any", value: scalarText(edit.values[0]), onChange: e => {
11994
+ const text = e.currentTarget.value;
11995
+ setEdit({ values: text === "" ? [] : [text] }, false);
11996
+ }, onBlur: commit, disabled: disabled, feedback: feedback }));
11997
+ default:
11998
+ if (parameter.MultiValue) {
11999
+ return (jsx(CwTextArea, { "data-testid": testId, labelProps: label, alignProps: LABEL_LAYOUT, value: edit.values.map(scalarText).join("\n"), onChange: e => {
12000
+ // Keep empty lines while typing (Enter must survive the re-render); they are dropped on serialization.
12001
+ setEdit({ values: e.currentTarget.value.split("\n") }, false);
12002
+ }, onBlur: commit, disabled: disabled, feedback: feedback ?? { type: "neutral", message: "One value per line." } }));
12003
+ }
12004
+ return (jsx(CwInputText, { "data-testid": testId, labelProps: label, alignProps: LABEL_LAYOUT, value: scalarText(edit.values[0]), onChange: e => {
12005
+ const text = e.currentTarget.value;
12006
+ setEdit({ values: [text] }, false);
12007
+ }, onBlur: commit, disabled: disabled, feedback: feedback }));
12008
+ }
12009
+ }
12010
+ /**
12011
+ * The report parameter form in the server's order: dropdowns (multi-value as tag selector with
12012
+ * select-all), date-time pickers, True/False, numbers and text. There is no NULL control: an empty
12013
+ * field of a nullable parameter is sent as NULL (see rdlParameterValues), as in the old WinOps
12014
+ * report page. Hidden parameters are not drawn; server-filled ones are read-only. Presentational:
12015
+ * the host owns the editor state (`useReportParameterForm`); a change to a parameter others depend
12016
+ * on calls its `onResolve`, "View report" its `onRender` with the values as invariant text
12017
+ * (`toRdlParameterValues`).
12018
+ *
12019
+ * The form fills its parent's height when the parent gives it one: the fields scroll and the
12020
+ * "View report" footer stays pinned at the bottom. In an unbounded parent it simply grows.
12021
+ */
12022
+ function CwReportParameterForm({ controller, loading = false, rendering = false }) {
12023
+ const { form } = controller;
12024
+ const visible = form?.Parameters.filter(parameter => !parameter.Hidden) ?? [];
12025
+ return (jsxs("form", { className: styles.parameterForm, "data-testid": "report-parameter-form", onSubmit: e => {
12026
+ e.preventDefault();
12027
+ controller.submit();
12028
+ }, children: [jsx("div", { className: styles.parameterFields, children: form ? (jsx(CwLoading, { isLoading: loading, size: "small", children: visible.length > 0 && (jsx("div", { className: `${styles.parameterGrid} cw-grid-base-auto`, children: visible.map(parameter => (jsx(ParameterField, { parameter: parameter, edit: controller.edits[parameter.Name] ?? { values: [] }, error: controller.errors[parameter.Name], disabled: loading || !!parameter.ServerValue, setEdit: (edit, commit) => controller.setEdit(parameter.Name, edit, commit), commit: () => controller.commit(parameter.Name) }, parameter.Name))) })) })) : (jsxs("div", { className: `${styles.parameterGrid} cw-grid-base-auto`, "aria-busy": "true", children: [jsx(CwSkeleton, { variant: "rect", height: "3.5rem" }), jsx(CwSkeleton, { variant: "rect", height: "3.5rem" }), jsx(CwSkeleton, { variant: "rect", height: "3.5rem" })] })) }), jsx("footer", { className: styles.parameterActions, children: jsx(CwButton, { type: "submit", text: "View report", icon: "file-view", className: styles.viewButton, disabled: !form || loading || rendering, "data-testid": "report-view-button" }) })] }));
12029
+ }
12030
+
12031
+ const REPORT_EXPORT_LABELS = {
12032
+ pdf: "PDF",
12033
+ xlsx: "Excel",
12034
+ docx: "Word"
12035
+ };
12036
+ /** A render with warnings asks before exporting or printing; without warnings the action runs at once. */
12037
+ function needsOutputConfirmation(warnings) {
12038
+ return (warnings?.length ?? 0) > 0;
12039
+ }
12040
+ /** Texts of the confirmation shown before an export or print of a render with warnings. */
12041
+ function outputConfirmation(action, warningCount) {
12042
+ const count = `${warningCount} warning${warningCount === 1 ? "" : "s"}`;
12043
+ if (action.kind === "print") {
12044
+ return {
12045
+ headline: "Print report",
12046
+ message: `This report has ${count}. The printout may not match the report exactly.`,
12047
+ confirmText: "Print anyway"
12048
+ };
12049
+ }
12050
+ const label = REPORT_EXPORT_LABELS[action.format];
12051
+ return {
12052
+ headline: `Export as ${label}`,
12053
+ message: `This report has ${count}. The ${label} export may not match the report exactly.`,
12054
+ confirmText: "Export anyway"
12055
+ };
12056
+ }
12057
+
12058
+ const EXPORTS = [
12059
+ { format: "pdf", label: REPORT_EXPORT_LABELS.pdf, icon: "file-pdf" },
12060
+ { format: "xlsx", label: REPORT_EXPORT_LABELS.xlsx, icon: "table" },
12061
+ { format: "docx", label: REPORT_EXPORT_LABELS.docx, icon: "document" }
12062
+ ];
12063
+ function zoomToValue(zoom) {
12064
+ return typeof zoom === "number" ? String(zoom) : zoom;
12065
+ }
12066
+ function valueToZoom(value) {
12067
+ if (value === "pageWidth" || value === "wholePage")
12068
+ return value;
12069
+ const factor = parseFloat(value);
12070
+ return Number.isFinite(factor) && factor > 0 ? factor : 1;
12071
+ }
12072
+ function closePopover(element) {
12073
+ element.closest("[popover]")?.hidePopover();
12074
+ }
12075
+ function PageInput({ pageNumber, pageCount, onPage, disabled }) {
12076
+ const [draft, setDraft] = useState({ page: pageNumber, text: String(pageNumber) });
12077
+ const text = draft.page === pageNumber ? draft.text : String(pageNumber);
12078
+ const commit = () => {
12079
+ const parsed = parseInt(text, 10);
12080
+ const target = Number.isFinite(parsed) ? Math.min(Math.max(1, parsed), Math.max(1, pageCount)) : pageNumber;
12081
+ setDraft({ page: pageNumber, text: String(target) });
12082
+ if (target !== pageNumber)
12083
+ onPage(target);
12084
+ };
12085
+ return (jsx(CwDigit, { "data-size": "tiny", "aria-label": "Page", min: 1, max: Math.max(1, pageCount), value: text, disabled: disabled, onChange: e => {
12086
+ const value = e.currentTarget.value;
12087
+ setDraft({ page: pageNumber, text: value });
12088
+ }, onKeyDown: (e) => {
12089
+ if (e.key === "Enter")
12090
+ commit();
12091
+ }, onBlur: commit }));
12092
+ }
12093
+ /**
12094
+ * The report viewer toolbar, like the old ReportViewer: page navigation, refresh, back, zoom,
12095
+ * find on the current page, export (PDF / Excel / Word) and print. Warnings stay invisible until
12096
+ * there are some (Dark Cockpit). Presentational: every action is a callback.
12097
+ */
12098
+ function CwReportToolbar({ pageNumber, pageCount, onPage, onRefresh, onBack, zoom, onZoomChange, findText, onFindTextChange, onFindNext, findMatchCount, findMatchIndex, onExport, onPrint, warnings = [], onToggleParameters, parametersVisible = true, disabled = false, reportName }) {
12099
+ const firstPage = disabled || pageNumber <= 1;
12100
+ const lastPage = disabled || pageNumber >= pageCount;
12101
+ const findStatus = findText.trim() === ""
12102
+ ? ""
12103
+ : findMatchCount === 0 ? "No matches" : `${Math.max(0, findMatchIndex) + 1} of ${findMatchCount}`;
12104
+ return (jsxs("header", { className: `${styles.toolbar} cw-flex-row cw-align-left-center cw-flex-wrap cw-gap-small`, "data-testid": "report-toolbar", children: [onBack && jsx(CwButton, { variant: "icon", icon: "arrow-left", title: "Back", onClick: onBack }), onToggleParameters && (jsx(CwButton, { variant: "icon", icon: "filter-list", title: parametersVisible ? "Hide parameters" : "Show parameters", pressed: parametersVisible, onClick: onToggleParameters })), jsxs("nav", { className: "cw-flex-row cw-align-left-center cw-gap-tiny", "aria-label": "Pages", children: [jsx(CwButton, { variant: "icon", icon: "chevron-left-double", title: "First page", disabled: firstPage, onClick: () => onPage(1) }), jsx(CwButton, { variant: "icon", icon: "chevron-left", title: "Previous page", disabled: firstPage, onClick: () => onPage(pageNumber - 1) }), jsx(PageInput, { pageNumber: pageNumber, pageCount: pageCount, onPage: onPage, disabled: disabled }), jsxs("span", { className: "cw-font-size-small", children: ["of ", disabled ? "-" : pageCount] }), jsx(CwButton, { variant: "icon", icon: "chevron-right", title: "Next page", disabled: lastPage, onClick: () => onPage(pageNumber + 1) }), jsx(CwButton, { variant: "icon", icon: "chevron-right-double", title: "Last page", disabled: lastPage, onClick: () => onPage(pageCount) })] }), onRefresh && jsx(CwButton, { variant: "icon", icon: "refresh", title: "Refresh", disabled: disabled, onClick: onRefresh }), jsxs(CwSelect, { "aria-label": "Zoom", value: zoomToValue(zoom), handleChange: value => onZoomChange(valueToZoom(value)), children: [REPORT_ZOOM_STEPS.map(step => (jsx(CwOption, { value: String(step), text: `${Math.round(step * 100)}%` }, step))), jsx(CwOption, { value: "pageWidth", text: "Page width" }), jsx(CwOption, { value: "wholePage", text: "Whole page" })] }), jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsx(CwInputText, { "aria-label": "Find text", placeholder: "Find", value: findText, disabled: disabled, onChange: e => onFindTextChange(e.currentTarget.value), onKeyDown: (e) => {
12105
+ if (e.key === "Enter")
12106
+ onFindNext();
12107
+ }, buttonProps: {
12108
+ text: "Next",
12109
+ variant: "outline",
12110
+ disabled: disabled || findMatchCount === 0,
12111
+ onClick: onFindNext
12112
+ } }), jsx("span", { className: `${styles.findStatus} cw-font-size-small`, "aria-live": "polite", children: findStatus })] }), jsx("div", { className: styles.reportName, children: reportName && (jsx(CwTooltipNew, { content: reportName, position: "bottom", children: jsx("strong", { className: "cw-text-ellipsis", "data-testid": "report-name", children: reportName }) })) }), warnings.length > 0 && (jsx(CwPopoverButton, { variant: "icon", icon: "warning", title: "Warnings", badge: { count: warnings.length, color: "warning" }, className: styles.warningsButton, placement: "bottom-end", panelClassName: styles.warningsPanel, children: jsx("ul", { className: styles.warningList, children: warnings.map((warning, index) => jsx("li", { children: warning }, index)) }) })), jsx(CwPopoverButton, { icon: "download", title: "Export", variant: "icon", disabled: disabled, placement: "bottom-end", children: jsx("div", { className: styles.menu, children: EXPORTS.map(item => (jsx(CwButton, { variant: "ghost", color: "neutral", text: item.label, icon: item.icon, className: styles.menuItem, onClick: e => {
12113
+ closePopover(e.currentTarget);
12114
+ onExport(item.format);
12115
+ } }, item.format))) }) }), jsx(CwButton, { variant: "icon", icon: "print", title: "Print", disabled: disabled, onClick: onPrint })] }));
12116
+ }
12117
+
12118
+ /** Width change of one arrow key press on the sidebar resize handle, in CSS pixels. */
12119
+ const SIDEBAR_KEY_STEP = 16;
12120
+ /** Keeps a sidebar width inside [min, max]; a max below min collapses to min. */
12121
+ function clampSidebarWidth(width, min, max) {
12122
+ const upper = Math.max(min, max);
12123
+ if (!Number.isFinite(width))
12124
+ return min;
12125
+ return Math.min(Math.max(width, min), upper);
12126
+ }
12127
+ /**
12128
+ * The sidebar width after a key press on the resize handle: arrows step, Home / End jump to the
12129
+ * bounds. Null for keys the handle does not use, so they keep their default behaviour.
12130
+ */
12131
+ function sidebarWidthForKey(key, current, min, max, step = SIDEBAR_KEY_STEP) {
12132
+ switch (key) {
12133
+ case "ArrowLeft":
12134
+ return clampSidebarWidth(current - step, min, max);
12135
+ case "ArrowRight":
12136
+ return clampSidebarWidth(current + step, min, max);
12137
+ case "Home":
12138
+ return clampSidebarWidth(min, min, max);
12139
+ case "End":
12140
+ return clampSidebarWidth(max, min, max);
12141
+ default:
12142
+ return null;
12143
+ }
12144
+ }
12145
+ /**
12146
+ * Whether the viewer shows the parameter sidebar. While the form loads for the first time it shows
12147
+ * the skeleton; once loaded only when the user has something to fill in. A report whose parameters
12148
+ * are all hidden or server-filled (or that has none) gets no sidebar.
12149
+ */
12150
+ function showsParameterSidebar(parameters, loadingParameters) {
12151
+ return parameters ? hasEditableParameters(parameters.Parameters) : loadingParameters;
12152
+ }
12153
+
12154
+ /**
12155
+ * Width of a left sidebar resized by dragging the handle on its right edge, like the master panel
12156
+ * of CwMasterDetail. The handle captures the pointer, so the drag keeps going outside it; the
12157
+ * keyboard steps the width for users who cannot drag.
12158
+ */
12159
+ function useSidebarResize(initialWidth, minWidth, maxWidth) {
12160
+ const [storedWidth, setStoredWidth] = useState(initialWidth);
12161
+ const [resizing, setResizing] = useState(false);
12162
+ const drag = useRef(null);
12163
+ const width = clampSidebarWidth(storedWidth, minWidth, maxWidth);
12164
+ const onPointerDown = useCallback((e) => {
12165
+ if (e.button !== 0)
12166
+ return;
12167
+ e.preventDefault();
12168
+ e.currentTarget.setPointerCapture(e.pointerId);
12169
+ drag.current = { startX: e.clientX, startWidth: width };
12170
+ setResizing(true);
12171
+ }, [width]);
12172
+ const onPointerMove = useCallback((e) => {
12173
+ const start = drag.current;
12174
+ if (!start)
12175
+ return;
12176
+ setStoredWidth(clampSidebarWidth(start.startWidth + e.clientX - start.startX, minWidth, maxWidth));
12177
+ }, [minWidth, maxWidth]);
12178
+ const endDrag = useCallback((e) => {
12179
+ if (!drag.current)
12180
+ return;
12181
+ drag.current = null;
12182
+ if (e.currentTarget.hasPointerCapture(e.pointerId))
12183
+ e.currentTarget.releasePointerCapture(e.pointerId);
12184
+ setResizing(false);
12185
+ }, []);
12186
+ const onKeyDown = useCallback((e) => {
12187
+ const next = sidebarWidthForKey(e.key, width, minWidth, maxWidth);
12188
+ if (next === null)
12189
+ return;
12190
+ e.preventDefault();
12191
+ setStoredWidth(next);
12192
+ }, [width, minWidth, maxWidth]);
12193
+ return {
12194
+ width,
12195
+ resizing,
12196
+ handleProps: { onPointerDown, onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onKeyDown }
12197
+ };
12198
+ }
12199
+
12200
+ /** Space the canvas keeps around the sheet when fitting it (its padding on both sides), in CSS pixels. */
12201
+ const CANVAS_GUTTER = 32;
12202
+ function useElementSize(ref) {
12203
+ const [size, setSize] = useState({ width: 0, height: 0 });
12204
+ useEffect(() => {
12205
+ const element = ref.current;
12206
+ if (!element || typeof ResizeObserver === "undefined")
12207
+ return;
12208
+ const observer = new ResizeObserver(() => {
12209
+ setSize({ width: element.clientWidth, height: element.clientHeight });
12210
+ });
12211
+ observer.observe(element);
12212
+ return () => observer.disconnect();
12213
+ }, [ref]);
12214
+ return size;
12215
+ }
12216
+ /**
12217
+ * The RDL report viewer: a resizable, collapsible parameter sidebar on the left, the toolbar and
12218
+ * the page on a neutral canvas on the right, like the old ReportViewer. The sidebar only exists
12219
+ * when the user has a parameter to fill in. Presentational: it fetches nothing and owns no report
12220
+ * state. The host calls `useReportViewerState` and `useReportParameterForm` and passes their results
12221
+ * as `state` and `parameterForm`; every request goes out through the callbacks given to those hooks
12222
+ * (or `onSort` / `onRefresh` / `onBack`) and comes back as their arguments.
12223
+ */
12224
+ function CwReportViewer({ definition, state, parameterForm, loadingParameters = false, loadingRender = false, error, onSort, onRefresh, onBack, getImageUrl, sidebarWidth = 320, minSidebarWidth = 240, maxSidebarWidth = 600, resizable = true, className }) {
12225
+ const { result } = state;
12226
+ const parameters = parameterForm.form;
12227
+ const sidebar = useSidebarResize(sidebarWidth, minSidebarWidth, maxSidebarWidth);
12228
+ const canvasRef = useRef(null);
12229
+ const canvasSize = useElementSize(canvasRef);
12230
+ const hasSidebar = showsParameterSidebar(parameters, loadingParameters);
12231
+ const sidebarOpen = hasSidebar && state.parametersVisible;
12232
+ const warnings = result?.Warnings ?? [];
12233
+ const reportName = result?.Name || definition?.Name || null;
12234
+ const confirmation = state.pendingOutput ? outputConfirmation(state.pendingOutput, warnings.length) : null;
12235
+ /** Where the clicked toggle sat in the canvas, so the re-rendered page keeps it in the same place. */
12236
+ const toggleAnchorRef = useRef(null);
12237
+ const handleToggle = (toggleId) => {
12238
+ if (state.serverToggles) {
12239
+ const canvas = canvasRef.current;
12240
+ const button = canvas?.querySelector(`[data-toggle-id="${CSS.escape(toggleId)}"]`);
12241
+ toggleAnchorRef.current = canvas && button
12242
+ ? { toggleId, offset: button.getBoundingClientRect().top - canvas.getBoundingClientRect().top }
12243
+ : null;
12244
+ }
12245
+ state.toggle(toggleId);
12246
+ };
12247
+ useLayoutEffect(() => {
12248
+ const anchor = toggleAnchorRef.current;
12249
+ const canvas = canvasRef.current;
12250
+ if (!anchor || !canvas || !result)
12251
+ return;
12252
+ toggleAnchorRef.current = null;
12253
+ const button = canvas.querySelector(`[data-toggle-id="${CSS.escape(anchor.toggleId)}"]`);
12254
+ if (button)
12255
+ canvas.scrollTop += button.getBoundingClientRect().top - canvas.getBoundingClientRect().top - anchor.offset;
12256
+ }, [result]);
12257
+ // Without a sidebar (nothing to fill in) the form's "View report" lives on the canvas instead.
12258
+ const runButton = !hasSidebar && parameters && !result ? (jsx(CwButton, { text: "View report", icon: "file-view", disabled: loadingParameters || loadingRender, onClick: parameterForm.submit, "data-testid": "report-view-button" })) : null;
12259
+ const zoomFactor = result
12260
+ ? resolveZoomFactor(state.zoom, pageSheetSizePt(result.Page, result.BodyWidth, SCREEN_PAGE_MARGINS), { width: canvasSize.width - CANVAS_GUTTER, height: canvasSize.height - CANVAS_GUTTER })
12261
+ : 1;
12262
+ const renderCanvas = () => {
12263
+ if (error) {
12264
+ return (jsxs(Fragment, { children: [jsx(CwNote, { color: "danger", variant: "soft", icon: "warning", content: error, className: styles.canvasNote }), runButton] }));
12265
+ }
12266
+ if (!result) {
12267
+ if (loadingRender) {
12268
+ return (jsx("div", { className: styles.sheetSkeleton, "aria-busy": "true", children: jsx(CwSkeleton, { variant: "text", count: 14 }) }));
12269
+ }
12270
+ return (jsxs("div", { className: `${styles.emptyState} cw-flex-column cw-align-center-center cw-gap-small`, children: [jsx(CwIcon, { iconId: "file-report", size: "huge", color: "neutral" }), jsx("p", { className: "cw-margin-none", children: hasSidebar ? "Set the parameters and select View report." : "Select View report to run the report." }), runButton] }));
12271
+ }
12272
+ return (jsx(CwLoading, { isLoading: loadingRender, children: jsx(CwReportPage, { page: result.Page, bodyWidth: result.BodyWidth, zoom: zoomFactor, culture: result.Culture, margins: SCREEN_PAGE_MARGINS, flippedToggles: state.drawnFlips, onToggle: handleToggle, onSort: onSort, getImageUrl: getImageUrl, findMatches: state.findMatches, activeMatchIndex: state.findIndex }) }));
12273
+ };
12274
+ return (jsxs("section", { className: `${styles.viewer}${className ? ` ${className}` : ""}`, "aria-label": result?.Name ?? definition?.Name ?? "Report", "data-resizing": sidebar.resizing || undefined, "data-testid": "report-viewer", children: [sidebarOpen && (jsxs(Fragment, { children: [jsx("aside", { className: styles.sidebar, style: { width: sidebar.width }, "aria-label": "Report parameters", "data-testid": "report-parameter-sidebar", children: jsx(CwReportParameterForm, { controller: parameterForm, loading: loadingParameters, rendering: loadingRender }) }), resizable && (jsx("div", { className: styles.resizer, role: "separator", "aria-orientation": "vertical", "aria-label": "Resize parameters", "aria-valuenow": sidebar.width, "aria-valuemin": minSidebarWidth, "aria-valuemax": Math.max(minSidebarWidth, maxSidebarWidth), tabIndex: 0, "data-resizing": sidebar.resizing, ...sidebar.handleProps }))] })), jsxs("div", { className: styles.main, children: [jsx(CwReportToolbar, { pageNumber: result?.Page.Number ?? 1, pageCount: result?.PageCount ?? 1, onPage: state.goToPage, onRefresh: onRefresh, onBack: onBack, zoom: state.zoom, onZoomChange: state.setZoom, findText: state.findText, onFindTextChange: state.setFindText, onFindNext: state.findNext, findMatchCount: state.findMatches.length, findMatchIndex: state.findIndex, onExport: format => state.requestOutput({ kind: "export", format }), onPrint: () => state.requestOutput({ kind: "print" }), warnings: warnings, reportName: reportName, onToggleParameters: hasSidebar ? state.toggleParameters : undefined, parametersVisible: state.parametersVisible, disabled: !result || loadingRender || !!error }), jsx("div", { ref: canvasRef, className: styles.canvas, "data-testid": "report-canvas", children: renderCanvas() })] }), confirmation && (jsx(CwDialog, { open: true, headline: confirmation.headline, width: "28rem", onClose: state.cancelOutput, customFooter: [
12275
+ jsx(CwButton, { text: "Cancel", variant: "outline", onClick: state.cancelOutput }, "cancel"),
12276
+ jsx(CwButton, { text: confirmation.confirmText, onClick: state.confirmOutput, "data-testid": "report-output-confirm" }, "confirm")
12277
+ ], "data-testid": "report-output-dialog", children: jsx("p", { className: "cw-margin-none", children: confirmation.message }) })), state.permissionDialogOpen && (jsx(CwDialog, { open: true, headline: "SQL ERROR", width: "30rem", onClose: state.closePermissionDialog, customFooter: [jsx(CwButton, { text: "OK", onClick: state.closePermissionDialog }, "ok")], "data-testid": "report-permission-dialog", children: jsx("p", { className: "cw-margin-none", children: "You do not have the database permission this report needs, so some of its data could not be read. Ask an administrator to grant access to the report data." }) }))] }));
12278
+ }
12279
+
12280
+ const NO_FLIPS = new Set();
12281
+ /**
12282
+ * Client-side state of the report viewer around one render result, owned by the host and handed to
12283
+ * `CwReportViewer` as `state`. The drilldown toggles belong to a render: a new RenderId (new render,
12284
+ * sort) starts with none flipped, paging and server views of the same render keep them. With
12285
+ * `onView` the host re-renders the page for the flipped toggles, so the page and find use it as drawn
12286
+ * (`drawnFlips` = none). The find position belongs to the query and the page shown. The permission
12287
+ * dialog is dismissed per render, and a pending export / print question is dropped by a new render.
12288
+ */
12289
+ function useReportViewerState(result, options) {
12290
+ const { onPage, onView, onExport, onPrint, initialZoom = 1 } = options;
12291
+ const renderId = result?.RenderId ?? null;
12292
+ const page = result?.Page ?? null;
12293
+ const pageNumber = page?.Number ?? 1;
12294
+ const warnings = result?.Warnings;
12295
+ const serverToggles = !!onView;
12296
+ const [zoom, setZoom] = useState(initialZoom);
12297
+ const [toggles, setToggles] = useState({ renderId: null, flipped: NO_FLIPS });
12298
+ const [findText, setFindText] = useState("");
12299
+ const [find, setFind] = useState({ key: "", index: 0 });
12300
+ const [parametersVisible, setParametersVisible] = useState(true);
12301
+ const [dismissedRenderId, setDismissedRenderId] = useState(null);
12302
+ const [output, setOutput] = useState(null);
12303
+ const flipped = toggles.renderId === renderId ? toggles.flipped : NO_FLIPS;
12304
+ const toggle = useCallback((toggleId) => {
12305
+ setToggles(previous => ({
12306
+ renderId,
12307
+ flipped: flipToggle(previous.renderId === renderId ? previous.flipped : NO_FLIPS, toggleId)
12308
+ }));
12309
+ if (onView)
12310
+ onView(toggledIds(flipped, toggleId), pageNumber);
12311
+ }, [renderId, onView, flipped, pageNumber]);
12312
+ const setFlipped = useCallback((toggleIds) => {
12313
+ setToggles({ renderId, flipped: new Set(toggleIds) });
12314
+ }, [renderId]);
12315
+ const goToPage = useCallback((target) => {
12316
+ if (onView && flipped.size > 0) {
12317
+ onView(flippedToggleIds(flipped), target);
12318
+ }
12319
+ else {
12320
+ onPage(target);
12321
+ }
12322
+ }, [onView, onPage, flipped]);
12323
+ // With server toggles the page arrives already drawn for the flipped toggles, so nothing is flipped again here.
12324
+ const drawnFlips = serverToggles ? NO_FLIPS : flipped;
12325
+ const findMatches = useMemo(() => (page ? findInPage(page, findText, drawnFlips) : []), [page, findText, drawnFlips]);
12326
+ const findKey = `${renderId ?? ""}|${page?.Number ?? 0}|${findText}`;
12327
+ const findIndex = activeMatchIndex(find.index, find.key === findKey, findMatches.length);
12328
+ const findNext = useCallback(() => {
12329
+ setFind({ key: findKey, index: nextMatchIndex(findIndex, findMatches.length) });
12330
+ }, [findKey, findIndex, findMatches.length]);
12331
+ const toggleParameters = useCallback(() => setParametersVisible(visible => !visible), []);
12332
+ const closePermissionDialog = useCallback(() => setDismissedRenderId(renderId), [renderId]);
12333
+ // A new render (refresh, sort) drops a question asked about the previous one.
12334
+ const pendingOutput = output && output.renderId === renderId ? output.action : null;
12335
+ const runOutput = useCallback((action) => {
12336
+ const toggleIds = flippedToggleIds(flipped);
12337
+ if (action.kind === "print") {
12338
+ onPrint(toggleIds);
12339
+ }
12340
+ else {
12341
+ onExport(action.format, toggleIds);
12342
+ }
12343
+ }, [flipped, onPrint, onExport]);
12344
+ const requestOutput = useCallback((action) => {
12345
+ if (needsOutputConfirmation(warnings)) {
12346
+ setOutput({ renderId, action });
12347
+ }
12348
+ else {
12349
+ runOutput(action);
12350
+ }
12351
+ }, [warnings, renderId, runOutput]);
12352
+ const confirmOutput = useCallback(() => {
12353
+ setOutput(null);
12354
+ if (pendingOutput)
12355
+ runOutput(pendingOutput);
12356
+ }, [pendingOutput, runOutput]);
12357
+ const cancelOutput = useCallback(() => setOutput(null), []);
12358
+ return {
12359
+ result,
12360
+ serverToggles,
12361
+ zoom,
12362
+ setZoom,
12363
+ flipped,
12364
+ drawnFlips,
12365
+ toggle,
12366
+ setFlipped,
12367
+ goToPage,
12368
+ findText,
12369
+ setFindText,
12370
+ findMatches,
12371
+ findIndex,
12372
+ findNext,
12373
+ parametersVisible,
12374
+ toggleParameters,
12375
+ permissionDialogOpen: !!result?.PermissionDenied && dismissedRenderId !== renderId,
12376
+ closePermissionDialog,
12377
+ pendingOutput,
12378
+ requestOutput,
12379
+ confirmOutput,
12380
+ cancelOutput
12381
+ };
12382
+ }
12383
+
12384
+ function stateFor(form) {
12385
+ return { source: form, edits: initialParameterEdits(form?.Parameters ?? []), pending: new Set(), showErrors: false };
12386
+ }
12387
+ /**
12388
+ * Editor state of the report parameter form, owned by the host and handed to `CwReportParameterForm`
12389
+ * as `controller`. A new form object from the host (after a resolve) resets the editors to the values
12390
+ * it carries; the server echoes the submitted values, so nothing is lost.
12391
+ */
12392
+ function useReportParameterForm(form, options) {
12393
+ const { onResolve, onRender } = options;
12394
+ const [state, setState] = useState(() => stateFor(form));
12395
+ const current = state.source === form ? state : stateFor(form);
12396
+ if (current !== state)
12397
+ setState(current);
12398
+ const parameters = form?.Parameters ?? [];
12399
+ const setEdit = useCallback((name, edit, commit) => {
12400
+ const params = form?.Parameters ?? [];
12401
+ const edits = { ...current.edits, [name]: edit };
12402
+ const pending = new Set(current.pending);
12403
+ if (commit) {
12404
+ pending.delete(name);
12405
+ }
12406
+ else {
12407
+ pending.add(name);
12408
+ }
12409
+ setState({ ...current, edits, pending });
12410
+ if (commit && hasDependentParameters(params, name))
12411
+ onResolve(toRdlParameterValues(params, edits));
12412
+ }, [current, form, onResolve]);
12413
+ const commit = useCallback((name) => {
12414
+ if (!current.pending.has(name))
12415
+ return;
12416
+ const params = form?.Parameters ?? [];
12417
+ const pending = new Set(current.pending);
12418
+ pending.delete(name);
12419
+ setState({ ...current, pending });
12420
+ if (hasDependentParameters(params, name))
12421
+ onResolve(toRdlParameterValues(params, current.edits));
12422
+ }, [current, form, onResolve]);
12423
+ const submit = useCallback(() => {
12424
+ const params = form?.Parameters ?? [];
12425
+ const errors = validateParameterEdits(params, current.edits);
12426
+ if (Object.keys(errors).length > 0) {
12427
+ setState({ ...current, showErrors: true });
12428
+ return;
12429
+ }
12430
+ onRender(toRdlParameterValues(params, current.edits));
12431
+ }, [current, form, onRender]);
12432
+ return {
12433
+ form,
12434
+ edits: current.edits,
12435
+ errors: current.showErrors ? validateParameterEdits(parameters, current.edits) : {},
12436
+ setEdit,
12437
+ commit,
12438
+ submit
12439
+ };
12440
+ }
12441
+
10101
12442
  /**
10102
12443
  * API-backed airport search input for WinOps.
10103
12444
  *
@@ -10532,4 +12873,4 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
10532
12873
  }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "person" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
10533
12874
  };
10534
12875
 
10535
- export { CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBadge, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwButtonSplit, CwButtonSwitch, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNavMenu, CwNote, CwOption, CwPopoverButton, CwProgress, CwRadioGroup, CwReportModal, CwSearchAsync, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSkeleton, CwSortableList, CwSortableTable, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PRESET_LIBRARY_TEMPORAL, PinRowHeader, Scheduler, SchedulerEvent, SuperScheduler, TooltipConstraintContext, UiEvent, Weekdays, configureCwLoading, eventIsVisible, filterNavItems, filterVisibleEvents, getCwLoadingDefaults, getDefaultDivisions, getEventSizes, getPresetsByKeysTemporal, itemsToMultiFilterTags, sortNavItems, useCwMessage, useSortableList, useSortableTable, useTooltipConstraint };
12876
+ export { CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBadge, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwButtonSplit, CwButtonSwitch, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNavMenu, CwNote, CwOption, CwPopoverButton, CwProgress, CwRadioGroup, CwReportGauge, CwReportLineChart, CwReportModal, CwReportPage, CwReportParameterForm, CwReportPieChart, CwReportToolbar, CwReportViewer, CwSearchAsync, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSkeleton, CwSortableList, CwSortableTable, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PRESET_LIBRARY_TEMPORAL, PinRowHeader, REPORT_ZOOM_STEPS, Scheduler, SchedulerEvent, SuperScheduler, TooltipConstraintContext, UiEvent, Weekdays, configureCwLoading, eventIsVisible, filterNavItems, filterVisibleEvents, findInPage, flipToggle, getCwLoadingDefaults, getDefaultDivisions, getEventSizes, getPresetsByKeysTemporal, initialParameterEdits, isRdlVisible, itemsToMultiFilterTags, sortNavItems, toRdlParameterValues, useCwMessage, useReportParameterForm, useReportViewerState, useSortableList, useSortableTable, useTooltipConstraint };