@cwellt_software/cwellt-reactjs-lib 1.4.0 → 1.4.2

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 (39) hide show
  1. package/dist/index.cjs.js +586 -213
  2. package/dist/index.css +2 -2
  3. package/dist/index.d.ts +205 -5
  4. package/dist/index.es.js +585 -214
  5. package/dist/src/common/hooks/useDropdownPortal.d.ts +86 -0
  6. package/dist/src/common/hooks/useDropdownPortal.d.ts.map +1 -0
  7. package/dist/src/components/control/action/search/CwSearch.d.ts +22 -0
  8. package/dist/src/components/control/action/search/CwSearch.d.ts.map +1 -1
  9. package/dist/src/components/control/choice/multi-filter/CwMultiFilter.d.ts.map +1 -1
  10. package/dist/src/components/control/choice/option/CwOption.d.ts +3 -1
  11. package/dist/src/components/control/choice/option/CwOption.d.ts.map +1 -1
  12. package/dist/src/components/control/choice/select/CwDropdown.d.ts +56 -0
  13. package/dist/src/components/control/choice/select/CwDropdown.d.ts.map +1 -0
  14. package/dist/src/components/control/choice/select/CwSelect.d.ts.map +1 -1
  15. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts +68 -0
  16. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts.map +1 -0
  17. package/dist/src/components/control/input/new-dates/CwDatePickerTemporal.d.ts +48 -0
  18. package/dist/src/components/control/input/new-dates/CwDatePickerTemporal.d.ts.map +1 -0
  19. package/dist/src/components/control/input/new-dates/datePickerHelpers.d.ts +20 -0
  20. package/dist/src/components/control/input/new-dates/datePickerHelpers.d.ts.map +1 -0
  21. package/dist/src/components/control/input/new-dates/usePickerPopup.d.ts +7 -8
  22. package/dist/src/components/control/input/new-dates/usePickerPopup.d.ts.map +1 -1
  23. package/dist/src/components/custom/find-airport/CwFindAirportComp.d.ts +36 -1
  24. package/dist/src/components/custom/find-airport/CwFindAirportComp.d.ts.map +1 -1
  25. package/dist/src/components/custom/find-crewmember/CwFindCrewmemberComp.d.ts +26 -0
  26. package/dist/src/components/custom/find-crewmember/CwFindCrewmemberComp.d.ts.map +1 -1
  27. package/dist/src/components/display/data/table/CwTable.d.ts.map +1 -1
  28. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts +2 -1
  29. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts.map +1 -1
  30. package/dist/src/index.d.ts +2 -0
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  33. package/dist/src/playground/pages/DatePickerTemporalPage.d.ts +3 -0
  34. package/dist/src/playground/pages/DatePickerTemporalPage.d.ts.map +1 -0
  35. package/dist/src/playground/pages/SelectorsPage.d.ts +3 -0
  36. package/dist/src/playground/pages/SelectorsPage.d.ts.map +1 -0
  37. package/dist/test/components/control/input/new-dates/datePickerHelpers.test.d.ts +2 -0
  38. package/dist/test/components/control/input/new-dates/datePickerHelpers.test.d.ts.map +1 -0
  39. package/package.json +1 -1
package/dist/index.cjs.js CHANGED
@@ -652,7 +652,7 @@ function CwLoadingSmall(CwelltLoadingAppointements) {
652
652
  return (jsxRuntime.jsx("div", { children: CwelltLoadingAppointements.isLoading === true ? (jsxRuntime.jsx("div", { className: "cw-loading-container", children: jsxRuntime.jsx("div", { className: "cw-loading" }) })) : (jsxRuntime.jsx("div", {})) }));
653
653
  }
654
654
 
655
- var styles$p = {"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"};
655
+ var styles$q = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
656
656
 
657
657
  // Constants moved outside to prevent recreation
658
658
  const margin$1 = 16;
@@ -775,12 +775,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
775
775
  const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
776
776
  setIsVisible(true);
777
777
  }, showDelay);
778
- const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$p["cw-generic-tooltip-content"]);
778
+ const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$q["cw-generic-tooltip-content"]);
779
779
  // Memoize tooltip content creation
780
780
  const tooltipContent = React.useMemo(() => {
781
781
  if (hide || !isVisible || !content)
782
782
  return null;
783
- return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$p["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
783
+ return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$q["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
784
784
  position: 'fixed',
785
785
  top: `${tooltipPosition.top}px`,
786
786
  left: `${tooltipPosition.left}px`,
@@ -795,10 +795,10 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
795
795
  clearTooltipTimeout();
796
796
  setIsVisible(false);
797
797
  }, [clearTooltipTimeout]);
798
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$p["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
798
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$q["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
799
799
  };
800
800
 
801
- var styles$o = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
801
+ var styles$p = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
802
802
 
803
803
  // Constants
804
804
  const margin = 16;
@@ -1013,7 +1013,7 @@ const CwTooltipManager = () => {
1013
1013
  if (!state.isVisible || !state.content) {
1014
1014
  return null;
1015
1015
  }
1016
- return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$o["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, style: {
1016
+ return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$p["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, style: {
1017
1017
  top: `${tooltipPosition.top}px`,
1018
1018
  left: `${tooltipPosition.left}px`,
1019
1019
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -1081,7 +1081,7 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
1081
1081
  React.useEffect(() => {
1082
1082
  ensureTooltipManager();
1083
1083
  }, []);
1084
- return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$o["cw-tooltip"], children: children }));
1084
+ return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$p["cw-tooltip"], children: children }));
1085
1085
  };
1086
1086
 
1087
1087
  function CwButton({ text, variant = 'solid', color = 'primary', className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }) {
@@ -1134,7 +1134,7 @@ function CwModal(custModalProps) {
1134
1134
  return (jsxRuntime.jsx("div", { children: custModalProps.modalState && (jsxRuntime.jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsxRuntime.jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsxRuntime.jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxRuntime.jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxRuntime.jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsxRuntime.jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsxRuntime.jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsxRuntime.jsx("span", { className: "cwelltCloseIcon" }) })] }), jsxRuntime.jsx("div", { className: "cwelltModalBody", children: jsxRuntime.jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsxRuntime.jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsxRuntime.jsx("div", { style: { display: "none" } }))] }) })] })) }));
1135
1135
  }
1136
1136
 
1137
- var styles$n = {"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"};
1137
+ var styles$o = {"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"};
1138
1138
 
1139
1139
  function CwConfirmationPopup(props) {
1140
1140
  const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
@@ -1198,15 +1198,15 @@ function CwConfirmationPopup(props) {
1198
1198
  onCancel();
1199
1199
  }
1200
1200
  };
1201
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$n.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$n.popup, style: {
1201
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$o.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$o.popup, style: {
1202
1202
  position: 'absolute',
1203
1203
  top: `${position.top}px`,
1204
1204
  left: `${position.left}px`,
1205
1205
  transform: 'none'
1206
- }, children: [jsxRuntime.jsx("p", { className: styles$n.message, children: message }), jsxRuntime.jsxs("div", { className: styles$n.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$n.button} ${styles$n.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$n.button} ${styles$n.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1206
+ }, children: [jsxRuntime.jsx("p", { className: styles$o.message, children: message }), jsxRuntime.jsxs("div", { className: styles$o.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$o.button} ${styles$o.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$o.button} ${styles$o.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1207
1207
  }
1208
1208
 
1209
- var styles$m = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1209
+ var styles$n = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1210
1210
 
1211
1211
  // Helper function to parse size values
1212
1212
  const parseSize = (size) => {
@@ -1479,7 +1479,7 @@ const CwDialog = props => {
1479
1479
  }
1480
1480
  }
1481
1481
  }, [open]);
1482
- const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$m["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1482
+ const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$n["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1483
1483
  const content = React.useMemo(() => (jsxRuntime.jsx("section", { children: children })), [children]);
1484
1484
  const footer = React.useMemo(() => (jsxRuntime.jsx("footer", { children: customFooter || (jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
1485
1485
  const resizeHandles = React.useMemo(() => size.autoHeight
@@ -1506,7 +1506,7 @@ const CwDialog = props => {
1506
1506
  : `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
1507
1507
  return { displayWidth, displayHeight };
1508
1508
  }, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
1509
- const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$m["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1509
+ const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$n["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1510
1510
  left: `${position.x}px`,
1511
1511
  top: `${position.y}px`,
1512
1512
  width: displayDimensions.displayWidth,
@@ -1709,7 +1709,7 @@ function CwAlign(props) {
1709
1709
  }, children: props.children }));
1710
1710
  }
1711
1711
 
1712
- var styles$l = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
1712
+ var styles$m = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
1713
1713
 
1714
1714
  /**
1715
1715
  * CwCard - A simple card component for displaying content in a contained format
@@ -1733,11 +1733,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1733
1733
  // Construct class names using CSS modules
1734
1734
  const cardClassNames = [
1735
1735
  'cw-card',
1736
- styles$l.card,
1736
+ styles$m.card,
1737
1737
  className,
1738
- clickable ? styles$l.clickable : '',
1739
- disabled ? styles$l.disabled : '',
1740
- isLoading ? styles$l.loading : '',
1738
+ clickable ? styles$m.clickable : '',
1739
+ disabled ? styles$m.disabled : '',
1740
+ isLoading ? styles$m.loading : '',
1741
1741
  ].filter(Boolean).join(' ');
1742
1742
  // Handle click event when card is clickable
1743
1743
  const handleClick = () => {
@@ -1754,15 +1754,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1754
1754
  // Determine if footer should be rendered
1755
1755
  const hasFooter = hasChips || footer || (hasActions && direction === "row");
1756
1756
  // Actions component to reuse
1757
- const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$l.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1757
+ const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$m.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1758
1758
  return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
1759
1759
  role: 'button',
1760
1760
  tabIndex: 0,
1761
1761
  onClick: handleClick,
1762
- }), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$l.headerContent, "data-alignment": alignment, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), direction === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$l.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$l.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$l.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$l.footerContent, children: footer }))] })), direction === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$l.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1762
+ }), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$m.headerContent, "data-alignment": alignment, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), direction === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$m.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$m.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$m.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$m.footerContent, children: footer }))] })), direction === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$m.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1763
1763
  };
1764
1764
 
1765
- var styles$k = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS","sortControls":"cw-card-list-module__sortControls__mWgZA"};
1765
+ var styles$l = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS","sortControls":"cw-card-list-module__sortControls__mWgZA"};
1766
1766
 
1767
1767
  function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, emptyState, sortOptions = [], defaultSortKey, ...htmlProps }) {
1768
1768
  const [currentPage, setCurrentPage] = React.useState(1);
@@ -1796,10 +1796,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
1796
1796
  '--card-width': `${defaultCardWidth}px`,
1797
1797
  '--card-gap': `${cardGap}px`
1798
1798
  };
1799
- return (jsxRuntime.jsxs("div", { ...htmlProps, children: [sortOptions.length > 0 && (jsxRuntime.jsxs("div", { className: styles$k.sortControls, children: [jsxRuntime.jsx("label", { htmlFor: "cardlist-sort-select", children: "Sort by:" }), jsxRuntime.jsx("select", { id: "cardlist-sort-select", value: sortKey, onChange: (e) => handleSortChange(e.target.value), className: styles$k.sortSelect, children: sortOptions.map(option => (jsxRuntime.jsx("option", { value: option.key, children: option.label }, option.key))) }), jsxRuntime.jsx("button", { onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'), className: `cw-button-icon ${sortDirection === 'asc' ? 'cwi-arrow-up' : 'cwi-arrow-down'}`, title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}` })] })), isLoading ? (jsxRuntime.jsx("div", { className: styles$k.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$k.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$k.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx("div", { className: styles$k.cardWrapper, children: renderCard(item, index) }, index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$k.pagination, children: [jsxRuntime.jsx("button", { disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)), className: "cw-button-icon cwi-chevron-left" }), jsxRuntime.jsxs("span", { className: styles$k.pageInfo, children: [currentPage, " of ", totalPages] }), jsxRuntime.jsx("button", { disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), className: "cw-button-icon cwi-chevron-right" })] }))] }))] }));
1799
+ return (jsxRuntime.jsxs("div", { ...htmlProps, children: [sortOptions.length > 0 && (jsxRuntime.jsxs("div", { className: styles$l.sortControls, children: [jsxRuntime.jsx("label", { htmlFor: "cardlist-sort-select", children: "Sort by:" }), jsxRuntime.jsx("select", { id: "cardlist-sort-select", value: sortKey, onChange: (e) => handleSortChange(e.target.value), className: styles$l.sortSelect, children: sortOptions.map(option => (jsxRuntime.jsx("option", { value: option.key, children: option.label }, option.key))) }), jsxRuntime.jsx("button", { onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'), className: `cw-button-icon ${sortDirection === 'asc' ? 'cwi-arrow-up' : 'cwi-arrow-down'}`, title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}` })] })), isLoading ? (jsxRuntime.jsx("div", { className: styles$l.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$l.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$l.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx("div", { className: styles$l.cardWrapper, children: renderCard(item, index) }, index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$l.pagination, children: [jsxRuntime.jsx("button", { disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)), className: "cw-button-icon cwi-chevron-left" }), jsxRuntime.jsxs("span", { className: styles$l.pageInfo, children: [currentPage, " of ", totalPages] }), jsxRuntime.jsx("button", { disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), className: "cw-button-icon cwi-chevron-right" })] }))] }))] }));
1800
1800
  }
1801
1801
 
1802
- var styles$j = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1802
+ var styles$k = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1803
1803
 
1804
1804
  /**
1805
1805
  *
@@ -1816,7 +1816,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
1816
1816
  setVisible_accordionBody(!isVisible_accordionBody);
1817
1817
  };
1818
1818
  // #endregion
1819
- return (jsxRuntime.jsxs("div", { className: styles$j["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$j["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1819
+ return (jsxRuntime.jsxs("div", { className: styles$k["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$k["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1820
1820
  }
1821
1821
 
1822
1822
  /**
@@ -2020,15 +2020,6 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2020
2020
  window.addEventListener("mousemove", onMouseMove);
2021
2021
  window.addEventListener("mouseup", onMouseUp);
2022
2022
  };
2023
- const scrollContainerStyle = React.useMemo(() => {
2024
- if (stickyHeader || scrollHeight) {
2025
- return {
2026
- maxHeight: scrollHeight ?? 300,
2027
- overflowY: "auto"
2028
- };
2029
- }
2030
- return {}; // no height or scroll
2031
- }, [stickyHeader, scrollHeight]);
2032
2023
  const getColSpan = () => columns.length + (expandedRowRender ? 1 : 0);
2033
2024
  const hasClassNameRow = (item) => {
2034
2025
  return typeof item === "object" && item !== null && "classNameRow" in item;
@@ -2057,23 +2048,21 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2057
2048
  : "cwi-chevron-right"}` }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", children: col.render ? col.render(item) : col.dataIndex ? String(item[col.dataIndex] ?? "") : "" }, `${itemKey}_${col.key}`)))] }), expandedRowRender && expandedRowKey === itemKey && (jsxRuntime.jsx("tr", { className: "cw-table-row-expanded", children: jsxRuntime.jsx("td", { colSpan: getColSpan(), children: expandedRowRender(item) }) }))] }, String(itemKey)));
2058
2049
  });
2059
2050
  };
2060
- return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container ${classNameContainer ?? ""}`, style: style, children: [jsxRuntime.jsx("div", { style: scrollContainerStyle, children: jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { style: stickyHeader
2061
- ? { position: "sticky", top: 0, background: "white", zIndex: 2 }
2062
- : undefined, children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map(col => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2063
- ? sortConfig.direction
2064
- : ""}`.trim(), style: {
2065
- cursor: col.sortable ? "pointer" : "default",
2066
- userSelect: "none",
2067
- width: columnWidths[col.key] ?? col.width,
2068
- ...((col.width || columnWidths[col.key]) && {
2069
- minWidth: 50,
2070
- maxWidth: columnWidths[col.key] ?? col.width
2071
- }),
2072
- }, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("span", { children: col.title }), col.sortable && col.dataIndex && (jsxRuntime.jsx(CwIcon, { style: { fontSize: "1.25em" }, iconId: sortConfig.key !== col.dataIndex
2073
- ? "sortable"
2074
- : sortConfig.direction === "asc"
2075
- ? "sortable-asc"
2076
- : "sortable-desc" }))] }), jsxRuntime.jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderTableBody() })] }) }), pagination && data.length > pageSizeOptions[0] && (jsxRuntime.jsxs("footer", { className: "cw-table-pagination", children: [jsxRuntime.jsxs("div", { className: "cw-table-pagination-size", children: [jsxRuntime.jsx(CwIcon, { iconId: "list" }), jsxRuntime.jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsxRuntime.jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxRuntime.jsxs("div", { className: "cw-table-pagination-nav", children: [jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left-double" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left" }), jsxRuntime.jsx("input", { type: "text", inputMode: "numeric", value: currentPage, onChange: (e) => {
2051
+ return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container${stickyHeader || scrollHeight ? " cw-table-scroll" : ""} ${classNameContainer ?? ""}`, style: { ...(scrollHeight ? { "--table-height": typeof scrollHeight === "number" ? `${scrollHeight}px` : scrollHeight } : {}), ...style }, children: [jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map(col => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2052
+ ? sortConfig.direction
2053
+ : ""}`.trim(), style: {
2054
+ cursor: col.sortable ? "pointer" : "default",
2055
+ userSelect: "none",
2056
+ width: columnWidths[col.key] ?? col.width,
2057
+ ...((col.width || columnWidths[col.key]) && {
2058
+ minWidth: 50,
2059
+ maxWidth: columnWidths[col.key] ?? col.width
2060
+ }),
2061
+ }, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("span", { children: col.title }), col.sortable && col.dataIndex && (jsxRuntime.jsx(CwIcon, { style: { fontSize: "1.25em" }, iconId: sortConfig.key !== col.dataIndex
2062
+ ? "sortable"
2063
+ : sortConfig.direction === "asc"
2064
+ ? "sortable-asc"
2065
+ : "sortable-desc" }))] }), jsxRuntime.jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderTableBody() })] }), pagination && data.length > pageSizeOptions[0] && (jsxRuntime.jsxs("footer", { className: "cw-table-pagination", children: [jsxRuntime.jsxs("div", { className: "cw-table-pagination-size", children: [jsxRuntime.jsx(CwIcon, { iconId: "list" }), jsxRuntime.jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsxRuntime.jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxRuntime.jsxs("div", { className: "cw-table-pagination-nav", children: [jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left-double" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left" }), jsxRuntime.jsx("input", { type: "text", inputMode: "numeric", value: currentPage, onChange: (e) => {
2077
2066
  const value = parseInt(e.target.value, 10);
2078
2067
  if (!isNaN(value))
2079
2068
  handlePageChange(value);
@@ -2085,7 +2074,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2085
2074
  }, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2086
2075
  }
2087
2076
 
2088
- var styles$i = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2077
+ var styles$j = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2089
2078
 
2090
2079
  /**
2091
2080
  * Hook that provides state management for CwSortableTable.
@@ -2148,9 +2137,9 @@ function useSortableTable(initialItems) {
2148
2137
  }
2149
2138
 
2150
2139
  // ─── Drop indicator row ───────────────────────────────────────────────────────
2151
- const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$i.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2140
+ const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$j.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2152
2141
  // ─── Loading skeleton ─────────────────────────────────────────────────────────
2153
- const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$i.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$i.skeleton }) }) }, i))) }));
2142
+ const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$j.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$j.skeleton }) }) }, i))) }));
2154
2143
  // ─── Component ────────────────────────────────────────────────────────────────
2155
2144
  /**
2156
2145
  * CwSortableTable
@@ -2237,11 +2226,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2237
2226
  return items.map((item, index) => {
2238
2227
  const key = item[rowKey];
2239
2228
  const isDragging = draggedItem?.[rowKey] === key;
2240
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$i.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2229
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$j.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2241
2230
  });
2242
2231
  };
2243
2232
  // ── Render ──────────────────────────────────────────────────────────────
2244
- return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$i.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2233
+ return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$j.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2245
2234
  }
2246
2235
 
2247
2236
  /**
@@ -2297,7 +2286,7 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2297
2286
  *
2298
2287
  * @returns React component
2299
2288
  */
2300
- function CwTableServerSide({ columns, data, totalItems, pagination = false, pageSizeOptions = [5, 10, 20, 50], expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, rowSelection, onChange, serverState, }) {
2289
+ function CwTableServerSide({ columns, data, totalItems, pagination = false, pageSizeOptions = [5, 10, 20, 50], pageLabel = "page", expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, rowSelection, onChange, serverState, }) {
2301
2290
  const [internalState, setInternalState] = React.useState({
2302
2291
  page: 1,
2303
2292
  pageSize: pageSizeOptions[0],
@@ -2446,10 +2435,10 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2446
2435
  if (isNaN(value) || value < 1 || value > totalPages) {
2447
2436
  handlePageChange(1);
2448
2437
  }
2449
- }, min: 1, max: totalPages }), jsxRuntime.jsxs("span", { children: ["of ", totalPages] }), jsxRuntime.jsx("button", { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right", title: "Next" }), jsxRuntime.jsx("button", { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right-double", title: "Last" }), jsxRuntime.jsx("select", { value: state.pageSize, onChange: handleItemsPerPageChange, children: pageSizeOptions.map((size) => (jsxRuntime.jsxs("option", { value: size, children: [size, " / page"] }, size))) })] }))] }));
2438
+ }, min: 1, max: totalPages }), jsxRuntime.jsxs("span", { children: ["of ", totalPages] }), jsxRuntime.jsx("button", { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right", title: "Next" }), jsxRuntime.jsx("button", { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right-double", title: "Last" }), jsxRuntime.jsx("select", { value: state.pageSize, onChange: handleItemsPerPageChange, children: pageSizeOptions.map((size) => (jsxRuntime.jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }))] }));
2450
2439
  }
2451
2440
 
2452
- var styles$h = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2441
+ var styles$i = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2453
2442
 
2454
2443
  const TabIcon = ({ icon }) => {
2455
2444
  if (!icon)
@@ -2499,7 +2488,7 @@ function CwTabs(CwTabsProps) {
2499
2488
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2500
2489
  ? { minWidth: CwTabsProps.tabsListWidth }
2501
2490
  : undefined;
2502
- return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$h['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$h['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$h['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2491
+ return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$i['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$i['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$i['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2503
2492
  }
2504
2493
 
2505
2494
  /**
@@ -2523,10 +2512,10 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
2523
2512
  onClose?.(ev);
2524
2513
  });
2525
2514
  }, [onClose, onOpen, onToggle]);
2526
- return (jsxRuntime.jsx("div", { className: "cw-expandable", children: jsxRuntime.jsxs("details", { ref: myRef, ...detailsProps, children: [jsxRuntime.jsx("summary", { children: briefing }), children && jsxRuntime.jsx("section", { children: children })] }) }));
2515
+ return (jsxRuntime.jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsxRuntime.jsx("summary", { children: briefing }), children && jsxRuntime.jsx("section", { children: children })] }));
2527
2516
  };
2528
2517
 
2529
- var styles$g = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2518
+ var styles$h = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2530
2519
 
2531
2520
  const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, detailContent, emptyDetail, searchPlaceholder = 'Search...', onSearch, masterHeader, masterFooter, masterWidth: initialWidth = 320, minMasterWidth = 240, maxMasterWidth = 500, resizable = true, showSearch = true, }) => {
2532
2521
  const [masterWidth, setMasterWidth] = React.useState(initialWidth);
@@ -2562,10 +2551,10 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2562
2551
  document.body.style.userSelect = '';
2563
2552
  };
2564
2553
  }, [isResizing, minMasterWidth, maxMasterWidth]);
2565
- const rootClassName = [styles$g['cw-master-detail'], className].filter(Boolean).join(' ');
2566
- return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$g.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$g.detail, children: selectedKey && detailContent
2554
+ const rootClassName = [styles$h['cw-master-detail'], className].filter(Boolean).join(' ');
2555
+ return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$h.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$h.detail, children: selectedKey && detailContent
2567
2556
  ? detailContent
2568
- : (jsxRuntime.jsx("div", { className: styles$g['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2557
+ : (jsxRuntime.jsx("div", { className: styles$h['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2569
2558
  };
2570
2559
 
2571
2560
  /**
@@ -2589,7 +2578,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
2589
2578
  : emptyValue })] }, item.key))) }));
2590
2579
  };
2591
2580
 
2592
- var styles$f = {"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"};
2581
+ var styles$g = {"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"};
2593
2582
 
2594
2583
  function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
2595
2584
  const [draggedItem, setDraggedItem] = React.useState(null);
@@ -2652,15 +2641,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
2652
2641
  }
2653
2642
  };
2654
2643
  if (items.length === 0) {
2655
- return (jsxRuntime.jsx("div", { className: `${styles$f.sortableList} ${styles$f.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$f.emptyMessage, children: emptyMessage }) }));
2644
+ return (jsxRuntime.jsx("div", { className: `${styles$g.sortableList} ${styles$g.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$g.emptyMessage, children: emptyMessage }) }));
2656
2645
  }
2657
- return (jsxRuntime.jsx("div", { className: `${styles$f.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2646
+ return (jsxRuntime.jsx("div", { className: `${styles$g.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2658
2647
  const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
2659
2648
  const isDragging = draggedItem?.id === item.id;
2660
2649
  const isMoved = movedItems.has(item.id);
2661
2650
  const canExpand = Boolean(expandedContent);
2662
2651
  const isExpanded = expandedItems.has(item.id);
2663
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$f.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$f.sortableItem} ${isDragging ? styles$f.dragging : ''} ${isMoved ? styles$f.moved : ''} ${readOnly ? styles$f.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$f.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$f.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$f.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$f.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$f.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$f.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$f.dropIndicator }))] }, item.id));
2652
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$g.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$g.sortableItem} ${isDragging ? styles$g.dragging : ''} ${isMoved ? styles$g.moved : ''} ${readOnly ? styles$g.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$g.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$g.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$g.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$g.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$g.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$g.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$g.dropIndicator }))] }, item.id));
2664
2653
  }) }));
2665
2654
  }
2666
2655
 
@@ -2837,7 +2826,7 @@ function CwFileUpload(fileUploadProps) {
2837
2826
  return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "row", children: [jsxRuntime.jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsxRuntime.jsx("div", { className: "row error", children: error }), jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
2838
2827
  }
2839
2828
 
2840
- var styles$e = {"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"};
2829
+ var styles$f = {"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"};
2841
2830
 
2842
2831
  const DEFAULT_LABELS = {
2843
2832
  uploadDisabled: 'Upload disabled',
@@ -3004,12 +2993,12 @@ function CwFileUploadMultiple(fileUploadProps) {
3004
2993
  }
3005
2994
  }
3006
2995
  };
3007
- return (jsxRuntime.jsxs("div", { className: `${styles$e.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$e.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$e.uploadArea} ${fileUploadProps.disabled ? styles$e.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$e.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$e.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$e.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$e.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$e.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$e.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$e.fileInfo, children: jsxRuntime.jsx("p", { className: styles$e.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
2996
+ return (jsxRuntime.jsxs("div", { className: `${styles$f.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$f.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$f.uploadArea} ${fileUploadProps.disabled ? styles$f.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$f.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$f.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$f.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$f.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$f.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$f.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$f.fileInfo, children: jsxRuntime.jsx("p", { className: styles$f.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3008
2997
  setExistingFile(undefined);
3009
2998
  if (fileUploadProps.onSelect) {
3010
2999
  fileUploadProps.onSelect(null);
3011
3000
  }
3012
- }, disabled: fileUploadProps.disabled, className: styles$e.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$e.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("small", { className: styles$e.filesCount, children: labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$e.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$e.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$e.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$e.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$e.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$e.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$e.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3001
+ }, disabled: fileUploadProps.disabled, className: styles$f.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$f.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("small", { className: styles$f.filesCount, children: labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$f.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$f.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$f.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$f.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$f.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$f.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$f.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3013
3002
  }
3014
3003
 
3015
3004
  function CwInput(CwInputProps) {
@@ -3050,7 +3039,7 @@ function CwDigit(props) {
3050
3039
  return (jsxRuntime.jsx("div", { className: "cw-input-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsx("input", { type: "number", ...inputProps }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3051
3040
  }
3052
3041
 
3053
- var styles$d = {"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"};
3042
+ var styles$e = {"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"};
3054
3043
 
3055
3044
  const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
3056
3045
  const [rgb, setRgb] = React.useState({ r: 255, g: 255, b: 255 });
@@ -3253,13 +3242,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
3253
3242
  // Calculate background color for the main area based on current hue
3254
3243
  const hueColor = hsvToRgb(hsv.h, 100, 100);
3255
3244
  const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
3256
- return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$d.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$d.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$d.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$d.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$d.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$d.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$d.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$d.whiteGradient }), jsxRuntime.jsx("div", { className: styles$d.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$d.colorAreaCursor, style: {
3245
+ return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$e.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$e.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$e.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$e.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$e.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$e.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$e.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$e.whiteGradient }), jsxRuntime.jsx("div", { className: styles$e.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$e.colorAreaCursor, style: {
3257
3246
  left: `${hsv.s}%`,
3258
3247
  top: `${100 - hsv.v}%`
3259
3248
  } })] })] })] }));
3260
3249
  };
3261
3250
 
3262
- var styles$c = {"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"};
3251
+ var styles$d = {"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"};
3263
3252
 
3264
3253
  const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
3265
3254
  const [isOpen, setIsOpen] = React.useState(false);
@@ -3392,11 +3381,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
3392
3381
  break;
3393
3382
  }
3394
3383
  };
3395
- return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$c.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$c.selectColor} ${disabled ? styles$c.disabled : ''} ${readOnly ? styles$c.readOnly : ''}`, style: {
3384
+ return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$d.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$d.selectColor} ${disabled ? styles$d.disabled : ''} ${readOnly ? styles$d.readOnly : ''}`, style: {
3396
3385
  width,
3397
3386
  height,
3398
3387
  backgroundColor: value,
3399
- }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$c.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3388
+ }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$d.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3400
3389
  };
3401
3390
 
3402
3391
  /**
@@ -4037,7 +4026,7 @@ const CwImageArea = React.forwardRef((props, ref) => {
4037
4026
  });
4038
4027
  CwImageArea.displayName = "CwImageArea";
4039
4028
 
4040
- var styles$b = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4029
+ var styles$c = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4041
4030
 
4042
4031
  /**
4043
4032
  * This class represents a week where days can be selected or unselected
@@ -4177,15 +4166,15 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4177
4166
  setSelectedDays(newWeekdays);
4178
4167
  onChange?.(newWeekdays.toString());
4179
4168
  };
4180
- return (jsxRuntime.jsx("div", { className: styles$b["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4169
+ return (jsxRuntime.jsx("div", { className: styles$c["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4181
4170
  };
4182
4171
 
4183
- var styles$a = {"check-container":"cw-check-module__check-container__4nscZ","checkbox-group-container":"cw-check-module__checkbox-group-container__WMNbG"};
4172
+ var styles$b = {"check-container":"cw-check-module__check-container__4nscZ","checkbox-group-container":"cw-check-module__checkbox-group-container__WMNbG"};
4184
4173
 
4185
4174
  function CwCheck(props) {
4186
4175
  const { labelProps, labelText, iconProps, alignment = "row", className, ...inputProps } = props;
4187
4176
  const displayText = labelText || labelProps?.text;
4188
- return (jsxRuntime.jsx("div", { className: `cw-check ${styles$a["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": alignment, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsxs("span", { className: "cw-icon-text", children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), displayText] }))] }) }));
4177
+ return (jsxRuntime.jsx("div", { className: `cw-check ${styles$b["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": alignment, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsxs("span", { className: "cw-icon-text", children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), displayText] }))] }) }));
4189
4178
  }
4190
4179
 
4191
4180
  function CwCheckbox(CwCheckboxProps) {
@@ -4217,7 +4206,7 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, alignProps
4217
4206
  : [];
4218
4207
  const flexDirection = alignProps?.flexDirection ?? "row";
4219
4208
  const dataDirection = { 'data-direction': flexDirection };
4220
- return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$a["checkbox-group-container"]}${className ? ` ${className}` : ''}`, ...dataDirection, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: `${optionsAlignment === "row" ? "cw-flex-column cw-gap-small" : "cw-flex-row cw-flex-wrap"}`, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelText: option.label, checked: value.includes(option.value), disabled: disabled || option.disabled, alignment: optionsAlignment, onChange: (e) => handleChange(option.value, e.target.checked) }, option.value))) })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4209
+ return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$b["checkbox-group-container"]}${className ? ` ${className}` : ''}`, ...dataDirection, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: `${optionsAlignment === "row" ? "cw-flex-column cw-gap-small" : "cw-flex-row cw-flex-wrap"}`, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelText: option.label, checked: value.includes(option.value), disabled: disabled || option.disabled, alignment: optionsAlignment, onChange: (e) => handleChange(option.value, e.target.checked) }, option.value))) })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4221
4210
  }
4222
4211
 
4223
4212
  function CwToggle(props) {
@@ -4235,13 +4224,16 @@ function CwToggle(props) {
4235
4224
  * @example
4236
4225
  * <CwSelect>
4237
4226
  * <CwOption>A</CwOption>
4238
- * <CwOption>B</CwOption>
4227
+ * <CwOption color="#4a90d9">Blue option</CwOption>
4239
4228
  * <CwOption>C</CwOption>
4240
4229
  * </CwSelect>
4241
4230
  */
4242
4231
  function CwOption(props) {
4243
- const { text, ...optionProps } = props;
4244
- return (jsxRuntime.jsx("option", { className: "cw-option", ...optionProps, children: optionProps.children ?? text }));
4232
+ const { text, color, style, ...optionProps } = props;
4233
+ const mergedStyle = color
4234
+ ? { ...style, backgroundColor: color, color: getContrastColor(color) }
4235
+ : style;
4236
+ return (jsxRuntime.jsx("option", { className: "cw-option", style: mergedStyle, ...optionProps, children: optionProps.children ?? text }));
4245
4237
  }
4246
4238
 
4247
4239
  /**
@@ -4275,7 +4267,248 @@ function CwSelect(props) {
4275
4267
  : [];
4276
4268
  const flexDirection = alignProps?.flexDirection ?? "row";
4277
4269
  const dataDirection = { 'data-direction': flexDirection };
4278
- return (jsxRuntime.jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: style, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxRuntime.jsxs("select", { ...selectProps, children: [placeholder && jsxRuntime.jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-type": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4270
+ const { backgroundColor, color: textColor, ...wrapperStyle } = style ?? {};
4271
+ return (jsxRuntime.jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: wrapperStyle, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxRuntime.jsxs("select", { ...selectProps, style: backgroundColor ? { backgroundColor, color: textColor } : undefined, children: [placeholder && jsxRuntime.jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4272
+ }
4273
+
4274
+ // ─── Default strategy: below anchor, match width, flip above if needed ────────
4275
+ function defaultPositionStrategy(anchorRect, panelRect) {
4276
+ const panelH = panelRect?.height ?? 200;
4277
+ const spaceBelow = window.innerHeight - anchorRect.bottom;
4278
+ const top = spaceBelow >= panelH + 4
4279
+ ? anchorRect.bottom + 4
4280
+ : Math.max(4, anchorRect.top - panelH);
4281
+ const width = anchorRect.width;
4282
+ const left = Math.max(4, Math.min(anchorRect.left, window.innerWidth - width - 4));
4283
+ return { top, left, width };
4284
+ }
4285
+ // ─── Hook ─────────────────────────────────────────────────────────────────────
4286
+ /**
4287
+ * Generic portal-based dropdown panel hook.
4288
+ *
4289
+ * Renders the panel as a direct child of `<body>` via `createPortal` so it
4290
+ * escapes any `overflow: hidden/auto` ancestor (dialogs, tabs, cards, etc.).
4291
+ * Positions the panel with `position: fixed` computed from the anchor element's
4292
+ * `getBoundingClientRect()`, and repositions on scroll and resize.
4293
+ *
4294
+ * The fix pattern is the same as {@link usePickerPopup} used by `CwDatePicker`.
4295
+ *
4296
+ * > **Future migration note:** Once the project's minimum browser baseline
4297
+ * > reaches Firefox 147 / Safari 26 (CSS Anchor Positioning — Baseline 2026),
4298
+ * > this hook can be replaced with `popover="manual"` + CSS `anchor()` with
4299
+ * > zero JS positioning.
4300
+ *
4301
+ * @example
4302
+ * ```tsx
4303
+ * const wrapperRef = useRef<HTMLDivElement>(null);
4304
+ * const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4305
+ * anchorRef: wrapperRef,
4306
+ * isOpen,
4307
+ * onClose: () => setIsOpen(false),
4308
+ * });
4309
+ *
4310
+ * return (
4311
+ * <div ref={wrapperRef}>
4312
+ * <input ... />
4313
+ * {renderPanel(
4314
+ * <div ref={panelRef} style={panelStyle} className={styles.dropdown}>
4315
+ * {options}
4316
+ * </div>
4317
+ * )}
4318
+ * </div>
4319
+ * );
4320
+ * ```
4321
+ */
4322
+ function useDropdownPortal({ anchorRef, isOpen, onClose, positionStrategy = defaultPositionStrategy, }) {
4323
+ const panelRef = React.useRef(null);
4324
+ const [style, setStyle] = React.useState({
4325
+ position: "fixed",
4326
+ top: 0,
4327
+ left: 0,
4328
+ width: "auto",
4329
+ zIndex: 1000,
4330
+ right: "auto",
4331
+ marginLeft: 0,
4332
+ });
4333
+ const reposition = React.useCallback(() => {
4334
+ const anchor = anchorRef.current;
4335
+ if (!anchor)
4336
+ return;
4337
+ const anchorRect = anchor.getBoundingClientRect();
4338
+ const panelRect = panelRef.current?.getBoundingClientRect() ?? null;
4339
+ const { top, left, width } = positionStrategy(anchorRect, panelRect);
4340
+ setStyle({
4341
+ position: "fixed",
4342
+ top,
4343
+ left,
4344
+ width: width ?? "auto",
4345
+ zIndex: 1000,
4346
+ right: "auto",
4347
+ marginLeft: 0,
4348
+ });
4349
+ }, [anchorRef, positionStrategy]);
4350
+ // Reposition when opened; re-measure after first paint to get real panel size
4351
+ React.useEffect(() => {
4352
+ if (!isOpen)
4353
+ return;
4354
+ reposition();
4355
+ const raf = requestAnimationFrame(reposition);
4356
+ const handleUpdate = () => reposition();
4357
+ window.addEventListener("resize", handleUpdate);
4358
+ // Capture phase catches scroll on all scrollable ancestors
4359
+ window.addEventListener("scroll", handleUpdate, true);
4360
+ return () => {
4361
+ cancelAnimationFrame(raf);
4362
+ window.removeEventListener("resize", handleUpdate);
4363
+ window.removeEventListener("scroll", handleUpdate, true);
4364
+ };
4365
+ }, [isOpen, reposition]);
4366
+ // Close when the anchor scrolls out of view in any overflow container
4367
+ React.useEffect(() => {
4368
+ if (!isOpen)
4369
+ return;
4370
+ const anchor = anchorRef.current;
4371
+ if (!anchor)
4372
+ return;
4373
+ const observer = new IntersectionObserver(([entry]) => { if (!entry.isIntersecting)
4374
+ onClose(); }, { threshold: 0 });
4375
+ observer.observe(anchor);
4376
+ return () => observer.disconnect();
4377
+ }, [isOpen, anchorRef, onClose]);
4378
+ // Close on outside click (anchor + panel are both considered "inside")
4379
+ React.useEffect(() => {
4380
+ if (!isOpen)
4381
+ return;
4382
+ const handleMouseDown = (e) => {
4383
+ const target = e.target;
4384
+ if (anchorRef.current?.contains(target) || panelRef.current?.contains(target))
4385
+ return;
4386
+ onClose();
4387
+ };
4388
+ document.addEventListener("mousedown", handleMouseDown);
4389
+ return () => document.removeEventListener("mousedown", handleMouseDown);
4390
+ }, [isOpen, onClose, anchorRef, panelRef]);
4391
+ const renderPanel = React.useCallback((children) => {
4392
+ if (!isOpen)
4393
+ return null;
4394
+ return reactDom.createPortal(children, document.body);
4395
+ }, [isOpen]);
4396
+ return { panelRef, panelStyle: style, renderPanel };
4397
+ }
4398
+
4399
+ var dropdownStyles = {"dropdown":"cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-choice-dropdown-module__optionFocused__BYMxj","optionSelected":"cw-choice-dropdown-module__optionSelected__Lt8Xg","optionDisabled":"cw-choice-dropdown-module__optionDisabled__n3scM","searchBox":"cw-choice-dropdown-module__searchBox__0gox7","searchInput":"cw-choice-dropdown-module__searchInput__G5oRs","emptyState":"cw-choice-dropdown-module__emptyState__HO0Y7","colorCircle":"cw-choice-dropdown-module__colorCircle__x7mI9"};
4400
+
4401
+ /**
4402
+ * Custom dropdown component with colour-coded options, optional search filter, and full
4403
+ * keyboard navigation (↑ ↓ Enter Esc Tab).
4404
+ *
4405
+ * Use `CwDropdown` instead of the native `<select>` when options need colour indicators or
4406
+ * when inline search filtering is required.
4407
+ *
4408
+ * @example
4409
+ * <CwDropdown
4410
+ * options={[{ value: 'a', label: 'Option A', color: '#1976D2' }]}
4411
+ * value={selected}
4412
+ * onChange={setSelected}
4413
+ * labelProps={{ text: 'My Label' }}
4414
+ * />
4415
+ */
4416
+ function CwDropdown({ options, value, onChange, labelProps, alignProps, placeholder = "Select...", allowSearch = false, disabled = false, required = false, feedback, className, style, ...otherProps }) {
4417
+ const [isOpen, setIsOpen] = React.useState(false);
4418
+ const [searchText, setSearchText] = React.useState("");
4419
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
4420
+ const containerRef = React.useRef(null);
4421
+ const wrapperRef = React.useRef(null);
4422
+ const inputRef = React.useRef(null);
4423
+ const highlightedItemRef = React.useRef(null);
4424
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4425
+ anchorRef: wrapperRef,
4426
+ isOpen,
4427
+ onClose: () => { setIsOpen(false); setSearchText(""); setHighlightedIndex(-1); },
4428
+ });
4429
+ const selectedOption = options.find(opt => opt.value === value);
4430
+ // Filter options based on search
4431
+ const filteredOptions = searchText
4432
+ ? options.filter(opt => opt.label.toLowerCase().includes(searchText.toLowerCase()))
4433
+ : options;
4434
+ // Feedback handling
4435
+ const feedbackMessages = feedback
4436
+ ? Array.isArray(feedback) ? feedback : [feedback]
4437
+ : [];
4438
+ // Scroll highlighted item into view
4439
+ React.useEffect(() => {
4440
+ if (isOpen && highlightedItemRef.current) {
4441
+ highlightedItemRef.current.scrollIntoView({
4442
+ block: "nearest",
4443
+ behavior: "smooth",
4444
+ });
4445
+ }
4446
+ }, [highlightedIndex, isOpen]);
4447
+ const handleTriggerClick = React.useCallback(() => {
4448
+ if (!disabled) {
4449
+ setIsOpen(!isOpen);
4450
+ setHighlightedIndex(-1);
4451
+ if (!isOpen && allowSearch) {
4452
+ setTimeout(() => inputRef.current?.focus(), 0);
4453
+ }
4454
+ }
4455
+ }, [isOpen, disabled, allowSearch]);
4456
+ const handleOptionSelect = React.useCallback((optionValue) => {
4457
+ const selected = options.find(opt => opt.value === optionValue);
4458
+ if (selected && !selected.disabled) {
4459
+ onChange?.(optionValue);
4460
+ setIsOpen(false);
4461
+ setSearchText("");
4462
+ setHighlightedIndex(-1);
4463
+ }
4464
+ }, [options, onChange]);
4465
+ const handleSearchChange = React.useCallback((e) => {
4466
+ setSearchText(e.target.value);
4467
+ setHighlightedIndex(-1);
4468
+ }, []);
4469
+ const handleKeyDown = React.useCallback((e) => {
4470
+ if (!isOpen) {
4471
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
4472
+ e.preventDefault();
4473
+ setIsOpen(true);
4474
+ }
4475
+ return;
4476
+ }
4477
+ switch (e.key) {
4478
+ case "ArrowDown":
4479
+ e.preventDefault();
4480
+ setHighlightedIndex(prev => prev < filteredOptions.length - 1 ? prev + 1 : 0);
4481
+ break;
4482
+ case "ArrowUp":
4483
+ e.preventDefault();
4484
+ setHighlightedIndex(prev => prev > 0 ? prev - 1 : filteredOptions.length - 1);
4485
+ break;
4486
+ case "Enter":
4487
+ e.preventDefault();
4488
+ if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {
4489
+ handleOptionSelect(filteredOptions[highlightedIndex].value);
4490
+ }
4491
+ break;
4492
+ case "Escape":
4493
+ e.preventDefault();
4494
+ setIsOpen(false);
4495
+ setSearchText("");
4496
+ setHighlightedIndex(-1);
4497
+ break;
4498
+ case "Tab":
4499
+ setIsOpen(false);
4500
+ setSearchText("");
4501
+ setHighlightedIndex(-1);
4502
+ break;
4503
+ }
4504
+ }, [isOpen, highlightedIndex, filteredOptions, handleOptionSelect]);
4505
+ const flexDirection = alignProps?.flexDirection ?? "row";
4506
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": selectedOption?.label || placeholder, children: jsxRuntime.jsx("div", { className: "cw-dropdown-trigger-content", children: selectedOption ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [selectedOption.color && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsxRuntime.jsx("span", { children: selectedOption.label })] })) : (jsxRuntime.jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }) }), jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", paddingRight: "0.5rem", flexShrink: 0, cursor: disabled ? "not-allowed" : "pointer" }, onClick: handleTriggerClick, children: jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small" }) }), renderPanel(jsxRuntime.jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsxRuntime.jsx("div", { className: dropdownStyles.searchBox, children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsxRuntime.jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxRuntime.jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4507
+ dropdownStyles.option,
4508
+ value === option.value ? dropdownStyles.optionSelected : "",
4509
+ highlightedIndex === index ? dropdownStyles.optionFocused : "",
4510
+ option.disabled ? dropdownStyles.optionDisabled : "",
4511
+ ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsxRuntime.jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsxRuntime.jsx("span", { children: option.label })] }, option.value)))) : (jsxRuntime.jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] })] }), feedbackMessages.map((item, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": item.type, children: item.message }, index)))] }));
4279
4512
  }
4280
4513
 
4281
4514
  function CwDropdownFilter(props) {
@@ -4288,7 +4521,7 @@ function CwDropdownFilter(props) {
4288
4521
  return (jsxRuntime.jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsxRuntime.jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsxRuntime.jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsxRuntime.jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
4289
4522
  }
4290
4523
 
4291
- var styles$9 = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4524
+ var styles$a = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4292
4525
 
4293
4526
  /**
4294
4527
  * Button that toggles a floating panel with arbitrary children.
@@ -4335,7 +4568,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4335
4568
  }
4336
4569
  panel.togglePopover();
4337
4570
  }, [placement]);
4338
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$9.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$9.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4571
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$a.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$a.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4339
4572
  }
4340
4573
 
4341
4574
  function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
@@ -4353,13 +4586,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
4353
4586
  return result;
4354
4587
  }
4355
4588
 
4356
- var styles$8 = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4589
+ var styles$9 = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4357
4590
 
4358
4591
  const CwMultiFilterTag = props => {
4359
4592
  const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
4360
4593
  const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
4361
4594
  const isOutlineMode = Selected && !Removable;
4362
- return (jsxRuntime.jsx("li", { className: styles$8["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4595
+ return (jsxRuntime.jsx("li", { className: styles$9["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4363
4596
  if (Selectable)
4364
4597
  props.OnSelect?.(props);
4365
4598
  }, children: jsxRuntime.jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
@@ -4369,7 +4602,7 @@ const CwMultiFilterTag = props => {
4369
4602
  } : undefined }) }));
4370
4603
  };
4371
4604
 
4372
- var styles$7 = {"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"};
4605
+ var styles$8 = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
4373
4606
 
4374
4607
  /**
4375
4608
  * A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
@@ -4517,19 +4750,14 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4517
4750
  const [selectedCategory, setSelectedCategory] = React.useState("All");
4518
4751
  const componentRef = React.useRef(null);
4519
4752
  const inputRef = React.useRef(null);
4753
+ const wrapperRef = React.useRef(null);
4754
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4755
+ anchorRef: wrapperRef,
4756
+ isOpen: isPanelOpen,
4757
+ onClose: () => { setIsPanelOpen(false); setFilteredTags(getUnselectedAll()); setSelectedCategory("All"); setInputTextValue(""); },
4758
+ });
4520
4759
  React.useEffect(() => {
4521
- function handleClickOutside(event) {
4522
- if (componentRef.current && !componentRef.current.contains(event.target)) {
4523
- setIsPanelOpen(false);
4524
- setFilteredTags(new Set());
4525
- setSelectedCategory("All");
4526
- setInputTextValue("");
4527
- }
4528
- }
4529
- document.addEventListener("mousedown", handleClickOutside);
4530
- return () => {
4531
- document.removeEventListener("mousedown", handleClickOutside);
4532
- };
4760
+ // Outside-click is now handled by useDropdownPortal
4533
4761
  }, []);
4534
4762
  const categoriesMappedToTags = () => {
4535
4763
  const categoriesMap = new Map();
@@ -4540,9 +4768,10 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4540
4768
  });
4541
4769
  return categoriesMap;
4542
4770
  };
4771
+ const getUnselectedAll = (excluded = selectedTags) => new Set(Array.from(allTags).filter(tag => !Array.from(excluded).some(t => t.ID === tag.ID)));
4543
4772
  const handleClickCategory = (category) => {
4544
4773
  setSelectedCategory(category);
4545
- setFilteredTags(category != "All" ? (categoriesMappedToTags().get(category) ?? new Set()) : new Set());
4774
+ setFilteredTags(category !== "All" ? (categoriesMappedToTags().get(category) ?? new Set()) : getUnselectedAll());
4546
4775
  };
4547
4776
  const rgbAString = (r, g, b) => {
4548
4777
  return `rgb(${r}, ${g}, ${b})`;
@@ -4574,7 +4803,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4574
4803
  setFilteredTags(new Set(newFilterTags));
4575
4804
  }
4576
4805
  else {
4577
- setFilteredTags(new Set());
4806
+ setFilteredTags(getUnselectedAll());
4578
4807
  }
4579
4808
  };
4580
4809
  const addTag = (newTag) => {
@@ -4588,7 +4817,13 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4588
4817
  const updatedTags = new Set(selectedTags).add(newTag);
4589
4818
  onChangeSelectedTags(updatedTags);
4590
4819
  setInputTextValue("");
4591
- //setFilteredTags(allTags);
4820
+ setFilteredTags(selectedCategory === "All" ? getUnselectedAll(updatedTags) : prev => {
4821
+ const next = new Set(prev);
4822
+ const toRemove = Array.from(next).find(t => t.ID === newTag.ID);
4823
+ if (toRemove)
4824
+ next.delete(toRemove);
4825
+ return next;
4826
+ });
4592
4827
  }
4593
4828
  };
4594
4829
  const removeTag = (id) => {
@@ -4612,9 +4847,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4612
4847
  inputRef.current?.focus();
4613
4848
  }
4614
4849
  };
4615
- return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$7["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4850
+ return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$8["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4616
4851
  e.preventDefault();
4617
- }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, className: styles$7["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-primary)", outlineOffset: "-2px" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.target.value), autoComplete: "off", placeholder: placeholder, onKeyDown: e => {
4852
+ }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$8["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4618
4853
  switch (e.key) {
4619
4854
  case "Enter":
4620
4855
  case "Tab": {
@@ -4641,21 +4876,10 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4641
4876
  break;
4642
4877
  }
4643
4878
  }
4644
- } })] }), selectedTags.size > 0 ? (jsxRuntime.jsx("input", { type: "reset", value: "\u00D7", onClick: e => {
4645
- e.preventDefault();
4646
- onChangeSelectedTags(new Set());
4647
- } })) : null] }), jsxRuntime.jsxs("section", { className: styles$7["cw-multi-filter-catalog-container"], "data-display-none": !isPanelOpen, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$7["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { style: selectedCategory === category
4648
- ? {
4649
- backgroundColor: getColor(category).primary,
4650
- color: getColor(category).onPrimary,
4651
- outline: "2px solid " + getColor(category).onPrimary,
4652
- outlineOffset: "-2px",
4653
- fontWeight: 400
4654
- }
4655
- : {
4656
- backgroundColor: getColor(category).primary,
4657
- color: getColor(category).onPrimary,
4658
- }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsxRuntime.jsx("ul", { children: Array.from(filteredTags)
4879
+ } })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$8["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$8["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$8["category-selected"] : undefined, style: {
4880
+ backgroundColor: getColor(category).primary,
4881
+ color: getColor(category).onPrimary,
4882
+ }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsxRuntime.jsx("ul", { children: Array.from(filteredTags)
4659
4883
  .sort((a, b) => {
4660
4884
  const input = inputTextValue.trim().toLowerCase();
4661
4885
  const aName = a.Name.trim().toLowerCase();
@@ -4675,9 +4899,148 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4675
4899
  removeTag(props.ID);
4676
4900
  else
4677
4901
  addTag(props);
4678
- } }, props.ID))) })] })] }));
4902
+ } }, props.ID))) })] }))] }));
4679
4903
  };
4680
4904
 
4905
+ var styles$7 = {"container":"cw-tag-selector-module__container__-do8i","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
4906
+
4907
+ /**
4908
+ * Multi-select input with chip tags and searchable dropdown.
4909
+ * Works like a Kendo MultiSelect: selected items appear as removable chips
4910
+ * inside the input area, and a filtered dropdown lets the user pick more.
4911
+ *
4912
+ * @example
4913
+ * ```tsx
4914
+ * const options = [
4915
+ * { value: "1", label: "Alpha" },
4916
+ * { value: "2", label: "Bravo" },
4917
+ * { value: "3", label: "Charlie" },
4918
+ * ];
4919
+ * const [selected, setSelected] = useState<string[]>([]);
4920
+ *
4921
+ * <CwTagSelector
4922
+ * labelProps={{ text: "Tags" }}
4923
+ * options={options}
4924
+ * value={selected}
4925
+ * onChange={setSelected}
4926
+ * placeholder="Select items…"
4927
+ * />
4928
+ * ```
4929
+ */
4930
+ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, alignProps, placeholder = "Select…", disabled = false, showSelectAll = false, feedback, className, style, }) {
4931
+ const [search, setSearch] = React.useState("");
4932
+ const [open, setOpen] = React.useState(false);
4933
+ const [focusedIndex, setFocusedIndex] = React.useState(-1);
4934
+ const containerRef = React.useRef(null);
4935
+ const inputBoxRef = React.useRef(null);
4936
+ const inputRef = React.useRef(null);
4937
+ const listRef = React.useRef(null);
4938
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4939
+ anchorRef: inputBoxRef,
4940
+ isOpen: open,
4941
+ onClose: () => { setOpen(false); setFocusedIndex(-1); },
4942
+ });
4943
+ const selectedSet = React.useMemo(() => new Set(value), [value]);
4944
+ const filtered = React.useMemo(() => {
4945
+ if (!search)
4946
+ return options.filter(o => !selectedSet.has(o.value));
4947
+ const lower = search.toLowerCase();
4948
+ return options.filter(o => !selectedSet.has(o.value) && o.label.toLowerCase().includes(lower));
4949
+ }, [options, selectedSet, search]);
4950
+ const selectedOptions = React.useMemo(() => value.map(v => options.find(o => o.value === v)).filter(Boolean), [value, options]);
4951
+ const handleSelect = React.useCallback((optionValue) => {
4952
+ onChange([...value, optionValue]);
4953
+ setSearch("");
4954
+ setFocusedIndex(-1);
4955
+ inputRef.current?.focus();
4956
+ }, [value, onChange]);
4957
+ const handleRemove = React.useCallback((optionValue) => {
4958
+ onChange(value.filter(v => v !== optionValue));
4959
+ inputRef.current?.focus();
4960
+ }, [value, onChange]);
4961
+ const allSelected = options.length > 0 && options.every(o => selectedSet.has(o.value));
4962
+ const handleToggleAll = React.useCallback(() => {
4963
+ if (allSelected) {
4964
+ onChange([]);
4965
+ }
4966
+ else {
4967
+ onChange(options.map(o => o.value));
4968
+ }
4969
+ setSearch("");
4970
+ setFocusedIndex(-1);
4971
+ inputRef.current?.focus();
4972
+ }, [allSelected, options, onChange]);
4973
+ const handleInputChange = React.useCallback((e) => {
4974
+ setSearch(e.currentTarget.value);
4975
+ if (!open)
4976
+ setOpen(true);
4977
+ setFocusedIndex(-1);
4978
+ }, [open]);
4979
+ const handleInputFocus = React.useCallback(() => {
4980
+ if (!disabled)
4981
+ setOpen(true);
4982
+ }, [disabled]);
4983
+ const handleKeyDown = React.useCallback((e) => {
4984
+ if (e.key === "Backspace" && !search && value.length > 0) {
4985
+ onChange(value.slice(0, -1));
4986
+ return;
4987
+ }
4988
+ if (e.key === "Escape") {
4989
+ setOpen(false);
4990
+ setFocusedIndex(-1);
4991
+ return;
4992
+ }
4993
+ if (e.key === "Enter") {
4994
+ e.preventDefault();
4995
+ if (focusedIndex >= 0 && focusedIndex < filtered.length) {
4996
+ handleSelect(filtered[focusedIndex].value);
4997
+ }
4998
+ else if (search.trim().length > 0 && filtered.length > 0) {
4999
+ const lower = search.trim().toLowerCase();
5000
+ const match = filtered.find(o => o.label.trim().toLowerCase() === lower) ??
5001
+ filtered.find(o => o.label.trim().toLowerCase().startsWith(lower)) ??
5002
+ filtered[0];
5003
+ if (match)
5004
+ handleSelect(match.value);
5005
+ }
5006
+ else if (!open) {
5007
+ setOpen(true);
5008
+ setFocusedIndex(0);
5009
+ }
5010
+ return;
5011
+ }
5012
+ if (!open) {
5013
+ if (e.key === "ArrowDown") {
5014
+ setOpen(true);
5015
+ setFocusedIndex(0);
5016
+ e.preventDefault();
5017
+ }
5018
+ return;
5019
+ }
5020
+ if (e.key === "ArrowDown") {
5021
+ e.preventDefault();
5022
+ setFocusedIndex(prev => (prev < filtered.length - 1 ? prev + 1 : prev));
5023
+ }
5024
+ else if (e.key === "ArrowUp") {
5025
+ e.preventDefault();
5026
+ setFocusedIndex(prev => (prev > 0 ? prev - 1 : 0));
5027
+ }
5028
+ }, [open, search, value, filtered, focusedIndex, onChange, handleSelect]);
5029
+ // Scroll focused item into view
5030
+ React.useEffect(() => {
5031
+ if (focusedIndex >= 0 && listRef.current) {
5032
+ const item = listRef.current.children[focusedIndex];
5033
+ item?.scrollIntoView({ block: "nearest" });
5034
+ }
5035
+ }, [focusedIndex]);
5036
+ // Close on outside click — now handled by useDropdownPortal
5037
+ // Keeping containerRef for any other potential use
5038
+ const direction = alignProps?.flexDirection ?? "row";
5039
+ const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
5040
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$7.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: `${styles$7.inputBox}${disabled ? ` ${styles$7.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5041
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$7.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$7.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.jsxs("li", { className: `${styles$7.option}${idx === focusedIndex ? ` ${styles$7.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsxRuntime.jsx("span", { className: styles$7.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5042
+ }
5043
+
4681
5044
  var styles$6 = {"tree-container":"cw-tree-view-module__tree-container__NN-HJ","tree-wrapper":"cw-tree-view-module__tree-wrapper__keBZI","tree-item":"cw-tree-view-module__tree-item__prE9N","tree-node":"cw-tree-view-module__tree-node__wfro9","selected":"cw-tree-view-module__selected__XJQ0w","non-selectable":"cw-tree-view-module__non-selectable__YuPSx","tree-children":"cw-tree-view-module__tree-children__ji8CZ","empty-state":"cw-tree-view-module__empty-state__yvRjo","tree-label":"cw-tree-view-module__tree-label__ss3Nf","tree-spacer":"cw-tree-view-module__tree-spacer__E9Ud2"};
4682
5045
 
4683
5046
  function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
@@ -4784,12 +5147,30 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
4784
5147
  return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$6["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$6["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$6["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
4785
5148
  }
4786
5149
 
5150
+ /**
5151
+ * Text input with a live-filtered suggestion dropdown backed by a local `CwSelectList` array.
5152
+ * Use `CwFindAirport` or `CwFindCrewmember` for API-backed search inputs.
5153
+ *
5154
+ * @example
5155
+ * <CwSearchInput
5156
+ * selectList={myItems}
5157
+ * handleChange={(id) => console.log('selected', id)}
5158
+ * labelProps={{ text: 'Employee' }}
5159
+ * placeholder="Search by name…"
5160
+ * />
5161
+ */
4787
5162
  function CwSearchInput(optionsProps) {
4788
5163
  const [searchText, setSearchText] = React.useState("");
4789
5164
  const [filteredOptions, setFilteredOptions] = React.useState([]);
4790
5165
  const [_selectedOption, setSelectedOption] = React.useState(null);
4791
5166
  const [showDropdown, setShowDropdown] = React.useState(false);
4792
5167
  const [isLoading, setIsLoading] = React.useState(false);
5168
+ const wrapperRef = React.useRef(null);
5169
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5170
+ anchorRef: wrapperRef,
5171
+ isOpen: showDropdown && filteredOptions.length > 0,
5172
+ onClose: () => setShowDropdown(false),
5173
+ });
4793
5174
  // Extract props
4794
5175
  const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
4795
5176
  // Get direction for data attribute
@@ -4840,9 +5221,8 @@ function CwSearchInput(optionsProps) {
4840
5221
  }
4841
5222
  };
4842
5223
  const handleInputBlur = () => {
4843
- setTimeout(() => {
4844
- setShowDropdown(false);
4845
- }, 150);
5224
+ // Dropdown is closed by useDropdownPortal's outside-click handler.
5225
+ // Blur alone must not close it — clicking an option would lose focus before the click fires.
4846
5226
  };
4847
5227
  const handleOptionSelect = (option) => {
4848
5228
  setSearchText(option.description);
@@ -4860,7 +5240,7 @@ function CwSearchInput(optionsProps) {
4860
5240
  handleChange("");
4861
5241
  }
4862
5242
  };
4863
- return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", children: [jsxRuntime.jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), showDropdown && filteredOptions.length > 0 && (jsxRuntime.jsx("div", { className: "cw-input-search-dropdown", children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option) => (jsxRuntime.jsx("li", { onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5243
+ return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option) => (jsxRuntime.jsx("li", { className: dropdownStyles.option, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
4864
5244
  }
4865
5245
 
4866
5246
  var styles$5 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
@@ -5117,81 +5497,49 @@ var styles$4 = {"pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","
5117
5497
  /**
5118
5498
  * Renders a picker popup in a portal so it escapes overflow containers.
5119
5499
  * Positions itself relative to the anchor element.
5500
+ *
5501
+ * Thin wrapper around {@link useDropdownPortal} that adds directional
5502
+ * preference logic ("left-bottom", "right-top", etc.) for calendar popups.
5503
+ * The public API is unchanged — existing callers (`CwDatePicker`, etc.) need
5504
+ * no modifications.
5120
5505
  */
5121
5506
  function usePickerPopup({ anchorRef, isOpen, onClose, position = "left-bottom" }) {
5122
- const popupRef = React.useRef(null);
5123
- const [style, setStyle] = React.useState({ position: "fixed", top: 0, left: 0, zIndex: 1000 });
5124
- const reposition = React.useCallback(() => {
5125
- const anchor = anchorRef.current;
5126
- const popup = popupRef.current;
5127
- if (!anchor || !popup)
5128
- return;
5129
- const rect = anchor.getBoundingClientRect();
5130
- const popupRect = popup.getBoundingClientRect();
5131
- // Determine vertical placement
5507
+ const pickerStrategy = React.useCallback((anchorRect, panelRect) => {
5508
+ const popupH = panelRect?.height ?? 300;
5509
+ const popupW = panelRect?.width ?? 300;
5132
5510
  const preferTop = position.includes("top");
5133
- const spaceBelow = window.innerHeight - rect.bottom;
5134
- const spaceAbove = rect.top;
5135
- const popupH = popupRect.height || 300; // fallback for first render
5511
+ const spaceBelow = window.innerHeight - anchorRect.bottom;
5512
+ const spaceAbove = anchorRect.top;
5136
5513
  let top;
5137
5514
  if (preferTop && spaceAbove >= popupH) {
5138
- top = rect.top - popupH;
5515
+ top = anchorRect.top - popupH;
5139
5516
  }
5140
5517
  else if (!preferTop && spaceBelow >= popupH + 4) {
5141
- top = rect.bottom + 4;
5518
+ top = anchorRect.bottom + 4;
5142
5519
  }
5143
5520
  else {
5144
- // Flip if preferred side doesn't fit
5145
- top = spaceBelow >= popupH + 4 ? rect.bottom + 4 : rect.top - popupH;
5521
+ top = spaceBelow >= popupH + 4 ? anchorRect.bottom + 4 : anchorRect.top - popupH;
5146
5522
  }
5147
- // Determine horizontal placement
5148
5523
  let left;
5149
5524
  if (position.includes("right")) {
5150
- left = rect.right - (popupRect.width || rect.width);
5525
+ left = anchorRect.right - popupW;
5151
5526
  }
5152
5527
  else {
5153
- left = rect.left;
5528
+ left = anchorRect.left;
5154
5529
  }
5155
- // Clamp to viewport
5156
- left = Math.max(4, Math.min(left, window.innerWidth - (popupRect.width || 200) - 4));
5530
+ left = Math.max(4, Math.min(left, window.innerWidth - popupW - 4));
5157
5531
  top = Math.max(4, top);
5158
- setStyle({ position: "fixed", top, left, zIndex: 1000 });
5159
- }, [anchorRef, position]);
5160
- // Reposition on open + observe scroll/resize on all ancestors
5161
- React.useEffect(() => {
5162
- if (!isOpen)
5163
- return;
5164
- reposition();
5165
- // Re-measure after the popup renders to get its actual size
5166
- requestAnimationFrame(reposition);
5167
- const handleUpdate = () => reposition();
5168
- window.addEventListener("resize", handleUpdate);
5169
- window.addEventListener("scroll", handleUpdate, true); // capture phase catches all scrollable ancestors
5170
- return () => {
5171
- window.removeEventListener("resize", handleUpdate);
5172
- window.removeEventListener("scroll", handleUpdate, true);
5173
- };
5174
- }, [isOpen, reposition]);
5175
- // Close on outside click — checks both anchor and popup
5176
- React.useEffect(() => {
5177
- if (!isOpen)
5178
- return;
5179
- const handleMouseDown = (e) => {
5180
- const target = e.target;
5181
- if (anchorRef.current?.contains(target) ||
5182
- popupRef.current?.contains(target))
5183
- return;
5184
- onClose();
5185
- };
5186
- document.addEventListener("mousedown", handleMouseDown);
5187
- return () => document.removeEventListener("mousedown", handleMouseDown);
5188
- }, [isOpen, onClose, anchorRef]);
5189
- const renderPopup = React.useCallback((children) => {
5190
- if (!isOpen)
5191
- return null;
5192
- return reactDom.createPortal(children, document.body);
5193
- }, [isOpen]);
5194
- return { popupRef, popupStyle: style, renderPopup };
5532
+ // No width override the calendar has its own intrinsic size
5533
+ return { top, left };
5534
+ }, [position]);
5535
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5536
+ anchorRef,
5537
+ isOpen,
5538
+ onClose,
5539
+ positionStrategy: pickerStrategy,
5540
+ });
5541
+ // Expose original API names so CwDatePicker needs zero changes
5542
+ return { popupRef: panelRef, popupStyle: panelStyle, renderPopup: renderPanel };
5195
5543
  }
5196
5544
 
5197
5545
  function CwDatePicker({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, locale: locale$1 = locale.enGB, todayLabel = "Today", feedback, }) {
@@ -9192,6 +9540,24 @@ const SuperScheduler = ({ id, state, header, rows, events, pinnedOrderCategory,
9192
9540
  }, children: "Clear pinned" }) })] })), jsxRuntime.jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem })] }));
9193
9541
  };
9194
9542
 
9543
+ /**
9544
+ * API-backed airport search input for WinOps.
9545
+ *
9546
+ * Fetches matching airports from the WinOps backend as the user types (debounced).
9547
+ * Renders results in a shared `cw-choice-dropdown` styled panel with keyboard navigation.
9548
+ * Supports pre-selecting an airport by `value` (AptKey) and customising the displayed text
9549
+ * format via `displayMode`.
9550
+ *
9551
+ * Requires a running WinOps backend — set `cblConfig` to its base URL.
9552
+ *
9553
+ * @example
9554
+ * <CwFindAirport
9555
+ * cblConfig="https://localhost:44300"
9556
+ * handleChange={(key) => setAirportKey(key)}
9557
+ * labelProps={{ text: 'Departure Airport' }}
9558
+ * displayMode="iata-only"
9559
+ * />
9560
+ */
9195
9561
  const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder = "Search airport…", required = false, cblConfig, className = "", value, disabled = false, displayMode, initialDisplayText, labelProps, alignProps, width }) => {
9196
9562
  // State
9197
9563
  const [inputValue, setInputValue] = React.useState("");
@@ -9204,8 +9570,13 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9204
9570
  const [tooltipText, setTooltipText] = React.useState("");
9205
9571
  // Refs
9206
9572
  const inputRef = React.useRef(null);
9207
- const dropdownRef = React.useRef(null);
9573
+ const wrapperRef = React.useRef(null);
9208
9574
  const searchTimeoutRef = React.useRef();
9575
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
9576
+ anchorRef: wrapperRef,
9577
+ isOpen: showDropdown && options.length > 0,
9578
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
9579
+ });
9209
9580
  // Utility function to extract ICAO from DisplayAirportText
9210
9581
  const extractIcao = React.useCallback((displayText) => {
9211
9582
  const match = displayText.match(/^([A-Z]{4})\(/);
@@ -9382,19 +9753,7 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9382
9753
  break;
9383
9754
  }
9384
9755
  };
9385
- // Handle clicks outside dropdown
9386
- React.useEffect(() => {
9387
- const handleClickOutside = (event) => {
9388
- if (dropdownRef.current &&
9389
- !dropdownRef.current.contains(event.target) &&
9390
- !inputRef.current?.contains(event.target)) {
9391
- setShowDropdown(false);
9392
- setHighlightedIndex(-1);
9393
- }
9394
- };
9395
- document.addEventListener("mousedown", handleClickOutside);
9396
- return () => document.removeEventListener("mousedown", handleClickOutside);
9397
- }, []);
9756
+ // Handle clicks outside dropdown — now handled by useDropdownPortal
9398
9757
  // Load initial value
9399
9758
  React.useEffect(() => {
9400
9759
  if (value && value !== 0 && value !== -1) {
@@ -9436,9 +9795,25 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9436
9795
  return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className}`, style: {
9437
9796
  ...(width ? { width } : {}),
9438
9797
  ...(labelProps?.labelWidth ? { '--label-width': labelProps.labelWidth } : {})
9439
- }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected airport", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "control-tower" })) })] })] }), showDropdown && options.length > 0 && (jsxRuntime.jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { className: index === highlightedIndex ? "highlighted" : "", onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9798
+ }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected airport", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "control-tower" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.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))) }) }))] }));
9440
9799
  };
9441
9800
 
9801
+ /**
9802
+ * API-backed crewmember search input for WinOps.
9803
+ *
9804
+ * Fetches matching crewmembers from the WinOps backend as the user types (debounced).
9805
+ * Renders results in a shared `cw-choice-dropdown` styled panel with keyboard navigation.
9806
+ * Supports pre-selecting a crewmember by numeric `value` (ID).
9807
+ *
9808
+ * Requires a running WinOps backend — set `cblConfig` to its base URL.
9809
+ *
9810
+ * @example
9811
+ * <CwFindCrewmember
9812
+ * cblConfig="https://localhost:44300"
9813
+ * handleChange={(id) => setCrewId(id)}
9814
+ * labelProps={{ text: 'Crew Member' }}
9815
+ * />
9816
+ */
9442
9817
  const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", required = false, cblConfig, className = "", value, disabled = false, initialDisplayText, labelProps, alignProps, width }) => {
9443
9818
  const [inputValue, setInputValue] = React.useState("");
9444
9819
  const [options, setOptions] = React.useState([]);
@@ -9449,8 +9824,13 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9449
9824
  const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
9450
9825
  const [tooltipText, setTooltipText] = React.useState("");
9451
9826
  const inputRef = React.useRef(null);
9452
- const dropdownRef = React.useRef(null);
9827
+ const wrapperRef = React.useRef(null);
9453
9828
  const searchTimeoutRef = React.useRef();
9829
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
9830
+ anchorRef: wrapperRef,
9831
+ isOpen: showDropdown && options.length > 0,
9832
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
9833
+ });
9454
9834
  const getDisplayText = React.useCallback((crew) => {
9455
9835
  return `${crew.threeLetterCode} - ${crew.lastName} ${crew.firstName}`;
9456
9836
  }, []);
@@ -9552,16 +9932,7 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9552
9932
  }
9553
9933
  };
9554
9934
  React.useEffect(() => {
9555
- const handleClickOutside = (event) => {
9556
- if (dropdownRef.current &&
9557
- !dropdownRef.current.contains(event.target) &&
9558
- !inputRef.current?.contains(event.target)) {
9559
- setShowDropdown(false);
9560
- setHighlightedIndex(-1);
9561
- }
9562
- };
9563
- document.addEventListener("mousedown", handleClickOutside);
9564
- return () => document.removeEventListener("mousedown", handleClickOutside);
9935
+ // Outside-click is now handled by useDropdownPortal
9565
9936
  }, []);
9566
9937
  React.useEffect(() => {
9567
9938
  if (value && value !== 0 && value !== -1) {
@@ -9600,7 +9971,7 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9600
9971
  return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className}`, style: {
9601
9972
  ...(width ? { width } : {}),
9602
9973
  ...(labelProps?.labelWidth ? { '--label-width': labelProps.labelWidth } : {})
9603
- }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "person" })) })] })] }), showDropdown && options.length > 0 && (jsxRuntime.jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.jsx("li", { className: index === highlightedIndex ? "highlighted" : "", onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9974
+ }, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsxRuntime.jsx(CwIcon, { iconId: "person" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: options.map((option, index) => (jsxRuntime.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))) }) }))] }));
9604
9975
  };
9605
9976
 
9606
9977
  exports.CblDragAndDrop = CblDragAndDrop;
@@ -9628,6 +9999,7 @@ exports.CwDialog = CwDialog;
9628
9999
  exports.CwDialogManager = CwDialogManager;
9629
10000
  exports.CwDigit = CwDigit;
9630
10001
  exports.CwDisplayMessage = CwDisplayMessage;
10002
+ exports.CwDropdown = CwDropdown;
9631
10003
  exports.CwDropdownFilter = CwDropdownFilter;
9632
10004
  exports.CwExpandable = CwExpandable;
9633
10005
  exports.CwFileUpload = CwFileUpload;
@@ -9679,6 +10051,7 @@ exports.CwTable = CwTable;
9679
10051
  exports.CwTableGrouped = CwTableGrouped;
9680
10052
  exports.CwTableServerSide = CwTableServerSide;
9681
10053
  exports.CwTabs = CwTabs;
10054
+ exports.CwTagSelector = CwTagSelector;
9682
10055
  exports.CwTextArea = CwTextArea;
9683
10056
  exports.CwTime = CwTime;
9684
10057
  exports.CwTimePicker = CwTimePicker;