@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.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useState, useRef, useEffect, useCallback, useLayoutEffect, createContext, useContext, cloneElement, useMemo, forwardRef, useImperativeHandle,
|
|
3
|
+
import React__default, { useState, useRef, useEffect, useCallback, useLayoutEffect, createContext, useContext, cloneElement, useMemo, forwardRef, useImperativeHandle, useId, createElement, memo, Fragment as Fragment$1, Component } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
5
|
import { createRoot } from 'react-dom/client';
|
|
6
6
|
import Draggable from 'react-draggable';
|
|
@@ -161,12 +161,7 @@ function getContrastColor(color) {
|
|
|
161
161
|
return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
'sortable-asc': (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [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" }), 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" })] })),
|
|
166
|
-
'sortable-desc': (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [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" }), 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" })] })),
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
var styles$r = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
|
|
164
|
+
var styles$v = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
|
|
170
165
|
|
|
171
166
|
// Constants
|
|
172
167
|
const margin$1 = 16;
|
|
@@ -456,7 +451,7 @@ const CwTooltipManager = () => {
|
|
|
456
451
|
if (!state.isVisible || !state.content) {
|
|
457
452
|
return null;
|
|
458
453
|
}
|
|
459
|
-
return createPortal(jsx("div", { ref: tooltipRef, className: styles$
|
|
454
|
+
return createPortal(jsx("div", { ref: tooltipRef, className: styles$v["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
|
|
460
455
|
top: `${tooltipPosition.top}px`,
|
|
461
456
|
left: `${tooltipPosition.left}px`,
|
|
462
457
|
opacity: (isPositioned && !isMeasuring) ? 1 : 0,
|
|
@@ -537,16 +532,22 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
|
|
|
537
532
|
useEffect(() => {
|
|
538
533
|
ensureTooltipManager();
|
|
539
534
|
}, []);
|
|
540
|
-
return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$
|
|
535
|
+
return (jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$v["cw-tooltip"], children: children }));
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
const SVG_ICONS = {
|
|
539
|
+
'sortable-asc': (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [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" }), 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" })] })),
|
|
540
|
+
'sortable-desc': (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [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" }), 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" })] })),
|
|
541
541
|
};
|
|
542
542
|
|
|
543
543
|
function CwIcon(props) {
|
|
544
|
-
const { iconId, color, size, title, tooltipPosition = 'bottom', ...iconProps } = props;
|
|
544
|
+
const { iconId, color, size, className, title, tooltipPosition = 'bottom', ...iconProps } = props;
|
|
545
545
|
const getClassName = (baseClass) => {
|
|
546
546
|
return [
|
|
547
547
|
baseClass,
|
|
548
548
|
color && `cw-color-${color}`,
|
|
549
|
-
size && `cw-font-size-${size}
|
|
549
|
+
size && `cw-font-size-${size}`,
|
|
550
|
+
className
|
|
550
551
|
].filter(Boolean).join(' ');
|
|
551
552
|
};
|
|
552
553
|
let iconElement;
|
|
@@ -958,49 +959,39 @@ function CwImageZoom(image) {
|
|
|
958
959
|
} }), jsx("div", { style: { color: "#fff", fontSize: "1rem", textAlign: "center" }, children: selectedImage.filename && jsx("div", { children: selectedImage.filename }) })] }))] }));
|
|
959
960
|
}
|
|
960
961
|
|
|
962
|
+
let defaults = {};
|
|
961
963
|
/**
|
|
962
|
-
* CwLoading
|
|
963
|
-
*
|
|
964
|
-
* A versatile loading component that shows a spinner with optional text
|
|
965
|
-
* and disables the wrapped content while in loading state.
|
|
966
|
-
*
|
|
967
|
-
* @example
|
|
968
|
-
* // Basic usage
|
|
969
|
-
* <CwLoading isLoading={isSubmitting}>
|
|
970
|
-
* <form>...</form>
|
|
971
|
-
* </CwLoading>
|
|
972
|
-
*
|
|
973
|
-
* // With custom text and size
|
|
974
|
-
* <CwLoading
|
|
975
|
-
* isLoading={isLoading}
|
|
976
|
-
* text="Please wait..."
|
|
977
|
-
* size="large"
|
|
978
|
-
* >
|
|
979
|
-
* <UserProfile />
|
|
980
|
-
* </CwLoading>
|
|
964
|
+
* Register global CwLoading defaults. Call once at app init, before the first render.
|
|
965
|
+
* Merges into any previously configured defaults.
|
|
981
966
|
*/
|
|
982
|
-
function
|
|
983
|
-
|
|
984
|
-
|
|
967
|
+
function configureCwLoading(next) {
|
|
968
|
+
defaults = { ...defaults, ...next };
|
|
969
|
+
}
|
|
970
|
+
/** Read the currently configured CwLoading defaults. */
|
|
971
|
+
function getCwLoadingDefaults() {
|
|
972
|
+
return defaults;
|
|
985
973
|
}
|
|
986
974
|
|
|
987
975
|
/**
|
|
988
|
-
*
|
|
976
|
+
* CwLoading — a spinner with optional text that dims the wrapped content while loading.
|
|
989
977
|
*
|
|
990
|
-
*
|
|
978
|
+
* Icon resolves as `iconName` prop → `getCwLoadingDefaults().icon` → none (neutral ring).
|
|
991
979
|
*
|
|
992
980
|
* @example
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
996
|
-
* // Use:
|
|
997
|
-
* <CwLoading size="small" />
|
|
981
|
+
* <CwLoading isLoading={isSubmitting}>
|
|
982
|
+
* <form>...</form>
|
|
983
|
+
* </CwLoading>
|
|
998
984
|
*/
|
|
999
|
-
function
|
|
1000
|
-
|
|
985
|
+
function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName, animation = 'spin', children }) {
|
|
986
|
+
let overlay = null;
|
|
987
|
+
if (isLoading) {
|
|
988
|
+
const resolvedIcon = iconName ?? getCwLoadingDefaults().icon;
|
|
989
|
+
overlay = (jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, role: "status", "aria-label": text || 'Loading', children: [jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, "data-has-icon": !!resolvedIcon, children: resolvedIcon && jsx("span", { className: `cwi-icons ${resolvedIcon}` }) }), text && (jsx("p", { children: text }))] }));
|
|
990
|
+
}
|
|
991
|
+
return (jsxs("div", { "aria-busy": isLoading, className: "cw-loading-container", "data-children": !!children, children: [overlay, jsx("div", { className: "cw-loading-disabled-content", children: children })] }));
|
|
1001
992
|
}
|
|
1002
993
|
|
|
1003
|
-
var styles$
|
|
994
|
+
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"};
|
|
1004
995
|
|
|
1005
996
|
// Constants moved outside to prevent recreation
|
|
1006
997
|
const margin = 16;
|
|
@@ -1123,12 +1114,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
1123
1114
|
const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
|
|
1124
1115
|
setIsVisible(true);
|
|
1125
1116
|
}, showDelay);
|
|
1126
|
-
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$
|
|
1117
|
+
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$u["cw-generic-tooltip-content"]);
|
|
1127
1118
|
// Memoize tooltip content creation
|
|
1128
1119
|
const tooltipContent = useMemo(() => {
|
|
1129
1120
|
if (hide || !isVisible || !content)
|
|
1130
1121
|
return null;
|
|
1131
|
-
return createPortal(jsx("div", { className: styles$
|
|
1122
|
+
return createPortal(jsx("div", { className: styles$u["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
|
|
1132
1123
|
position: 'fixed',
|
|
1133
1124
|
top: `${tooltipPosition.top}px`,
|
|
1134
1125
|
left: `${tooltipPosition.left}px`,
|
|
@@ -1143,10 +1134,10 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
1143
1134
|
clearTooltipTimeout();
|
|
1144
1135
|
setIsVisible(false);
|
|
1145
1136
|
}, [clearTooltipTimeout]);
|
|
1146
|
-
return (jsxs("div", { ref: containerRef, className: styles$
|
|
1137
|
+
return (jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
|
|
1147
1138
|
};
|
|
1148
1139
|
|
|
1149
|
-
function CwButton({ text, variant = 'solid', color = 'primary', className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }) {
|
|
1140
|
+
const CwButton = React__default.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
|
|
1150
1141
|
// Build CSS classes based on variant and props
|
|
1151
1142
|
let buttonClass = `cw-button-${variant}`;
|
|
1152
1143
|
// Add icon class only for icon variant without children
|
|
@@ -1157,9 +1148,18 @@ function CwButton({ text, variant = 'solid', color = 'primary', className = '',
|
|
|
1157
1148
|
buttonClass += ` ${className}`;
|
|
1158
1149
|
}
|
|
1159
1150
|
const tooltipContent = title || (variant === 'icon' && text ? text : undefined);
|
|
1160
|
-
const
|
|
1151
|
+
const iconElement = icon ? jsx(CwIcon, { iconId: icon }) : null;
|
|
1152
|
+
const textElement = text ? jsx("strong", { children: text }) : null;
|
|
1153
|
+
// Only emit toggle attributes when `pressed` is defined; otherwise output stays identical to a normal button.
|
|
1154
|
+
const pressedProps = pressed !== undefined
|
|
1155
|
+
? { "aria-pressed": pressed, "data-pressed": pressed ? "true" : undefined }
|
|
1156
|
+
: {};
|
|
1157
|
+
const buttonElement = (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'
|
|
1158
|
+
? jsxs(Fragment, { children: [textElement, iconElement] })
|
|
1159
|
+
: jsxs(Fragment, { children: [iconElement, textElement] }))) }));
|
|
1161
1160
|
return tooltipContent ? (jsx(CwTooltipNew, { content: tooltipContent, position: tooltipPosition, displayInline: true, children: buttonElement })) : (buttonElement);
|
|
1162
|
-
}
|
|
1161
|
+
});
|
|
1162
|
+
CwButton.displayName = "CwButton";
|
|
1163
1163
|
|
|
1164
1164
|
// Reference for draggable modal
|
|
1165
1165
|
/**
|
|
@@ -1196,7 +1196,7 @@ function CwModal(custModalProps) {
|
|
|
1196
1196
|
return (jsx("div", { children: custModalProps.modalState && (jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsx("span", { className: "cwelltCloseIcon" }) })] }), jsx("div", { className: "cwelltModalBody", children: jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsx("div", { style: { display: "none" } }))] }) })] })) }));
|
|
1197
1197
|
}
|
|
1198
1198
|
|
|
1199
|
-
var styles$
|
|
1199
|
+
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"};
|
|
1200
1200
|
|
|
1201
1201
|
function CwConfirmationPopup(props) {
|
|
1202
1202
|
const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
|
|
@@ -1260,15 +1260,15 @@ function CwConfirmationPopup(props) {
|
|
|
1260
1260
|
onCancel();
|
|
1261
1261
|
}
|
|
1262
1262
|
};
|
|
1263
|
-
return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$
|
|
1263
|
+
return (jsxs(Fragment, { children: [renderChildren(), isOpen && (jsx("div", { className: styles$t.overlayPositioned, onClick: handleOverlayClick, children: jsxs("div", { ref: popupRef, className: styles$t.popup, style: {
|
|
1264
1264
|
position: 'absolute',
|
|
1265
1265
|
top: `${position.top}px`,
|
|
1266
1266
|
left: `${position.left}px`,
|
|
1267
1267
|
transform: 'none'
|
|
1268
|
-
}, children: [jsx("p", { className: styles$
|
|
1268
|
+
}, children: [jsx("p", { className: styles$t.message, children: message }), jsxs("div", { className: styles$t.buttons, children: [jsx("button", { className: `${styles$t.button} ${styles$t.confirmButton}`, onClick: onConfirm, children: confirmText }), jsx("button", { className: `${styles$t.button} ${styles$t.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
|
|
1269
1269
|
}
|
|
1270
1270
|
|
|
1271
|
-
var styles$
|
|
1271
|
+
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"};
|
|
1272
1272
|
|
|
1273
1273
|
// Helper function to parse size values
|
|
1274
1274
|
const parseSize = (size) => {
|
|
@@ -1541,7 +1541,7 @@ const CwDialog = props => {
|
|
|
1541
1541
|
}
|
|
1542
1542
|
}
|
|
1543
1543
|
}, [open]);
|
|
1544
|
-
const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$
|
|
1544
|
+
const header = useMemo(() => (jsxs("header", { onMouseDown: handleMouseDown, children: [jsx("span", { children: headline }), customHeader || (jsx("button", { className: styles$s["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
|
|
1545
1545
|
const content = useMemo(() => (jsx("section", { children: children })), [children]);
|
|
1546
1546
|
const footer = useMemo(() => (jsx("footer", { children: customFooter || (jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
|
|
1547
1547
|
const resizeHandles = useMemo(() => size.autoHeight
|
|
@@ -1568,7 +1568,7 @@ const CwDialog = props => {
|
|
|
1568
1568
|
: `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
|
|
1569
1569
|
return { displayWidth, displayHeight };
|
|
1570
1570
|
}, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
|
|
1571
|
-
const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$
|
|
1571
|
+
const dialogContent = (jsx("div", { "data-has-scrim": hasScrim, className: styles$s["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxs("dialog", { ...domProps, ref: dialogRef, style: {
|
|
1572
1572
|
left: `${position.x}px`,
|
|
1573
1573
|
top: `${position.y}px`,
|
|
1574
1574
|
width: displayDimensions.displayWidth,
|
|
@@ -1729,7 +1729,7 @@ function CwAlign(props) {
|
|
|
1729
1729
|
}, children: props.children }));
|
|
1730
1730
|
}
|
|
1731
1731
|
|
|
1732
|
-
var styles$
|
|
1732
|
+
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"};
|
|
1733
1733
|
|
|
1734
1734
|
/**
|
|
1735
1735
|
* CwCard - A simple card component for displaying content in a contained format
|
|
@@ -1755,11 +1755,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1755
1755
|
// Construct class names using CSS modules
|
|
1756
1756
|
const cardClassNames = [
|
|
1757
1757
|
'cw-card',
|
|
1758
|
-
styles$
|
|
1758
|
+
styles$r.card,
|
|
1759
1759
|
className,
|
|
1760
|
-
clickable ? styles$
|
|
1761
|
-
disabled ? styles$
|
|
1762
|
-
isLoading ? styles$
|
|
1760
|
+
clickable ? styles$r.clickable : '',
|
|
1761
|
+
disabled ? styles$r.disabled : '',
|
|
1762
|
+
isLoading ? styles$r.loading : '',
|
|
1763
1763
|
].filter(Boolean).join(' ');
|
|
1764
1764
|
// Handle click event when card is clickable
|
|
1765
1765
|
const handleClick = () => {
|
|
@@ -1776,15 +1776,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1776
1776
|
// Determine if footer should be rendered
|
|
1777
1777
|
const hasFooter = hasChips || footer || (hasActions && resolvedDirection === "row");
|
|
1778
1778
|
// Actions component to reuse
|
|
1779
|
-
const ActionsComponent = hasActions && !disabled ? (jsxs("div", { className: styles$
|
|
1779
|
+
const ActionsComponent = hasActions && !disabled ? (jsxs("div", { className: styles$r.actions, children: [extraActions ?? null, onEdit && jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
|
|
1780
1780
|
return (jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
|
|
1781
1781
|
role: 'button',
|
|
1782
1782
|
tabIndex: 0,
|
|
1783
1783
|
onClick: handleClick,
|
|
1784
|
-
}), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$
|
|
1784
|
+
}), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxs("header", { children: [(title || subtitle) && (jsxs("div", { className: styles$r.headerContent, "data-align": resolvedAlign, children: [title && jsx("h5", { children: title }), subtitle && jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] })), jsx("div", { className: styles$r.content, children: children }), hasFooter && (jsxs("footer", { children: [hasChips && (jsx("div", { className: styles$r.footerTags, children: chips.map((chip, index) => (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 && (jsx("div", { className: styles$r.footerContent, children: footer }))] })), resolvedDirection === "row" && ActionsComponent, isLoading && (jsx("div", { className: styles$r.loadingOverlay, children: jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
|
|
1785
1785
|
};
|
|
1786
1786
|
|
|
1787
|
-
var styles$
|
|
1787
|
+
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"};
|
|
1788
1788
|
|
|
1789
1789
|
/**
|
|
1790
1790
|
* Option to display in the CwSelect
|
|
@@ -1879,10 +1879,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
|
|
|
1879
1879
|
icon: sortDirection === 'asc' ? 'arrow-up' : 'arrow-down',
|
|
1880
1880
|
onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'),
|
|
1881
1881
|
title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}`,
|
|
1882
|
-
}, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsx("div", { className: styles$
|
|
1882
|
+
}, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsx("div", { className: styles$q.loading, children: jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsx("div", { className: styles$q.emptyState, children: emptyState || jsx("p", { children: "No items to display" }) })) : (jsxs(Fragment, { children: [jsx("div", { className: `${styles$q.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsx(React__default.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxs("div", { className: styles$q.pagination, children: [jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxs("span", { className: styles$q.pageInfo, children: [currentPage, " / ", totalPages] }), jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
|
|
1883
1883
|
}
|
|
1884
1884
|
|
|
1885
|
-
var styles$
|
|
1885
|
+
var styles$p = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
|
|
1886
1886
|
|
|
1887
1887
|
/**
|
|
1888
1888
|
*
|
|
@@ -1899,7 +1899,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
|
|
|
1899
1899
|
setVisible_accordionBody(!isVisible_accordionBody);
|
|
1900
1900
|
};
|
|
1901
1901
|
// #endregion
|
|
1902
|
-
return (jsxs("div", { className: styles$
|
|
1902
|
+
return (jsxs("div", { className: styles$p["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxs("header", { onClick: () => showAccordionBody(), children: [jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsx("button", { className: "cw-button-icon" })] }), jsx("div", { className: styles$p["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
|
|
1903
1903
|
}
|
|
1904
1904
|
|
|
1905
1905
|
/**
|
|
@@ -2157,7 +2157,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
|
|
|
2157
2157
|
}, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
|
|
2158
2158
|
}
|
|
2159
2159
|
|
|
2160
|
-
var styles$
|
|
2160
|
+
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"};
|
|
2161
2161
|
|
|
2162
2162
|
/**
|
|
2163
2163
|
* Hook that provides state management for CwSortableTable.
|
|
@@ -2220,9 +2220,9 @@ function useSortableTable(initialItems) {
|
|
|
2220
2220
|
}
|
|
2221
2221
|
|
|
2222
2222
|
// ─── Drop indicator row ───────────────────────────────────────────────────────
|
|
2223
|
-
const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$
|
|
2223
|
+
const DropIndicatorRow = ({ colSpan }) => (jsx("tr", { className: styles$o.dropIndicator, "aria-hidden": true, children: jsx("td", { colSpan: colSpan, children: jsx("div", {}) }) }));
|
|
2224
2224
|
// ─── Loading skeleton ─────────────────────────────────────────────────────────
|
|
2225
|
-
const LoadingRows = ({ colSpan }) => (jsx(Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsx("tr", { className: styles$
|
|
2225
|
+
const LoadingRows = ({ colSpan }) => (jsx(Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsx("tr", { className: styles$o.skeletonRow, children: jsx("td", { colSpan: colSpan, children: jsx("div", { className: styles$o.skeleton }) }) }, i))) }));
|
|
2226
2226
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
2227
2227
|
/**
|
|
2228
2228
|
* CwSortableTable
|
|
@@ -2309,11 +2309,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
|
|
|
2309
2309
|
return items.map((item, index) => {
|
|
2310
2310
|
const key = item[rowKey];
|
|
2311
2311
|
const isDragging = draggedItem?.[rowKey] === key;
|
|
2312
|
-
return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$
|
|
2312
|
+
return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && (jsx(DropIndicatorRow, { colSpan: totalCols })), jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$o.dragging : "", children: [showHandle && (jsx("td", { className: "cw-table-col-action", children: jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
|
|
2313
2313
|
});
|
|
2314
2314
|
};
|
|
2315
2315
|
// ── Render ──────────────────────────────────────────────────────────────
|
|
2316
|
-
return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxs("footer", { className: styles$
|
|
2316
|
+
return (jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsx("thead", { children: jsxs("tr", { children: [showHandle && jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxs("footer", { className: styles$o.saveBar, children: [jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
|
|
2317
2317
|
}
|
|
2318
2318
|
|
|
2319
2319
|
/**
|
|
@@ -2512,7 +2512,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
|
|
|
2512
2512
|
}, min: 1, max: totalPages }), jsx("span", { children: "/" }), jsx("span", { children: totalPages }), jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
|
|
2513
2513
|
}
|
|
2514
2514
|
|
|
2515
|
-
var styles$
|
|
2515
|
+
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"};
|
|
2516
2516
|
|
|
2517
2517
|
const TabIcon = ({ icon }) => {
|
|
2518
2518
|
if (!icon)
|
|
@@ -2562,7 +2562,7 @@ function CwTabs(CwTabsProps) {
|
|
|
2562
2562
|
const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
|
|
2563
2563
|
? { minWidth: CwTabsProps.tabsListWidth }
|
|
2564
2564
|
: undefined;
|
|
2565
|
-
return (jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$
|
|
2565
|
+
return (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: [jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsx("span", { className: styles$n['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), 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 })] }));
|
|
2566
2566
|
}
|
|
2567
2567
|
|
|
2568
2568
|
/**
|
|
@@ -2589,7 +2589,7 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
|
|
|
2589
2589
|
return (jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsx("summary", { children: briefing }), children && jsx("section", { children: children })] }));
|
|
2590
2590
|
};
|
|
2591
2591
|
|
|
2592
|
-
var styles$
|
|
2592
|
+
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"};
|
|
2593
2593
|
|
|
2594
2594
|
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, }) => {
|
|
2595
2595
|
const [masterWidth, setMasterWidth] = useState(initialWidth);
|
|
@@ -2625,10 +2625,10 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
|
|
|
2625
2625
|
document.body.style.userSelect = '';
|
|
2626
2626
|
};
|
|
2627
2627
|
}, [isResizing, minMasterWidth, maxMasterWidth]);
|
|
2628
|
-
const rootClassName = [styles$
|
|
2629
|
-
return (jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsx("search", { children: jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsx("header", { children: masterHeader })), jsx("ul", { children: items.map((item) => (jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$
|
|
2628
|
+
const rootClassName = [styles$m['cw-master-detail'], className].filter(Boolean).join(' ');
|
|
2629
|
+
return (jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsx("search", { children: jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsx("header", { children: masterHeader })), jsx("ul", { children: items.map((item) => (jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsx("footer", { children: masterFooter }))] }), resizable && (jsx("div", { className: styles$m.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsx("section", { className: styles$m.detail, children: selectedKey && detailContent
|
|
2630
2630
|
? detailContent
|
|
2631
|
-
: (jsx("div", { className: styles$
|
|
2631
|
+
: (jsx("div", { className: styles$m['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
|
|
2632
2632
|
};
|
|
2633
2633
|
|
|
2634
2634
|
/**
|
|
@@ -2653,7 +2653,7 @@ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "
|
|
|
2653
2653
|
: emptyValue })] }, item.key))) }));
|
|
2654
2654
|
};
|
|
2655
2655
|
|
|
2656
|
-
var styles$
|
|
2656
|
+
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"};
|
|
2657
2657
|
|
|
2658
2658
|
function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
|
|
2659
2659
|
const [draggedItem, setDraggedItem] = useState(null);
|
|
@@ -2716,15 +2716,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
|
|
|
2716
2716
|
}
|
|
2717
2717
|
};
|
|
2718
2718
|
if (items.length === 0) {
|
|
2719
|
-
return (jsx("div", { className: `${styles$
|
|
2719
|
+
return (jsx("div", { className: `${styles$l.sortableList} ${styles$l.emptyState} ${className}`, children: jsx("div", { className: styles$l.emptyMessage, children: emptyMessage }) }));
|
|
2720
2720
|
}
|
|
2721
|
-
return (jsx("div", { className: `${styles$
|
|
2721
|
+
return (jsx("div", { className: `${styles$l.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
|
|
2722
2722
|
const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
|
|
2723
2723
|
const isDragging = draggedItem?.id === item.id;
|
|
2724
2724
|
const isMoved = movedItems.has(item.id);
|
|
2725
2725
|
const canExpand = Boolean(expandedContent);
|
|
2726
2726
|
const isExpanded = expandedItems.has(item.id);
|
|
2727
|
-
return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$
|
|
2727
|
+
return (jsxs(React__default.Fragment, { children: [dropIndicatorIndex === index && jsx("div", { className: styles$l.dropIndicator }), 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: [jsxs("header", { children: [canExpand ? (jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsx("div", { className: styles$l.sortableHandle, children: jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxs("div", { className: styles$l.sortableContent, children: [jsx("div", { className: styles$l.sortableTitle, children: title }), extraContent && jsx("div", { className: styles$l.sortableExtraContent, children: extraContent })] }), jsx("div", { className: styles$l.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsx("div", { className: styles$l.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsx("div", { className: styles$l.dropIndicator }))] }, item.id));
|
|
2728
2728
|
}) }));
|
|
2729
2729
|
}
|
|
2730
2730
|
|
|
@@ -2850,60 +2850,9 @@ const CwTableGrouped = props => {
|
|
|
2850
2850
|
group.rows.map((child, j) => (jsx("tr", { "data-row": true, "data-row-last-of-group": j == group.rows.length - 1, children: child.cells.map((cell, k) => (jsx("td", { children: cell.content }, k))) }, j)))] }, i))) }), jsx("tfoot", {})] }) }));
|
|
2851
2851
|
};
|
|
2852
2852
|
|
|
2853
|
-
|
|
2854
|
-
const [previewURL, setPreviewURL] = useState("");
|
|
2855
|
-
const [error, setError] = useState(null);
|
|
2856
|
-
const [_selectedFileName, setSelectedFileName] = useState("");
|
|
2857
|
-
const [_currentHexContent, setCurrentHexContent] = useState("");
|
|
2858
|
-
useEffect(() => {
|
|
2859
|
-
// If there is hexadecimal preview content, set the Preview URL
|
|
2860
|
-
if (fileUploadProps.file?.Bindata) {
|
|
2861
|
-
setPreviewURL(`data:image/png;base64,${fileUploadProps.file.Bindata}`);
|
|
2862
|
-
}
|
|
2863
|
-
}, [fileUploadProps.file?.Bindata]);
|
|
2864
|
-
const handleFileChange = (event) => {
|
|
2865
|
-
const file = event.target.files?.[0];
|
|
2866
|
-
setSelectedFileName(file?.name ?? "");
|
|
2867
|
-
if (file) {
|
|
2868
|
-
const allowedExts = fileUploadProps.accept.split(',').map(ext => ext.trim().replace('.', '').toLowerCase());
|
|
2869
|
-
const fileExt = file.name.split('.').pop()?.toLowerCase() ?? "";
|
|
2870
|
-
if (!allowedExts.includes(fileExt)) {
|
|
2871
|
-
setError(`Invalid file type. Only ${fileUploadProps.acceptString} files are allowed.`);
|
|
2872
|
-
setPreviewURL("");
|
|
2873
|
-
return;
|
|
2874
|
-
}
|
|
2875
|
-
setError(null);
|
|
2876
|
-
const reader = new FileReader();
|
|
2877
|
-
reader.onloadend = () => {
|
|
2878
|
-
if (typeof reader.result === "string") {
|
|
2879
|
-
const hexContent = arrayBufferToHex(reader.result);
|
|
2880
|
-
setCurrentHexContent(hexContent);
|
|
2881
|
-
setPreviewURL(reader.result);
|
|
2882
|
-
setCurrentHexContent(arrayBufferToHex(reader.result));
|
|
2883
|
-
// Call function to store hexadecimal content
|
|
2884
|
-
fileUploadProps.onSaveHexContent(arrayBufferToHex(reader.result));
|
|
2885
|
-
}
|
|
2886
|
-
};
|
|
2887
|
-
reader.readAsDataURL(file);
|
|
2888
|
-
}
|
|
2889
|
-
};
|
|
2890
|
-
// Function to convert the image buffer into hexadecimal content
|
|
2891
|
-
const arrayBufferToHex = (dataUrl) => {
|
|
2892
|
-
// Decodes the base64 of the URL data
|
|
2893
|
-
const base64 = dataUrl.split(",")[1];
|
|
2894
|
-
const binary = atob(base64);
|
|
2895
|
-
let hex = "";
|
|
2896
|
-
for (let i = 0; i < binary.length; i++) {
|
|
2897
|
-
hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
|
|
2898
|
-
}
|
|
2899
|
-
return hex;
|
|
2900
|
-
};
|
|
2901
|
-
return (jsxs("div", { children: [jsxs("div", { className: "row", children: [jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsx("div", { className: "row", children: jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsx("div", { className: "row error", children: error }), jsx("div", { className: "row", children: jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
|
|
2902
|
-
}
|
|
2903
|
-
|
|
2904
|
-
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"};
|
|
2853
|
+
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"};
|
|
2905
2854
|
|
|
2906
|
-
const DEFAULT_LABELS = {
|
|
2855
|
+
const DEFAULT_LABELS$1 = {
|
|
2907
2856
|
uploadDisabled: 'Upload disabled',
|
|
2908
2857
|
clickToUpload: 'Click to upload or drag and drop',
|
|
2909
2858
|
acceptedFiles: (accept) => `Accepted files: ${accept}`,
|
|
@@ -2911,6 +2860,7 @@ const DEFAULT_LABELS = {
|
|
|
2911
2860
|
allTypesAccepted: 'All file types accepted',
|
|
2912
2861
|
changeFile: 'Change File',
|
|
2913
2862
|
clearAll: 'Clear all',
|
|
2863
|
+
upload: 'Upload',
|
|
2914
2864
|
addMoreFiles: 'Add More Files',
|
|
2915
2865
|
filesSelected: (count) => `${count} file${count !== 1 ? 's' : ''} selected`,
|
|
2916
2866
|
fileTooLarge: (name, maxSize) => `File "${name}" is too large. Maximum size allowed is ${maxSize}MB.`,
|
|
@@ -2918,11 +2868,38 @@ const DEFAULT_LABELS = {
|
|
|
2918
2868
|
invalidMimeType: (name, types) => `File "${name}" has an invalid MIME type. Allowed types: ${types}`,
|
|
2919
2869
|
alreadySelected: (name) => `File "${name}" is already selected.`,
|
|
2920
2870
|
};
|
|
2871
|
+
/**
|
|
2872
|
+
* Checks a file against an `accept` string (comma-separated tokens). A token can be a dotted
|
|
2873
|
+
* extension (".pdf"), an exact MIME type ("application/pdf"), a wildcard MIME ("image" + slash + "star"),
|
|
2874
|
+
* or a bare "star" / "star-slash-star" for anything. Returns true if the file matches ANY token
|
|
2875
|
+
* (or if `accept` is empty).
|
|
2876
|
+
*/
|
|
2877
|
+
function fileMatchesAccept(fileName, fileType, accept) {
|
|
2878
|
+
const tokens = accept.split(',').map(token => token.trim().toLowerCase()).filter(Boolean);
|
|
2879
|
+
if (tokens.length === 0) {
|
|
2880
|
+
return true;
|
|
2881
|
+
}
|
|
2882
|
+
const fileExtension = '.' + (fileName.split('.').pop()?.toLowerCase() ?? '');
|
|
2883
|
+
const mimeType = fileType.toLowerCase();
|
|
2884
|
+
return tokens.some(token => {
|
|
2885
|
+
if (token === '*' || token === '*/*') {
|
|
2886
|
+
return true;
|
|
2887
|
+
}
|
|
2888
|
+
if (token.startsWith('.')) {
|
|
2889
|
+
return token === fileExtension;
|
|
2890
|
+
}
|
|
2891
|
+
if (token.endsWith('/*')) {
|
|
2892
|
+
const prefix = token.slice(0, token.indexOf('/') + 1);
|
|
2893
|
+
return mimeType.startsWith(prefix);
|
|
2894
|
+
}
|
|
2895
|
+
return token === mimeType;
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2921
2898
|
function CwFileUploadMultiple(fileUploadProps) {
|
|
2922
2899
|
const fileInputRef = useRef(null);
|
|
2923
2900
|
const [selectedFiles, setSelectedFiles] = useState([]);
|
|
2924
2901
|
const [existingFile, setExistingFile] = useState(fileUploadProps.initialFileName);
|
|
2925
|
-
const labels = { ...DEFAULT_LABELS, ...fileUploadProps.labels };
|
|
2902
|
+
const labels = { ...DEFAULT_LABELS$1, ...fileUploadProps.labels };
|
|
2926
2903
|
React__default.useEffect(() => {
|
|
2927
2904
|
setExistingFile(fileUploadProps.initialFileName);
|
|
2928
2905
|
}, [fileUploadProps.initialFileName]);
|
|
@@ -2940,17 +2917,9 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2940
2917
|
};
|
|
2941
2918
|
}
|
|
2942
2919
|
}
|
|
2943
|
-
// Validate file type
|
|
2920
|
+
// Validate file type against accept (dotted extensions, exact MIME, wildcard MIME, or *)
|
|
2944
2921
|
if (fileUploadProps.accept) {
|
|
2945
|
-
|
|
2946
|
-
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
2947
|
-
const isExtensionValid = acceptedExtensions.some(ext => {
|
|
2948
|
-
if (ext.startsWith('.')) {
|
|
2949
|
-
return ext === fileExtension;
|
|
2950
|
-
}
|
|
2951
|
-
return false;
|
|
2952
|
-
});
|
|
2953
|
-
if (!isExtensionValid) {
|
|
2922
|
+
if (!fileMatchesAccept(file.name, file.type, fileUploadProps.accept)) {
|
|
2954
2923
|
return {
|
|
2955
2924
|
isValid: false,
|
|
2956
2925
|
error: labels.invalidFormat(file.name, fileUploadProps.accept)
|
|
@@ -2975,7 +2944,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2975
2944
|
const errors = [];
|
|
2976
2945
|
for (const file of fileArray) {
|
|
2977
2946
|
// Check if the file already exists (by name and size)
|
|
2978
|
-
const isDuplicate =
|
|
2947
|
+
const isDuplicate = validFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
|
|
2979
2948
|
if (isDuplicate) {
|
|
2980
2949
|
errors.push(labels.alreadySelected(file.name));
|
|
2981
2950
|
continue;
|
|
@@ -2993,8 +2962,7 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
2993
2962
|
fileUploadProps.onError(errors.join('\n'));
|
|
2994
2963
|
}
|
|
2995
2964
|
else {
|
|
2996
|
-
|
|
2997
|
-
alert(errors.join('\n')); // Fallback if there is no onError
|
|
2965
|
+
CwDisplayMessage(errors.join('\n'), CwMessageType.ERROR);
|
|
2998
2966
|
}
|
|
2999
2967
|
}
|
|
3000
2968
|
// If not multiple, only take the first valid file (replace)
|
|
@@ -3068,12 +3036,20 @@ function CwFileUploadMultiple(fileUploadProps) {
|
|
|
3068
3036
|
}
|
|
3069
3037
|
}
|
|
3070
3038
|
};
|
|
3071
|
-
return (jsxs("div", { className: `${styles$
|
|
3039
|
+
return (jsxs("div", { className: `${styles$k.fileUploadContainer} ${fileUploadProps.className}`, children: [jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$k.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxs("div", { className: `${styles$k.uploadArea} ${fileUploadProps.disabled ? styles$k.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsx(CwIcon, { iconId: "upload" }), jsx("p", { className: `${styles$k.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxs("p", { className: `${styles$k.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxs("div", { className: styles$k.filesContainer, children: [jsxs("div", { className: styles$k.fileItem, children: [jsxs("div", { className: styles$k.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$k.fileExtension, children: getFileExtension(existingFile) })] }), jsx("div", { className: styles$k.fileInfo, children: jsx("p", { className: styles$k.fileName, children: existingFile }) }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
|
|
3072
3040
|
setExistingFile(undefined);
|
|
3073
3041
|
if (fileUploadProps.onSelect) {
|
|
3074
3042
|
fileUploadProps.onSelect(null);
|
|
3075
3043
|
}
|
|
3076
|
-
}, disabled: fileUploadProps.disabled, className: styles$
|
|
3044
|
+
}, disabled: fileUploadProps.disabled, className: styles$k.smallButton })] }), jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxs("div", { className: styles$k.filesContainer, children: [jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsx("small", { className: styles$k.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsx(CwButton, { onClick: () => {
|
|
3045
|
+
let files = fileInputRef.current?.files ?? null;
|
|
3046
|
+
if (!files) {
|
|
3047
|
+
const dataTransfer = new DataTransfer();
|
|
3048
|
+
selectedFiles.forEach(file => dataTransfer.items.add(file));
|
|
3049
|
+
files = dataTransfer.files;
|
|
3050
|
+
}
|
|
3051
|
+
fileUploadProps.onConfirm?.(files);
|
|
3052
|
+
}, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxs("div", { className: styles$k.fileItem, children: [jsxs("div", { className: styles$k.fileIcon, children: [jsx(CwIcon, { iconId: "page" }), jsx("span", { className: styles$k.fileExtension, children: getFileExtension(file.name) })] }), jsxs("div", { className: styles$k.fileInfo, children: [jsx("p", { className: styles$k.fileName, children: file.name }), jsxs("p", { className: styles$k.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$k.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
|
|
3077
3053
|
}
|
|
3078
3054
|
|
|
3079
3055
|
function CwInput(CwInputProps) {
|
|
@@ -3114,7 +3090,7 @@ function CwDigit(props) {
|
|
|
3114
3090
|
return (jsx("div", { className: "cw-input-text", children: jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsx("input", { type: "number", ...inputProps }), buttonProps && jsx(CwButton, { ...buttonProps })] }) }));
|
|
3115
3091
|
}
|
|
3116
3092
|
|
|
3117
|
-
var styles$
|
|
3093
|
+
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"};
|
|
3118
3094
|
|
|
3119
3095
|
const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
|
|
3120
3096
|
const [rgb, setRgb] = useState({ r: 255, g: 255, b: 255 });
|
|
@@ -3317,13 +3293,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
|
|
|
3317
3293
|
// Calculate background color for the main area based on current hue
|
|
3318
3294
|
const hueColor = hsvToRgb(hsv.h, 100, 100);
|
|
3319
3295
|
const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
|
|
3320
|
-
return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$
|
|
3296
|
+
return (jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsx("div", { className: styles$j.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxs("div", { children: [jsx("label", { children: "R:" }), jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "G:" }), jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxs("div", { children: [jsx("label", { children: "B:" }), jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxs("div", { className: styles$j.colorPickerInteractiveArea, children: [jsx("div", { className: styles$j.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsx("div", { className: styles$j.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxs("div", { className: styles$j.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxs("div", { className: styles$j.colorAreaOverlay, children: [jsx("div", { className: styles$j.hueBackground, style: { backgroundColor: hueHex } }), jsx("div", { className: styles$j.whiteGradient }), jsx("div", { className: styles$j.blackGradient })] }), jsx("div", { className: styles$j.colorAreaCursor, style: {
|
|
3321
3297
|
left: `${hsv.s}%`,
|
|
3322
3298
|
top: `${100 - hsv.v}%`
|
|
3323
3299
|
} })] })] })] }));
|
|
3324
3300
|
};
|
|
3325
3301
|
|
|
3326
|
-
var styles$
|
|
3302
|
+
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"};
|
|
3327
3303
|
|
|
3328
3304
|
const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
|
|
3329
3305
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -3456,11 +3432,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
|
|
|
3456
3432
|
break;
|
|
3457
3433
|
}
|
|
3458
3434
|
};
|
|
3459
|
-
return (jsxs("div", { className: `cw-input-color ${styles$
|
|
3435
|
+
return (jsxs("div", { className: `cw-input-color ${styles$i.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsx(CwLabel, { ...labelProps })), jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$i.selectColor} ${disabled ? styles$i.disabled : ''} ${readOnly ? styles$i.readOnly : ''}`, style: {
|
|
3460
3436
|
width,
|
|
3461
3437
|
height,
|
|
3462
3438
|
backgroundColor: value,
|
|
3463
|
-
}, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$
|
|
3439
|
+
}, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && createPortal(jsx("div", { ref: dropdownRef, className: styles$i.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
|
|
3464
3440
|
};
|
|
3465
3441
|
|
|
3466
3442
|
/**
|
|
@@ -3710,31 +3686,63 @@ function CwInputDateText(props) {
|
|
|
3710
3686
|
return (jsx("div", { className: "cw-input-date-text", children: jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { children: [jsx("input", { type: "text", disabled: disabled, maxLength: 10, onChange: onChangeInputText, pattern: "^$ --|[.0-9\\/\\-]{10}", placeholder: format.toLowerCase(), readOnly: readOnly, ref: textInputRef, required: required, size: width, tabIndex: tabIndex, value: displayedDate }), jsxs("span", { children: [jsx(CwIcon, { iconId: "calendar" }), jsx("input", { type: "date", disabled: disabled, onChange: onChangeInputDate, readOnly: readOnly, ref: dateInputRef, tabIndex: -1, value: date, ...inputProps })] })] }), buttonProps && jsx(CwButton, { ...buttonProps })] }) }));
|
|
3711
3687
|
}
|
|
3712
3688
|
|
|
3713
|
-
var styles$
|
|
3689
|
+
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"};
|
|
3714
3690
|
|
|
3691
|
+
const DEFAULT_LABELS = {
|
|
3692
|
+
dropImageHere: "Drop image here",
|
|
3693
|
+
paste: "Paste",
|
|
3694
|
+
browse: "Browse",
|
|
3695
|
+
acceptedFormats: (formats) => `(${formats})`,
|
|
3696
|
+
clipboardError: "Failed to read from clipboard. Ensure the app has permission to access the clipboard.",
|
|
3697
|
+
invalidType: (formats) => `Unsupported file type. Allowed: ${formats}`,
|
|
3698
|
+
readError: "Could not read the image file.",
|
|
3699
|
+
};
|
|
3700
|
+
/** Reads a file/blob into a base64 data URL (persistable, no blob URL to revoke). */
|
|
3701
|
+
function readImageFileAsDataUrl(file) {
|
|
3702
|
+
return new Promise((resolve, reject) => {
|
|
3703
|
+
const reader = new FileReader();
|
|
3704
|
+
reader.onload = () => resolve(reader.result);
|
|
3705
|
+
reader.onerror = () => reject(reader.error ?? new Error("Failed to read file"));
|
|
3706
|
+
reader.readAsDataURL(file);
|
|
3707
|
+
});
|
|
3708
|
+
}
|
|
3715
3709
|
function CwInputImage(props) {
|
|
3716
3710
|
const [_uploadedImage, setUploadedImage] = useState(null);
|
|
3717
3711
|
const inputRef = useRef(null);
|
|
3718
|
-
const { allowedImageFormats, onChange, ...inputProps } = props;
|
|
3712
|
+
const { allowedImageFormats, onChange, onError, labels: labelsProp, size, ...inputProps } = props;
|
|
3719
3713
|
const allowedFormats = allowedImageFormats || ["image/jpeg", "image/png", "image/gif"];
|
|
3714
|
+
const labels = { ...DEFAULT_LABELS, ...labelsProp };
|
|
3720
3715
|
const isValidFileType = (type) => allowedFormats.includes(type);
|
|
3721
|
-
const
|
|
3722
|
-
if (
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3716
|
+
const reportError = (message) => {
|
|
3717
|
+
if (onError)
|
|
3718
|
+
onError(message);
|
|
3719
|
+
else
|
|
3720
|
+
CwDisplayMessage(message, CwMessageType.ERROR);
|
|
3721
|
+
};
|
|
3722
|
+
const handleFile = async (file) => {
|
|
3723
|
+
if (!file) {
|
|
3724
|
+
onChange?.(null);
|
|
3725
|
+
return;
|
|
3727
3726
|
}
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3727
|
+
if (!isValidFileType(file.type)) {
|
|
3728
|
+
reportError(labels.invalidType(allowedFormats.join(", ").replace(/image\//g, "")));
|
|
3729
|
+
onChange?.(null);
|
|
3730
|
+
return;
|
|
3731
|
+
}
|
|
3732
|
+
try {
|
|
3733
|
+
const dataUrl = await readImageFileAsDataUrl(file);
|
|
3734
|
+
setUploadedImage(dataUrl);
|
|
3735
|
+
onChange?.(dataUrl, file);
|
|
3736
|
+
}
|
|
3737
|
+
catch {
|
|
3738
|
+
reportError(labels.readError);
|
|
3739
|
+
onChange?.(null);
|
|
3732
3740
|
}
|
|
3733
3741
|
};
|
|
3734
3742
|
const handleDrop = (e) => {
|
|
3735
3743
|
e.preventDefault();
|
|
3736
3744
|
const file = e.dataTransfer.files[0];
|
|
3737
|
-
handleFile(file);
|
|
3745
|
+
void handleFile(file ?? null);
|
|
3738
3746
|
};
|
|
3739
3747
|
const onPasteButtonClick = async () => {
|
|
3740
3748
|
try {
|
|
@@ -3744,21 +3752,20 @@ function CwInputImage(props) {
|
|
|
3744
3752
|
for (const type of clipboardItem.types) {
|
|
3745
3753
|
if (type.startsWith("image/")) {
|
|
3746
3754
|
const blob = await clipboardItem.getType(type);
|
|
3747
|
-
handleFile(blob);
|
|
3755
|
+
await handleFile(blob);
|
|
3748
3756
|
}
|
|
3749
3757
|
}
|
|
3750
3758
|
}
|
|
3751
3759
|
}
|
|
3752
|
-
catch
|
|
3753
|
-
|
|
3754
|
-
alert("Failed to read from clipboard. Ensure the app has permission to access clipboard.");
|
|
3760
|
+
catch {
|
|
3761
|
+
reportError(labels.clipboardError);
|
|
3755
3762
|
}
|
|
3756
3763
|
};
|
|
3757
3764
|
const handleFileChange = (e) => {
|
|
3758
|
-
const file = e.
|
|
3759
|
-
handleFile(file ?? null);
|
|
3765
|
+
const file = e.currentTarget.files?.[0];
|
|
3766
|
+
void handleFile(file ?? null);
|
|
3760
3767
|
};
|
|
3761
|
-
return (jsxs("div", { className:
|
|
3768
|
+
return (jsxs("div", { className: `cw-input-image ${styles$h.container}`, "data-size": size, children: [jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$h.dropZone, children: [jsx(CwIcon, { iconId: "upload" }), jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsx("p", { className: styles$h.title, children: labels.dropImageHere }), jsx("p", { className: styles$h.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$h.hiddenInput, ...inputProps })] }));
|
|
3762
3769
|
}
|
|
3763
3770
|
|
|
3764
3771
|
/**
|
|
@@ -3890,7 +3897,7 @@ const CwImageArea = forwardRef((props, ref) => {
|
|
|
3890
3897
|
});
|
|
3891
3898
|
CwImageArea.displayName = "CwImageArea";
|
|
3892
3899
|
|
|
3893
|
-
var styles$
|
|
3900
|
+
var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
|
|
3894
3901
|
|
|
3895
3902
|
/**
|
|
3896
3903
|
* This class represents a week where days can be selected or unselected
|
|
@@ -4030,15 +4037,16 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
|
|
|
4030
4037
|
setSelectedDays(newWeekdays);
|
|
4031
4038
|
onChange?.(newWeekdays.toString());
|
|
4032
4039
|
};
|
|
4033
|
-
return (jsx("div", { className: styles$
|
|
4040
|
+
return (jsx("div", { className: styles$g["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
|
|
4034
4041
|
};
|
|
4035
4042
|
|
|
4036
|
-
var styles$
|
|
4043
|
+
var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
|
|
4037
4044
|
|
|
4038
4045
|
function CwCheck(props) {
|
|
4039
|
-
const { labelProps, labelText,
|
|
4040
|
-
const
|
|
4041
|
-
|
|
4046
|
+
const { labelProps, labelText, direction, alignment, className, ...inputProps } = props;
|
|
4047
|
+
const resolvedDirection = direction ?? alignment ?? "row";
|
|
4048
|
+
const displayText = labelProps?.text ?? labelText;
|
|
4049
|
+
return (jsx("div", { className: `cw-check ${styles$f["check-container"]}${className ? ` ${className}` : ''}`, children: jsxs("label", { "data-direction": resolvedDirection, children: [jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
|
|
4042
4050
|
}
|
|
4043
4051
|
|
|
4044
4052
|
function CwCheckbox(CwCheckboxProps) {
|
|
@@ -4056,7 +4064,16 @@ function CwCheckbox(CwCheckboxProps) {
|
|
|
4056
4064
|
: "cw_checkboxContent cwellt_flex_row" + " " + CwCheckboxProps.classNameContainer, style: CwCheckboxProps.styleContainer, children: [inputElement, CwCheckboxProps.labelName ? (jsx("label", { htmlFor: CwCheckboxProps.id, className: CwCheckboxProps.labelClassName, children: CwCheckboxProps.labelName })) : null] }));
|
|
4057
4065
|
}
|
|
4058
4066
|
|
|
4059
|
-
|
|
4067
|
+
/**
|
|
4068
|
+
* CwCheckboxGroup - Multi-select group of native checkbox inputs.
|
|
4069
|
+
*
|
|
4070
|
+
* Use for selecting any number of values from a list of options. Layout follows the
|
|
4071
|
+
* CwKeyValueList / CwRadioGroup convention with two nested {@link CwLayoutProps} axes applied as
|
|
4072
|
+
* `data-*` attributes: `groupLayout` positions the label relative to the group block (root grid),
|
|
4073
|
+
* `itemLayout` controls how the checkboxes flow among themselves (options container) and, on the
|
|
4074
|
+
* opposite axis, each checkbox's own box-to-text layout.
|
|
4075
|
+
*/
|
|
4076
|
+
function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayout, itemLayout, required, disabled, className, feedback, alignProps, optionsAlignment, "data-testid": dataTestId, }) {
|
|
4060
4077
|
const handleChange = (optionValue, checked) => {
|
|
4061
4078
|
if (checked) {
|
|
4062
4079
|
onChange([...value, optionValue]);
|
|
@@ -4068,15 +4085,57 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, alignProps
|
|
|
4068
4085
|
const feedbackMessages = feedback
|
|
4069
4086
|
? Array.isArray(feedback) ? feedback : [feedback]
|
|
4070
4087
|
: [];
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4088
|
+
// Effective layout — precedence: new `groupLayout`/`itemLayout` > legacy-derived > default.
|
|
4089
|
+
// Legacy `alignProps.flexDirection` drove the label-vs-options axis (default "row" = label
|
|
4090
|
+
// beside the options); map it to `groupLayout.direction`.
|
|
4091
|
+
const groupDirection = groupLayout?.direction
|
|
4092
|
+
?? (alignProps?.flexDirection === "column" ? "column" : "row");
|
|
4093
|
+
// Legacy `optionsAlignment` is inverted relative to the options flow: "row" stacked the options
|
|
4094
|
+
// (column flow) with each check internally row; "column" laid them inline (row flow) with each
|
|
4095
|
+
// check internally column. Default reproduces the legacy `optionsAlignment="row"` case.
|
|
4096
|
+
const itemDirection = itemLayout?.direction
|
|
4097
|
+
?? (optionsAlignment === "column" ? "row" : "column");
|
|
4098
|
+
// Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
|
|
4099
|
+
const checkDirection = itemDirection === "row" ? "column" : "row";
|
|
4100
|
+
return (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 && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), 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) => (jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
|
|
4101
|
+
}
|
|
4102
|
+
|
|
4103
|
+
var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
|
|
4104
|
+
|
|
4105
|
+
/** Single native radio input. Building block for CwRadioGroup. */
|
|
4106
|
+
function CwRadio({ label, direction = "row", className, ...inputProps }) {
|
|
4107
|
+
return (jsxs("label", { className: `cw-radio ${styles$e.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsx("input", { type: "radio", ...inputProps }), label && jsx("span", { children: label })] }));
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
/**
|
|
4111
|
+
* CwRadioGroup - Single-select group of native radio inputs.
|
|
4112
|
+
*
|
|
4113
|
+
* Built on `<input type="radio">` sharing one `name`, so the browser provides radio-group
|
|
4114
|
+
* semantics (roving tabindex, arrow-key navigation) natively. Use for a single choice from a
|
|
4115
|
+
* list of options; for 2–3 options shown as a strip use CwButtonSwitch.
|
|
4116
|
+
*
|
|
4117
|
+
* Layout follows the CwKeyValueList convention with two nested {@link CwLayoutProps} axes
|
|
4118
|
+
* applied as `data-*` attributes: `groupLayout` positions the label relative to the radiogroup
|
|
4119
|
+
* block (root grid), `itemLayout` controls how the radios flow among themselves (options
|
|
4120
|
+
* container) and, on the opposite axis, each radio's own circle-to-text layout.
|
|
4121
|
+
*/
|
|
4122
|
+
function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemLayout, required, disabled, className, feedback, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "data-testid": dataTestId, }) {
|
|
4123
|
+
const groupName = useId();
|
|
4124
|
+
const feedbackMessages = feedback
|
|
4125
|
+
? Array.isArray(feedback) ? feedback : [feedback]
|
|
4126
|
+
: [];
|
|
4127
|
+
// Each radio's circle-to-text layout is the opposite of the options flow: a stacked list
|
|
4128
|
+
// (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
|
|
4129
|
+
// best with the circle above the text.
|
|
4130
|
+
const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
|
|
4131
|
+
return (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 && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), 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) => (jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
|
|
4074
4132
|
}
|
|
4075
4133
|
|
|
4076
4134
|
function CwToggle(props) {
|
|
4077
|
-
const { labelProps, labelText,
|
|
4078
|
-
const
|
|
4079
|
-
|
|
4135
|
+
const { labelProps, labelText, direction, alignment, className, style, ...inputProps } = props;
|
|
4136
|
+
const resolvedDirection = direction ?? alignment ?? "row";
|
|
4137
|
+
const displayText = labelProps?.text ?? labelText;
|
|
4138
|
+
return (jsx("div", { className: `cw-toggle ${className ? ` ${className}` : ''}`, style: style, children: jsxs("label", { className: "cw-toggle-label", "data-direction": resolvedDirection, children: [displayText && (jsx("span", { className: "cw-icon-text", children: displayText })), jsx("input", {
|
|
4080
4139
|
//data-color={color}
|
|
4081
4140
|
type: "checkbox", ...inputProps })] }) }));
|
|
4082
4141
|
}
|
|
@@ -4335,7 +4394,7 @@ function CwDropdownFilter(props) {
|
|
|
4335
4394
|
return (jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
|
|
4336
4395
|
}
|
|
4337
4396
|
|
|
4338
|
-
var styles$
|
|
4397
|
+
var styles$d = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
|
|
4339
4398
|
|
|
4340
4399
|
/**
|
|
4341
4400
|
* Button that toggles a floating panel with arbitrary children.
|
|
@@ -4414,7 +4473,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
|
|
|
4414
4473
|
}
|
|
4415
4474
|
panel.showPopover();
|
|
4416
4475
|
}, [placement]);
|
|
4417
|
-
return (jsxs("div", { ref: containerRef, className: styles$
|
|
4476
|
+
return (jsxs("div", { ref: containerRef, className: styles$d.container, children: [jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsx("div", { ref: panelCallbackRef, className: `${styles$d.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
|
|
4418
4477
|
}
|
|
4419
4478
|
|
|
4420
4479
|
function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
|
|
@@ -4432,13 +4491,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
|
|
|
4432
4491
|
return result;
|
|
4433
4492
|
}
|
|
4434
4493
|
|
|
4435
|
-
var styles$
|
|
4494
|
+
var styles$c = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
|
|
4436
4495
|
|
|
4437
4496
|
const CwMultiFilterTag = props => {
|
|
4438
4497
|
const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
|
|
4439
4498
|
const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
|
|
4440
4499
|
const isOutlineMode = Selected && !Removable;
|
|
4441
|
-
return (jsx("li", { className: styles$
|
|
4500
|
+
return (jsx("li", { className: styles$c["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
|
|
4442
4501
|
if (Selectable)
|
|
4443
4502
|
props.OnSelect?.(props);
|
|
4444
4503
|
}, children: jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
|
|
@@ -4448,7 +4507,7 @@ const CwMultiFilterTag = props => {
|
|
|
4448
4507
|
} : undefined }) }));
|
|
4449
4508
|
};
|
|
4450
4509
|
|
|
4451
|
-
var styles$
|
|
4510
|
+
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"};
|
|
4452
4511
|
|
|
4453
4512
|
/**
|
|
4454
4513
|
* A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
|
|
@@ -4675,9 +4734,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4675
4734
|
inputRef.current?.focus();
|
|
4676
4735
|
}
|
|
4677
4736
|
};
|
|
4678
|
-
return (jsxs("form", { ref: componentRef, id: id, className: `${styles$
|
|
4737
|
+
return (jsxs("form", { ref: componentRef, id: id, className: `${styles$b["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
|
|
4679
4738
|
e.preventDefault();
|
|
4680
|
-
}, children: [jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$
|
|
4739
|
+
}, children: [jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$b["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
|
|
4681
4740
|
switch (e.key) {
|
|
4682
4741
|
case "Enter":
|
|
4683
4742
|
case "Tab": {
|
|
@@ -4704,7 +4763,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4704
4763
|
break;
|
|
4705
4764
|
}
|
|
4706
4765
|
}
|
|
4707
|
-
} })] }), selectedTags.size > 0 && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxs("section", { ref: panelRef, className: styles$
|
|
4766
|
+
} })] }), selectedTags.size > 0 && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxs("section", { ref: panelRef, className: styles$b["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxs("nav", { children: [jsx("button", { className: selectedCategory === "All" ? styles$b["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsx("button", { className: selectedCategory === category ? styles$b["category-selected"] : undefined, style: {
|
|
4708
4767
|
backgroundColor: getColor(category).primary,
|
|
4709
4768
|
color: getColor(category).onPrimary,
|
|
4710
4769
|
}, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsx("ul", { children: displayTags
|
|
@@ -4730,7 +4789,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
|
|
|
4730
4789
|
} }, props.ID))) })] }))] }));
|
|
4731
4790
|
};
|
|
4732
4791
|
|
|
4733
|
-
var styles$
|
|
4792
|
+
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"};
|
|
4734
4793
|
|
|
4735
4794
|
/**
|
|
4736
4795
|
* Multi-select input with chip tags and searchable dropdown.
|
|
@@ -4865,11 +4924,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
|
|
|
4865
4924
|
// Keeping containerRef for any other potential use
|
|
4866
4925
|
const direction = alignProps?.flexDirection ?? "row";
|
|
4867
4926
|
const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
|
|
4868
|
-
return (jsxs("div", { ref: containerRef, className: `${styles$
|
|
4869
|
-
inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$
|
|
4927
|
+
return (jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxs(CwLabel, { ...labelProps, children: [iconProps && jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
|
|
4928
|
+
inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxs("li", { className: `${styles$a.option}${idx === focusedIndex ? ` ${styles$a.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
|
|
4870
4929
|
}
|
|
4871
4930
|
|
|
4872
|
-
var styles$
|
|
4931
|
+
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"};
|
|
4873
4932
|
|
|
4874
4933
|
function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
|
|
4875
4934
|
const [expanded, setExpanded] = useState(new Set());
|
|
@@ -4936,10 +4995,10 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
4936
4995
|
const isLeaf = !hasChildren;
|
|
4937
4996
|
const isSelected = selectedId?.toString().toLowerCase() === node.id.toString().toLowerCase();
|
|
4938
4997
|
const selectable = allowParentSelection || isLeaf;
|
|
4939
|
-
return (jsxs("div", { className: styles$
|
|
4940
|
-
styles$
|
|
4941
|
-
isSelected && styles$
|
|
4942
|
-
!selectable && styles$
|
|
4998
|
+
return (jsxs("div", { className: styles$9["tree-item"], children: [jsxs("div", { className: [
|
|
4999
|
+
styles$9["tree-node"],
|
|
5000
|
+
isSelected && styles$9["selected"],
|
|
5001
|
+
!selectable && styles$9["non-selectable"]
|
|
4943
5002
|
].filter(Boolean).join(' '), style: { paddingLeft: `${depth * 24 + 8}px` }, onClick: () => {
|
|
4944
5003
|
if (selectable) {
|
|
4945
5004
|
setSelectedId(node.id);
|
|
@@ -4948,7 +5007,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
4948
5007
|
else {
|
|
4949
5008
|
toggleExpand(node.id);
|
|
4950
5009
|
}
|
|
4951
|
-
}, children: [hasChildren && (jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsx("div", { className: `${styles$
|
|
5010
|
+
}, children: [hasChildren && (jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsx("div", { className: `${styles$9["tree-label"]} ${!hasChildren ? styles$9["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsx("div", { className: styles$9["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
|
|
4952
5011
|
};
|
|
4953
5012
|
// Function to search for nodes that match the search term
|
|
4954
5013
|
const searchInTree = (nodes, searchTerm) => {
|
|
@@ -4972,7 +5031,129 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
|
|
|
4972
5031
|
return results;
|
|
4973
5032
|
};
|
|
4974
5033
|
const filteredData = searchInTree(data, search);
|
|
4975
|
-
return (jsxs("div", { className: `cw-tree-view ${styles$
|
|
5034
|
+
return (jsxs("div", { className: `cw-tree-view ${styles$9["tree-container"]}`, children: [jsxs("header", { children: [jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsx("div", { className: styles$9["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxs("div", { className: styles$9["empty-state"], children: [jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
|
|
5035
|
+
}
|
|
5036
|
+
|
|
5037
|
+
const EXACT_PHRASE = /"([^"]+)"/g;
|
|
5038
|
+
/**
|
|
5039
|
+
* Quoted phrases are matched against the label only; loose words against label + description + href.
|
|
5040
|
+
* Parsed once instead of per node.
|
|
5041
|
+
*/
|
|
5042
|
+
function parseSearch(search) {
|
|
5043
|
+
const phrases = Array.from(search.matchAll(EXACT_PHRASE), match => match[1].toLowerCase());
|
|
5044
|
+
const words = search
|
|
5045
|
+
.replace(EXACT_PHRASE, "")
|
|
5046
|
+
.trim()
|
|
5047
|
+
.toLowerCase()
|
|
5048
|
+
.split(/\s+/)
|
|
5049
|
+
.filter(Boolean);
|
|
5050
|
+
return { phrases, words };
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
5053
|
+
* Filters a nav tree by a search string, keeping a group whose descendants match.
|
|
5054
|
+
*
|
|
5055
|
+
* Supports `"quoted phrases"` (must appear in the label) alongside loose words (any field) — this is
|
|
5056
|
+
* behaviour users are told about, so don't simplify it.
|
|
5057
|
+
*/
|
|
5058
|
+
function filterNavItems(items, search) {
|
|
5059
|
+
if (!search?.trim())
|
|
5060
|
+
return items;
|
|
5061
|
+
const { phrases, words } = parseSearch(search);
|
|
5062
|
+
if (phrases.length === 0 && words.length === 0)
|
|
5063
|
+
return items;
|
|
5064
|
+
const keep = (item, parentMatchedPhrases) => {
|
|
5065
|
+
const label = item.label.toLowerCase();
|
|
5066
|
+
const haystack = [item.label, item.description, item.href].filter(Boolean).join(" ").toLowerCase();
|
|
5067
|
+
const matchesPhrases = phrases.every(phrase => label.includes(phrase));
|
|
5068
|
+
const matchesWords = words.every(word => haystack.includes(word));
|
|
5069
|
+
const selfMatches = (phrases.length === 0 || matchesPhrases || parentMatchedPhrases) && matchesWords;
|
|
5070
|
+
if (!item.children?.length)
|
|
5071
|
+
return selfMatches ? item : null;
|
|
5072
|
+
let children = item.children
|
|
5073
|
+
.map(child => keep(child, matchesPhrases || parentMatchedPhrases))
|
|
5074
|
+
.filter((child) => child !== null);
|
|
5075
|
+
// A phrase-only search narrows the survivors further: each must carry the phrase itself.
|
|
5076
|
+
if (phrases.length > 0 && words.length === 0 && matchesPhrases) {
|
|
5077
|
+
children = children.filter(child => phrases.every(phrase => child.label.toLowerCase().includes(phrase)));
|
|
5078
|
+
}
|
|
5079
|
+
if (children.length > 0)
|
|
5080
|
+
return { ...item, children };
|
|
5081
|
+
// The group matched but nothing under it did. Returning `children: []` would make it a leaf —
|
|
5082
|
+
// and a leaf with no href — so keep the subtree instead of emptying it.
|
|
5083
|
+
return selfMatches ? item : null;
|
|
5084
|
+
};
|
|
5085
|
+
return items
|
|
5086
|
+
.map(item => keep(item, false))
|
|
5087
|
+
.filter((item) => item !== null);
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
/**
|
|
5091
|
+
* Sorts the top level alphabetically, leaving every nested list in the order the consumer gave.
|
|
5092
|
+
*
|
|
5093
|
+
* Deliberately level 1 only: this exists because a long list of modules is hard to scan, while the
|
|
5094
|
+
* pages inside a module are ordered on purpose. Returns the input untouched when not sorting.
|
|
5095
|
+
*/
|
|
5096
|
+
function sortNavItems(items, alphabetically) {
|
|
5097
|
+
if (!alphabetically)
|
|
5098
|
+
return items;
|
|
5099
|
+
return [...items].sort((first, second) => first.label.localeCompare(second.label));
|
|
5100
|
+
}
|
|
5101
|
+
|
|
5102
|
+
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"};
|
|
5103
|
+
|
|
5104
|
+
const SKELETON_ROW_COUNT = 5;
|
|
5105
|
+
const defaultRenderLink = (item, children) => (jsx("a", { href: item.href, children: children }));
|
|
5106
|
+
/** Sizes only its own icons — content injected via `renderLink` is styled by the consumer. */
|
|
5107
|
+
function CwNavMenu({ items, loading = false, isActive, renderLink = defaultRenderLink, showExpandIndicator = false, search, emptyMessage, sortAlphabetically = false, favoritesSlot, favoritesLabel = "Favorites", favoritesProps, isFavorite, beforeTreeSlot, className, ...navProps }) {
|
|
5108
|
+
const visibleItems = sortNavItems(filterNavItems(items, search), sortAlphabetically);
|
|
5109
|
+
const showEmptyMessage = !loading && Boolean(emptyMessage) && Boolean(search?.trim()) && visibleItems.length === 0;
|
|
5110
|
+
const hasActiveDescendant = (node) => node.children?.some(child => isActive?.(child) || hasActiveDescendant(child)) ?? false;
|
|
5111
|
+
const renderItem = (item, level) => {
|
|
5112
|
+
const children = item.children;
|
|
5113
|
+
if (children && children.length > 0) {
|
|
5114
|
+
return (jsx("li", { children: jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxs("summary", { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$8.expandIndicator }))] }), jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
|
|
5115
|
+
}
|
|
5116
|
+
return (jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxs(Fragment, { children: [item.icon && jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsx(CwIcon, { iconId: "star", size: "small", className: styles$8.favoriteStar })] })) }, item.id));
|
|
5117
|
+
};
|
|
5118
|
+
return (jsxs("nav", { ...navProps, className: [styles$8.menu, className].filter(Boolean).join(" "), children: [favoritesSlot && (jsxs("details", { open: true, ...favoritesProps, className: [styles$8.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxs("summary", { children: [jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsx("div", { className: styles$8.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsx("ul", { children: loading
|
|
5119
|
+
? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsx("li", { className: styles$8.skeleton }, index)))
|
|
5120
|
+
: visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsx("p", { className: styles$8.emptyMessage, children: emptyMessage })] }));
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5123
|
+
/**
|
|
5124
|
+
* Pure keyboard-navigation resolver shared by the `CwSearchInput` combobox.
|
|
5125
|
+
* Kept side-effect-free so the arrow/home/end/enter/escape behaviour can be unit
|
|
5126
|
+
* tested without a DOM (the library's vitest runs with `environment: "node"`).
|
|
5127
|
+
*/
|
|
5128
|
+
/**
|
|
5129
|
+
* Resolves a key press against the current highlight into a {@link SearchKeyAction}.
|
|
5130
|
+
* Arrow navigation wraps around; `Enter` selects only when a valid row is highlighted.
|
|
5131
|
+
*
|
|
5132
|
+
* @param key `KeyboardEvent.key` value.
|
|
5133
|
+
* @param currentIndex Currently highlighted option index (`-1` = none).
|
|
5134
|
+
* @param optionsLength Number of options currently in the dropdown.
|
|
5135
|
+
*/
|
|
5136
|
+
function resolveSearchKeyAction(key, currentIndex, optionsLength) {
|
|
5137
|
+
if (optionsLength <= 0)
|
|
5138
|
+
return { type: "none" };
|
|
5139
|
+
switch (key) {
|
|
5140
|
+
case "ArrowDown":
|
|
5141
|
+
return { type: "move", index: currentIndex < optionsLength - 1 ? currentIndex + 1 : 0 };
|
|
5142
|
+
case "ArrowUp":
|
|
5143
|
+
return { type: "move", index: currentIndex > 0 ? currentIndex - 1 : optionsLength - 1 };
|
|
5144
|
+
case "Home":
|
|
5145
|
+
return { type: "move", index: 0 };
|
|
5146
|
+
case "End":
|
|
5147
|
+
return { type: "move", index: optionsLength - 1 };
|
|
5148
|
+
case "Enter":
|
|
5149
|
+
return currentIndex >= 0 && currentIndex < optionsLength
|
|
5150
|
+
? { type: "select", index: currentIndex }
|
|
5151
|
+
: { type: "none" };
|
|
5152
|
+
case "Escape":
|
|
5153
|
+
return { type: "close" };
|
|
5154
|
+
default:
|
|
5155
|
+
return { type: "none" };
|
|
5156
|
+
}
|
|
4976
5157
|
}
|
|
4977
5158
|
|
|
4978
5159
|
/**
|
|
@@ -4993,14 +5174,19 @@ function CwSearchInput(optionsProps) {
|
|
|
4993
5174
|
const [_selectedOption, setSelectedOption] = useState(null);
|
|
4994
5175
|
const [showDropdown, setShowDropdown] = useState(false);
|
|
4995
5176
|
const [isLoading, setIsLoading] = useState(false);
|
|
5177
|
+
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
|
4996
5178
|
const wrapperRef = useRef(null);
|
|
5179
|
+
const inputRef = useRef(null);
|
|
5180
|
+
// Stable ids wiring the combobox input to its listbox popup for assistive tech.
|
|
5181
|
+
const listboxId = useId();
|
|
5182
|
+
const optionId = (index) => `${listboxId}-opt-${index}`;
|
|
4997
5183
|
const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
|
|
4998
5184
|
anchorRef: wrapperRef,
|
|
4999
5185
|
isOpen: showDropdown && filteredOptions.length > 0,
|
|
5000
|
-
onClose: () => setShowDropdown(false),
|
|
5186
|
+
onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
|
|
5001
5187
|
});
|
|
5002
5188
|
// Extract props
|
|
5003
|
-
const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
|
|
5189
|
+
const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, autoFocus, ...otherProps } = optionsProps;
|
|
5004
5190
|
// Get direction for data attribute
|
|
5005
5191
|
const direction = alignProps?.flexDirection || "row";
|
|
5006
5192
|
// Make default value selection when loading the component
|
|
@@ -5019,9 +5205,10 @@ function CwSearchInput(optionsProps) {
|
|
|
5019
5205
|
}
|
|
5020
5206
|
}, [defaultValue, selectList]);
|
|
5021
5207
|
const handleInputChange = (event) => {
|
|
5022
|
-
const text = event.
|
|
5208
|
+
const text = event.currentTarget.value;
|
|
5023
5209
|
setSearchText(text);
|
|
5024
5210
|
setShowDropdown(true);
|
|
5211
|
+
setHighlightedIndex(-1);
|
|
5025
5212
|
if (text === "") {
|
|
5026
5213
|
setFilteredOptions(selectList);
|
|
5027
5214
|
setSelectedOption(null);
|
|
@@ -5044,10 +5231,30 @@ function CwSearchInput(optionsProps) {
|
|
|
5044
5231
|
};
|
|
5045
5232
|
const handleInputFocus = () => {
|
|
5046
5233
|
setShowDropdown(true);
|
|
5234
|
+
setHighlightedIndex(-1);
|
|
5047
5235
|
if (searchText === "") {
|
|
5048
5236
|
setFilteredOptions(selectList);
|
|
5049
5237
|
}
|
|
5050
5238
|
};
|
|
5239
|
+
const handleKeyDown = (event) => {
|
|
5240
|
+
if (!(showDropdown && filteredOptions.length > 0))
|
|
5241
|
+
return;
|
|
5242
|
+
const action = resolveSearchKeyAction(event.key, highlightedIndex, filteredOptions.length);
|
|
5243
|
+
switch (action.type) {
|
|
5244
|
+
case "move":
|
|
5245
|
+
event.preventDefault();
|
|
5246
|
+
setHighlightedIndex(action.index);
|
|
5247
|
+
break;
|
|
5248
|
+
case "select":
|
|
5249
|
+
event.preventDefault();
|
|
5250
|
+
handleOptionSelect(filteredOptions[action.index]);
|
|
5251
|
+
break;
|
|
5252
|
+
case "close":
|
|
5253
|
+
setShowDropdown(false);
|
|
5254
|
+
setHighlightedIndex(-1);
|
|
5255
|
+
break;
|
|
5256
|
+
}
|
|
5257
|
+
};
|
|
5051
5258
|
const handleInputBlur = () => {
|
|
5052
5259
|
// Dropdown is closed by useDropdownPortal's outside-click handler.
|
|
5053
5260
|
// Blur alone must not close it — clicking an option would lose focus before the click fires.
|
|
@@ -5059,16 +5266,19 @@ function CwSearchInput(optionsProps) {
|
|
|
5059
5266
|
handleChange(option.id);
|
|
5060
5267
|
}
|
|
5061
5268
|
setFilteredOptions([]);
|
|
5269
|
+
setHighlightedIndex(-1);
|
|
5062
5270
|
};
|
|
5063
5271
|
const handleClearClick = () => {
|
|
5064
5272
|
setSearchText("");
|
|
5065
5273
|
setFilteredOptions([]);
|
|
5066
5274
|
setSelectedOption(null);
|
|
5275
|
+
setHighlightedIndex(-1);
|
|
5067
5276
|
if (handleChange) {
|
|
5068
5277
|
handleChange("");
|
|
5069
5278
|
}
|
|
5279
|
+
inputRef.current?.focus();
|
|
5070
5280
|
};
|
|
5071
|
-
return (jsxs("div", { className: `cw-search-input ${className || ""}`, style: style,
|
|
5281
|
+
return (jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, ...otherProps, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, id: id, type: "text", value: searchText, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled, autoFocus: autoFocus, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown && filteredOptions.length > 0, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined }), isLoading && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsx(CwIcon, { ...iconProps }) : jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: filteredOptions.map((option, index) => (jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
|
|
5072
5282
|
}
|
|
5073
5283
|
|
|
5074
5284
|
/**
|
|
@@ -5330,7 +5540,7 @@ const CwSearchAsync = ({ onSearch, onChange, value, onResolveInitial, onResolveS
|
|
|
5330
5540
|
}, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeholder, disabled: disabled, required: required, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined, title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selection", variant: "icon", icon: "close", color: "neutral" })) : (icon ? jsx(CwIcon, { ...icon }) : jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.id), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.subLabel ? (jsxs("span", { className: "cw-search-async-option-lines", children: [jsx("span", { children: option.label }), jsx("span", { className: "cw-search-async-option-sub", children: option.subLabel })] })) : (option.label) }, option.id))) }) }))] }));
|
|
5331
5541
|
};
|
|
5332
5542
|
|
|
5333
|
-
var styles$
|
|
5543
|
+
var styles$7 = {"menu":"cw-context-menu-module__menu__tXmun","item":"cw-context-menu-module__item__-ko8L","arrow":"cw-context-menu-module__arrow__LHZmQ"};
|
|
5334
5544
|
|
|
5335
5545
|
const ARROW_SIZE = 8;
|
|
5336
5546
|
const SAFETY_MARGIN = 8;
|
|
@@ -5471,14 +5681,14 @@ const CwAnchoredMenu = ({ children, options, onSelect, placement = 'bottom', ope
|
|
|
5471
5681
|
document.removeEventListener("keydown", handleEscape);
|
|
5472
5682
|
};
|
|
5473
5683
|
}, [isOpen]);
|
|
5474
|
-
return (jsxs(Fragment, { children: [jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && createPortal(jsxs("div", { ref: menuRef, className: styles$
|
|
5684
|
+
return (jsxs(Fragment, { children: [jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, style: { display: "contents" }, children: children }), isOpen && normalizedOptions.length > 0 && createPortal(jsxs("div", { ref: menuRef, className: styles$7["menu"], style: {
|
|
5475
5685
|
top: `${position.y}px`,
|
|
5476
5686
|
left: `${position.x}px`,
|
|
5477
|
-
}, "data-has-arrow": "true", children: [jsx("div", { ref: arrowRef, className: styles$
|
|
5687
|
+
}, "data-has-arrow": "true", children: [jsx("div", { ref: arrowRef, className: styles$7["arrow"], "data-placement": placement }), normalizedOptions.map(option => (jsxs("div", { onClick: (e) => {
|
|
5478
5688
|
e.stopPropagation();
|
|
5479
5689
|
e.preventDefault();
|
|
5480
5690
|
handleOptionClick(option);
|
|
5481
|
-
}, className: `${styles$
|
|
5691
|
+
}, className: `${styles$7["item"]} ${option.disabled ? styles$7["disabled"] : ""}`, "data-disabled": option.disabled, children: [option.icon && jsx("span", { className: styles$7["icon"], children: option.icon }), option.label] }, option.key)))] }), document.body)] }));
|
|
5482
5692
|
};
|
|
5483
5693
|
|
|
5484
5694
|
/**
|
|
@@ -5551,12 +5761,143 @@ const CwContextMenu = ({ children, options, offset = DEFAULT_OFFSET, onSelect })
|
|
|
5551
5761
|
document.removeEventListener("keydown", handleEscape);
|
|
5552
5762
|
};
|
|
5553
5763
|
}, [isOpen]);
|
|
5554
|
-
return (jsxs(Fragment, { children: [jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && createPortal(jsx("div", { ref: menuRef, className: styles$
|
|
5764
|
+
return (jsxs(Fragment, { children: [jsx("div", { onContextMenu: handleContextMenu, children: children }), isOpen && createPortal(jsx("div", { ref: menuRef, className: styles$7["menu"], style: {
|
|
5555
5765
|
top: `${position.y}px`,
|
|
5556
5766
|
left: `${position.x}px`,
|
|
5557
|
-
}, children: options.map(option => (jsx("div", { onClick: () => handleOptionClick(option), className: styles$
|
|
5767
|
+
}, children: options.map(option => (jsx("div", { onClick: () => handleOptionClick(option), className: styles$7["item"], children: option }, option))) }), document.body)] }));
|
|
5558
5768
|
};
|
|
5559
5769
|
|
|
5770
|
+
var styles$6 = {"split":"cw-button-split-module__split__B2KbU","menu":"cw-button-split-module__menu__mKDlt","item":"cw-button-split-module__item__Aqw6f"};
|
|
5771
|
+
|
|
5772
|
+
/**
|
|
5773
|
+
* CwButtonSplit - A primary action joined to a dropdown of alternative actions.
|
|
5774
|
+
*
|
|
5775
|
+
* Composes a main {@link CwButton} with a {@link CwPopoverButton} chevron whose
|
|
5776
|
+
* panel holds a vertical menu of alternatives (rendered as `variant="ghost"` rows).
|
|
5777
|
+
* Both parts share variant, color and size and read as one joined control.
|
|
5778
|
+
*
|
|
5779
|
+
* @example
|
|
5780
|
+
* <CwButtonSplit
|
|
5781
|
+
* text="Save"
|
|
5782
|
+
* icon="save"
|
|
5783
|
+
* onClick={handleSave}
|
|
5784
|
+
* actions={[
|
|
5785
|
+
* { key: "saveAs", label: "Save as…", icon: "copy" },
|
|
5786
|
+
* { key: "saveAndClose", label: "Save and close" },
|
|
5787
|
+
* ]}
|
|
5788
|
+
* onSelect={handleSelect}
|
|
5789
|
+
* />
|
|
5790
|
+
*/
|
|
5791
|
+
function CwButtonSplit({ text, icon, onClick, actions, onSelect, variant = "solid", color = "primary", size = "medium", disabled = false, placement = "bottom-end", "data-testid": dataTestId, }) {
|
|
5792
|
+
const handleSelect = (action) => (event) => {
|
|
5793
|
+
onSelect(action.key);
|
|
5794
|
+
event.currentTarget.closest("[popover]")?.hidePopover();
|
|
5795
|
+
};
|
|
5796
|
+
return (jsxs("div", { className: styles$6.split, "data-variant": variant, "data-testid": dataTestId, children: [jsx(CwButton, { text: text, icon: icon, variant: variant, color: color, size: size, onClick: onClick, disabled: disabled }), jsx(CwPopoverButton, { icon: "chevron-down", title: "More actions", variant: variant, color: color, size: size, disabled: disabled, placement: placement, children: jsx("div", { className: styles$6.menu, children: actions.map((action) => (jsx(CwButton, { variant: "ghost", color: "neutral", text: action.label, icon: action.icon, disabled: action.disabled, className: styles$6.item, onClick: handleSelect(action) }, action.key))) }) })] }));
|
|
5797
|
+
}
|
|
5798
|
+
|
|
5799
|
+
/**
|
|
5800
|
+
* Roving-tabindex single-select behaviour for a custom radio group (e.g. a segmented
|
|
5801
|
+
* button strip that has no native grouping). The active segment is the selected one,
|
|
5802
|
+
* or the first enabled option when nothing is selected. Arrow keys (Right/Down = next,
|
|
5803
|
+
* Left/Up = previous) move focus and select, wrapping around and skipping disabled
|
|
5804
|
+
* options; Space/Enter selects the focused segment.
|
|
5805
|
+
*
|
|
5806
|
+
* Native form controls (e.g. `<input type="radio">` sharing a name) already get this
|
|
5807
|
+
* behaviour from the browser — use this hook only for non-native custom groups.
|
|
5808
|
+
*/
|
|
5809
|
+
function useRovingSingleSelect(options, value, onChange) {
|
|
5810
|
+
const elementRefs = useRef([]);
|
|
5811
|
+
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
5812
|
+
const firstEnabledIndex = options.findIndex((option) => !option.disabled);
|
|
5813
|
+
// If the selected option is disabled it cannot hold the tab stop (disabled elements are out of
|
|
5814
|
+
// the tab order), so fall back to the first enabled option to keep the group reachable by Tab.
|
|
5815
|
+
const activeIndex = selectedIndex >= 0 && !options[selectedIndex]?.disabled ? selectedIndex : firstEnabledIndex;
|
|
5816
|
+
const focusAndSelect = useCallback((index) => {
|
|
5817
|
+
const option = options[index];
|
|
5818
|
+
if (!option || option.disabled)
|
|
5819
|
+
return;
|
|
5820
|
+
onChange(option.value);
|
|
5821
|
+
elementRefs.current[index]?.focus();
|
|
5822
|
+
}, [options, onChange]);
|
|
5823
|
+
const moveFocus = useCallback((fromIndex, direction) => {
|
|
5824
|
+
const count = options.length;
|
|
5825
|
+
if (count === 0)
|
|
5826
|
+
return;
|
|
5827
|
+
let nextIndex = fromIndex;
|
|
5828
|
+
for (let step = 0; step < count; step++) {
|
|
5829
|
+
nextIndex = (nextIndex + direction + count) % count;
|
|
5830
|
+
if (!options[nextIndex]?.disabled) {
|
|
5831
|
+
focusAndSelect(nextIndex);
|
|
5832
|
+
return;
|
|
5833
|
+
}
|
|
5834
|
+
}
|
|
5835
|
+
}, [options, focusAndSelect]);
|
|
5836
|
+
const getSegmentProps = useCallback((index) => ({
|
|
5837
|
+
tabIndex: index === activeIndex ? 0 : -1,
|
|
5838
|
+
ref: (element) => {
|
|
5839
|
+
elementRefs.current[index] = element;
|
|
5840
|
+
},
|
|
5841
|
+
onKeyDown: (event) => {
|
|
5842
|
+
switch (event.key) {
|
|
5843
|
+
case "ArrowRight":
|
|
5844
|
+
case "ArrowDown":
|
|
5845
|
+
event.preventDefault();
|
|
5846
|
+
moveFocus(index, 1);
|
|
5847
|
+
break;
|
|
5848
|
+
case "ArrowLeft":
|
|
5849
|
+
case "ArrowUp":
|
|
5850
|
+
event.preventDefault();
|
|
5851
|
+
moveFocus(index, -1);
|
|
5852
|
+
break;
|
|
5853
|
+
case " ":
|
|
5854
|
+
case "Enter":
|
|
5855
|
+
event.preventDefault();
|
|
5856
|
+
focusAndSelect(index);
|
|
5857
|
+
break;
|
|
5858
|
+
}
|
|
5859
|
+
},
|
|
5860
|
+
}), [activeIndex, moveFocus, focusAndSelect]);
|
|
5861
|
+
return { activeIndex, getSegmentProps };
|
|
5862
|
+
}
|
|
5863
|
+
|
|
5864
|
+
var styles$5 = {"switch":"cw-button-switch-module__switch__vdWV-","segment":"cw-button-switch-module__segment__JmVla","iconOnly":"cw-button-switch-module__iconOnly__-kCwj"};
|
|
5865
|
+
|
|
5866
|
+
/**
|
|
5867
|
+
* CwButtonSwitch - Segmented single-select control: a strip of joined CwButtons.
|
|
5868
|
+
*
|
|
5869
|
+
* The selected segment renders `solid`, the others `outline`, both sharing the `color`
|
|
5870
|
+
* theme (`primary` default, `danger`, or `neutral`). It is a proper ARIA radiogroup with
|
|
5871
|
+
* roving tabindex (one tab stop) and arrow-key navigation, provided by
|
|
5872
|
+
* {@link useRovingSingleSelect}. Use for 2–3 mutually-exclusive options that benefit from
|
|
5873
|
+
* being shown side by side; for a longer list use CwRadioGroup.
|
|
5874
|
+
*
|
|
5875
|
+
* `direction="column"` renders the strip vertically (stacked, full-width segments) instead of
|
|
5876
|
+
* the default horizontal `row`; arrow-key navigation handles both orientations.
|
|
5877
|
+
*
|
|
5878
|
+
* Set `iconOnly` to render just each option's icon; the option's `label` is still required
|
|
5879
|
+
* and is passed as the segment title, so it becomes the tooltip and the accessible name.
|
|
5880
|
+
*
|
|
5881
|
+
* It is an inline control with no form label — if a caption is needed, place it next to the
|
|
5882
|
+
* control at the call site, and pass `aria-label` (or `aria-labelledby`) to name the radiogroup
|
|
5883
|
+
* for screen readers.
|
|
5884
|
+
*
|
|
5885
|
+
* @example
|
|
5886
|
+
* <CwButtonSwitch
|
|
5887
|
+
* options={[{ value: "list", label: "List", icon: "list" }, { value: "grid", label: "Grid", icon: "grid" }]}
|
|
5888
|
+
* value={view}
|
|
5889
|
+
* onChange={setView}
|
|
5890
|
+
* />
|
|
5891
|
+
*/
|
|
5892
|
+
function CwButtonSwitch({ options, value, onChange, size = "medium", color = "primary", iconOnly = false, direction = "row", disabled = false, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "data-testid": dataTestId, }) {
|
|
5893
|
+
const { getSegmentProps } = useRovingSingleSelect(options, value, onChange);
|
|
5894
|
+
return (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) => {
|
|
5895
|
+
const selected = option.value === value;
|
|
5896
|
+
const segmentProps = getSegmentProps(index);
|
|
5897
|
+
return (jsx(CwButton, { text: iconOnly ? undefined : option.label, title: iconOnly ? option.label : undefined, icon: option.icon, size: size, color: color, variant: selected ? "solid" : "outline", role: "radio", "aria-checked": selected, disabled: disabled || option.disabled, onClick: () => onChange(option.value), className: `${styles$5.segment}${iconOnly ? ` ${styles$5.iconOnly}` : ""}`, tabIndex: segmentProps.tabIndex, ref: segmentProps.ref, onKeyDown: segmentProps.onKeyDown }, option.value));
|
|
5898
|
+
}) }));
|
|
5899
|
+
}
|
|
5900
|
+
|
|
5560
5901
|
/**
|
|
5561
5902
|
* Save button wrapper (6 uses pending delete)
|
|
5562
5903
|
* @deprecated Use <CwButton variant="icon" icon="save" onClick={...} /> instead
|
|
@@ -11100,4 +11441,4 @@ const CwFindCrewmember = ({ handleChange, placeHolder = "Search crew…", requir
|
|
|
11100
11441
|
}, "data-direction": direction, children: [jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsx("input", { ref: inputRef, type: "text", value: inputValue, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, placeholder: isInitialLoading ? "Loading…" : placeHolder, disabled: disabled, required: required, autoComplete: "off", "aria-expanded": showDropdown, "aria-haspopup": "listbox", role: "combobox", title: tooltipText }), (isLoading || isInitialLoading) && (jsx("div", { className: "cw-search-input-loading", children: jsx(CwIcon, { iconId: "spinner" }) })), jsx("div", { className: "cw-search-input-icons", children: inputValue && !disabled && !isInitialLoading ? (jsx(CwButton, { type: "button", onClick: handleClear, "aria-label": "Clear selected crewmember", variant: "icon", icon: "close", color: "neutral" })) : (jsx(CwIcon, { iconId: "person" })) })] })] }), renderPanel(jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsx("ul", { children: options.map((option, index) => (jsx("li", { className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option.value), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: option.text }, option.value))) }) }))] }));
|
|
11101
11442
|
};
|
|
11102
11443
|
|
|
11103
|
-
export { CblDragAndDrop, CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable,
|
|
11444
|
+
export { CblDragAndDrop, CwAccordionContainer, CwAlign, CwAnchoredMenu, CwBtnApprove, CwBtnCancel, CwBtnDelete, CwBtnEdit, CwBtnSave, CwButton, CwButtonSplit, CwButtonSwitch, CwCard, CwCardList, CwCheck, CwCheckbox, CwCheckboxGroup, CwChip, CwColorPicker, CwConfirmationPopup, CwContextMenu, CwDatePicker, CwDatePickerTemporal, CwDateRangePicker, CwDateRangePickerTemporal, CwDateTimePicker, CwDateTimePickerCompact, CwDateTimePickerTemporal, CwDialog, CwDigit, CwDisplayMessage, CwDropdown, CwDropdownFilter, CwExpandable, CwFileUploadMultiple, CwFindAirport, CwFindCrewmember, CwGenericTooltip, CwHeadingMain, CwHeadingSecond, CwIcon, CwImageArea, CwImageGallery, CwImageZoom, CwInput, CwInputColor, CwInputDateText, CwInputDatetime, CwInputImage, CwInputNumber, CwInputPhone, CwInputText, CwKeyValueList, CwLabel, CwLoading, CwMasterDetail, CwMessage, CwMessageManager, CwMessageType, CwModal, CwModalHover, CwModalReportFunctional, CwMultiFilter, CwMultiFilterTag, CwNavMenu, CwNote, CwOption, CwPopoverButton, CwRadioGroup, CwReportModal, CwScheduler, CwSearchAsync, CwSearchInput, CwSelect, CwSelectList, CwSelectListItems, CwSortableList, CwSortableTable, CwSuperScheduler, CwTable, CwTableGrouped, CwTableServerSide, CwTabs, CwTagSelector, CwTextArea, CwTime, CwTimePicker, CwToggle, CwTooltipManager, CwTooltipNew, CwTreeView, CwWeekdaySelector, DefaultRowHeader, OnClearPinned, OnClickContextMenu, OnClickEvent, OnClickRowEvent, OnClickRowHeader, OnClickUtc, OnDoubleClickEvent, OnDoubleClickRowEvent, OnDragEvent, OnDropCtrlEvent, OnDropEvent, OnEndClickHeaderEvent, OnLeftDragStart, OnMultiClickEvent, OnPinRow, OnRangeClickEvent, OnRightClickEvent, OnRightClickRow, OnRightDragStart, OnStartClickHeaderEvent, OnUnpinRow, PRESET_LIBRARY_TEMPORAL, PinRowHeader, Resource, Scheduler, SchedulerEvent, SuperScheduler, TooltipConstraintContext, UiEvent, Weekdays, cblEvent, configureCwLoading, eventIsVisible, filterNavItems, filterVisibleEvents, getCwLoadingDefaults, getDefaultDivisions, getEventSizes, getPresetsByKeysTemporal, itemsToMultiFilterTags, sortNavItems, useCwMessage, useSortableList, useSortableTable, useTooltipConstraint };
|