@cwellt_software/cwellt-reactjs-lib 1.4.15 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content/icons/new-cw-icons/NewCwIcons.json +1 -1
- package/dist/content/icons/new-cw-icons/css/new-cw-icons.css +260 -824
- package/dist/content/icons/new-cw-icons/fonts/NewCwIcons.woff +0 -0
- package/dist/index.cjs.js +355 -203
- package/dist/index.css +2 -2
- package/dist/index.d.ts +133 -48
- package/dist/index.es.js +351 -202
- package/dist/src/components/control/action/search/CwSearch.d.ts +2 -0
- package/dist/src/components/control/action/search/CwSearch.d.ts.map +1 -1
- package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts +35 -0
- package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts.map +1 -0
- package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts +78 -0
- package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts.map +1 -0
- package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts +9 -0
- package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts.map +1 -0
- package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts +9 -0
- package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts.map +1 -0
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +12 -0
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -1
- package/dist/src/components/control/input/image/CwInputImage.d.ts +17 -2
- package/dist/src/components/control/input/image/CwInputImage.d.ts.map +1 -1
- package/dist/src/components/display/graphics/icon/CwIcon.d.ts +1 -1
- package/dist/src/components/display/graphics/icon/CwIcon.d.ts.map +1 -1
- package/dist/src/components/display/graphics/loading/CwLoading.d.ts +3 -14
- package/dist/src/components/display/graphics/loading/CwLoading.d.ts.map +1 -1
- package/dist/src/components/display/graphics/loading/loadingConfig.d.ts +16 -0
- package/dist/src/components/display/graphics/loading/loadingConfig.d.ts.map +1 -0
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
- package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts +3 -0
- package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts.map +1 -0
- package/dist/src/playground/pages/CwInputImagePage.d.ts.map +1 -1
- package/dist/src/playground/pages/CwNavMenuPage.d.ts +3 -0
- package/dist/src/playground/pages/CwNavMenuPage.d.ts.map +1 -0
- package/dist/src/playground/pages/IconLibraryPage.d.ts +3 -0
- package/dist/src/playground/pages/IconLibraryPage.d.ts.map +1 -0
- package/dist/src/playground/pages/LoadingPage.d.ts +3 -0
- package/dist/src/playground/pages/LoadingPage.d.ts.map +1 -0
- package/dist/src/playground/pages/SelectorsPage.d.ts.map +1 -1
- package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts +2 -0
- package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts.map +1 -0
- package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts +2 -0
- package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts.map +1 -0
- package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts +2 -0
- package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts.map +1 -0
- package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts +2 -0
- package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts.map +1 -0
- package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts +2 -0
- package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts.map +1 -0
- package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts +2 -0
- package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts.map +1 -0
- package/package.json +1 -2
package/dist/index.cjs.js
CHANGED
|
@@ -181,12 +181,7 @@ function getContrastColor(color) {
|
|
|
181
181
|
return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
|
|
186
|
-
'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
var styles$u = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
|
|
184
|
+
var styles$v = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
|
|
190
185
|
|
|
191
186
|
// Constants
|
|
192
187
|
const margin$1 = 16;
|
|
@@ -476,7 +471,7 @@ const CwTooltipManager = () => {
|
|
|
476
471
|
if (!state.isVisible || !state.content) {
|
|
477
472
|
return null;
|
|
478
473
|
}
|
|
479
|
-
return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$
|
|
474
|
+
return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$v["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
|
|
480
475
|
top: `${tooltipPosition.top}px`,
|
|
481
476
|
left: `${tooltipPosition.left}px`,
|
|
482
477
|
opacity: (isPositioned && !isMeasuring) ? 1 : 0,
|
|
@@ -557,16 +552,22 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
|
|
|
557
552
|
React.useEffect(() => {
|
|
558
553
|
ensureTooltipManager();
|
|
559
554
|
}, []);
|
|
560
|
-
return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$
|
|
555
|
+
return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$v["cw-tooltip"], children: children }));
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
const SVG_ICONS = {
|
|
559
|
+
'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
|
|
560
|
+
'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
|
|
561
561
|
};
|
|
562
562
|
|
|
563
563
|
function CwIcon(props) {
|
|
564
|
-
const { iconId, color, size, title, tooltipPosition = 'bottom', ...iconProps } = props;
|
|
564
|
+
const { iconId, color, size, className, title, tooltipPosition = 'bottom', ...iconProps } = props;
|
|
565
565
|
const getClassName = (baseClass) => {
|
|
566
566
|
return [
|
|
567
567
|
baseClass,
|
|
568
568
|
color && `cw-color-${color}`,
|
|
569
|
-
size && `cw-font-size-${size}
|
|
569
|
+
size && `cw-font-size-${size}`,
|
|
570
|
+
className
|
|
570
571
|
].filter(Boolean).join(' ');
|
|
571
572
|
};
|
|
572
573
|
let iconElement;
|
|
@@ -978,49 +979,39 @@ function CwImageZoom(image) {
|
|
|
978
979
|
} }), jsxRuntime.jsx("div", { style: { color: "#fff", fontSize: "1rem", textAlign: "center" }, children: selectedImage.filename && jsxRuntime.jsx("div", { children: selectedImage.filename }) })] }))] }));
|
|
979
980
|
}
|
|
980
981
|
|
|
982
|
+
let defaults = {};
|
|
981
983
|
/**
|
|
982
|
-
* CwLoading
|
|
983
|
-
*
|
|
984
|
-
* A versatile loading component that shows a spinner with optional text
|
|
985
|
-
* and disables the wrapped content while in loading state.
|
|
986
|
-
*
|
|
987
|
-
* @example
|
|
988
|
-
* // Basic usage
|
|
989
|
-
* <CwLoading isLoading={isSubmitting}>
|
|
990
|
-
* <form>...</form>
|
|
991
|
-
* </CwLoading>
|
|
992
|
-
*
|
|
993
|
-
* // With custom text and size
|
|
994
|
-
* <CwLoading
|
|
995
|
-
* isLoading={isLoading}
|
|
996
|
-
* text="Please wait..."
|
|
997
|
-
* size="large"
|
|
998
|
-
* >
|
|
999
|
-
* <UserProfile />
|
|
1000
|
-
* </CwLoading>
|
|
984
|
+
* Register global CwLoading defaults. Call once at app init, before the first render.
|
|
985
|
+
* Merges into any previously configured defaults.
|
|
1001
986
|
*/
|
|
1002
|
-
function
|
|
1003
|
-
|
|
1004
|
-
|
|
987
|
+
function configureCwLoading(next) {
|
|
988
|
+
defaults = { ...defaults, ...next };
|
|
989
|
+
}
|
|
990
|
+
/** Read the currently configured CwLoading defaults. */
|
|
991
|
+
function getCwLoadingDefaults() {
|
|
992
|
+
return defaults;
|
|
1005
993
|
}
|
|
1006
994
|
|
|
1007
995
|
/**
|
|
1008
|
-
*
|
|
996
|
+
* CwLoading — a spinner with optional text that dims the wrapped content while loading.
|
|
1009
997
|
*
|
|
1010
|
-
*
|
|
998
|
+
* Icon resolves as `iconName` prop → `getCwLoadingDefaults().icon` → none (neutral ring).
|
|
1011
999
|
*
|
|
1012
1000
|
* @example
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
* // Use:
|
|
1017
|
-
* <CwLoading size="small" />
|
|
1001
|
+
* <CwLoading isLoading={isSubmitting}>
|
|
1002
|
+
* <form>...</form>
|
|
1003
|
+
* </CwLoading>
|
|
1018
1004
|
*/
|
|
1019
|
-
function
|
|
1020
|
-
|
|
1005
|
+
function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName, animation = 'spin', children }) {
|
|
1006
|
+
let overlay = null;
|
|
1007
|
+
if (isLoading) {
|
|
1008
|
+
const resolvedIcon = iconName ?? getCwLoadingDefaults().icon;
|
|
1009
|
+
overlay = (jsxRuntime.jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, role: "status", "aria-label": text || 'Loading', children: [jsxRuntime.jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, "data-has-icon": !!resolvedIcon, children: resolvedIcon && jsxRuntime.jsx("span", { className: `cwi-icons ${resolvedIcon}` }) }), text && (jsxRuntime.jsx("p", { children: text }))] }));
|
|
1010
|
+
}
|
|
1011
|
+
return (jsxRuntime.jsxs("div", { "aria-busy": isLoading, className: "cw-loading-container", "data-children": !!children, children: [overlay, jsxRuntime.jsx("div", { className: "cw-loading-disabled-content", children: children })] }));
|
|
1021
1012
|
}
|
|
1022
1013
|
|
|
1023
|
-
var styles$
|
|
1014
|
+
var styles$u = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
|
|
1024
1015
|
|
|
1025
1016
|
// Constants moved outside to prevent recreation
|
|
1026
1017
|
const margin = 16;
|
|
@@ -1143,12 +1134,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
1143
1134
|
const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
|
|
1144
1135
|
setIsVisible(true);
|
|
1145
1136
|
}, showDelay);
|
|
1146
|
-
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$
|
|
1137
|
+
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$u["cw-generic-tooltip-content"]);
|
|
1147
1138
|
// Memoize tooltip content creation
|
|
1148
1139
|
const tooltipContent = React.useMemo(() => {
|
|
1149
1140
|
if (hide || !isVisible || !content)
|
|
1150
1141
|
return null;
|
|
1151
|
-
return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$
|
|
1142
|
+
return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$u["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
|
|
1152
1143
|
position: 'fixed',
|
|
1153
1144
|
top: `${tooltipPosition.top}px`,
|
|
1154
1145
|
left: `${tooltipPosition.left}px`,
|
|
@@ -1163,7 +1154,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
1163
1154
|
clearTooltipTimeout();
|
|
1164
1155
|
setIsVisible(false);
|
|
1165
1156
|
}, [clearTooltipTimeout]);
|
|
1166
|
-
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$
|
|
1157
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
|
|
1167
1158
|
};
|
|
1168
1159
|
|
|
1169
1160
|
const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
|
|
@@ -1225,7 +1216,7 @@ function CwModal(custModalProps) {
|
|
|
1225
1216
|
return (jsxRuntime.jsx("div", { children: custModalProps.modalState && (jsxRuntime.jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsxRuntime.jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsxRuntime.jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxRuntime.jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxRuntime.jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsxRuntime.jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsxRuntime.jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsxRuntime.jsx("span", { className: "cwelltCloseIcon" }) })] }), jsxRuntime.jsx("div", { className: "cwelltModalBody", children: jsxRuntime.jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsxRuntime.jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsxRuntime.jsx("div", { style: { display: "none" } }))] }) })] })) }));
|
|
1226
1217
|
}
|
|
1227
1218
|
|
|
1228
|
-
var styles$
|
|
1219
|
+
var styles$t = {"overlayPositioned":"CwConfirmationPopup-module__overlayPositioned__11qYB","popup":"CwConfirmationPopup-module__popup__ahPjM","message":"CwConfirmationPopup-module__message__MnNL4","buttons":"CwConfirmationPopup-module__buttons__fGYYE","button":"CwConfirmationPopup-module__button__ugYQE","confirmButton":"CwConfirmationPopup-module__confirmButton__rTP4S","cancelButton":"CwConfirmationPopup-module__cancelButton__Ry694"};
|
|
1229
1220
|
|
|
1230
1221
|
function CwConfirmationPopup(props) {
|
|
1231
1222
|
const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
|
|
@@ -1289,15 +1280,15 @@ function CwConfirmationPopup(props) {
|
|
|
1289
1280
|
onCancel();
|
|
1290
1281
|
}
|
|
1291
1282
|
};
|
|
1292
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$
|
|
1283
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$t.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$t.popup, style: {
|
|
1293
1284
|
position: 'absolute',
|
|
1294
1285
|
top: `${position.top}px`,
|
|
1295
1286
|
left: `${position.left}px`,
|
|
1296
1287
|
transform: 'none'
|
|
1297
|
-
}, children: [jsxRuntime.jsx("p", { className: styles$
|
|
1288
|
+
}, children: [jsxRuntime.jsx("p", { className: styles$t.message, children: message }), jsxRuntime.jsxs("div", { className: styles$t.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
|
|
1298
1289
|
}
|
|
1299
1290
|
|
|
1300
|
-
var styles$
|
|
1291
|
+
var styles$s = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
|
|
1301
1292
|
|
|
1302
1293
|
// Helper function to parse size values
|
|
1303
1294
|
const parseSize = (size) => {
|
|
@@ -1570,7 +1561,7 @@ const CwDialog = props => {
|
|
|
1570
1561
|
}
|
|
1571
1562
|
}
|
|
1572
1563
|
}, [open]);
|
|
1573
|
-
const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$
|
|
1564
|
+
const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$s["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
|
|
1574
1565
|
const content = React.useMemo(() => (jsxRuntime.jsx("section", { children: children })), [children]);
|
|
1575
1566
|
const footer = React.useMemo(() => (jsxRuntime.jsx("footer", { children: customFooter || (jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
|
|
1576
1567
|
const resizeHandles = React.useMemo(() => size.autoHeight
|
|
@@ -1597,7 +1588,7 @@ const CwDialog = props => {
|
|
|
1597
1588
|
: `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
|
|
1598
1589
|
return { displayWidth, displayHeight };
|
|
1599
1590
|
}, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
|
|
1600
|
-
const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$
|
|
1591
|
+
const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$s["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
|
|
1601
1592
|
left: `${position.x}px`,
|
|
1602
1593
|
top: `${position.y}px`,
|
|
1603
1594
|
width: displayDimensions.displayWidth,
|
|
@@ -1758,7 +1749,7 @@ function CwAlign(props) {
|
|
|
1758
1749
|
}, children: props.children }));
|
|
1759
1750
|
}
|
|
1760
1751
|
|
|
1761
|
-
var styles$
|
|
1752
|
+
var styles$r = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
|
|
1762
1753
|
|
|
1763
1754
|
/**
|
|
1764
1755
|
* CwCard - A simple card component for displaying content in a contained format
|
|
@@ -1784,11 +1775,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1784
1775
|
// Construct class names using CSS modules
|
|
1785
1776
|
const cardClassNames = [
|
|
1786
1777
|
'cw-card',
|
|
1787
|
-
styles$
|
|
1778
|
+
styles$r.card,
|
|
1788
1779
|
className,
|
|
1789
|
-
clickable ? styles$
|
|
1790
|
-
disabled ? styles$
|
|
1791
|
-
isLoading ? styles$
|
|
1780
|
+
clickable ? styles$r.clickable : '',
|
|
1781
|
+
disabled ? styles$r.disabled : '',
|
|
1782
|
+
isLoading ? styles$r.loading : '',
|
|
1792
1783
|
].filter(Boolean).join(' ');
|
|
1793
1784
|
// Handle click event when card is clickable
|
|
1794
1785
|
const handleClick = () => {
|
|
@@ -1805,15 +1796,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1805
1796
|
// Determine if footer should be rendered
|
|
1806
1797
|
const hasFooter = hasChips || footer || (hasActions && resolvedDirection === "row");
|
|
1807
1798
|
// Actions component to reuse
|
|
1808
|
-
const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$
|
|
1799
|
+
const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$r.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
|
|
1809
1800
|
return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
|
|
1810
1801
|
role: 'button',
|
|
1811
1802
|
tabIndex: 0,
|
|
1812
1803
|
onClick: handleClick,
|
|
1813
|
-
}), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$
|
|
1804
|
+
}), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$r.headerContent, "data-align": resolvedAlign, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$r.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$r.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$r.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$r.footerContent, children: footer }))] })), resolvedDirection === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$r.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
|
|
1814
1805
|
};
|
|
1815
1806
|
|
|
1816
|
-
var styles$
|
|
1807
|
+
var styles$q = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS"};
|
|
1817
1808
|
|
|
1818
1809
|
/**
|
|
1819
1810
|
* Option to display in the CwSelect
|
|
@@ -1908,10 +1899,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
|
|
|
1908
1899
|
icon: sortDirection === 'asc' ? 'arrow-up' : 'arrow-down',
|
|
1909
1900
|
onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'),
|
|
1910
1901
|
title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}`,
|
|
1911
|
-
}, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: styles$
|
|
1902
|
+
}, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: styles$q.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$q.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$q.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$q.pagination, children: [jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxRuntime.jsxs("span", { className: styles$q.pageInfo, children: [currentPage, " / ", totalPages] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
|
|
1912
1903
|
}
|
|
1913
1904
|
|
|
1914
|
-
var styles$
|
|
1905
|
+
var styles$p = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
|
|
1915
1906
|
|
|
1916
1907
|
/**
|
|
1917
1908
|
*
|
|
@@ -1928,7 +1919,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
|
|
|
1928
1919
|
setVisible_accordionBody(!isVisible_accordionBody);
|
|
1929
1920
|
};
|
|
1930
1921
|
// #endregion
|
|
1931
|
-
return (jsxRuntime.jsxs("div", { className: styles$
|
|
1922
|
+
return (jsxRuntime.jsxs("div", { className: styles$p["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$p["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
|
|
1932
1923
|
}
|
|
1933
1924
|
|
|
1934
1925
|
/**
|
|
@@ -2186,7 +2177,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
|
|
|
2186
2177
|
}, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
|
|
2187
2178
|
}
|
|
2188
2179
|
|
|
2189
|
-
var styles$
|
|
2180
|
+
var styles$o = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
|
|
2190
2181
|
|
|
2191
2182
|
/**
|
|
2192
2183
|
* Hook that provides state management for CwSortableTable.
|
|
@@ -2249,9 +2240,9 @@ function useSortableTable(initialItems) {
|
|
|
2249
2240
|
}
|
|
2250
2241
|
|
|
2251
2242
|
// ─── Drop indicator row ───────────────────────────────────────────────────────
|
|
2252
|
-
const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$
|
|
2243
|
+
const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$o.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
|
|
2253
2244
|
// ─── Loading skeleton ─────────────────────────────────────────────────────────
|
|
2254
|
-
const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$
|
|
2245
|
+
const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$o.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$o.skeleton }) }) }, i))) }));
|
|
2255
2246
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
2256
2247
|
/**
|
|
2257
2248
|
* CwSortableTable
|
|
@@ -2338,11 +2329,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
|
|
|
2338
2329
|
return items.map((item, index) => {
|
|
2339
2330
|
const key = item[rowKey];
|
|
2340
2331
|
const isDragging = draggedItem?.[rowKey] === key;
|
|
2341
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$
|
|
2332
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$o.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
|
|
2342
2333
|
});
|
|
2343
2334
|
};
|
|
2344
2335
|
// ── Render ──────────────────────────────────────────────────────────────
|
|
2345
|
-
return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$
|
|
2336
|
+
return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$o.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
|
|
2346
2337
|
}
|
|
2347
2338
|
|
|
2348
2339
|
/**
|
|
@@ -2541,7 +2532,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
|
|
|
2541
2532
|
}, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
|
|
2542
2533
|
}
|
|
2543
2534
|
|
|
2544
|
-
var styles$
|
|
2535
|
+
var styles$n = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
|
|
2545
2536
|
|
|
2546
2537
|
const TabIcon = ({ icon }) => {
|
|
2547
2538
|
if (!icon)
|
|
@@ -2591,7 +2582,7 @@ function CwTabs(CwTabsProps) {
|
|
|
2591
2582
|
const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
|
|
2592
2583
|
? { minWidth: CwTabsProps.tabsListWidth }
|
|
2593
2584
|
: undefined;
|
|
2594
|
-
return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$
|
|
2585
|
+
return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$n['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$n['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$n['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
|
|
2595
2586
|
}
|
|
2596
2587
|
|
|
2597
2588
|
/**
|
|
@@ -2618,7 +2609,7 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
|
|
|
2618
2609
|
return (jsxRuntime.jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsxRuntime.jsx("summary", { children: briefing }), children && jsxRuntime.jsx("section", { children: children })] }));
|
|
2619
2610
|
};
|
|
2620
2611
|
|
|
2621
|
-
var styles$
|
|
2612
|
+
var styles$m = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
|
|
2622
2613
|
|
|
2623
2614
|
const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, detailContent, emptyDetail, searchPlaceholder = 'Search...', onSearch, masterHeader, masterFooter, masterWidth: initialWidth = 320, minMasterWidth = 240, maxMasterWidth = 500, resizable = true, showSearch = true, }) => {
|
|
2624
2615
|
const [masterWidth, setMasterWidth] = React.useState(initialWidth);
|
|
@@ -2654,10 +2645,10 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
|
|
|
2654
2645
|
document.body.style.userSelect = '';
|
|
2655
2646
|
};
|
|
2656
2647
|
}, [isResizing, minMasterWidth, maxMasterWidth]);
|
|
2657
|
-
const rootClassName = [styles$
|
|
2658
|
-
return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$
|
|
2648
|
+
const rootClassName = [styles$m['cw-master-detail'], className].filter(Boolean).join(' ');
|
|
2649
|
+
return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$m.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$m.detail, children: selectedKey && detailContent
|
|
2659
2650
|
? detailContent
|
|
2660
|
-
: (jsxRuntime.jsx("div", { className: styles$
|
|
2651
|
+
: (jsxRuntime.jsx("div", { className: styles$m['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
|
|
2661
2652
|
};
|
|
2662
2653
|
|
|
2663
2654
|
/**
|
|
@@ -2682,7 +2673,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
|
|
|
2682
2673
|
: emptyValue })] }, item.key))) }));
|
|
2683
2674
|
};
|
|
2684
2675
|
|
|
2685
|
-
var styles$
|
|
2676
|
+
var styles$l = {"sortableList":"cw-sortable-list-module__sortableList__PyLO-","sortableItem":"cw-sortable-list-module__sortableItem__FAnn2","readOnly":"cw-sortable-list-module__readOnly__r7GcH","dragging":"cw-sortable-list-module__dragging__MD715","moved":"cw-sortable-list-module__moved__sE6-N","expandedContent":"cw-sortable-list-module__expandedContent__Kocna","sortableHandle":"cw-sortable-list-module__sortableHandle__HvYBK","sortableContent":"cw-sortable-list-module__sortableContent__C6JhR","sortableTitle":"cw-sortable-list-module__sortableTitle__EgWXr","sortableExtraContent":"cw-sortable-list-module__sortableExtraContent__s4LSv","sortableActions":"cw-sortable-list-module__sortableActions__gwQOU","dropIndicator":"cw-sortable-list-module__dropIndicator__MNSF-","emptyMessage":"cw-sortable-list-module__emptyMessage__gMpaL"};
|
|
2686
2677
|
|
|
2687
2678
|
function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
|
|
2688
2679
|
const [draggedItem, setDraggedItem] = React.useState(null);
|
|
@@ -2745,15 +2736,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
|
|
|
2745
2736
|
}
|
|
2746
2737
|
};
|
|
2747
2738
|
if (items.length === 0) {
|
|
2748
|
-
return (jsxRuntime.jsx("div", { className: `${styles$
|
|
2739
|
+
return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${styles$l.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$l.emptyMessage, children: emptyMessage }) }));
|
|
2749
2740
|
}
|
|
2750
|
-
return (jsxRuntime.jsx("div", { className: `${styles$
|
|
2741
|
+
return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
|
|
2751
2742
|
const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
|
|
2752
2743
|
const isDragging = draggedItem?.id === item.id;
|
|
2753
2744
|
const isMoved = movedItems.has(item.id);
|
|
2754
2745
|
const canExpand = Boolean(expandedContent);
|
|
2755
2746
|
const isExpanded = expandedItems.has(item.id);
|
|
2756
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$
|
|
2747
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$l.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$l.sortableItem} ${isDragging ? styles$l.dragging : ''} ${isMoved ? styles$l.moved : ''} ${readOnly ? styles$l.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$l.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$l.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$l.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$l.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$l.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$l.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$l.dropIndicator }))] }, item.id));
|
|
2757
2748
|
}) }));
|
|
2758
2749
|
}
|
|
2759
2750
|
|
|
@@ -2879,60 +2870,9 @@ const CwTableGrouped = props => {
|
|
|
2879
2870
|
group.rows.map((child, j) => (jsxRuntime.jsx("tr", { "data-row": true, "data-row-last-of-group": j == group.rows.length - 1, children: child.cells.map((cell, k) => (jsxRuntime.jsx("td", { children: cell.content }, k))) }, j)))] }, i))) }), jsxRuntime.jsx("tfoot", {})] }) }));
|
|
2880
2871
|
};
|
|
2881
2872
|
|
|
2882
|
-
|
|
2883
|
-
const [previewURL, setPreviewURL] = React.useState("");
|
|
2884
|
-
const [error, setError] = React.useState(null);
|
|
2885
|
-
const [_selectedFileName, setSelectedFileName] = React.useState("");
|
|
2886
|
-
const [_currentHexContent, setCurrentHexContent] = React.useState("");
|
|
2887
|
-
React.useEffect(() => {
|
|
2888
|
-
// If there is hexadecimal preview content, set the Preview URL
|
|
2889
|
-
if (fileUploadProps.file?.Bindata) {
|
|
2890
|
-
setPreviewURL(`data:image/png;base64,${fileUploadProps.file.Bindata}`);
|
|
2891
|
-
}
|
|
2892
|
-
}, [fileUploadProps.file?.Bindata]);
|
|
2893
|
-
const handleFileChange = (event) => {
|
|
2894
|
-
const file = event.target.files?.[0];
|
|
2895
|
-
setSelectedFileName(file?.name ?? "");
|
|
2896
|
-
if (file) {
|
|
2897
|
-
const allowedExts = fileUploadProps.accept.split(',').map(ext => ext.trim().replace('.', '').toLowerCase());
|
|
2898
|
-
const fileExt = file.name.split('.').pop()?.toLowerCase() ?? "";
|
|
2899
|
-
if (!allowedExts.includes(fileExt)) {
|
|
2900
|
-
setError(`Invalid file type. Only ${fileUploadProps.acceptString} files are allowed.`);
|
|
2901
|
-
setPreviewURL("");
|
|
2902
|
-
return;
|
|
2903
|
-
}
|
|
2904
|
-
setError(null);
|
|
2905
|
-
const reader = new FileReader();
|
|
2906
|
-
reader.onloadend = () => {
|
|
2907
|
-
if (typeof reader.result === "string") {
|
|
2908
|
-
const hexContent = arrayBufferToHex(reader.result);
|
|
2909
|
-
setCurrentHexContent(hexContent);
|
|
2910
|
-
setPreviewURL(reader.result);
|
|
2911
|
-
setCurrentHexContent(arrayBufferToHex(reader.result));
|
|
2912
|
-
// Call function to store hexadecimal content
|
|
2913
|
-
fileUploadProps.onSaveHexContent(arrayBufferToHex(reader.result));
|
|
2914
|
-
}
|
|
2915
|
-
};
|
|
2916
|
-
reader.readAsDataURL(file);
|
|
2917
|
-
}
|
|
2918
|
-
};
|
|
2919
|
-
// Function to convert the image buffer into hexadecimal content
|
|
2920
|
-
const arrayBufferToHex = (dataUrl) => {
|
|
2921
|
-
// Decodes the base64 of the URL data
|
|
2922
|
-
const base64 = dataUrl.split(",")[1];
|
|
2923
|
-
const binary = atob(base64);
|
|
2924
|
-
let hex = "";
|
|
2925
|
-
for (let i = 0; i < binary.length; i++) {
|
|
2926
|
-
hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
|
|
2927
|
-
}
|
|
2928
|
-
return hex;
|
|
2929
|
-
};
|
|
2930
|
-
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "row", children: [jsxRuntime.jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsxRuntime.jsx("div", { className: "row error", children: error }), jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
|
|
2931
|
-
}
|
|
2932
|
-
|
|
2933
|
-
var styles$j = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
|
|
2873
|
+
var styles$k = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
|
|
2934
2874
|
|
|
2935
|
-
const DEFAULT_LABELS = {
|
|
2875
|
+
const DEFAULT_LABELS$1 = {
|
|
2936
2876
|
uploadDisabled: 'Upload disabled',
|
|
2937
2877
|
clickToUpload: 'Click to upload or drag and drop',
|
|
2938
2878
|
acceptedFiles: (accept) => `Accepted files: ${accept}`,
|
|
@@ -2940,6 +2880,7 @@ const DEFAULT_LABELS = {
|
|
|
2940
2880
|
allTypesAccepted: 'All file types accepted',
|
|
2941
2881
|
changeFile: 'Change File',
|
|
2942
2882
|
clearAll: 'Clear all',
|
|
2883
|
+
upload: 'Upload',
|
|
2943
2884
|
addMoreFiles: 'Add More Files',
|
|
2944
2885
|
filesSelected: (count) => `${count} file${count !== 1 ? 's' : ''} selected`,
|
|
2945
2886
|
fileTooLarge: (name, maxSize) => `File "${name}" is too large. Maximum size allowed is ${maxSize}MB.`,
|
|
@@ -2947,11 +2888,38 @@ const DEFAULT_LABELS = {
|
|
|
2947
2888
|
invalidMimeType: (name, types) => `File "${name}" has an invalid MIME type. Allowed types: ${types}`,
|
|
2948
2889
|
alreadySelected: (name) => `File "${name}" is already selected.`,
|
|
2949
2890
|
};
|
|
2891
|
+
/**
|
|
2892
|
+
* Checks a file against an `accept` string (comma-separated tokens). A token can be a dotted
|
|
2893
|
+
* extension (".pdf"), an exact MIME type ("application/pdf"), a wildcard MIME ("image" + slash + "star"),
|
|
2894
|
+
* or a bare "star" / "star-slash-star" for anything. Returns true if the file matches ANY token
|
|
2895
|
+
* (or if `accept` is empty).
|
|
2896
|
+
*/
|
|
2897
|
+
function fileMatchesAccept(fileName, fileType, accept) {
|
|
2898
|
+
const tokens = accept.split(',').map(token => token.trim().toLowerCase()).filter(Boolean);
|
|
2899
|
+
if (tokens.length === 0) {
|
|
2900
|
+
return true;
|
|
2901
|
+
}
|
|
2902
|
+
const fileExtension = '.' + (fileName.split('.').pop()?.toLowerCase() ?? '');
|
|
2903
|
+
const mimeType = fileType.toLowerCase();
|
|
2904
|
+
return tokens.some(token => {
|
|
2905
|
+
if (token === '*' || token === '*/*') {
|
|
2906
|
+
return true;
|
|
2907
|
+
}
|
|
2908
|
+
if (token.startsWith('.')) {
|
|
2909
|
+
return token === fileExtension;
|
|
2910
|
+
}
|
|
2911
|
+
if (token.endsWith('/*')) {
|
|
2912
|
+
const prefix = token.slice(0, token.indexOf('/') + 1);
|
|
2913
|
+
return mimeType.startsWith(prefix);
|
|
2914
|
+
}
|
|
2915
|
+
return token === mimeType;
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2950
2918
|
function CwFileUploadMultiple(fileUploadProps) {
|
|
2951
2919
|
const fileInputRef = React.useRef(null);
|
|
2952
2920
|
const [selectedFiles, setSelectedFiles] = React.useState([]);
|
|
2953
2921
|
const [existingFile, setExistingFile] = React.useState(fileUploadProps.initialFileName);
|
|
2954
|
-
const labels = { ...DEFAULT_LABELS, ...fileUploadProps.labels };
|
|
2922
|
+
const labels = { ...DEFAULT_LABELS$1, ...fileUploadProps.labels };
|
|
2955
2923
|
React.useEffect(() => {
|
|
2956
2924
|
setExistingFile(fileUploadProps.initialFileName);
|
|
2957
2925
|
}, [fileUploadProps.initialFileName]);
|
|
@@ -2969,17 +2937,9 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2969
2937
|
};
|
|
2970
2938
|
}
|
|
2971
2939
|
}
|
|
2972
|
-
// Validate file type
|
|
2940
|
+
// Validate file type against accept (dotted extensions, exact MIME, wildcard MIME, or *)
|
|
2973
2941
|
if (fileUploadProps.accept) {
|
|
2974
|
-
|
|
2975
|
-
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
2976
|
-
const isExtensionValid = acceptedExtensions.some(ext => {
|
|
2977
|
-
if (ext.startsWith('.')) {
|
|
2978
|
-
return ext === fileExtension;
|
|
2979
|
-
}
|
|
2980
|
-
return false;
|
|
2981
|
-
});
|
|
2982
|
-
if (!isExtensionValid) {
|
|
2942
|
+
if (!fileMatchesAccept(file.name, file.type, fileUploadProps.accept)) {
|
|
2983
2943
|
return {
|
|
2984
2944
|
isValid: false,
|
|
2985
2945
|
error: labels.invalidFormat(file.name, fileUploadProps.accept)
|
|
@@ -3004,7 +2964,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
3004
2964
|
const errors = [];
|
|
3005
2965
|
for (const file of fileArray) {
|
|
3006
2966
|
// Check if the file already exists (by name and size)
|
|
3007
|
-
const isDuplicate =
|
|
2967
|
+
const isDuplicate = validFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
|
|
3008
2968
|
if (isDuplicate) {
|
|
3009
2969
|
errors.push(labels.alreadySelected(file.name));
|
|
3010
2970
|
continue;
|
|
@@ -3022,8 +2982,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
3022
2982
|
fileUploadProps.onError(errors.join('\n'));
|
|
3023
2983
|
}
|
|
3024
2984
|
else {
|
|
3025
|
-
|
|
3026
|
-
alert(errors.join('\n')); // Fallback if there is no onError
|
|
2985
|
+
CwDisplayMessage(errors.join('\n'), exports.CwMessageType.ERROR);
|
|
3027
2986
|
}
|
|
3028
2987
|
}
|
|
3029
2988
|
// If not multiple, only take the first valid file (replace)
|
|
@@ -3097,12 +3056,20 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
3097
3056
|
}
|
|
3098
3057
|
}
|
|
3099
3058
|
};
|
|
3100
|
-
return (jsxRuntime.jsxs("div", { className: `${styles$
|
|
3059
|
+
return (jsxRuntime.jsxs("div", { className: `${styles$k.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$k.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$k.uploadArea} ${fileUploadProps.disabled ? styles$k.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$k.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$k.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$k.fileInfo, children: jsxRuntime.jsx("p", { className: styles$k.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
|
|
3101
3060
|
setExistingFile(undefined);
|
|
3102
3061
|
if (fileUploadProps.onSelect) {
|
|
3103
3062
|
fileUploadProps.onSelect(null);
|
|
3104
3063
|
}
|
|
3105
|
-
}, disabled: fileUploadProps.disabled, className: styles$
|
|
3064
|
+
}, disabled: fileUploadProps.disabled, className: styles$k.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsxRuntime.jsx("small", { className: styles$k.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsxRuntime.jsx(CwButton, { onClick: () => {
|
|
3065
|
+
let files = fileInputRef.current?.files ?? null;
|
|
3066
|
+
if (!files) {
|
|
3067
|
+
const dataTransfer = new DataTransfer();
|
|
3068
|
+
selectedFiles.forEach(file => dataTransfer.items.add(file));
|
|
3069
|
+
files = dataTransfer.files;
|
|
3070
|
+
}
|
|
3071
|
+
fileUploadProps.onConfirm?.(files);
|
|
3072
|
+
}, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$k.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$k.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$k.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$k.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
|
|
3106
3073
|
}
|
|
3107
3074
|
|
|
3108
3075
|
function CwInput(CwInputProps) {
|
|
@@ -3143,7 +3110,7 @@ function CwDigit(props) {
|
|
|
3143
3110
|
return (jsxRuntime.jsx("div", { className: "cw-input-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsx("input", { type: "number", ...inputProps }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
|
|
3144
3111
|
}
|
|
3145
3112
|
|
|
3146
|
-
var styles$
|
|
3113
|
+
var styles$j = {"colorPreview":"cw-color-picker-module__colorPreview__ylJcD","hueBar":"cw-color-picker-module__hueBar__bFhyC","hueBarSlider":"cw-color-picker-module__hueBarSlider__D53IV","colorPickerInteractiveArea":"cw-color-picker-module__colorPickerInteractiveArea__KZFR1","colorArea":"cw-color-picker-module__colorArea__xgpSE","colorAreaOverlay":"cw-color-picker-module__colorAreaOverlay__pmgOc","hueBackground":"cw-color-picker-module__hueBackground__Mks78","whiteGradient":"cw-color-picker-module__whiteGradient__Bt-fU","blackGradient":"cw-color-picker-module__blackGradient__VnEKJ","colorAreaCursor":"cw-color-picker-module__colorAreaCursor__lotg3"};
|
|
3147
3114
|
|
|
3148
3115
|
const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
|
|
3149
3116
|
const [rgb, setRgb] = React.useState({ r: 255, g: 255, b: 255 });
|
|
@@ -3346,13 +3313,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
|
|
|
3346
3313
|
// Calculate background color for the main area based on current hue
|
|
3347
3314
|
const hueColor = hsvToRgb(hsv.h, 100, 100);
|
|
3348
3315
|
const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
|
|
3349
|
-
return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$
|
|
3316
|
+
return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$j.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$j.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$j.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$j.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$j.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$j.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$j.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$j.whiteGradient }), jsxRuntime.jsx("div", { className: styles$j.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$j.colorAreaCursor, style: {
|
|
3350
3317
|
left: `${hsv.s}%`,
|
|
3351
3318
|
top: `${100 - hsv.v}%`
|
|
3352
3319
|
} })] })] })] }));
|
|
3353
3320
|
};
|
|
3354
3321
|
|
|
3355
|
-
var styles$
|
|
3322
|
+
var styles$i = {"container":"cw-input-color-module__container__x7gpk","selectColor":"cw-input-color-module__selectColor__DTo3V","disabled":"cw-input-color-module__disabled__O1fK5","readOnly":"cw-input-color-module__readOnly__HL-Bz","colorDropdown":"cw-input-color-module__colorDropdown__pX2bc"};
|
|
3356
3323
|
|
|
3357
3324
|
const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
|
|
3358
3325
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
@@ -3485,11 +3452,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
|
|
|
3485
3452
|
break;
|
|
3486
3453
|
}
|
|
3487
3454
|
};
|
|
3488
|
-
return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$
|
|
3455
|
+
return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$i.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$i.selectColor} ${disabled ? styles$i.disabled : ''} ${readOnly ? styles$i.readOnly : ''}`, style: {
|
|
3489
3456
|
width,
|
|
3490
3457
|
height,
|
|
3491
3458
|
backgroundColor: value,
|
|
3492
|
-
}, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$
|
|
3459
|
+
}, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$i.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
|
|
3493
3460
|
};
|
|
3494
3461
|
|
|
3495
3462
|
/**
|
|
@@ -3739,31 +3706,63 @@ function CwInputDateText(props) {
|
|
|
3739
3706
|
return (jsxRuntime.jsx("div", { className: "cw-input-date-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("input", { type: "text", disabled: disabled, maxLength: 10, onChange: onChangeInputText, pattern: "^$ --|[.0-9\\/\\-]{10}", placeholder: format.toLowerCase(), readOnly: readOnly, ref: textInputRef, required: required, size: width, tabIndex: tabIndex, value: displayedDate }), jsxRuntime.jsxs("span", { children: [jsxRuntime.jsx(CwIcon, { iconId: "calendar" }), jsxRuntime.jsx("input", { type: "date", disabled: disabled, onChange: onChangeInputDate, readOnly: readOnly, ref: dateInputRef, tabIndex: -1, value: date, ...inputProps })] })] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
|
|
3740
3707
|
}
|
|
3741
3708
|
|
|
3742
|
-
var styles$
|
|
3709
|
+
var styles$h = {"hiddenInput":"cw-input-image-module__hiddenInput__pS7hb","dropZone":"cw-input-image-module__dropZone__ygrGu","title":"cw-input-image-module__title__Rji5M","subtitle":"cw-input-image-module__subtitle__djYYu","container":"cw-input-image-module__container__qh7Tm"};
|
|
3743
3710
|
|
|
3711
|
+
const DEFAULT_LABELS = {
|
|
3712
|
+
dropImageHere: "Drop image here",
|
|
3713
|
+
paste: "Paste",
|
|
3714
|
+
browse: "Browse",
|
|
3715
|
+
acceptedFormats: (formats) => `(${formats})`,
|
|
3716
|
+
clipboardError: "Failed to read from clipboard. Ensure the app has permission to access the clipboard.",
|
|
3717
|
+
invalidType: (formats) => `Unsupported file type. Allowed: ${formats}`,
|
|
3718
|
+
readError: "Could not read the image file.",
|
|
3719
|
+
};
|
|
3720
|
+
/** Reads a file/blob into a base64 data URL (persistable, no blob URL to revoke). */
|
|
3721
|
+
function readImageFileAsDataUrl(file) {
|
|
3722
|
+
return new Promise((resolve, reject) => {
|
|
3723
|
+
const reader = new FileReader();
|
|
3724
|
+
reader.onload = () => resolve(reader.result);
|
|
3725
|
+
reader.onerror = () => reject(reader.error ?? new Error("Failed to read file"));
|
|
3726
|
+
reader.readAsDataURL(file);
|
|
3727
|
+
});
|
|
3728
|
+
}
|
|
3744
3729
|
function CwInputImage(props) {
|
|
3745
3730
|
const [_uploadedImage, setUploadedImage] = React.useState(null);
|
|
3746
3731
|
const inputRef = React.useRef(null);
|
|
3747
|
-
const { allowedImageFormats, onChange, ...inputProps } = props;
|
|
3732
|
+
const { allowedImageFormats, onChange, onError, labels: labelsProp, size, ...inputProps } = props;
|
|
3748
3733
|
const allowedFormats = allowedImageFormats || ["image/jpeg", "image/png", "image/gif"];
|
|
3734
|
+
const labels = { ...DEFAULT_LABELS, ...labelsProp };
|
|
3749
3735
|
const isValidFileType = (type) => allowedFormats.includes(type);
|
|
3750
|
-
const
|
|
3751
|
-
if (
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3736
|
+
const reportError = (message) => {
|
|
3737
|
+
if (onError)
|
|
3738
|
+
onError(message);
|
|
3739
|
+
else
|
|
3740
|
+
CwDisplayMessage(message, exports.CwMessageType.ERROR);
|
|
3741
|
+
};
|
|
3742
|
+
const handleFile = async (file) => {
|
|
3743
|
+
if (!file) {
|
|
3744
|
+
onChange?.(null);
|
|
3745
|
+
return;
|
|
3756
3746
|
}
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3747
|
+
if (!isValidFileType(file.type)) {
|
|
3748
|
+
reportError(labels.invalidType(allowedFormats.join(", ").replace(/image\//g, "")));
|
|
3749
|
+
onChange?.(null);
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
try {
|
|
3753
|
+
const dataUrl = await readImageFileAsDataUrl(file);
|
|
3754
|
+
setUploadedImage(dataUrl);
|
|
3755
|
+
onChange?.(dataUrl, file);
|
|
3756
|
+
}
|
|
3757
|
+
catch {
|
|
3758
|
+
reportError(labels.readError);
|
|
3759
|
+
onChange?.(null);
|
|
3761
3760
|
}
|
|
3762
3761
|
};
|
|
3763
3762
|
const handleDrop = (e) => {
|
|
3764
3763
|
e.preventDefault();
|
|
3765
3764
|
const file = e.dataTransfer.files[0];
|
|
3766
|
-
handleFile(file);
|
|
3765
|
+
void handleFile(file ?? null);
|
|
3767
3766
|
};
|
|
3768
3767
|
const onPasteButtonClick = async () => {
|
|
3769
3768
|
try {
|
|
@@ -3773,21 +3772,20 @@ function CwInputImage(props) {
|
|
|
3773
3772
|
for (const type of clipboardItem.types) {
|
|
3774
3773
|
if (type.startsWith("image/")) {
|
|
3775
3774
|
const blob = await clipboardItem.getType(type);
|
|
3776
|
-
handleFile(blob);
|
|
3775
|
+
await handleFile(blob);
|
|
3777
3776
|
}
|
|
3778
3777
|
}
|
|
3779
3778
|
}
|
|
3780
3779
|
}
|
|
3781
|
-
catch
|
|
3782
|
-
|
|
3783
|
-
alert("Failed to read from clipboard. Ensure the app has permission to access clipboard.");
|
|
3780
|
+
catch {
|
|
3781
|
+
reportError(labels.clipboardError);
|
|
3784
3782
|
}
|
|
3785
3783
|
};
|
|
3786
3784
|
const handleFileChange = (e) => {
|
|
3787
|
-
const file = e.
|
|
3788
|
-
handleFile(file ?? null);
|
|
3785
|
+
const file = e.currentTarget.files?.[0];
|
|
3786
|
+
void handleFile(file ?? null);
|
|
3789
3787
|
};
|
|
3790
|
-
return (jsxRuntime.jsxs("div", { className:
|
|
3788
|
+
return (jsxRuntime.jsxs("div", { className: `cw-input-image ${styles$h.container}`, "data-size": size, children: [jsxRuntime.jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$h.dropZone, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsxRuntime.jsx("p", { className: styles$h.title, children: labels.dropImageHere }), jsxRuntime.jsx("p", { className: styles$h.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsxRuntime.jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsxRuntime.jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsxRuntime.jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$h.hiddenInput, ...inputProps })] }));
|
|
3791
3789
|
}
|
|
3792
3790
|
|
|
3793
3791
|
/**
|
|
@@ -3919,7 +3917,7 @@ const CwImageArea = React.forwardRef((props, ref) => {
|
|
|
3919
3917
|
});
|
|
3920
3918
|
CwImageArea.displayName = "CwImageArea";
|
|
3921
3919
|
|
|
3922
|
-
var styles$
|
|
3920
|
+
var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
|
|
3923
3921
|
|
|
3924
3922
|
/**
|
|
3925
3923
|
* This class represents a week where days can be selected or unselected
|
|
@@ -4059,16 +4057,16 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
|
|
|
4059
4057
|
setSelectedDays(newWeekdays);
|
|
4060
4058
|
onChange?.(newWeekdays.toString());
|
|
4061
4059
|
};
|
|
4062
|
-
return (jsxRuntime.jsx("div", { className: styles$
|
|
4060
|
+
return (jsxRuntime.jsx("div", { className: styles$g["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
|
|
4063
4061
|
};
|
|
4064
4062
|
|
|
4065
|
-
var styles$
|
|
4063
|
+
var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
|
|
4066
4064
|
|
|
4067
4065
|
function CwCheck(props) {
|
|
4068
4066
|
const { labelProps, labelText, direction, alignment, className, ...inputProps } = props;
|
|
4069
4067
|
const resolvedDirection = direction ?? alignment ?? "row";
|
|
4070
4068
|
const displayText = labelProps?.text ?? labelText;
|
|
4071
|
-
return (jsxRuntime.jsx("div", { className: `cw-check ${styles$
|
|
4069
|
+
return (jsxRuntime.jsx("div", { className: `cw-check ${styles$f["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": resolvedDirection, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
|
|
4072
4070
|
}
|
|
4073
4071
|
|
|
4074
4072
|
function CwCheckbox(CwCheckboxProps) {
|
|
@@ -4119,14 +4117,14 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
|
|
|
4119
4117
|
?? (optionsAlignment === "column" ? "row" : "column");
|
|
4120
4118
|
// Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
|
|
4121
4119
|
const checkDirection = itemDirection === "row" ? "column" : "row";
|
|
4122
|
-
return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$
|
|
4120
|
+
return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$f.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$f.options, role: "group", "aria-label": labelProps?.text, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
|
|
4123
4121
|
}
|
|
4124
4122
|
|
|
4125
|
-
var styles$
|
|
4123
|
+
var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
|
|
4126
4124
|
|
|
4127
4125
|
/** Single native radio input. Building block for CwRadioGroup. */
|
|
4128
4126
|
function CwRadio({ label, direction = "row", className, ...inputProps }) {
|
|
4129
|
-
return (jsxRuntime.jsxs("label", { className: `cw-radio ${styles$
|
|
4127
|
+
return (jsxRuntime.jsxs("label", { className: `cw-radio ${styles$e.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsxRuntime.jsx("input", { type: "radio", ...inputProps }), label && jsxRuntime.jsx("span", { children: label })] }));
|
|
4130
4128
|
}
|
|
4131
4129
|
|
|
4132
4130
|
/**
|
|
@@ -4150,7 +4148,7 @@ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemL
|
|
|
4150
4148
|
// (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
|
|
4151
4149
|
// best with the circle above the text.
|
|
4152
4150
|
const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
|
|
4153
|
-
return (jsxRuntime.jsxs("div", { className: `cw-radio-group ${styles$
|
|
4151
|
+
return (jsxRuntime.jsxs("div", { className: `cw-radio-group ${styles$e.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$e.options, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
|
|
4154
4152
|
}
|
|
4155
4153
|
|
|
4156
4154
|
function CwToggle(props) {
|
|
@@ -4416,7 +4414,7 @@ function CwDropdownFilter(props) {
|
|
|
4416
4414
|
return (jsxRuntime.jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsxRuntime.jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsxRuntime.jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsxRuntime.jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
|
|
4417
4415
|
}
|
|
4418
4416
|
|
|
4419
|
-
var styles$
|
|
4417
|
+
var styles$d = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
|
|
4420
4418
|
|
|
4421
4419
|
/**
|
|
4422
4420
|
* Button that toggles a floating panel with arbitrary children.
|
|
@@ -4495,7 +4493,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
|
|
|
4495
4493
|
}
|
|
4496
4494
|
panel.showPopover();
|
|
4497
4495
|
}, [placement]);
|
|
4498
|
-
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$
|
|
4496
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$d.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$d.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
|
|
4499
4497
|
}
|
|
4500
4498
|
|
|
4501
4499
|
function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
|
|
@@ -4513,13 +4511,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
|
|
|
4513
4511
|
return result;
|
|
4514
4512
|
}
|
|
4515
4513
|
|
|
4516
|
-
var styles$
|
|
4514
|
+
var styles$c = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
|
|
4517
4515
|
|
|
4518
4516
|
const CwMultiFilterTag = props => {
|
|
4519
4517
|
const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
|
|
4520
4518
|
const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
|
|
4521
4519
|
const isOutlineMode = Selected && !Removable;
|
|
4522
|
-
return (jsxRuntime.jsx("li", { className: styles$
|
|
4520
|
+
return (jsxRuntime.jsx("li", { className: styles$c["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
|
|
4523
4521
|
if (Selectable)
|
|
4524
4522
|
props.OnSelect?.(props);
|
|
4525
4523
|
}, children: jsxRuntime.jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
|
|
@@ -4529,7 +4527,7 @@ const CwMultiFilterTag = props => {
|
|
|
4529
4527
|
} : undefined }) }));
|
|
4530
4528
|
};
|
|
4531
4529
|
|
|
4532
|
-
var styles$
|
|
4530
|
+
var styles$b = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
|
|
4533
4531
|
|
|
4534
4532
|
/**
|
|
4535
4533
|
* A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
|
|
@@ -4756,9 +4754,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4756
4754
|
inputRef.current?.focus();
|
|
4757
4755
|
}
|
|
4758
4756
|
};
|
|
4759
|
-
return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$
|
|
4757
|
+
return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$b["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
|
|
4760
4758
|
e.preventDefault();
|
|
4761
|
-
}, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$
|
|
4759
|
+
}, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$b["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
|
|
4762
4760
|
switch (e.key) {
|
|
4763
4761
|
case "Enter":
|
|
4764
4762
|
case "Tab": {
|
|
@@ -4785,7 +4783,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4785
4783
|
break;
|
|
4786
4784
|
}
|
|
4787
4785
|
}
|
|
4788
|
-
} })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$
|
|
4786
|
+
} })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$b["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$b["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$b["category-selected"] : undefined, style: {
|
|
4789
4787
|
backgroundColor: getColor(category).primary,
|
|
4790
4788
|
color: getColor(category).onPrimary,
|
|
4791
4789
|
}, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsxRuntime.jsx("ul", { children: displayTags
|
|
@@ -4811,7 +4809,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4811
4809
|
} }, props.ID))) })] }))] }));
|
|
4812
4810
|
};
|
|
4813
4811
|
|
|
4814
|
-
var styles$
|
|
4812
|
+
var styles$a = {"container":"cw-tag-selector-module__container__-do8i","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
|
|
4815
4813
|
|
|
4816
4814
|
/**
|
|
4817
4815
|
* Multi-select input with chip tags and searchable dropdown.
|
|
@@ -4946,11 +4944,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
|
|
|
4946
4944
|
// Keeping containerRef for any other potential use
|
|
4947
4945
|
const direction = alignProps?.flexDirection ?? "row";
|
|
4948
4946
|
const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
|
|
4949
|
-
return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$
|
|
4950
|
-
inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$
|
|
4947
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
|
|
4948
|
+
inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.jsxs("li", { className: `${styles$a.option}${idx === focusedIndex ? ` ${styles$a.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsxRuntime.jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
|
|
4951
4949
|
}
|
|
4952
4950
|
|
|
4953
|
-
var styles$
|
|
4951
|
+
var styles$9 = {"tree-container":"cw-tree-view-module__tree-container__NN-HJ","tree-wrapper":"cw-tree-view-module__tree-wrapper__keBZI","tree-item":"cw-tree-view-module__tree-item__prE9N","tree-node":"cw-tree-view-module__tree-node__wfro9","selected":"cw-tree-view-module__selected__XJQ0w","non-selectable":"cw-tree-view-module__non-selectable__YuPSx","tree-children":"cw-tree-view-module__tree-children__ji8CZ","empty-state":"cw-tree-view-module__empty-state__yvRjo","tree-label":"cw-tree-view-module__tree-label__ss3Nf","tree-spacer":"cw-tree-view-module__tree-spacer__E9Ud2"};
|
|
4954
4952
|
|
|
4955
4953
|
function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
|
|
4956
4954
|
const [expanded, setExpanded] = React.useState(new Set());
|
|
@@ -5017,10 +5015,10 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
5017
5015
|
const isLeaf = !hasChildren;
|
|
5018
5016
|
const isSelected = selectedId?.toString().toLowerCase() === node.id.toString().toLowerCase();
|
|
5019
5017
|
const selectable = allowParentSelection || isLeaf;
|
|
5020
|
-
return (jsxRuntime.jsxs("div", { className: styles$
|
|
5021
|
-
styles$
|
|
5022
|
-
isSelected && styles$
|
|
5023
|
-
!selectable && styles$
|
|
5018
|
+
return (jsxRuntime.jsxs("div", { className: styles$9["tree-item"], children: [jsxRuntime.jsxs("div", { className: [
|
|
5019
|
+
styles$9["tree-node"],
|
|
5020
|
+
isSelected && styles$9["selected"],
|
|
5021
|
+
!selectable && styles$9["non-selectable"]
|
|
5024
5022
|
].filter(Boolean).join(' '), style: { paddingLeft: `${depth * 24 + 8}px` }, onClick: () => {
|
|
5025
5023
|
if (selectable) {
|
|
5026
5024
|
setSelectedId(node.id);
|
|
@@ -5029,7 +5027,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
5029
5027
|
else {
|
|
5030
5028
|
toggleExpand(node.id);
|
|
5031
5029
|
}
|
|
5032
|
-
}, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$
|
|
5030
|
+
}, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$9["tree-label"]} ${!hasChildren ? styles$9["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsxRuntime.jsx("div", { className: styles$9["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
|
|
5033
5031
|
};
|
|
5034
5032
|
// Function to search for nodes that match the search term
|
|
5035
5033
|
const searchInTree = (nodes, searchTerm) => {
|
|
@@ -5053,7 +5051,129 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
5053
5051
|
return results;
|
|
5054
5052
|
};
|
|
5055
5053
|
const filteredData = searchInTree(data, search);
|
|
5056
|
-
return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$
|
|
5054
|
+
return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$9["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$9["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$9["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
|
|
5055
|
+
}
|
|
5056
|
+
|
|
5057
|
+
const EXACT_PHRASE = /"([^"]+)"/g;
|
|
5058
|
+
/**
|
|
5059
|
+
* Quoted phrases are matched against the label only; loose words against label + description + href.
|
|
5060
|
+
* Parsed once instead of per node.
|
|
5061
|
+
*/
|
|
5062
|
+
function parseSearch(search) {
|
|
5063
|
+
const phrases = Array.from(search.matchAll(EXACT_PHRASE), match => match[1].toLowerCase());
|
|
5064
|
+
const words = search
|
|
5065
|
+
.replace(EXACT_PHRASE, "")
|
|
5066
|
+
.trim()
|
|
5067
|
+
.toLowerCase()
|
|
5068
|
+
.split(/\s+/)
|
|
5069
|
+
.filter(Boolean);
|
|
5070
|
+
return { phrases, words };
|
|
5071
|
+
}
|
|
5072
|
+
/**
|
|
5073
|
+
* Filters a nav tree by a search string, keeping a group whose descendants match.
|
|
5074
|
+
*
|
|
5075
|
+
* Supports `"quoted phrases"` (must appear in the label) alongside loose words (any field) — this is
|
|
5076
|
+
* behaviour users are told about, so don't simplify it.
|
|
5077
|
+
*/
|
|
5078
|
+
function filterNavItems(items, search) {
|
|
5079
|
+
if (!search?.trim())
|
|
5080
|
+
return items;
|
|
5081
|
+
const { phrases, words } = parseSearch(search);
|
|
5082
|
+
if (phrases.length === 0 && words.length === 0)
|
|
5083
|
+
return items;
|
|
5084
|
+
const keep = (item, parentMatchedPhrases) => {
|
|
5085
|
+
const label = item.label.toLowerCase();
|
|
5086
|
+
const haystack = [item.label, item.description, item.href].filter(Boolean).join(" ").toLowerCase();
|
|
5087
|
+
const matchesPhrases = phrases.every(phrase => label.includes(phrase));
|
|
5088
|
+
const matchesWords = words.every(word => haystack.includes(word));
|
|
5089
|
+
const selfMatches = (phrases.length === 0 || matchesPhrases || parentMatchedPhrases) && matchesWords;
|
|
5090
|
+
if (!item.children?.length)
|
|
5091
|
+
return selfMatches ? item : null;
|
|
5092
|
+
let children = item.children
|
|
5093
|
+
.map(child => keep(child, matchesPhrases || parentMatchedPhrases))
|
|
5094
|
+
.filter((child) => child !== null);
|
|
5095
|
+
// A phrase-only search narrows the survivors further: each must carry the phrase itself.
|
|
5096
|
+
if (phrases.length > 0 && words.length === 0 && matchesPhrases) {
|
|
5097
|
+
children = children.filter(child => phrases.every(phrase => child.label.toLowerCase().includes(phrase)));
|
|
5098
|
+
}
|
|
5099
|
+
if (children.length > 0)
|
|
5100
|
+
return { ...item, children };
|
|
5101
|
+
// The group matched but nothing under it did. Returning `children: []` would make it a leaf —
|
|
5102
|
+
// and a leaf with no href — so keep the subtree instead of emptying it.
|
|
5103
|
+
return selfMatches ? item : null;
|
|
5104
|
+
};
|
|
5105
|
+
return items
|
|
5106
|
+
.map(item => keep(item, false))
|
|
5107
|
+
.filter((item) => item !== null);
|
|
5108
|
+
}
|
|
5109
|
+
|
|
5110
|
+
/**
|
|
5111
|
+
* Sorts the top level alphabetically, leaving every nested list in the order the consumer gave.
|
|
5112
|
+
*
|
|
5113
|
+
* Deliberately level 1 only: this exists because a long list of modules is hard to scan, while the
|
|
5114
|
+
* pages inside a module are ordered on purpose. Returns the input untouched when not sorting.
|
|
5115
|
+
*/
|
|
5116
|
+
function sortNavItems(items, alphabetically) {
|
|
5117
|
+
if (!alphabetically)
|
|
5118
|
+
return items;
|
|
5119
|
+
return [...items].sort((first, second) => first.label.localeCompare(second.label));
|
|
5120
|
+
}
|
|
5121
|
+
|
|
5122
|
+
var styles$8 = {"menu":"cw-nav-menu-module__menu__LmeQg","expandIndicator":"cw-nav-menu-module__expandIndicator__TBSdQ","favorites":"cw-nav-menu-module__favorites__Esaqd","favoritesContent":"cw-nav-menu-module__favoritesContent__l5DGG","favoriteStar":"cw-nav-menu-module__favoriteStar__J-jzg","emptyMessage":"cw-nav-menu-module__emptyMessage__-CQNd","skeleton":"cw-nav-menu-module__skeleton__INQqF"};
|
|
5123
|
+
|
|
5124
|
+
const SKELETON_ROW_COUNT = 5;
|
|
5125
|
+
const defaultRenderLink = (item, children) => (jsxRuntime.jsx("a", { href: item.href, children: children }));
|
|
5126
|
+
/** Sizes only its own icons — content injected via `renderLink` is styled by the consumer. */
|
|
5127
|
+
function CwNavMenu({ items, loading = false, isActive, renderLink = defaultRenderLink, showExpandIndicator = false, search, emptyMessage, sortAlphabetically = false, favoritesSlot, favoritesLabel = "Favorites", favoritesProps, isFavorite, beforeTreeSlot, className, ...navProps }) {
|
|
5128
|
+
const visibleItems = sortNavItems(filterNavItems(items, search), sortAlphabetically);
|
|
5129
|
+
const showEmptyMessage = !loading && Boolean(emptyMessage) && Boolean(search?.trim()) && visibleItems.length === 0;
|
|
5130
|
+
const hasActiveDescendant = (node) => node.children?.some(child => isActive?.(child) || hasActiveDescendant(child)) ?? false;
|
|
5131
|
+
const renderItem = (item, level) => {
|
|
5132
|
+
const children = item.children;
|
|
5133
|
+
if (children && children.length > 0) {
|
|
5134
|
+
return (jsxRuntime.jsx("li", { children: jsxRuntime.jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxRuntime.jsxs("summary", { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$8.expandIndicator }))] }), jsxRuntime.jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
|
|
5135
|
+
}
|
|
5136
|
+
return (jsxRuntime.jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsxRuntime.jsx(CwIcon, { iconId: "star", size: "small", className: styles$8.favoriteStar })] })) }, item.id));
|
|
5137
|
+
};
|
|
5138
|
+
return (jsxRuntime.jsxs("nav", { ...navProps, className: [styles$8.menu, className].filter(Boolean).join(" "), children: [favoritesSlot && (jsxRuntime.jsxs("details", { open: true, ...favoritesProps, className: [styles$8.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxRuntime.jsxs("summary", { children: [jsxRuntime.jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsxRuntime.jsx("div", { className: styles$8.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsxRuntime.jsx("ul", { children: loading
|
|
5139
|
+
? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsxRuntime.jsx("li", { className: styles$8.skeleton }, index)))
|
|
5140
|
+
: visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsxRuntime.jsx("p", { className: styles$8.emptyMessage, children: emptyMessage })] }));
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
/**
|
|
5144
|
+
* Pure keyboard-navigation resolver shared by the `CwSearchInput` combobox.
|
|
5145
|
+
* Kept side-effect-free so the arrow/home/end/enter/escape behaviour can be unit
|
|
5146
|
+
* tested without a DOM (the library's vitest runs with `environment: "node"`).
|
|
5147
|
+
*/
|
|
5148
|
+
/**
|
|
5149
|
+
* Resolves a key press against the current highlight into a {@link SearchKeyAction}.
|
|
5150
|
+
* Arrow navigation wraps around; `Enter` selects only when a valid row is highlighted.
|
|
5151
|
+
*
|
|
5152
|
+
* @param key `KeyboardEvent.key` value.
|
|
5153
|
+
* @param currentIndex Currently highlighted option index (`-1` = none).
|
|
5154
|
+
* @param optionsLength Number of options currently in the dropdown.
|
|
5155
|
+
*/
|
|
5156
|
+
function resolveSearchKeyAction(key, currentIndex, optionsLength) {
|
|
5157
|
+
if (optionsLength <= 0)
|
|
5158
|
+
return { type: "none" };
|
|
5159
|
+
switch (key) {
|
|
5160
|
+
case "ArrowDown":
|
|
5161
|
+
return { type: "move", index: currentIndex < optionsLength - 1 ? currentIndex + 1 : 0 };
|
|
5162
|
+
case "ArrowUp":
|
|
5163
|
+
return { type: "move", index: currentIndex > 0 ? currentIndex - 1 : optionsLength - 1 };
|
|
5164
|
+
case "Home":
|
|
5165
|
+
return { type: "move", index: 0 };
|
|
5166
|
+
case "End":
|
|
5167
|
+
return { type: "move", index: optionsLength - 1 };
|
|
5168
|
+
case "Enter":
|
|
5169
|
+
return currentIndex >= 0 && currentIndex < optionsLength
|
|
5170
|
+
? { type: "select", index: currentIndex }
|
|
5171
|
+
: { type: "none" };
|
|
5172
|
+
case "Escape":
|
|
5173
|
+
return { type: "close" };
|
|
5174
|
+
default:
|
|
5175
|
+
return { type: "none" };
|
|
5176
|
+
}
|
|
5057
5177
|
}
|
|
5058
5178
|
|
|
5059
5179
|
/**
|
|
@@ -5074,14 +5194,19 @@ function CwSearchInput(optionsProps) {
|
|
|
5074
5194
|
const [_selectedOption, setSelectedOption] = React.useState(null);
|
|
5075
5195
|
const [showDropdown, setShowDropdown] = React.useState(false);
|
|
5076
5196
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
5197
|
+
const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
|
|
5077
5198
|
const wrapperRef = React.useRef(null);
|
|
5199
|
+
const inputRef = React.useRef(null);
|
|
5200
|
+
// Stable ids wiring the combobox input to its listbox popup for assistive tech.
|
|
5201
|
+
const listboxId = React.useId();
|
|
5202
|
+
const optionId = (index) => `${listboxId}-opt-${index}`;
|
|
5078
5203
|
const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
|
|
5079
5204
|
anchorRef: wrapperRef,
|
|
5080
5205
|
isOpen: showDropdown && filteredOptions.length > 0,
|
|
5081
|
-
onClose: () => setShowDropdown(false),
|
|
5206
|
+
onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
|
|
5082
5207
|
});
|
|
5083
5208
|
// Extract props
|
|
5084
|
-
const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
|
|
5209
|
+
const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, autoFocus, ...otherProps } = optionsProps;
|
|
5085
5210
|
// Get direction for data attribute
|
|
5086
5211
|
const direction = alignProps?.flexDirection || "row";
|
|
5087
5212
|
// Make default value selection when loading the component
|
|
@@ -5100,9 +5225,10 @@ function CwSearchInput(optionsProps) {
|
|
|
5100
5225
|
}
|
|
5101
5226
|
}, [defaultValue, selectList]);
|
|
5102
5227
|
const handleInputChange = (event) => {
|
|
5103
|
-
const text = event.
|
|
5228
|
+
const text = event.currentTarget.value;
|
|
5104
5229
|
setSearchText(text);
|
|
5105
5230
|
setShowDropdown(true);
|
|
5231
|
+
setHighlightedIndex(-1);
|
|
5106
5232
|
if (text === "") {
|
|
5107
5233
|
setFilteredOptions(selectList);
|
|
5108
5234
|
setSelectedOption(null);
|
|
@@ -5125,10 +5251,30 @@ function CwSearchInput(optionsProps) {
|
|
|
5125
5251
|
};
|
|
5126
5252
|
const handleInputFocus = () => {
|
|
5127
5253
|
setShowDropdown(true);
|
|
5254
|
+
setHighlightedIndex(-1);
|
|
5128
5255
|
if (searchText === "") {
|
|
5129
5256
|
setFilteredOptions(selectList);
|
|
5130
5257
|
}
|
|
5131
5258
|
};
|
|
5259
|
+
const handleKeyDown = (event) => {
|
|
5260
|
+
if (!(showDropdown && filteredOptions.length > 0))
|
|
5261
|
+
return;
|
|
5262
|
+
const action = resolveSearchKeyAction(event.key, highlightedIndex, filteredOptions.length);
|
|
5263
|
+
switch (action.type) {
|
|
5264
|
+
case "move":
|
|
5265
|
+
event.preventDefault();
|
|
5266
|
+
setHighlightedIndex(action.index);
|
|
5267
|
+
break;
|
|
5268
|
+
case "select":
|
|
5269
|
+
event.preventDefault();
|
|
5270
|
+
handleOptionSelect(filteredOptions[action.index]);
|
|
5271
|
+
break;
|
|
5272
|
+
case "close":
|
|
5273
|
+
setShowDropdown(false);
|
|
5274
|
+
setHighlightedIndex(-1);
|
|
5275
|
+
break;
|
|
5276
|
+
}
|
|
5277
|
+
};
|
|
5132
5278
|
const handleInputBlur = () => {
|
|
5133
5279
|
// Dropdown is closed by useDropdownPortal's outside-click handler.
|
|
5134
5280
|
// Blur alone must not close it — clicking an option would lose focus before the click fires.
|
|
@@ -5140,16 +5286,19 @@ function CwSearchInput(optionsProps) {
|
|
|
5140
5286
|
handleChange(option.id);
|
|
5141
5287
|
}
|
|
5142
5288
|
setFilteredOptions([]);
|
|
5289
|
+
setHighlightedIndex(-1);
|
|
5143
5290
|
};
|
|
5144
5291
|
const handleClearClick = () => {
|
|
5145
5292
|
setSearchText("");
|
|
5146
5293
|
setFilteredOptions([]);
|
|
5147
5294
|
setSelectedOption(null);
|
|
5295
|
+
setHighlightedIndex(-1);
|
|
5148
5296
|
if (handleChange) {
|
|
5149
5297
|
handleChange("");
|
|
5150
5298
|
}
|
|
5299
|
+
inputRef.current?.focus();
|
|
5151
5300
|
};
|
|
5152
|
-
return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style,
|
|
5301
|
+
return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, id: id, type: "text", value: searchText, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled, autoFocus: autoFocus, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown && filteredOptions.length > 0, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option, index) => (jsxRuntime.jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
|
|
5153
5302
|
}
|
|
5154
5303
|
|
|
5155
5304
|
/**
|
|
@@ -11346,7 +11495,6 @@ exports.CwDisplayMessage = CwDisplayMessage;
|
|
|
11346
11495
|
exports.CwDropdown = CwDropdown;
|
|
11347
11496
|
exports.CwDropdownFilter = CwDropdownFilter;
|
|
11348
11497
|
exports.CwExpandable = CwExpandable;
|
|
11349
|
-
exports.CwFileUpload = CwFileUpload;
|
|
11350
11498
|
exports.CwFileUploadMultiple = CwFileUploadMultiple;
|
|
11351
11499
|
exports.CwFindAirport = CwFindAirport;
|
|
11352
11500
|
exports.CwFindCrewmember = CwFindCrewmember;
|
|
@@ -11368,7 +11516,6 @@ exports.CwInputText = CwInputText;
|
|
|
11368
11516
|
exports.CwKeyValueList = CwKeyValueList;
|
|
11369
11517
|
exports.CwLabel = CwLabel;
|
|
11370
11518
|
exports.CwLoading = CwLoading;
|
|
11371
|
-
exports.CwLoadingSmall = CwLoadingSmall;
|
|
11372
11519
|
exports.CwMasterDetail = CwMasterDetail;
|
|
11373
11520
|
exports.CwMessage = CwMessage;
|
|
11374
11521
|
exports.CwMessageManager = CwMessageManager;
|
|
@@ -11377,6 +11524,7 @@ exports.CwModalHover = CwModalHover;
|
|
|
11377
11524
|
exports.CwModalReportFunctional = CwModalReportFunctional;
|
|
11378
11525
|
exports.CwMultiFilter = CwMultiFilter;
|
|
11379
11526
|
exports.CwMultiFilterTag = CwMultiFilterTag;
|
|
11527
|
+
exports.CwNavMenu = CwNavMenu;
|
|
11380
11528
|
exports.CwNote = CwNote;
|
|
11381
11529
|
exports.CwOption = CwOption;
|
|
11382
11530
|
exports.CwPopoverButton = CwPopoverButton;
|
|
@@ -11436,12 +11584,16 @@ exports.TooltipConstraintContext = TooltipConstraintContext;
|
|
|
11436
11584
|
exports.UiEvent = UiEvent;
|
|
11437
11585
|
exports.Weekdays = Weekdays;
|
|
11438
11586
|
exports.cblEvent = cblEvent;
|
|
11587
|
+
exports.configureCwLoading = configureCwLoading;
|
|
11439
11588
|
exports.eventIsVisible = eventIsVisible;
|
|
11589
|
+
exports.filterNavItems = filterNavItems;
|
|
11440
11590
|
exports.filterVisibleEvents = filterVisibleEvents;
|
|
11591
|
+
exports.getCwLoadingDefaults = getCwLoadingDefaults;
|
|
11441
11592
|
exports.getDefaultDivisions = getDefaultDivisions;
|
|
11442
11593
|
exports.getEventSizes = getEventSizes;
|
|
11443
11594
|
exports.getPresetsByKeysTemporal = getPresetsByKeysTemporal;
|
|
11444
11595
|
exports.itemsToMultiFilterTags = itemsToMultiFilterTags;
|
|
11596
|
+
exports.sortNavItems = sortNavItems;
|
|
11445
11597
|
exports.useCwMessage = useCwMessage;
|
|
11446
11598
|
exports.useSortableList = useSortableList;
|
|
11447
11599
|
exports.useSortableTable = useSortableTable;
|