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