@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.es.js CHANGED
@@ -632,7 +632,7 @@ function CwLoadingSmall(CwelltLoadingAppointements) {
632
632
  return (jsx("div", { children: CwelltLoadingAppointements.isLoading === true ? (jsx("div", { className: "cw-loading-container", children: jsx("div", { className: "cw-loading" }) })) : (jsx("div", {})) }));
633
633
  }
634
634
 
635
- 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"};
635
+ 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"};
636
636
 
637
637
  // Constants moved outside to prevent recreation
638
638
  const margin$1 = 16;
@@ -755,12 +755,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
755
755
  const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
756
756
  setIsVisible(true);
757
757
  }, showDelay);
758
- const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$p["cw-generic-tooltip-content"]);
758
+ const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$q["cw-generic-tooltip-content"]);
759
759
  // Memoize tooltip content creation
760
760
  const tooltipContent = useMemo(() => {
761
761
  if (hide || !isVisible || !content)
762
762
  return null;
763
- return createPortal(jsx("div", { className: styles$p["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
763
+ return createPortal(jsx("div", { className: styles$q["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
764
764
  position: 'fixed',
765
765
  top: `${tooltipPosition.top}px`,
766
766
  left: `${tooltipPosition.left}px`,
@@ -775,10 +775,10 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
775
775
  clearTooltipTimeout();
776
776
  setIsVisible(false);
777
777
  }, [clearTooltipTimeout]);
778
- return (jsxs("div", { ref: containerRef, className: styles$p["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
778
+ return (jsxs("div", { ref: containerRef, className: styles$q["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
779
779
  };
780
780
 
781
- var styles$o = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
781
+ var styles$p = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
782
782
 
783
783
  // Constants
784
784
  const margin = 16;
@@ -993,7 +993,7 @@ const CwTooltipManager = () => {
993
993
  if (!state.isVisible || !state.content) {
994
994
  return null;
995
995
  }
996
- return createPortal(jsx("div", { ref: tooltipRef, className: styles$o["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, style: {
996
+ return createPortal(jsx("div", { ref: tooltipRef, className: styles$p["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, style: {
997
997
  top: `${tooltipPosition.top}px`,
998
998
  left: `${tooltipPosition.left}px`,
999
999
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -1061,7 +1061,7 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
1061
1061
  useEffect(() => {
1062
1062
  ensureTooltipManager();
1063
1063
  }, []);
1064
- return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$o["cw-tooltip"], children: children }));
1064
+ return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$p["cw-tooltip"], children: children }));
1065
1065
  };
1066
1066
 
1067
1067
  function CwButton({ text, variant = 'solid', color = 'primary', className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }) {
@@ -1114,7 +1114,7 @@ function CwModal(custModalProps) {
1114
1114
  return (jsx("div", { children: custModalProps.modalState && (jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsx("span", { className: "cwelltCloseIcon" }) })] }), jsx("div", { className: "cwelltModalBody", children: jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsx("div", { style: { display: "none" } }))] }) })] })) }));
1115
1115
  }
1116
1116
 
1117
- 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"};
1117
+ 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"};
1118
1118
 
1119
1119
  function CwConfirmationPopup(props) {
1120
1120
  const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
@@ -1178,15 +1178,15 @@ function CwConfirmationPopup(props) {
1178
1178
  onCancel();
1179
1179
  }
1180
1180
  };
1181
- return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$n.overlayPositioned, onClick: handleOverlayClick, children: jsxs("div", { ref: popupRef, className: styles$n.popup, style: {
1181
+ return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$o.overlayPositioned, onClick: handleOverlayClick, children: jsxs("div", { ref: popupRef, className: styles$o.popup, style: {
1182
1182
  position: 'absolute',
1183
1183
  top: `${position.top}px`,
1184
1184
  left: `${position.left}px`,
1185
1185
  transform: 'none'
1186
- }, children: [jsx("p", { className: styles$n.message, children: message }), jsxs("div", { className: styles$n.buttons, children: [jsx("button", { className: `${styles$n.button} ${styles$n.confirmButton}`, onClick: onConfirm, children: confirmText }), jsx("button", { className: `${styles$n.button} ${styles$n.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1186
+ }, children: [jsx("p", { className: styles$o.message, children: message }), jsxs("div", { className: styles$o.buttons, children: [jsx("button", { className: `${styles$o.button} ${styles$o.confirmButton}`, onClick: onConfirm, children: confirmText }), jsx("button", { className: `${styles$o.button} ${styles$o.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1187
1187
  }
1188
1188
 
1189
- 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"};
1189
+ 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"};
1190
1190
 
1191
1191
  // Helper function to parse size values
1192
1192
  const parseSize = (size) => {
@@ -1459,7 +1459,7 @@ const CwDialog = props => {
1459
1459
  }
1460
1460
  }
1461
1461
  }, [open]);
1462
- const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$m["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1462
+ const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$n["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1463
1463
  const content = useMemo(() => (jsx("section", { children: children })), [children]);
1464
1464
  const footer = useMemo(() => (jsx("footer", { children: customFooter || (jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
1465
1465
  const resizeHandles = useMemo(() => size.autoHeight
@@ -1486,7 +1486,7 @@ const CwDialog = props => {
1486
1486
  : `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
1487
1487
  return { displayWidth, displayHeight };
1488
1488
  }, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
1489
- const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$m["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1489
+ const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$n["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1490
1490
  left: `${position.x}px`,
1491
1491
  top: `${position.y}px`,
1492
1492
  width: displayDimensions.displayWidth,
@@ -1689,7 +1689,7 @@ function CwAlign(props) {
1689
1689
  }, children: props.children }));
1690
1690
  }
1691
1691
 
1692
- 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"};
1692
+ 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"};
1693
1693
 
1694
1694
  /**
1695
1695
  * CwCard - A simple card component for displaying content in a contained format
@@ -1713,11 +1713,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1713
1713
  // Construct class names using CSS modules
1714
1714
  const cardClassNames = [
1715
1715
  'cw-card',
1716
- styles$l.card,
1716
+ styles$m.card,
1717
1717
  className,
1718
- clickable ? styles$l.clickable : '',
1719
- disabled ? styles$l.disabled : '',
1720
- isLoading ? styles$l.loading : '',
1718
+ clickable ? styles$m.clickable : '',
1719
+ disabled ? styles$m.disabled : '',
1720
+ isLoading ? styles$m.loading : '',
1721
1721
  ].filter(Boolean).join(' ');
1722
1722
  // Handle click event when card is clickable
1723
1723
  const handleClick = () => {
@@ -1734,15 +1734,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1734
1734
  // Determine if footer should be rendered
1735
1735
  const hasFooter = hasChips || footer || (hasActions && direction === "row");
1736
1736
  // Actions component to reuse
1737
- const ActionsComponent = hasActions && !disabled ? (jsxs("div", { className: styles$l.actions, children: [extraActions ?? null, onEdit && jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1737
+ const ActionsComponent = hasActions && !disabled ? (jsxs("div", { className: styles$m.actions, children: [extraActions ?? null, onEdit && jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1738
1738
  return (jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
1739
1739
  role: 'button',
1740
1740
  tabIndex: 0,
1741
1741
  onClick: handleClick,
1742
- }), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$l.headerContent, "data-alignment": alignment, children: [title && jsx("h5", { children: title }), subtitle && jsx("strong", { children: subtitle })] })), direction === "column" && ActionsComponent] })), jsx("div", { className: styles$l.content, children: children }), hasFooter && (jsxs("footer", { children: [hasChips && (jsx("div", { className: styles$l.footerTags, children: chips.map((chip, index) => (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 && (jsx("div", { className: styles$l.footerContent, children: footer }))] })), direction === "row" && ActionsComponent, isLoading && (jsx("div", { className: styles$l.loadingOverlay, children: jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1742
+ }), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$m.headerContent, "data-alignment": alignment, children: [title && jsx("h5", { children: title }), subtitle && jsx("strong", { children: subtitle })] })), direction === "column" && ActionsComponent] })), jsx("div", { className: styles$m.content, children: children }), hasFooter && (jsxs("footer", { children: [hasChips && (jsx("div", { className: styles$m.footerTags, children: chips.map((chip, index) => (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 && (jsx("div", { className: styles$m.footerContent, children: footer }))] })), direction === "row" && ActionsComponent, isLoading && (jsx("div", { className: styles$m.loadingOverlay, children: jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1743
1743
  };
1744
1744
 
1745
- 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"};
1745
+ 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"};
1746
1746
 
1747
1747
  function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, emptyState, sortOptions = [], defaultSortKey, ...htmlProps }) {
1748
1748
  const [currentPage, setCurrentPage] = useState(1);
@@ -1776,10 +1776,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
1776
1776
  '--card-width': `${defaultCardWidth}px`,
1777
1777
  '--card-gap': `${cardGap}px`
1778
1778
  };
1779
- return (jsxs("div", { ...htmlProps, children: [sortOptions.length > 0 && (jsxs("div", { className: styles$k.sortControls, children: [jsx("label", { htmlFor: "cardlist-sort-select", children: "Sort by:" }), jsx("select", { id: "cardlist-sort-select", value: sortKey, onChange: (e) => handleSortChange(e.target.value), className: styles$k.sortSelect, children: sortOptions.map(option => (jsx("option", { value: option.key, children: option.label }, option.key))) }), 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 ? (jsx("div", { className: styles$k.loading, children: jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsx("div", { className: styles$k.emptyState, children: emptyState || jsx("p", { children: "No items to display" }) })) : (jsxs(Fragment, { children: [jsx("div", { className: `${styles$k.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsx("div", { className: styles$k.cardWrapper, children: renderCard(item, index) }, index))) }), totalPages > 1 && (jsxs("div", { className: styles$k.pagination, children: [jsx("button", { disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)), className: "cw-button-icon cwi-chevron-left" }), jsxs("span", { className: styles$k.pageInfo, children: [currentPage, " of ", totalPages] }), jsx("button", { disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), className: "cw-button-icon cwi-chevron-right" })] }))] }))] }));
1779
+ return (jsxs("div", { ...htmlProps, children: [sortOptions.length > 0 && (jsxs("div", { className: styles$l.sortControls, children: [jsx("label", { htmlFor: "cardlist-sort-select", children: "Sort by:" }), jsx("select", { id: "cardlist-sort-select", value: sortKey, onChange: (e) => handleSortChange(e.target.value), className: styles$l.sortSelect, children: sortOptions.map(option => (jsx("option", { value: option.key, children: option.label }, option.key))) }), 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 ? (jsx("div", { className: styles$l.loading, children: jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsx("div", { className: styles$l.emptyState, children: emptyState || jsx("p", { children: "No items to display" }) })) : (jsxs(Fragment, { children: [jsx("div", { className: `${styles$l.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsx("div", { className: styles$l.cardWrapper, children: renderCard(item, index) }, index))) }), totalPages > 1 && (jsxs("div", { className: styles$l.pagination, children: [jsx("button", { disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)), className: "cw-button-icon cwi-chevron-left" }), jsxs("span", { className: styles$l.pageInfo, children: [currentPage, " of ", totalPages] }), jsx("button", { disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), className: "cw-button-icon cwi-chevron-right" })] }))] }))] }));
1780
1780
  }
1781
1781
 
1782
- var styles$j = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1782
+ var styles$k = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1783
1783
 
1784
1784
  /**
1785
1785
  *
@@ -1796,7 +1796,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
1796
1796
  setVisible_accordionBody(!isVisible_accordionBody);
1797
1797
  };
1798
1798
  // #endregion
1799
- return (jsxs("div", { className: styles$j["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxs("header", { onClick: () => showAccordionBody(), children: [jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsx("button", { className: "cw-button-icon" })] }), jsx("div", { className: styles$j["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1799
+ return (jsxs("div", { className: styles$k["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxs("header", { onClick: () => showAccordionBody(), children: [jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsx("button", { className: "cw-button-icon" })] }), jsx("div", { className: styles$k["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
1800
1800
  }
1801
1801
 
1802
1802
  /**
@@ -2000,15 +2000,6 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2000
2000
  window.addEventListener("mousemove", onMouseMove);
2001
2001
  window.addEventListener("mouseup", onMouseUp);
2002
2002
  };
2003
- const scrollContainerStyle = useMemo(() => {
2004
- if (stickyHeader || scrollHeight) {
2005
- return {
2006
- maxHeight: scrollHeight ?? 300,
2007
- overflowY: "auto"
2008
- };
2009
- }
2010
- return {}; // no height or scroll
2011
- }, [stickyHeader, scrollHeight]);
2012
2003
  const getColSpan = () => columns.length + (expandedRowRender ? 1 : 0);
2013
2004
  const hasClassNameRow = (item) => {
2014
2005
  return typeof item === "object" && item !== null && "classNameRow" in item;
@@ -2037,23 +2028,21 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2037
2028
  : "cwi-chevron-right"}` }) })), columns.map(col => (jsx("td", { className: col.className ?? "", children: col.render ? col.render(item) : col.dataIndex ? String(item[col.dataIndex] ?? "") : "" }, `${itemKey}_${col.key}`)))] }), expandedRowRender && expandedRowKey === itemKey && (jsx("tr", { className: "cw-table-row-expanded", children: jsx("td", { colSpan: getColSpan(), children: expandedRowRender(item) }) }))] }, String(itemKey)));
2038
2029
  });
2039
2030
  };
2040
- return (jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container ${classNameContainer ?? ""}`, style: style, children: [jsx("div", { style: scrollContainerStyle, children: jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { style: stickyHeader
2041
- ? { position: "sticky", top: 0, background: "white", zIndex: 2 }
2042
- : undefined, children: jsxs("tr", { children: [expandedRowRender && jsx("th", {}), columns.map(col => (jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2043
- ? sortConfig.direction
2044
- : ""}`.trim(), style: {
2045
- cursor: col.sortable ? "pointer" : "default",
2046
- userSelect: "none",
2047
- width: columnWidths[col.key] ?? col.width,
2048
- ...((col.width || columnWidths[col.key]) && {
2049
- minWidth: 50,
2050
- maxWidth: columnWidths[col.key] ?? col.width
2051
- }),
2052
- }, children: [jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsx("span", { children: col.title }), col.sortable && col.dataIndex && (jsx(CwIcon, { style: { fontSize: "1.25em" }, iconId: sortConfig.key !== col.dataIndex
2053
- ? "sortable"
2054
- : sortConfig.direction === "asc"
2055
- ? "sortable-asc"
2056
- : "sortable-desc" }))] }), jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsx("tbody", { children: renderTableBody() })] }) }), pagination && data.length > pageSizeOptions[0] && (jsxs("footer", { className: "cw-table-pagination", children: [jsxs("div", { className: "cw-table-pagination-size", children: [jsx(CwIcon, { iconId: "list" }), jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxs("div", { className: "cw-table-pagination-nav", children: [jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left-double" }), jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left" }), jsx("input", { type: "text", inputMode: "numeric", value: currentPage, onChange: (e) => {
2031
+ return (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: [jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [expandedRowRender && jsx("th", {}), columns.map(col => (jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2032
+ ? sortConfig.direction
2033
+ : ""}`.trim(), style: {
2034
+ cursor: col.sortable ? "pointer" : "default",
2035
+ userSelect: "none",
2036
+ width: columnWidths[col.key] ?? col.width,
2037
+ ...((col.width || columnWidths[col.key]) && {
2038
+ minWidth: 50,
2039
+ maxWidth: columnWidths[col.key] ?? col.width
2040
+ }),
2041
+ }, children: [jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsx("span", { children: col.title }), col.sortable && col.dataIndex && (jsx(CwIcon, { style: { fontSize: "1.25em" }, iconId: sortConfig.key !== col.dataIndex
2042
+ ? "sortable"
2043
+ : sortConfig.direction === "asc"
2044
+ ? "sortable-asc"
2045
+ : "sortable-desc" }))] }), jsx("span", { onMouseDown: (e) => startResize(e, col.key), className: "th-column-resizer" })] }, col.key)))] }) }), jsx("tbody", { children: renderTableBody() })] }), pagination && data.length > pageSizeOptions[0] && (jsxs("footer", { className: "cw-table-pagination", children: [jsxs("div", { className: "cw-table-pagination-size", children: [jsx(CwIcon, { iconId: "list" }), jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, children: pageSizeOptions.map(size => (jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }), jsxs("div", { className: "cw-table-pagination-nav", children: [jsx(CwButton, { onClick: () => handlePageChange(1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left-double" }), jsx(CwButton, { onClick: () => handlePageChange(currentPage - 1), disabled: currentPage === 1 || totalPages === 1, variant: "icon", icon: "chevron-left" }), jsx("input", { type: "text", inputMode: "numeric", value: currentPage, onChange: (e) => {
2057
2046
  const value = parseInt(e.target.value, 10);
2058
2047
  if (!isNaN(value))
2059
2048
  handlePageChange(value);
@@ -2065,7 +2054,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2065
2054
  }, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages === 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2066
2055
  }
2067
2056
 
2068
- 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"};
2057
+ 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"};
2069
2058
 
2070
2059
  /**
2071
2060
  * Hook that provides state management for CwSortableTable.
@@ -2128,9 +2117,9 @@ function useSortableTable(initialItems) {
2128
2117
  }
2129
2118
 
2130
2119
  // ─── Drop indicator row ───────────────────────────────────────────────────────
2131
- const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$i.dropIndicator, "aria-hidden": true, children: jsx("td", { colSpan: colSpan, children: jsx("div", {}) }) }));
2120
+ const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$j.dropIndicator, "aria-hidden": true, children: jsx("td", { colSpan: colSpan, children: jsx("div", {}) }) }));
2132
2121
  // ─── Loading skeleton ─────────────────────────────────────────────────────────
2133
- const LoadingRows = ({ colSpan }) => (jsx(Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsx("tr", { className: styles$i.skeletonRow, children: jsx("td", { colSpan: colSpan, children: jsx("div", { className: styles$i.skeleton }) }) }, i))) }));
2122
+ const LoadingRows = ({ colSpan }) => (jsx(Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsx("tr", { className: styles$j.skeletonRow, children: jsx("td", { colSpan: colSpan, children: jsx("div", { className: styles$j.skeleton }) }) }, i))) }));
2134
2123
  // ─── Component ────────────────────────────────────────────────────────────────
2135
2124
  /**
2136
2125
  * CwSortableTable
@@ -2217,11 +2206,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2217
2206
  return items.map((item, index) => {
2218
2207
  const key = item[rowKey];
2219
2208
  const isDragging = draggedItem?.[rowKey] === key;
2220
- return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$i.dragging : "", children: [showHandle && (jsx("td", { className: "cw-table-col-action", children: jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2209
+ return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$j.dragging : "", children: [showHandle && (jsx("td", { className: "cw-table-col-action", children: jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2221
2210
  });
2222
2211
  };
2223
2212
  // ── Render ──────────────────────────────────────────────────────────────
2224
- return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxs("footer", { className: styles$i.saveBar, children: [jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2213
+ return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxs("footer", { className: styles$j.saveBar, children: [jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2225
2214
  }
2226
2215
 
2227
2216
  /**
@@ -2277,7 +2266,7 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2277
2266
  *
2278
2267
  * @returns React component
2279
2268
  */
2280
- 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, }) {
2269
+ 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, }) {
2281
2270
  const [internalState, setInternalState] = useState({
2282
2271
  page: 1,
2283
2272
  pageSize: pageSizeOptions[0],
@@ -2426,10 +2415,10 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2426
2415
  if (isNaN(value) || value < 1 || value > totalPages) {
2427
2416
  handlePageChange(1);
2428
2417
  }
2429
- }, min: 1, max: totalPages }), jsxs("span", { children: ["of ", totalPages] }), jsx("button", { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right", title: "Next" }), jsx("button", { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right-double", title: "Last" }), jsx("select", { value: state.pageSize, onChange: handleItemsPerPageChange, children: pageSizeOptions.map((size) => (jsxs("option", { value: size, children: [size, " / page"] }, size))) })] }))] }));
2418
+ }, min: 1, max: totalPages }), jsxs("span", { children: ["of ", totalPages] }), jsx("button", { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right", title: "Next" }), jsx("button", { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right-double", title: "Last" }), jsx("select", { value: state.pageSize, onChange: handleItemsPerPageChange, children: pageSizeOptions.map((size) => (jsx("option", { value: size, children: pageLabel ? `${size} / ${pageLabel}` : size }, size))) })] }))] }));
2430
2419
  }
2431
2420
 
2432
- 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"};
2421
+ 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"};
2433
2422
 
2434
2423
  const TabIcon = ({ icon }) => {
2435
2424
  if (!icon)
@@ -2479,7 +2468,7 @@ function CwTabs(CwTabsProps) {
2479
2468
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2480
2469
  ? { minWidth: CwTabsProps.tabsListWidth }
2481
2470
  : undefined;
2482
- return (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: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx("span", { className: styles$h['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), 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 })] }));
2471
+ return (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: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx("span", { className: styles$i['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), 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 })] }));
2483
2472
  }
2484
2473
 
2485
2474
  /**
@@ -2503,10 +2492,10 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
2503
2492
  onClose?.(ev);
2504
2493
  });
2505
2494
  }, [onClose, onOpen, onToggle]);
2506
- return (jsx("div", { className: "cw-expandable", children: jsxs("details", { ref: myRef, ...detailsProps, children: [jsx("summary", { children: briefing }), children && jsx("section", { children: children })] }) }));
2495
+ return (jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsx("summary", { children: briefing }), children && jsx("section", { children: children })] }));
2507
2496
  };
2508
2497
 
2509
- 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"};
2498
+ 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"};
2510
2499
 
2511
2500
  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, }) => {
2512
2501
  const [masterWidth, setMasterWidth] = useState(initialWidth);
@@ -2542,10 +2531,10 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2542
2531
  document.body.style.userSelect = '';
2543
2532
  };
2544
2533
  }, [isResizing, minMasterWidth, maxMasterWidth]);
2545
- const rootClassName = [styles$g['cw-master-detail'], className].filter(Boolean).join(' ');
2546
- return (jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsx("search", { children: jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsx("header", { children: masterHeader })), jsx("ul", { children: items.map((item) => (jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$g.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsx("section", { className: styles$g.detail, children: selectedKey && detailContent
2534
+ const rootClassName = [styles$h['cw-master-detail'], className].filter(Boolean).join(' ');
2535
+ return (jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsx("search", { children: jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsx("header", { children: masterHeader })), jsx("ul", { children: items.map((item) => (jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$h.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsx("section", { className: styles$h.detail, children: selectedKey && detailContent
2547
2536
  ? detailContent
2548
- : (jsx("div", { className: styles$g['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2537
+ : (jsx("div", { className: styles$h['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2549
2538
  };
2550
2539
 
2551
2540
  /**
@@ -2569,7 +2558,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
2569
2558
  : emptyValue })] }, item.key))) }));
2570
2559
  };
2571
2560
 
2572
- 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"};
2561
+ 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"};
2573
2562
 
2574
2563
  function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
2575
2564
  const [draggedItem, setDraggedItem] = useState(null);
@@ -2632,15 +2621,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
2632
2621
  }
2633
2622
  };
2634
2623
  if (items.length === 0) {
2635
- return (jsx("div", { className: `${styles$f.sortableList} ${styles$f.emptyState} ${className}`, children: jsx("div", { className: styles$f.emptyMessage, children: emptyMessage }) }));
2624
+ return (jsx("div", { className: `${styles$g.sortableList} ${styles$g.emptyState} ${className}`, children: jsx("div", { className: styles$g.emptyMessage, children: emptyMessage }) }));
2636
2625
  }
2637
- return (jsx("div", { className: `${styles$f.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2626
+ return (jsx("div", { className: `${styles$g.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2638
2627
  const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
2639
2628
  const isDragging = draggedItem?.id === item.id;
2640
2629
  const isMoved = movedItems.has(item.id);
2641
2630
  const canExpand = Boolean(expandedContent);
2642
2631
  const isExpanded = expandedItems.has(item.id);
2643
- return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$f.dropIndicator }), 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: [jsxs("header", { children: [canExpand ? (jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsx("div", { className: styles$f.sortableHandle, children: jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxs("div", { className: styles$f.sortableContent, children: [jsx("div", { className: styles$f.sortableTitle, children: title }), extraContent && jsx("div", { className: styles$f.sortableExtraContent, children: extraContent })] }), jsx("div", { className: styles$f.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsx("div", { className: styles$f.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsx("div", { className: styles$f.dropIndicator }))] }, item.id));
2632
+ return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$g.dropIndicator }), 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: [jsxs("header", { children: [canExpand ? (jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsx("div", { className: styles$g.sortableHandle, children: jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxs("div", { className: styles$g.sortableContent, children: [jsx("div", { className: styles$g.sortableTitle, children: title }), extraContent && jsx("div", { className: styles$g.sortableExtraContent, children: extraContent })] }), jsx("div", { className: styles$g.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsx("div", { className: styles$g.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsx("div", { className: styles$g.dropIndicator }))] }, item.id));
2644
2633
  }) }));
2645
2634
  }
2646
2635
 
@@ -2817,7 +2806,7 @@ function CwFileUpload(fileUploadProps) {
2817
2806
  return (jsxs("div", { children: [jsxs("div", { className: "row", children: [jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsx("div", { className: "row", children: jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsx("div", { className: "row error", children: error }), jsx("div", { className: "row", children: jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
2818
2807
  }
2819
2808
 
2820
- 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"};
2809
+ 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"};
2821
2810
 
2822
2811
  const DEFAULT_LABELS = {
2823
2812
  uploadDisabled: 'Upload disabled',
@@ -2984,12 +2973,12 @@ function CwFileUploadMultiple(fileUploadProps) {
2984
2973
  }
2985
2974
  }
2986
2975
  };
2987
- return (jsxs("div", { className: `${styles$e.fileUploadContainer} ${fileUploadProps.className}`, children: [jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$e.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxs("div", { className: `${styles$e.uploadArea} ${fileUploadProps.disabled ? styles$e.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsx(CwIcon, { iconId: "upload" }), jsx("p", { className: `${styles$e.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxs("p", { className: `${styles$e.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxs("div", { className: styles$e.filesContainer, children: [jsxs("div", { className: styles$e.fileItem, children: [jsxs("div", { className: styles$e.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$e.fileExtension, children: getFileExtension(existingFile) })] }), jsx("div", { className: styles$e.fileInfo, children: jsx("p", { className: styles$e.fileName, children: existingFile }) }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
2976
+ return (jsxs("div", { className: `${styles$f.fileUploadContainer} ${fileUploadProps.className}`, children: [jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$f.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxs("div", { className: `${styles$f.uploadArea} ${fileUploadProps.disabled ? styles$f.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsx(CwIcon, { iconId: "upload" }), jsx("p", { className: `${styles$f.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxs("p", { className: `${styles$f.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxs("div", { className: styles$f.filesContainer, children: [jsxs("div", { className: styles$f.fileItem, children: [jsxs("div", { className: styles$f.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$f.fileExtension, children: getFileExtension(existingFile) })] }), jsx("div", { className: styles$f.fileInfo, children: jsx("p", { className: styles$f.fileName, children: existingFile }) }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
2988
2977
  setExistingFile(undefined);
2989
2978
  if (fileUploadProps.onSelect) {
2990
2979
  fileUploadProps.onSelect(null);
2991
2980
  }
2992
- }, disabled: fileUploadProps.disabled, className: styles$e.smallButton })] }), jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxs("div", { className: styles$e.filesContainer, children: [jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsx("small", { className: styles$e.filesCount, children: labels.filesSelected(selectedFiles.length) }), jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll })] }), selectedFiles.map((file, index) => (jsxs("div", { className: styles$e.fileItem, children: [jsxs("div", { className: styles$e.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$e.fileExtension, children: getFileExtension(file.name) })] }), jsxs("div", { className: styles$e.fileInfo, children: [jsx("p", { className: styles$e.fileName, children: file.name }), jsxs("p", { className: styles$e.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$e.smallButton })] }, index))), fileUploadProps.multiple && (jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
2981
+ }, disabled: fileUploadProps.disabled, className: styles$f.smallButton })] }), jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxs("div", { className: styles$f.filesContainer, children: [jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsx("small", { className: styles$f.filesCount, children: labels.filesSelected(selectedFiles.length) }), jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll })] }), selectedFiles.map((file, index) => (jsxs("div", { className: styles$f.fileItem, children: [jsxs("div", { className: styles$f.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$f.fileExtension, children: getFileExtension(file.name) })] }), jsxs("div", { className: styles$f.fileInfo, children: [jsx("p", { className: styles$f.fileName, children: file.name }), jsxs("p", { className: styles$f.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$f.smallButton })] }, index))), fileUploadProps.multiple && (jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
2993
2982
  }
2994
2983
 
2995
2984
  function CwInput(CwInputProps) {
@@ -3030,7 +3019,7 @@ function CwDigit(props) {
3030
3019
  return (jsx("div", { className: "cw-input-text", children: jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsx("input", { type: "number", ...inputProps }), buttonProps && jsx(CwButton, { ...buttonProps })] }) }));
3031
3020
  }
3032
3021
 
3033
- 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"};
3022
+ 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"};
3034
3023
 
3035
3024
  const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
3036
3025
  const [rgb, setRgb] = useState({ r: 255, g: 255, b: 255 });
@@ -3233,13 +3222,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
3233
3222
  // Calculate background color for the main area based on current hue
3234
3223
  const hueColor = hsvToRgb(hsv.h, 100, 100);
3235
3224
  const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
3236
- return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$d.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxs("div", { children: [jsx("label", { children: "R:" }), jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "G:" }), jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "B:" }), jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxs("div", { className: styles$d.colorPickerInteractiveArea, children: [jsx("div", { className: styles$d.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsx("div", { className: styles$d.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxs("div", { className: styles$d.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxs("div", { className: styles$d.colorAreaOverlay, children: [jsx("div", { className: styles$d.hueBackground, style: { backgroundColor: hueHex } }), jsx("div", { className: styles$d.whiteGradient }), jsx("div", { className: styles$d.blackGradient })] }), jsx("div", { className: styles$d.colorAreaCursor, style: {
3225
+ return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$e.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxs("div", { children: [jsx("label", { children: "R:" }), jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "G:" }), jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "B:" }), jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxs("div", { className: styles$e.colorPickerInteractiveArea, children: [jsx("div", { className: styles$e.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsx("div", { className: styles$e.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxs("div", { className: styles$e.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxs("div", { className: styles$e.colorAreaOverlay, children: [jsx("div", { className: styles$e.hueBackground, style: { backgroundColor: hueHex } }), jsx("div", { className: styles$e.whiteGradient }), jsx("div", { className: styles$e.blackGradient })] }), jsx("div", { className: styles$e.colorAreaCursor, style: {
3237
3226
  left: `${hsv.s}%`,
3238
3227
  top: `${100 - hsv.v}%`
3239
3228
  } })] })] })] }));
3240
3229
  };
3241
3230
 
3242
- 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"};
3231
+ 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"};
3243
3232
 
3244
3233
  const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
3245
3234
  const [isOpen, setIsOpen] = useState(false);
@@ -3372,11 +3361,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
3372
3361
  break;
3373
3362
  }
3374
3363
  };
3375
- return (jsxs("div", { className: `cw-input-color ${styles$c.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsx(CwLabel, { ...labelProps })), jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$c.selectColor} ${disabled ? styles$c.disabled : ''} ${readOnly ? styles$c.readOnly : ''}`, style: {
3364
+ return (jsxs("div", { className: `cw-input-color ${styles$d.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsx(CwLabel, { ...labelProps })), jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$d.selectColor} ${disabled ? styles$d.disabled : ''} ${readOnly ? styles$d.readOnly : ''}`, style: {
3376
3365
  width,
3377
3366
  height,
3378
3367
  backgroundColor: value,
3379
- }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$c.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3368
+ }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$d.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3380
3369
  };
3381
3370
 
3382
3371
  /**
@@ -4017,7 +4006,7 @@ const CwImageArea = forwardRef((props, ref) => {
4017
4006
  });
4018
4007
  CwImageArea.displayName = "CwImageArea";
4019
4008
 
4020
- var styles$b = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4009
+ var styles$c = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4021
4010
 
4022
4011
  /**
4023
4012
  * This class represents a week where days can be selected or unselected
@@ -4157,15 +4146,15 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4157
4146
  setSelectedDays(newWeekdays);
4158
4147
  onChange?.(newWeekdays.toString());
4159
4148
  };
4160
- return (jsx("div", { className: styles$b["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4149
+ return (jsx("div", { className: styles$c["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4161
4150
  };
4162
4151
 
4163
- var styles$a = {"check-container":"cw-check-module__check-container__4nscZ","checkbox-group-container":"cw-check-module__checkbox-group-container__WMNbG"};
4152
+ var styles$b = {"check-container":"cw-check-module__check-container__4nscZ","checkbox-group-container":"cw-check-module__checkbox-group-container__WMNbG"};
4164
4153
 
4165
4154
  function CwCheck(props) {
4166
4155
  const { labelProps, labelText, iconProps, alignment = "row", className, ...inputProps } = props;
4167
4156
  const displayText = labelText || labelProps?.text;
4168
- return (jsx("div", { className: `cw-check ${styles$a["check-container"]}${className ? ` ${className}` : ''}`, children: jsxs("label", { "data-direction": alignment, children: [jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxs("span", { className: "cw-icon-text", children: [iconProps && jsx(CwIcon, { ...iconProps }), displayText] }))] }) }));
4157
+ return (jsx("div", { className: `cw-check ${styles$b["check-container"]}${className ? ` ${className}` : ''}`, children: jsxs("label", { "data-direction": alignment, children: [jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxs("span", { className: "cw-icon-text", children: [iconProps && jsx(CwIcon, { ...iconProps }), displayText] }))] }) }));
4169
4158
  }
4170
4159
 
4171
4160
  function CwCheckbox(CwCheckboxProps) {
@@ -4197,7 +4186,7 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, alignProps
4197
4186
  : [];
4198
4187
  const flexDirection = alignProps?.flexDirection ?? "row";
4199
4188
  const dataDirection = { 'data-direction': flexDirection };
4200
- return (jsxs("div", { className: `cw-checkbox-group ${styles$a["checkbox-group-container"]}${className ? ` ${className}` : ''}`, ...dataDirection, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: `${optionsAlignment === "row" ? "cw-flex-column cw-gap-small" : "cw-flex-row cw-flex-wrap"}`, children: options.map((option) => (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) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4189
+ return (jsxs("div", { className: `cw-checkbox-group ${styles$b["checkbox-group-container"]}${className ? ` ${className}` : ''}`, ...dataDirection, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsx("div", { className: `${optionsAlignment === "row" ? "cw-flex-column cw-gap-small" : "cw-flex-row cw-flex-wrap"}`, children: options.map((option) => (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) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4201
4190
  }
4202
4191
 
4203
4192
  function CwToggle(props) {
@@ -4215,13 +4204,16 @@ function CwToggle(props) {
4215
4204
  * @example
4216
4205
  * <CwSelect>
4217
4206
  * <CwOption>A</CwOption>
4218
- * <CwOption>B</CwOption>
4207
+ * <CwOption color="#4a90d9">Blue option</CwOption>
4219
4208
  * <CwOption>C</CwOption>
4220
4209
  * </CwSelect>
4221
4210
  */
4222
4211
  function CwOption(props) {
4223
- const { text, ...optionProps } = props;
4224
- return (jsx("option", { className: "cw-option", ...optionProps, children: optionProps.children ?? text }));
4212
+ const { text, color, style, ...optionProps } = props;
4213
+ const mergedStyle = color
4214
+ ? { ...style, backgroundColor: color, color: getContrastColor(color) }
4215
+ : style;
4216
+ return (jsx("option", { className: "cw-option", style: mergedStyle, ...optionProps, children: optionProps.children ?? text }));
4225
4217
  }
4226
4218
 
4227
4219
  /**
@@ -4255,7 +4247,248 @@ function CwSelect(props) {
4255
4247
  : [];
4256
4248
  const flexDirection = alignProps?.flexDirection ?? "row";
4257
4249
  const dataDirection = { 'data-direction': flexDirection };
4258
- return (jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: style, children: [jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxs("select", { ...selectProps, children: [placeholder && jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-type": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4250
+ const { backgroundColor, color: textColor, ...wrapperStyle } = style ?? {};
4251
+ return (jsxs("div", { className: `cw-select${className ? ` ${className}` : ''}`, ...dataDirection, style: wrapperStyle, children: [jsxs(CwAlign, { ...alignProps, itemProp: selectProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: "cw-flex-row cw-gap-small cw-flex-grow", children: [jsxs("select", { ...selectProps, style: backgroundColor ? { backgroundColor, color: textColor } : undefined, children: [placeholder && jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4252
+ }
4253
+
4254
+ // ─── Default strategy: below anchor, match width, flip above if needed ────────
4255
+ function defaultPositionStrategy(anchorRect, panelRect) {
4256
+ const panelH = panelRect?.height ?? 200;
4257
+ const spaceBelow = window.innerHeight - anchorRect.bottom;
4258
+ const top = spaceBelow >= panelH + 4
4259
+ ? anchorRect.bottom + 4
4260
+ : Math.max(4, anchorRect.top - panelH);
4261
+ const width = anchorRect.width;
4262
+ const left = Math.max(4, Math.min(anchorRect.left, window.innerWidth - width - 4));
4263
+ return { top, left, width };
4264
+ }
4265
+ // ─── Hook ─────────────────────────────────────────────────────────────────────
4266
+ /**
4267
+ * Generic portal-based dropdown panel hook.
4268
+ *
4269
+ * Renders the panel as a direct child of `<body>` via `createPortal` so it
4270
+ * escapes any `overflow: hidden/auto` ancestor (dialogs, tabs, cards, etc.).
4271
+ * Positions the panel with `position: fixed` computed from the anchor element's
4272
+ * `getBoundingClientRect()`, and repositions on scroll and resize.
4273
+ *
4274
+ * The fix pattern is the same as {@link usePickerPopup} used by `CwDatePicker`.
4275
+ *
4276
+ * > **Future migration note:** Once the project's minimum browser baseline
4277
+ * > reaches Firefox 147 / Safari 26 (CSS Anchor Positioning — Baseline 2026),
4278
+ * > this hook can be replaced with `popover="manual"` + CSS `anchor()` with
4279
+ * > zero JS positioning.
4280
+ *
4281
+ * @example
4282
+ * ```tsx
4283
+ * const wrapperRef = useRef<HTMLDivElement>(null);
4284
+ * const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4285
+ * anchorRef: wrapperRef,
4286
+ * isOpen,
4287
+ * onClose: () => setIsOpen(false),
4288
+ * });
4289
+ *
4290
+ * return (
4291
+ * <div ref={wrapperRef}>
4292
+ * <input ... />
4293
+ * {renderPanel(
4294
+ * <div ref={panelRef} style={panelStyle} className={styles.dropdown}>
4295
+ * {options}
4296
+ * </div>
4297
+ * )}
4298
+ * </div>
4299
+ * );
4300
+ * ```
4301
+ */
4302
+ function useDropdownPortal({ anchorRef, isOpen, onClose, positionStrategy = defaultPositionStrategy, }) {
4303
+ const panelRef = useRef(null);
4304
+ const [style, setStyle] = useState({
4305
+ position: "fixed",
4306
+ top: 0,
4307
+ left: 0,
4308
+ width: "auto",
4309
+ zIndex: 1000,
4310
+ right: "auto",
4311
+ marginLeft: 0,
4312
+ });
4313
+ const reposition = useCallback(() => {
4314
+ const anchor = anchorRef.current;
4315
+ if (!anchor)
4316
+ return;
4317
+ const anchorRect = anchor.getBoundingClientRect();
4318
+ const panelRect = panelRef.current?.getBoundingClientRect() ?? null;
4319
+ const { top, left, width } = positionStrategy(anchorRect, panelRect);
4320
+ setStyle({
4321
+ position: "fixed",
4322
+ top,
4323
+ left,
4324
+ width: width ?? "auto",
4325
+ zIndex: 1000,
4326
+ right: "auto",
4327
+ marginLeft: 0,
4328
+ });
4329
+ }, [anchorRef, positionStrategy]);
4330
+ // Reposition when opened; re-measure after first paint to get real panel size
4331
+ useEffect(() => {
4332
+ if (!isOpen)
4333
+ return;
4334
+ reposition();
4335
+ const raf = requestAnimationFrame(reposition);
4336
+ const handleUpdate = () => reposition();
4337
+ window.addEventListener("resize", handleUpdate);
4338
+ // Capture phase catches scroll on all scrollable ancestors
4339
+ window.addEventListener("scroll", handleUpdate, true);
4340
+ return () => {
4341
+ cancelAnimationFrame(raf);
4342
+ window.removeEventListener("resize", handleUpdate);
4343
+ window.removeEventListener("scroll", handleUpdate, true);
4344
+ };
4345
+ }, [isOpen, reposition]);
4346
+ // Close when the anchor scrolls out of view in any overflow container
4347
+ useEffect(() => {
4348
+ if (!isOpen)
4349
+ return;
4350
+ const anchor = anchorRef.current;
4351
+ if (!anchor)
4352
+ return;
4353
+ const observer = new IntersectionObserver(([entry]) => { if (!entry.isIntersecting)
4354
+ onClose(); }, { threshold: 0 });
4355
+ observer.observe(anchor);
4356
+ return () => observer.disconnect();
4357
+ }, [isOpen, anchorRef, onClose]);
4358
+ // Close on outside click (anchor + panel are both considered "inside")
4359
+ useEffect(() => {
4360
+ if (!isOpen)
4361
+ return;
4362
+ const handleMouseDown = (e) => {
4363
+ const target = e.target;
4364
+ if (anchorRef.current?.contains(target) || panelRef.current?.contains(target))
4365
+ return;
4366
+ onClose();
4367
+ };
4368
+ document.addEventListener("mousedown", handleMouseDown);
4369
+ return () => document.removeEventListener("mousedown", handleMouseDown);
4370
+ }, [isOpen, onClose, anchorRef, panelRef]);
4371
+ const renderPanel = useCallback((children) => {
4372
+ if (!isOpen)
4373
+ return null;
4374
+ return createPortal(children, document.body);
4375
+ }, [isOpen]);
4376
+ return { panelRef, panelStyle: style, renderPanel };
4377
+ }
4378
+
4379
+ 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"};
4380
+
4381
+ /**
4382
+ * Custom dropdown component with colour-coded options, optional search filter, and full
4383
+ * keyboard navigation (↑ ↓ Enter Esc Tab).
4384
+ *
4385
+ * Use `CwDropdown` instead of the native `<select>` when options need colour indicators or
4386
+ * when inline search filtering is required.
4387
+ *
4388
+ * @example
4389
+ * <CwDropdown
4390
+ * options={[{ value: 'a', label: 'Option A', color: '#1976D2' }]}
4391
+ * value={selected}
4392
+ * onChange={setSelected}
4393
+ * labelProps={{ text: 'My Label' }}
4394
+ * />
4395
+ */
4396
+ function CwDropdown({ options, value, onChange, labelProps, alignProps, placeholder = "Select...", allowSearch = false, disabled = false, required = false, feedback, className, style, ...otherProps }) {
4397
+ const [isOpen, setIsOpen] = useState(false);
4398
+ const [searchText, setSearchText] = useState("");
4399
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
4400
+ const containerRef = useRef(null);
4401
+ const wrapperRef = useRef(null);
4402
+ const inputRef = useRef(null);
4403
+ const highlightedItemRef = useRef(null);
4404
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4405
+ anchorRef: wrapperRef,
4406
+ isOpen,
4407
+ onClose: () => { setIsOpen(false); setSearchText(""); setHighlightedIndex(-1); },
4408
+ });
4409
+ const selectedOption = options.find(opt => opt.value === value);
4410
+ // Filter options based on search
4411
+ const filteredOptions = searchText
4412
+ ? options.filter(opt => opt.label.toLowerCase().includes(searchText.toLowerCase()))
4413
+ : options;
4414
+ // Feedback handling
4415
+ const feedbackMessages = feedback
4416
+ ? Array.isArray(feedback) ? feedback : [feedback]
4417
+ : [];
4418
+ // Scroll highlighted item into view
4419
+ useEffect(() => {
4420
+ if (isOpen && highlightedItemRef.current) {
4421
+ highlightedItemRef.current.scrollIntoView({
4422
+ block: "nearest",
4423
+ behavior: "smooth",
4424
+ });
4425
+ }
4426
+ }, [highlightedIndex, isOpen]);
4427
+ const handleTriggerClick = useCallback(() => {
4428
+ if (!disabled) {
4429
+ setIsOpen(!isOpen);
4430
+ setHighlightedIndex(-1);
4431
+ if (!isOpen && allowSearch) {
4432
+ setTimeout(() => inputRef.current?.focus(), 0);
4433
+ }
4434
+ }
4435
+ }, [isOpen, disabled, allowSearch]);
4436
+ const handleOptionSelect = useCallback((optionValue) => {
4437
+ const selected = options.find(opt => opt.value === optionValue);
4438
+ if (selected && !selected.disabled) {
4439
+ onChange?.(optionValue);
4440
+ setIsOpen(false);
4441
+ setSearchText("");
4442
+ setHighlightedIndex(-1);
4443
+ }
4444
+ }, [options, onChange]);
4445
+ const handleSearchChange = useCallback((e) => {
4446
+ setSearchText(e.target.value);
4447
+ setHighlightedIndex(-1);
4448
+ }, []);
4449
+ const handleKeyDown = useCallback((e) => {
4450
+ if (!isOpen) {
4451
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
4452
+ e.preventDefault();
4453
+ setIsOpen(true);
4454
+ }
4455
+ return;
4456
+ }
4457
+ switch (e.key) {
4458
+ case "ArrowDown":
4459
+ e.preventDefault();
4460
+ setHighlightedIndex(prev => prev < filteredOptions.length - 1 ? prev + 1 : 0);
4461
+ break;
4462
+ case "ArrowUp":
4463
+ e.preventDefault();
4464
+ setHighlightedIndex(prev => prev > 0 ? prev - 1 : filteredOptions.length - 1);
4465
+ break;
4466
+ case "Enter":
4467
+ e.preventDefault();
4468
+ if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {
4469
+ handleOptionSelect(filteredOptions[highlightedIndex].value);
4470
+ }
4471
+ break;
4472
+ case "Escape":
4473
+ e.preventDefault();
4474
+ setIsOpen(false);
4475
+ setSearchText("");
4476
+ setHighlightedIndex(-1);
4477
+ break;
4478
+ case "Tab":
4479
+ setIsOpen(false);
4480
+ setSearchText("");
4481
+ setHighlightedIndex(-1);
4482
+ break;
4483
+ }
4484
+ }, [isOpen, highlightedIndex, filteredOptions, handleOptionSelect]);
4485
+ const flexDirection = alignProps?.flexDirection ?? "row";
4486
+ return (jsxs("div", { ref: containerRef, className: `cw-dropdown${className ? ` ${className}` : ""}`, "data-direction": flexDirection, style: style, ...otherProps, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-dropdown-wrapper", ref: wrapperRef, children: [jsx("button", { type: "button", className: "cw-dropdown-trigger", onClick: handleTriggerClick, onKeyDown: handleKeyDown, disabled: disabled, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": selectedOption?.label || placeholder, children: jsx("div", { className: "cw-dropdown-trigger-content", children: selectedOption ? (jsxs(Fragment, { children: [selectedOption.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: selectedOption.color } })), jsx("span", { children: selectedOption.label })] })) : (jsx("span", { className: "cw-dropdown-placeholder", children: placeholder })) }) }), jsx("div", { style: { display: "flex", alignItems: "center", paddingRight: "0.5rem", flexShrink: 0, cursor: disabled ? "not-allowed" : "pointer" }, onClick: handleTriggerClick, children: jsx(CwIcon, { iconId: "chevron-down", size: "small" }) }), renderPanel(jsxs("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", onKeyDown: handleKeyDown, children: [allowSearch && (jsx("div", { className: dropdownStyles.searchBox, children: jsx("input", { ref: inputRef, type: "text", placeholder: "Search...", value: searchText, onChange: handleSearchChange, onKeyDown: handleKeyDown, className: dropdownStyles.searchInput, autoComplete: "off" }) })), jsx("ul", { children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => (jsxs("li", { ref: highlightedIndex === index ? highlightedItemRef : null, className: [
4487
+ dropdownStyles.option,
4488
+ value === option.value ? dropdownStyles.optionSelected : "",
4489
+ highlightedIndex === index ? dropdownStyles.optionFocused : "",
4490
+ option.disabled ? dropdownStyles.optionDisabled : "",
4491
+ ].filter(Boolean).join(" "), onClick: () => !option.disabled && handleOptionSelect(option.value), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": value === option.value, "aria-disabled": option.disabled, children: [option.color && (jsx("span", { className: dropdownStyles.colorCircle, style: { backgroundColor: option.color } })), jsx("span", { children: option.label })] }, option.value)))) : (jsx("li", { className: dropdownStyles.emptyState, children: "No options available" })) })] }))] })] }), feedbackMessages.map((item, index) => (jsx("p", { className: "cw-input-info", "data-color": item.type, children: item.message }, index)))] }));
4259
4492
  }
4260
4493
 
4261
4494
  function CwDropdownFilter(props) {
@@ -4268,7 +4501,7 @@ function CwDropdownFilter(props) {
4268
4501
  return (jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
4269
4502
  }
4270
4503
 
4271
- var styles$9 = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4504
+ var styles$a = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4272
4505
 
4273
4506
  /**
4274
4507
  * Button that toggles a floating panel with arbitrary children.
@@ -4315,7 +4548,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4315
4548
  }
4316
4549
  panel.togglePopover();
4317
4550
  }, [placement]);
4318
- return (jsxs("div", { ref: containerRef, className: styles$9.container, children: [jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsx("div", { ref: panelCallbackRef, className: `${styles$9.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4551
+ return (jsxs("div", { ref: containerRef, className: styles$a.container, children: [jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsx("div", { ref: panelCallbackRef, className: `${styles$a.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4319
4552
  }
4320
4553
 
4321
4554
  function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
@@ -4333,13 +4566,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
4333
4566
  return result;
4334
4567
  }
4335
4568
 
4336
- var styles$8 = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4569
+ var styles$9 = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4337
4570
 
4338
4571
  const CwMultiFilterTag = props => {
4339
4572
  const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
4340
4573
  const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
4341
4574
  const isOutlineMode = Selected && !Removable;
4342
- return (jsx("li", { className: styles$8["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4575
+ return (jsx("li", { className: styles$9["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4343
4576
  if (Selectable)
4344
4577
  props.OnSelect?.(props);
4345
4578
  }, children: jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
@@ -4349,7 +4582,7 @@ const CwMultiFilterTag = props => {
4349
4582
  } : undefined }) }));
4350
4583
  };
4351
4584
 
4352
- 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"};
4585
+ 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"};
4353
4586
 
4354
4587
  /**
4355
4588
  * A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
@@ -4497,19 +4730,14 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4497
4730
  const [selectedCategory, setSelectedCategory] = useState("All");
4498
4731
  const componentRef = useRef(null);
4499
4732
  const inputRef = useRef(null);
4733
+ const wrapperRef = useRef(null);
4734
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4735
+ anchorRef: wrapperRef,
4736
+ isOpen: isPanelOpen,
4737
+ onClose: () => { setIsPanelOpen(false); setFilteredTags(getUnselectedAll()); setSelectedCategory("All"); setInputTextValue(""); },
4738
+ });
4500
4739
  useEffect(() => {
4501
- function handleClickOutside(event) {
4502
- if (componentRef.current && !componentRef.current.contains(event.target)) {
4503
- setIsPanelOpen(false);
4504
- setFilteredTags(new Set());
4505
- setSelectedCategory("All");
4506
- setInputTextValue("");
4507
- }
4508
- }
4509
- document.addEventListener("mousedown", handleClickOutside);
4510
- return () => {
4511
- document.removeEventListener("mousedown", handleClickOutside);
4512
- };
4740
+ // Outside-click is now handled by useDropdownPortal
4513
4741
  }, []);
4514
4742
  const categoriesMappedToTags = () => {
4515
4743
  const categoriesMap = new Map();
@@ -4520,9 +4748,10 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4520
4748
  });
4521
4749
  return categoriesMap;
4522
4750
  };
4751
+ const getUnselectedAll = (excluded = selectedTags) => new Set(Array.from(allTags).filter(tag => !Array.from(excluded).some(t => t.ID === tag.ID)));
4523
4752
  const handleClickCategory = (category) => {
4524
4753
  setSelectedCategory(category);
4525
- setFilteredTags(category != "All" ? (categoriesMappedToTags().get(category) ?? new Set()) : new Set());
4754
+ setFilteredTags(category !== "All" ? (categoriesMappedToTags().get(category) ?? new Set()) : getUnselectedAll());
4526
4755
  };
4527
4756
  const rgbAString = (r, g, b) => {
4528
4757
  return `rgb(${r}, ${g}, ${b})`;
@@ -4554,7 +4783,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4554
4783
  setFilteredTags(new Set(newFilterTags));
4555
4784
  }
4556
4785
  else {
4557
- setFilteredTags(new Set());
4786
+ setFilteredTags(getUnselectedAll());
4558
4787
  }
4559
4788
  };
4560
4789
  const addTag = (newTag) => {
@@ -4568,7 +4797,13 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4568
4797
  const updatedTags = new Set(selectedTags).add(newTag);
4569
4798
  onChangeSelectedTags(updatedTags);
4570
4799
  setInputTextValue("");
4571
- //setFilteredTags(allTags);
4800
+ setFilteredTags(selectedCategory === "All" ? getUnselectedAll(updatedTags) : prev => {
4801
+ const next = new Set(prev);
4802
+ const toRemove = Array.from(next).find(t => t.ID === newTag.ID);
4803
+ if (toRemove)
4804
+ next.delete(toRemove);
4805
+ return next;
4806
+ });
4572
4807
  }
4573
4808
  };
4574
4809
  const removeTag = (id) => {
@@ -4592,9 +4827,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4592
4827
  inputRef.current?.focus();
4593
4828
  }
4594
4829
  };
4595
- return (jsxs("form", { ref: componentRef, id: id, className: `${styles$7["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4830
+ return (jsxs("form", { ref: componentRef, id: id, className: `${styles$8["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4596
4831
  e.preventDefault();
4597
- }, children: [jsxs("div", { onClick: handleDivClick, className: styles$7["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-primary)", outlineOffset: "-2px" } : {}, children: [jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.target.value), autoComplete: "off", placeholder: placeholder, onKeyDown: e => {
4832
+ }, children: [jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$8["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4598
4833
  switch (e.key) {
4599
4834
  case "Enter":
4600
4835
  case "Tab": {
@@ -4621,21 +4856,10 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4621
4856
  break;
4622
4857
  }
4623
4858
  }
4624
- } })] }), selectedTags.size > 0 ? (jsx("input", { type: "reset", value: "\u00D7", onClick: e => {
4625
- e.preventDefault();
4626
- onChangeSelectedTags(new Set());
4627
- } })) : null] }), jsxs("section", { className: styles$7["cw-multi-filter-catalog-container"], "data-display-none": !isPanelOpen, children: [jsxs("nav", { children: [jsx("button", { className: selectedCategory === "All" ? styles$7["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsx("button", { style: selectedCategory === category
4628
- ? {
4629
- backgroundColor: getColor(category).primary,
4630
- color: getColor(category).onPrimary,
4631
- outline: "2px solid " + getColor(category).onPrimary,
4632
- outlineOffset: "-2px",
4633
- fontWeight: 400
4634
- }
4635
- : {
4636
- backgroundColor: getColor(category).primary,
4637
- color: getColor(category).onPrimary,
4638
- }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsx("ul", { children: Array.from(filteredTags)
4859
+ } })] }), selectedTags.size > 0 && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxs("section", { ref: panelRef, className: styles$8["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxs("nav", { children: [jsx("button", { className: selectedCategory === "All" ? styles$8["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsx("button", { className: selectedCategory === category ? styles$8["category-selected"] : undefined, style: {
4860
+ backgroundColor: getColor(category).primary,
4861
+ color: getColor(category).onPrimary,
4862
+ }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsx("ul", { children: Array.from(filteredTags)
4639
4863
  .sort((a, b) => {
4640
4864
  const input = inputTextValue.trim().toLowerCase();
4641
4865
  const aName = a.Name.trim().toLowerCase();
@@ -4655,9 +4879,148 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4655
4879
  removeTag(props.ID);
4656
4880
  else
4657
4881
  addTag(props);
4658
- } }, props.ID))) })] })] }));
4882
+ } }, props.ID))) })] }))] }));
4659
4883
  };
4660
4884
 
4885
+ 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"};
4886
+
4887
+ /**
4888
+ * Multi-select input with chip tags and searchable dropdown.
4889
+ * Works like a Kendo MultiSelect: selected items appear as removable chips
4890
+ * inside the input area, and a filtered dropdown lets the user pick more.
4891
+ *
4892
+ * @example
4893
+ * ```tsx
4894
+ * const options = [
4895
+ * { value: "1", label: "Alpha" },
4896
+ * { value: "2", label: "Bravo" },
4897
+ * { value: "3", label: "Charlie" },
4898
+ * ];
4899
+ * const [selected, setSelected] = useState<string[]>([]);
4900
+ *
4901
+ * <CwTagSelector
4902
+ * labelProps={{ text: "Tags" }}
4903
+ * options={options}
4904
+ * value={selected}
4905
+ * onChange={setSelected}
4906
+ * placeholder="Select items…"
4907
+ * />
4908
+ * ```
4909
+ */
4910
+ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, alignProps, placeholder = "Select…", disabled = false, showSelectAll = false, feedback, className, style, }) {
4911
+ const [search, setSearch] = useState("");
4912
+ const [open, setOpen] = useState(false);
4913
+ const [focusedIndex, setFocusedIndex] = useState(-1);
4914
+ const containerRef = useRef(null);
4915
+ const inputBoxRef = useRef(null);
4916
+ const inputRef = useRef(null);
4917
+ const listRef = useRef(null);
4918
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
4919
+ anchorRef: inputBoxRef,
4920
+ isOpen: open,
4921
+ onClose: () => { setOpen(false); setFocusedIndex(-1); },
4922
+ });
4923
+ const selectedSet = useMemo(() => new Set(value), [value]);
4924
+ const filtered = useMemo(() => {
4925
+ if (!search)
4926
+ return options.filter(o => !selectedSet.has(o.value));
4927
+ const lower = search.toLowerCase();
4928
+ return options.filter(o => !selectedSet.has(o.value) && o.label.toLowerCase().includes(lower));
4929
+ }, [options, selectedSet, search]);
4930
+ const selectedOptions = useMemo(() => value.map(v => options.find(o => o.value === v)).filter(Boolean), [value, options]);
4931
+ const handleSelect = useCallback((optionValue) => {
4932
+ onChange([...value, optionValue]);
4933
+ setSearch("");
4934
+ setFocusedIndex(-1);
4935
+ inputRef.current?.focus();
4936
+ }, [value, onChange]);
4937
+ const handleRemove = useCallback((optionValue) => {
4938
+ onChange(value.filter(v => v !== optionValue));
4939
+ inputRef.current?.focus();
4940
+ }, [value, onChange]);
4941
+ const allSelected = options.length > 0 && options.every(o => selectedSet.has(o.value));
4942
+ const handleToggleAll = useCallback(() => {
4943
+ if (allSelected) {
4944
+ onChange([]);
4945
+ }
4946
+ else {
4947
+ onChange(options.map(o => o.value));
4948
+ }
4949
+ setSearch("");
4950
+ setFocusedIndex(-1);
4951
+ inputRef.current?.focus();
4952
+ }, [allSelected, options, onChange]);
4953
+ const handleInputChange = useCallback((e) => {
4954
+ setSearch(e.currentTarget.value);
4955
+ if (!open)
4956
+ setOpen(true);
4957
+ setFocusedIndex(-1);
4958
+ }, [open]);
4959
+ const handleInputFocus = useCallback(() => {
4960
+ if (!disabled)
4961
+ setOpen(true);
4962
+ }, [disabled]);
4963
+ const handleKeyDown = useCallback((e) => {
4964
+ if (e.key === "Backspace" && !search && value.length > 0) {
4965
+ onChange(value.slice(0, -1));
4966
+ return;
4967
+ }
4968
+ if (e.key === "Escape") {
4969
+ setOpen(false);
4970
+ setFocusedIndex(-1);
4971
+ return;
4972
+ }
4973
+ if (e.key === "Enter") {
4974
+ e.preventDefault();
4975
+ if (focusedIndex >= 0 && focusedIndex < filtered.length) {
4976
+ handleSelect(filtered[focusedIndex].value);
4977
+ }
4978
+ else if (search.trim().length > 0 && filtered.length > 0) {
4979
+ const lower = search.trim().toLowerCase();
4980
+ const match = filtered.find(o => o.label.trim().toLowerCase() === lower) ??
4981
+ filtered.find(o => o.label.trim().toLowerCase().startsWith(lower)) ??
4982
+ filtered[0];
4983
+ if (match)
4984
+ handleSelect(match.value);
4985
+ }
4986
+ else if (!open) {
4987
+ setOpen(true);
4988
+ setFocusedIndex(0);
4989
+ }
4990
+ return;
4991
+ }
4992
+ if (!open) {
4993
+ if (e.key === "ArrowDown") {
4994
+ setOpen(true);
4995
+ setFocusedIndex(0);
4996
+ e.preventDefault();
4997
+ }
4998
+ return;
4999
+ }
5000
+ if (e.key === "ArrowDown") {
5001
+ e.preventDefault();
5002
+ setFocusedIndex(prev => (prev < filtered.length - 1 ? prev + 1 : prev));
5003
+ }
5004
+ else if (e.key === "ArrowUp") {
5005
+ e.preventDefault();
5006
+ setFocusedIndex(prev => (prev > 0 ? prev - 1 : 0));
5007
+ }
5008
+ }, [open, search, value, filtered, focusedIndex, onChange, handleSelect]);
5009
+ // Scroll focused item into view
5010
+ useEffect(() => {
5011
+ if (focusedIndex >= 0 && listRef.current) {
5012
+ const item = listRef.current.children[focusedIndex];
5013
+ item?.scrollIntoView({ block: "nearest" });
5014
+ }
5015
+ }, [focusedIndex]);
5016
+ // Close on outside click — now handled by useDropdownPortal
5017
+ // Keeping containerRef for any other potential use
5018
+ const direction = alignProps?.flexDirection ?? "row";
5019
+ const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
5020
+ return (jsxs("div", { ref: containerRef, className: `${styles$7.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: `${styles$7.inputBox}${disabled ? ` ${styles$7.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5021
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$7.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$7.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$7.option}${idx === focusedIndex ? ` ${styles$7.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$7.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5022
+ }
5023
+
4661
5024
  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"};
4662
5025
 
4663
5026
  function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
@@ -4764,12 +5127,30 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
4764
5127
  return (jsxs("div", { className: `cw-tree-view ${styles$6["tree-container"]}`, children: [jsxs("header", { children: [jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsx("div", { className: styles$6["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxs("div", { className: styles$6["empty-state"], children: [jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
4765
5128
  }
4766
5129
 
5130
+ /**
5131
+ * Text input with a live-filtered suggestion dropdown backed by a local `CwSelectList` array.
5132
+ * Use `CwFindAirport` or `CwFindCrewmember` for API-backed search inputs.
5133
+ *
5134
+ * @example
5135
+ * <CwSearchInput
5136
+ * selectList={myItems}
5137
+ * handleChange={(id) => console.log('selected', id)}
5138
+ * labelProps={{ text: 'Employee' }}
5139
+ * placeholder="Search by name…"
5140
+ * />
5141
+ */
4767
5142
  function CwSearchInput(optionsProps) {
4768
5143
  const [searchText, setSearchText] = useState("");
4769
5144
  const [filteredOptions, setFilteredOptions] = useState([]);
4770
5145
  const [_selectedOption, setSelectedOption] = useState(null);
4771
5146
  const [showDropdown, setShowDropdown] = useState(false);
4772
5147
  const [isLoading, setIsLoading] = useState(false);
5148
+ const wrapperRef = useRef(null);
5149
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5150
+ anchorRef: wrapperRef,
5151
+ isOpen: showDropdown && filteredOptions.length > 0,
5152
+ onClose: () => setShowDropdown(false),
5153
+ });
4773
5154
  // Extract props
4774
5155
  const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
4775
5156
  // Get direction for data attribute
@@ -4820,9 +5201,8 @@ function CwSearchInput(optionsProps) {
4820
5201
  }
4821
5202
  };
4822
5203
  const handleInputBlur = () => {
4823
- setTimeout(() => {
4824
- setShowDropdown(false);
4825
- }, 150);
5204
+ // Dropdown is closed by useDropdownPortal's outside-click handler.
5205
+ // Blur alone must not close it — clicking an option would lose focus before the click fires.
4826
5206
  };
4827
5207
  const handleOptionSelect = (option) => {
4828
5208
  setSearchText(option.description);
@@ -4840,7 +5220,7 @@ function CwSearchInput(optionsProps) {
4840
5220
  handleChange("");
4841
5221
  }
4842
5222
  };
4843
- return (jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", children: [jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsx(CwIcon, { ...iconProps }) : jsx(CwIcon, { iconId: "search" })) })] })] }), showDropdown && filteredOptions.length > 0 && (jsx("div", { className: "cw-input-search-dropdown", children: jsx("ul", { children: filteredOptions.map((option) => (jsx("li", { onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5223
+ return (jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsx(CwIcon, { ...iconProps }) : jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, children: jsx("ul", { children: filteredOptions.map((option) => (jsx("li", { className: dropdownStyles.option, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
4844
5224
  }
4845
5225
 
4846
5226
  var styles$5 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
@@ -5097,81 +5477,49 @@ var styles$4 = {"pickerWrapper":"cw-pickers-base-module__pickerWrapper__Fb9Zo","
5097
5477
  /**
5098
5478
  * Renders a picker popup in a portal so it escapes overflow containers.
5099
5479
  * Positions itself relative to the anchor element.
5480
+ *
5481
+ * Thin wrapper around {@link useDropdownPortal} that adds directional
5482
+ * preference logic ("left-bottom", "right-top", etc.) for calendar popups.
5483
+ * The public API is unchanged — existing callers (`CwDatePicker`, etc.) need
5484
+ * no modifications.
5100
5485
  */
5101
5486
  function usePickerPopup({ anchorRef, isOpen, onClose, position = "left-bottom" }) {
5102
- const popupRef = useRef(null);
5103
- const [style, setStyle] = useState({ position: "fixed", top: 0, left: 0, zIndex: 1000 });
5104
- const reposition = useCallback(() => {
5105
- const anchor = anchorRef.current;
5106
- const popup = popupRef.current;
5107
- if (!anchor || !popup)
5108
- return;
5109
- const rect = anchor.getBoundingClientRect();
5110
- const popupRect = popup.getBoundingClientRect();
5111
- // Determine vertical placement
5487
+ const pickerStrategy = useCallback((anchorRect, panelRect) => {
5488
+ const popupH = panelRect?.height ?? 300;
5489
+ const popupW = panelRect?.width ?? 300;
5112
5490
  const preferTop = position.includes("top");
5113
- const spaceBelow = window.innerHeight - rect.bottom;
5114
- const spaceAbove = rect.top;
5115
- const popupH = popupRect.height || 300; // fallback for first render
5491
+ const spaceBelow = window.innerHeight - anchorRect.bottom;
5492
+ const spaceAbove = anchorRect.top;
5116
5493
  let top;
5117
5494
  if (preferTop && spaceAbove >= popupH) {
5118
- top = rect.top - popupH;
5495
+ top = anchorRect.top - popupH;
5119
5496
  }
5120
5497
  else if (!preferTop && spaceBelow >= popupH + 4) {
5121
- top = rect.bottom + 4;
5498
+ top = anchorRect.bottom + 4;
5122
5499
  }
5123
5500
  else {
5124
- // Flip if preferred side doesn't fit
5125
- top = spaceBelow >= popupH + 4 ? rect.bottom + 4 : rect.top - popupH;
5501
+ top = spaceBelow >= popupH + 4 ? anchorRect.bottom + 4 : anchorRect.top - popupH;
5126
5502
  }
5127
- // Determine horizontal placement
5128
5503
  let left;
5129
5504
  if (position.includes("right")) {
5130
- left = rect.right - (popupRect.width || rect.width);
5505
+ left = anchorRect.right - popupW;
5131
5506
  }
5132
5507
  else {
5133
- left = rect.left;
5508
+ left = anchorRect.left;
5134
5509
  }
5135
- // Clamp to viewport
5136
- left = Math.max(4, Math.min(left, window.innerWidth - (popupRect.width || 200) - 4));
5510
+ left = Math.max(4, Math.min(left, window.innerWidth - popupW - 4));
5137
5511
  top = Math.max(4, top);
5138
- setStyle({ position: "fixed", top, left, zIndex: 1000 });
5139
- }, [anchorRef, position]);
5140
- // Reposition on open + observe scroll/resize on all ancestors
5141
- useEffect(() => {
5142
- if (!isOpen)
5143
- return;
5144
- reposition();
5145
- // Re-measure after the popup renders to get its actual size
5146
- requestAnimationFrame(reposition);
5147
- const handleUpdate = () => reposition();
5148
- window.addEventListener("resize", handleUpdate);
5149
- window.addEventListener("scroll", handleUpdate, true); // capture phase catches all scrollable ancestors
5150
- return () => {
5151
- window.removeEventListener("resize", handleUpdate);
5152
- window.removeEventListener("scroll", handleUpdate, true);
5153
- };
5154
- }, [isOpen, reposition]);
5155
- // Close on outside click — checks both anchor and popup
5156
- useEffect(() => {
5157
- if (!isOpen)
5158
- return;
5159
- const handleMouseDown = (e) => {
5160
- const target = e.target;
5161
- if (anchorRef.current?.contains(target) ||
5162
- popupRef.current?.contains(target))
5163
- return;
5164
- onClose();
5165
- };
5166
- document.addEventListener("mousedown", handleMouseDown);
5167
- return () => document.removeEventListener("mousedown", handleMouseDown);
5168
- }, [isOpen, onClose, anchorRef]);
5169
- const renderPopup = useCallback((children) => {
5170
- if (!isOpen)
5171
- return null;
5172
- return createPortal(children, document.body);
5173
- }, [isOpen]);
5174
- return { popupRef, popupStyle: style, renderPopup };
5512
+ // No width override the calendar has its own intrinsic size
5513
+ return { top, left };
5514
+ }, [position]);
5515
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5516
+ anchorRef,
5517
+ isOpen,
5518
+ onClose,
5519
+ positionStrategy: pickerStrategy,
5520
+ });
5521
+ // Expose original API names so CwDatePicker needs zero changes
5522
+ return { popupRef: panelRef, popupStyle: panelStyle, renderPopup: renderPanel };
5175
5523
  }
5176
5524
 
5177
5525
  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 = enGB, todayLabel = "Today", feedback, }) {
@@ -9172,6 +9520,24 @@ const SuperScheduler = ({ id, state, header, rows, events, pinnedOrderCategory,
9172
9520
  }, children: "Clear pinned" }) })] })), jsx(Scheduler, { id: `${id}-notPinned`, state: { ...state, isHeaderVisible: !isFirstVisible }, header: header, rows: notPinnedRows, events: events, backgroundEvents: backgroundEvents, indicatorRows: indicatorRows, contextMenuItems: contextMenuItems, orderCategories: unPinnedOrderCategory, onEvent: onEvent, EventComp: SchedulerEvent, RowTitleComp: PinRowHeader, rowHeightRem: rowHeightRem })] }));
9173
9521
  };
9174
9522
 
9523
+ /**
9524
+ * API-backed airport search input for WinOps.
9525
+ *
9526
+ * Fetches matching airports from the WinOps backend as the user types (debounced).
9527
+ * Renders results in a shared `cw-choice-dropdown` styled panel with keyboard navigation.
9528
+ * Supports pre-selecting an airport by `value` (AptKey) and customising the displayed text
9529
+ * format via `displayMode`.
9530
+ *
9531
+ * Requires a running WinOps backend — set `cblConfig` to its base URL.
9532
+ *
9533
+ * @example
9534
+ * <CwFindAirport
9535
+ * cblConfig="https://localhost:44300"
9536
+ * handleChange={(key) => setAirportKey(key)}
9537
+ * labelProps={{ text: 'Departure Airport' }}
9538
+ * displayMode="iata-only"
9539
+ * />
9540
+ */
9175
9541
  const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder = "Search airport…", required = false, cblConfig, className = "", value, disabled = false, displayMode, initialDisplayText, labelProps, alignProps, width }) => {
9176
9542
  // State
9177
9543
  const [inputValue, setInputValue] = useState("");
@@ -9184,8 +9550,13 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9184
9550
  const [tooltipText, setTooltipText] = useState("");
9185
9551
  // Refs
9186
9552
  const inputRef = useRef(null);
9187
- const dropdownRef = useRef(null);
9553
+ const wrapperRef = useRef(null);
9188
9554
  const searchTimeoutRef = useRef();
9555
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
9556
+ anchorRef: wrapperRef,
9557
+ isOpen: showDropdown && options.length > 0,
9558
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
9559
+ });
9189
9560
  // Utility function to extract ICAO from DisplayAirportText
9190
9561
  const extractIcao = useCallback((displayText) => {
9191
9562
  const match = displayText.match(/^([A-Z]{4})\(/);
@@ -9362,19 +9733,7 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9362
9733
  break;
9363
9734
  }
9364
9735
  };
9365
- // Handle clicks outside dropdown
9366
- useEffect(() => {
9367
- const handleClickOutside = (event) => {
9368
- if (dropdownRef.current &&
9369
- !dropdownRef.current.contains(event.target) &&
9370
- !inputRef.current?.contains(event.target)) {
9371
- setShowDropdown(false);
9372
- setHighlightedIndex(-1);
9373
- }
9374
- };
9375
- document.addEventListener("mousedown", handleClickOutside);
9376
- return () => document.removeEventListener("mousedown", handleClickOutside);
9377
- }, []);
9736
+ // Handle clicks outside dropdown — now handled by useDropdownPortal
9378
9737
  // Load initial value
9379
9738
  useEffect(() => {
9380
9739
  if (value && value !== 0 && value !== -1) {
@@ -9416,9 +9775,25 @@ const CwFindAirport = ({ handleChange, searchType = "OnlyDatabase", placeHolder
9416
9775
  return (jsxs("div", { className: `cw-search-input ${className}`, style: {
9417
9776
  ...(width ? { width } : {}),
9418
9777
  ...(labelProps?.labelWidth ? { '--label-width': labelProps.labelWidth } : {})
9419
- }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected airport", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "control-tower" })) })] })] }), showDropdown && options.length > 0 && (jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsx("ul", { children: options.map((option, index) => (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))) }) }))] }));
9778
+ }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected airport", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "control-tower" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9420
9779
  };
9421
9780
 
9781
+ /**
9782
+ * API-backed crewmember search input for WinOps.
9783
+ *
9784
+ * Fetches matching crewmembers from the WinOps backend as the user types (debounced).
9785
+ * Renders results in a shared `cw-choice-dropdown` styled panel with keyboard navigation.
9786
+ * Supports pre-selecting a crewmember by numeric `value` (ID).
9787
+ *
9788
+ * Requires a running WinOps backend — set `cblConfig` to its base URL.
9789
+ *
9790
+ * @example
9791
+ * <CwFindCrewmember
9792
+ * cblConfig="https://localhost:44300"
9793
+ * handleChange={(id) => setCrewId(id)}
9794
+ * labelProps={{ text: 'Crew Member' }}
9795
+ * />
9796
+ */
9422
9797
  const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", required = false, cblConfig, className = "", value, disabled = false, initialDisplayText, labelProps, alignProps, width }) => {
9423
9798
  const [inputValue, setInputValue] = useState("");
9424
9799
  const [options, setOptions] = useState([]);
@@ -9429,8 +9804,13 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9429
9804
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
9430
9805
  const [tooltipText, setTooltipText] = useState("");
9431
9806
  const inputRef = useRef(null);
9432
- const dropdownRef = useRef(null);
9807
+ const wrapperRef = useRef(null);
9433
9808
  const searchTimeoutRef = useRef();
9809
+ const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
9810
+ anchorRef: wrapperRef,
9811
+ isOpen: showDropdown && options.length > 0,
9812
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
9813
+ });
9434
9814
  const getDisplayText = useCallback((crew) => {
9435
9815
  return `${crew.threeLetterCode} - ${crew.lastName} ${crew.firstName}`;
9436
9816
  }, []);
@@ -9532,16 +9912,7 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9532
9912
  }
9533
9913
  };
9534
9914
  useEffect(() => {
9535
- const handleClickOutside = (event) => {
9536
- if (dropdownRef.current &&
9537
- !dropdownRef.current.contains(event.target) &&
9538
- !inputRef.current?.contains(event.target)) {
9539
- setShowDropdown(false);
9540
- setHighlightedIndex(-1);
9541
- }
9542
- };
9543
- document.addEventListener("mousedown", handleClickOutside);
9544
- return () => document.removeEventListener("mousedown", handleClickOutside);
9915
+ // Outside-click is now handled by useDropdownPortal
9545
9916
  }, []);
9546
9917
  useEffect(() => {
9547
9918
  if (value && value !== 0 && value !== -1) {
@@ -9580,7 +9951,7 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
9580
9951
  return (jsxs("div", { className: `cw-search-input ${className}`, style: {
9581
9952
  ...(width ? { width } : {}),
9582
9953
  ...(labelProps?.labelWidth ? { '--label-width': labelProps.labelWidth } : {})
9583
- }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "person" })) })] })] }), showDropdown && options.length > 0 && (jsx("div", { ref: dropdownRef, className: "cw-input-search-dropdown", role: "listbox", children: jsx("ul", { children: options.map((option, index) => (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))) }) }))] }));
9954
+ }, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "person" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
9584
9955
  };
9585
9956
 
9586
- export { CblDragAndDrop, CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDateRangePicker, CwDateTimePicker, CwDateTimePickerCompact, CwDialog, CwDialogManager, CwDigit, CwDisplayMessage, CwDropdownFilter, CwExpandable, CwFileUpload, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDate, CwInputDatePicker, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwLoadingSmall, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNote, CwOption, CwPopoverButton, CwReportModal, CwScheduler, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSortableList, CwSortableTable, CwSuperScheduler, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PinRowHeader, Resource, Scheduler, SchedulerEvent, SuperScheduler, UiEvent, Weekdays, cblEvent, eventIsVisible, filterVisibleEvents, getDefaultDivisions, getEventSizes, itemsToMultiFilterTags, useCwMessage, useSortableList, useSortableTable };
9957
+ export { CblDragAndDrop, CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDateRangePicker, CwDateTimePicker, CwDateTimePickerCompact, CwDialog, CwDialogManager, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUpload, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDate, CwInputDatePicker, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwLoadingSmall, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNote, CwOption, CwPopoverButton, CwReportModal, CwScheduler, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSortableList, CwSortableTable, CwSuperScheduler, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PinRowHeader, Resource, Scheduler, SchedulerEvent, SuperScheduler, UiEvent, Weekdays, cblEvent, eventIsVisible, filterVisibleEvents, getDefaultDivisions, getEventSizes, itemsToMultiFilterTags, useCwMessage, useSortableList, useSortableTable };