@cwellt_software/cwellt-reactjs-lib 1.0.8 → 1.0.9
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/components/control/input/file/CwFileUpload.d.ts.map +1 -1
- package/dist/components/control/input/file/CwFileUploadMultiple.d.ts +15 -0
- package/dist/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -0
- package/dist/index.cjs.js +192 -42
- package/dist/index.css +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +192 -43
- package/dist/src/components/control/input/file/CwFileUpload.d.ts.map +1 -1
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +15 -0
- package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CwFileUpload.d.ts","sourceRoot":"","sources":["../../../../../src/components/control/input/file/CwFileUpload.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,UAAU,QAAQ;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,YAAY,CAAC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"CwFileUpload.d.ts","sourceRoot":"","sources":["../../../../../src/components/control/input/file/CwFileUpload.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,UAAU,QAAQ;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,YAAY,CAAC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,2CAmFvF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface CwFileUploadMultipleProps {
|
|
3
|
+
name?: string;
|
|
4
|
+
accept?: string;
|
|
5
|
+
multiple?: boolean;
|
|
6
|
+
maxFileSize?: number;
|
|
7
|
+
allowedTypes?: string[];
|
|
8
|
+
onSelect?: (files: FileList | null) => void;
|
|
9
|
+
onError?: (error: string) => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function CwFileUploadMultiple(fileUploadProps: React.PropsWithChildren<CwFileUploadMultipleProps>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=CwFileUploadMultiple.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CwFileUploadMultiple.d.ts","sourceRoot":"","sources":["../../../../../src/components/control/input/file/CwFileUploadMultiple.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAK7D,UAAU,yBAAyB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAC,yBAAyB,CAAC,2CAyRvG"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -423,7 +423,7 @@ function CwLoadingSmall(CwelltLoadingAppointements) {
|
|
|
423
423
|
jsxRuntime.jsx("div", {})) }));
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
var styles$
|
|
426
|
+
var styles$e = {"cw-generic-tooltip-content":"cw-generic-tooltip-module_cw-generic-tooltip-content__la-Si"};
|
|
427
427
|
|
|
428
428
|
// Constants moved outside to prevent recreation
|
|
429
429
|
const margin = 16;
|
|
@@ -534,12 +534,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
534
534
|
const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
|
|
535
535
|
setIsVisible(true);
|
|
536
536
|
}, showDelay);
|
|
537
|
-
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$
|
|
537
|
+
const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$e["cw-generic-tooltip-content"]);
|
|
538
538
|
// Memoize tooltip content creation
|
|
539
539
|
const tooltipContent = React.useMemo(() => {
|
|
540
540
|
if (hide || !isVisible || !content)
|
|
541
541
|
return null;
|
|
542
|
-
return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$
|
|
542
|
+
return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$e["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, style: {
|
|
543
543
|
position: 'fixed',
|
|
544
544
|
top: `${tooltipPosition.top}px`,
|
|
545
545
|
left: `${tooltipPosition.left}px`,
|
|
@@ -554,7 +554,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
|
|
|
554
554
|
clearTooltipTimeout();
|
|
555
555
|
setIsVisible(false);
|
|
556
556
|
}, [clearTooltipTimeout]);
|
|
557
|
-
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$
|
|
557
|
+
return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$e["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, children: [tooltipContent, children] }));
|
|
558
558
|
};
|
|
559
559
|
|
|
560
560
|
// Reference for draggable modal
|
|
@@ -673,7 +673,7 @@ class CwModalIframe extends React__namespace.Component {
|
|
|
673
673
|
}
|
|
674
674
|
}
|
|
675
675
|
|
|
676
|
-
var styles$
|
|
676
|
+
var styles$d = {"cw-dialog-main":"cw-dialog-module_cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module_cw-dialog-button-close__9GRd8"};
|
|
677
677
|
|
|
678
678
|
// Helper function to parse size values
|
|
679
679
|
const parseSize = (size) => {
|
|
@@ -866,7 +866,7 @@ const CwDialog = props => {
|
|
|
866
866
|
onClose();
|
|
867
867
|
}
|
|
868
868
|
}, [onClose]);
|
|
869
|
-
const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$
|
|
869
|
+
const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$d["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
|
|
870
870
|
const content = React.useMemo(() => (jsxRuntime.jsx("section", { children: children })), [children]);
|
|
871
871
|
const footer = React.useMemo(() => (jsxRuntime.jsx("footer", { children: customFooter || (jsxRuntime.jsx("button", { className: "cw-button-icon cwi-save", onClick: onSave })) })), [customFooter, onSave]);
|
|
872
872
|
const resizeHandles = React.useMemo(() => size.autoHeight
|
|
@@ -895,7 +895,7 @@ const CwDialog = props => {
|
|
|
895
895
|
: `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
|
|
896
896
|
return { displayWidth, displayHeight };
|
|
897
897
|
}, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
|
|
898
|
-
return (open && (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$
|
|
898
|
+
return (open && (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$d["cw-dialog-main"], onClick: handleScrimClick, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
|
|
899
899
|
left: `${position.x}px`,
|
|
900
900
|
top: `${position.y}px`,
|
|
901
901
|
width: displayDimensions.displayWidth,
|
|
@@ -1058,7 +1058,7 @@ function CwButton({ text, variant = 'solid', color = 'primary', className = '',
|
|
|
1058
1058
|
return (jsxRuntime.jsx("button", { type: "button", className: buttonClass, ...buttonProps, "data-color": color, children: variant === 'icon' ? null : (children ?? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [icon && jsxRuntime.jsx("span", { className: `cwi-icons cwi-${icon}` }), text && jsxRuntime.jsx("strong", { children: text })] }))) }));
|
|
1059
1059
|
}
|
|
1060
1060
|
|
|
1061
|
-
var styles$
|
|
1061
|
+
var styles$c = {"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"};
|
|
1062
1062
|
|
|
1063
1063
|
/**
|
|
1064
1064
|
* CwCard - A simple card component for displaying content in a contained format
|
|
@@ -1082,11 +1082,11 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1082
1082
|
// Construct class names using CSS modules
|
|
1083
1083
|
const cardClassNames = [
|
|
1084
1084
|
'cw-card',
|
|
1085
|
-
styles$
|
|
1085
|
+
styles$c.card,
|
|
1086
1086
|
className,
|
|
1087
|
-
clickable ? styles$
|
|
1088
|
-
disabled ? styles$
|
|
1089
|
-
isLoading ? styles$
|
|
1087
|
+
clickable ? styles$c.clickable : '',
|
|
1088
|
+
disabled ? styles$c.disabled : '',
|
|
1089
|
+
isLoading ? styles$c.loading : '',
|
|
1090
1090
|
].filter(Boolean).join(' ');
|
|
1091
1091
|
// Handle click event when card is clickable
|
|
1092
1092
|
const handleClick = () => {
|
|
@@ -1103,15 +1103,15 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
|
|
|
1103
1103
|
// Determine if footer should be rendered
|
|
1104
1104
|
const hasFooter = hasChips || footer || (hasActions && direction === "row");
|
|
1105
1105
|
// Actions component to reuse
|
|
1106
|
-
const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$
|
|
1106
|
+
const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$c.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
|
|
1107
1107
|
return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
|
|
1108
1108
|
role: 'button',
|
|
1109
1109
|
tabIndex: 0,
|
|
1110
1110
|
onClick: handleClick,
|
|
1111
|
-
}), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$
|
|
1111
|
+
}), "data-variant": variant, "data-direction": direction, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$c.headerContent, "data-alignment": alignment, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), direction === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$c.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$c.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$c.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$c.footerContent, children: footer }))] })), direction === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$c.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
|
|
1112
1112
|
};
|
|
1113
1113
|
|
|
1114
|
-
var styles$
|
|
1114
|
+
var styles$b = {"cardContainer":"cw-card-list-module_cardContainer__l3YEh","pagination":"cw-card-list-module_pagination__5Ay78","pageInfo":"cw-card-list-module_pageInfo__uiMel","emptyState":"cw-card-list-module_emptyState__RlqiS","sortControls":"cw-card-list-module_sortControls__mWgZA"};
|
|
1115
1115
|
|
|
1116
1116
|
function CwCardList({ items, renderCard, pageSize = 10, className = '', layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, emptyState, sortOptions = [], defaultSortKey }) {
|
|
1117
1117
|
const [currentPage, setCurrentPage] = React.useState(1);
|
|
@@ -1145,10 +1145,10 @@ function CwCardList({ items, renderCard, pageSize = 10, className = '', layout =
|
|
|
1145
1145
|
'--card-width': `${defaultCardWidth}px`,
|
|
1146
1146
|
'--card-gap': `${cardGap}px`
|
|
1147
1147
|
};
|
|
1148
|
-
return (jsxRuntime.jsxs("div", { className: `${className}`, children: [sortOptions.length > 0 && (jsxRuntime.jsxs("div", { className: styles$
|
|
1148
|
+
return (jsxRuntime.jsxs("div", { className: `${className}`, children: [sortOptions.length > 0 && (jsxRuntime.jsxs("div", { className: styles$b.sortControls, children: [jsxRuntime.jsx("label", { htmlFor: "cardlist-sort-select", children: "Sort by:" }), jsxRuntime.jsx("select", { id: "cardlist-sort-select", value: sortKey, onChange: (e) => handleSortChange(e.target.value), className: styles$b.sortSelect, children: sortOptions.map(option => (jsxRuntime.jsx("option", { value: option.key, children: option.label }, option.key))) }), jsxRuntime.jsx("button", { onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'), className: `cw-button-icon ${sortDirection === 'asc' ? 'cwi-arrow-up' : 'cwi-arrow-down'}`, title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}` })] })), isLoading ? (jsxRuntime.jsx("div", { className: styles$b.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$b.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$b.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx("div", { className: styles$b.cardWrapper, children: renderCard(item, index) }, index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$b.pagination, children: [jsxRuntime.jsx("button", { disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)), className: "cw-button-icon cwi-chevron-left" }), jsxRuntime.jsxs("span", { className: styles$b.pageInfo, children: [currentPage, " of ", totalPages] }), jsxRuntime.jsx("button", { disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)), className: "cw-button-icon cwi-chevron-right" })] }))] }))] }));
|
|
1149
1149
|
}
|
|
1150
1150
|
|
|
1151
|
-
var styles$
|
|
1151
|
+
var styles$a = {"cw-accordion":"cw-accordion-module_cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module_cw-accordion-body__xlI8b"};
|
|
1152
1152
|
|
|
1153
1153
|
/**
|
|
1154
1154
|
*
|
|
@@ -1165,7 +1165,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
|
|
|
1165
1165
|
setVisible_accordionBody(!isVisible_accordionBody);
|
|
1166
1166
|
};
|
|
1167
1167
|
// #endregion
|
|
1168
|
-
return (jsxRuntime.jsxs("div", { className: styles$
|
|
1168
|
+
return (jsxRuntime.jsxs("div", { className: styles$a["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$a["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
|
|
1169
1169
|
}
|
|
1170
1170
|
|
|
1171
1171
|
/**
|
|
@@ -1370,7 +1370,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
|
|
|
1370
1370
|
} }), "of ", totalPages, jsxRuntime.jsx("button", { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right", title: "Next" }), jsxRuntime.jsx("button", { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages === 1, className: "cw-button-icon cwi-chevron-right-double", title: "Last" }), jsxRuntime.jsx("select", { value: localItemsPerPage, onChange: handleItemsPerPageChange, style: { marginLeft: "1rem" }, children: pageSizeOptions.map(size => (jsxRuntime.jsxs("option", { value: size, children: [size, " / page"] }, size))) })] }))] }));
|
|
1371
1371
|
}
|
|
1372
1372
|
|
|
1373
|
-
var styles$
|
|
1373
|
+
var styles$9 = {"cw-tabs":"cw-tabs-module_cw-tabs__1pmji","cw-tabs-content":"cw-tabs-module_cw-tabs-content__HTp8d"};
|
|
1374
1374
|
|
|
1375
1375
|
const TabIcon = ({ icon }) => {
|
|
1376
1376
|
if (!icon)
|
|
@@ -1420,7 +1420,7 @@ function CwTabs(CwTabsProps) {
|
|
|
1420
1420
|
const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
|
|
1421
1421
|
? { minWidth: CwTabsProps.tabsListWidth }
|
|
1422
1422
|
: undefined;
|
|
1423
|
-
return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, className: styles$
|
|
1423
|
+
return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, className: styles$9['cw-tabs'], style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$9['cw-tabs-content'], children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
|
|
1424
1424
|
}
|
|
1425
1425
|
|
|
1426
1426
|
/**
|
|
@@ -1538,7 +1538,7 @@ const CwTableGrouped = props => {
|
|
|
1538
1538
|
function CwFileUpload(fileUploadProps) {
|
|
1539
1539
|
const [previewURL, setPreviewURL] = React.useState("");
|
|
1540
1540
|
const [error, setError] = React.useState(null);
|
|
1541
|
-
const [
|
|
1541
|
+
const [_selectedFileName, setSelectedFileName] = React.useState("");
|
|
1542
1542
|
const [_currentHexContent, setCurrentHexContent] = React.useState("");
|
|
1543
1543
|
React.useEffect(() => {
|
|
1544
1544
|
// If there is hexadecimal preview content, set the Preview URL
|
|
@@ -1550,36 +1550,185 @@ function CwFileUpload(fileUploadProps) {
|
|
|
1550
1550
|
const file = event.target.files?.[0];
|
|
1551
1551
|
setSelectedFileName(file?.name ?? "");
|
|
1552
1552
|
if (file) {
|
|
1553
|
-
|
|
1553
|
+
const allowedExts = fileUploadProps.accept.split(',').map(ext => ext.trim().replace('.', '').toLowerCase());
|
|
1554
|
+
const fileExt = file.name.split('.').pop()?.toLowerCase() ?? "";
|
|
1555
|
+
if (!allowedExts.includes(fileExt)) {
|
|
1554
1556
|
setError(`Invalid file type. Only ${fileUploadProps.acceptString} files are allowed.`);
|
|
1555
1557
|
setPreviewURL("");
|
|
1558
|
+
return;
|
|
1556
1559
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
reader.
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1560
|
+
setError(null);
|
|
1561
|
+
const reader = new FileReader();
|
|
1562
|
+
reader.onloadend = () => {
|
|
1563
|
+
if (typeof reader.result === "string") {
|
|
1564
|
+
const hexContent = arrayBufferToHex(reader.result);
|
|
1565
|
+
setCurrentHexContent(hexContent);
|
|
1566
|
+
setPreviewURL(reader.result);
|
|
1567
|
+
setCurrentHexContent(arrayBufferToHex(reader.result));
|
|
1568
|
+
// Call function to store hexadecimal content
|
|
1569
|
+
fileUploadProps.onSaveHexContent(arrayBufferToHex(reader.result));
|
|
1570
|
+
}
|
|
1571
|
+
};
|
|
1572
|
+
reader.readAsDataURL(file);
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
// Function to convert the image buffer into hexadecimal content
|
|
1576
|
+
const arrayBufferToHex = (dataUrl) => {
|
|
1577
|
+
// Decodes the base64 of the URL data
|
|
1578
|
+
const base64 = dataUrl.split(",")[1];
|
|
1579
|
+
const binary = atob(base64);
|
|
1580
|
+
let hex = "";
|
|
1581
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1582
|
+
hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
|
|
1583
|
+
}
|
|
1584
|
+
return hex;
|
|
1585
|
+
};
|
|
1586
|
+
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "row", children: [jsxRuntime.jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsxRuntime.jsx("div", { className: "row error", children: error }), jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
var styles$8 = {"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"};
|
|
1590
|
+
|
|
1591
|
+
function CwFileUploadMultiple(fileUploadProps) {
|
|
1592
|
+
const fileInputRef = React.useRef(null);
|
|
1593
|
+
const [selectedFiles, setSelectedFiles] = React.useState([]);
|
|
1594
|
+
const getFileExtension = (filename) => {
|
|
1595
|
+
return filename.split('.').pop()?.toUpperCase() || '';
|
|
1596
|
+
};
|
|
1597
|
+
const validateFile = (file) => {
|
|
1598
|
+
// Validate the size of the file
|
|
1599
|
+
if (fileUploadProps.maxFileSize) {
|
|
1600
|
+
const fileSizeInMB = file.size / (1024 * 1024);
|
|
1601
|
+
if (fileSizeInMB > fileUploadProps.maxFileSize) {
|
|
1602
|
+
return {
|
|
1603
|
+
isValid: false,
|
|
1604
|
+
error: `File "${file.name}" is too large. Maximum size allowed is ${fileUploadProps.maxFileSize}MB.`
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
// Validate file type by extension (based in accept)
|
|
1609
|
+
if (fileUploadProps.accept) {
|
|
1610
|
+
const acceptedExtensions = fileUploadProps.accept.split(',').map(ext => ext.trim().toLowerCase());
|
|
1611
|
+
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
1612
|
+
const isExtensionValid = acceptedExtensions.some(ext => {
|
|
1613
|
+
if (ext.startsWith('.')) {
|
|
1614
|
+
return ext === fileExtension;
|
|
1615
|
+
}
|
|
1616
|
+
return false;
|
|
1617
|
+
});
|
|
1618
|
+
if (!isExtensionValid) {
|
|
1619
|
+
return {
|
|
1620
|
+
isValid: false,
|
|
1621
|
+
error: `File "${file.name}" has an invalid format. Allowed formats: ${fileUploadProps.accept}`
|
|
1569
1622
|
};
|
|
1570
|
-
reader.readAsDataURL(file);
|
|
1571
1623
|
}
|
|
1572
1624
|
}
|
|
1625
|
+
// Validate MIME type if specified
|
|
1626
|
+
if (fileUploadProps.allowedTypes && fileUploadProps.allowedTypes.length > 0) {
|
|
1627
|
+
const isMimeTypeValid = fileUploadProps.allowedTypes.includes(file.type);
|
|
1628
|
+
if (!isMimeTypeValid) {
|
|
1629
|
+
return {
|
|
1630
|
+
isValid: false,
|
|
1631
|
+
error: `File "${file.name}" has an invalid MIME type. Allowed types: ${fileUploadProps.allowedTypes.join(', ')}`
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return { isValid: true };
|
|
1636
|
+
};
|
|
1637
|
+
const processFiles = (files, existingFiles = []) => {
|
|
1638
|
+
const fileArray = Array.from(files);
|
|
1639
|
+
const validFiles = [...existingFiles]; // Start with existing files
|
|
1640
|
+
const errors = [];
|
|
1641
|
+
for (const file of fileArray) {
|
|
1642
|
+
// Check if the file already exists (by name and size)
|
|
1643
|
+
const isDuplicate = existingFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
|
|
1644
|
+
if (isDuplicate) {
|
|
1645
|
+
errors.push(`File "${file.name}" is already selected.`);
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
const validation = validateFile(file);
|
|
1649
|
+
if (!validation.isValid) {
|
|
1650
|
+
errors.push(validation.error);
|
|
1651
|
+
continue;
|
|
1652
|
+
}
|
|
1653
|
+
validFiles.push(file);
|
|
1654
|
+
}
|
|
1655
|
+
// Show errors if any
|
|
1656
|
+
if (errors.length > 0) {
|
|
1657
|
+
if (fileUploadProps.onError) {
|
|
1658
|
+
fileUploadProps.onError(errors.join('\n'));
|
|
1659
|
+
}
|
|
1660
|
+
else {
|
|
1661
|
+
console.error(errors.join('\n'));
|
|
1662
|
+
alert(errors.join('\n')); // Fallback if there is no onError
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
// If not multiple, only take the first valid file (replace)
|
|
1666
|
+
if (!fileUploadProps.multiple && validFiles.length > 1) {
|
|
1667
|
+
return [validFiles[validFiles.length - 1]]; // Take the last file added
|
|
1668
|
+
}
|
|
1669
|
+
return validFiles;
|
|
1573
1670
|
};
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
const
|
|
1577
|
-
|
|
1578
|
-
|
|
1671
|
+
const updateFileInput = (files) => {
|
|
1672
|
+
// Create FileList with all files
|
|
1673
|
+
const dataTransfer = new DataTransfer();
|
|
1674
|
+
files.forEach(file => dataTransfer.items.add(file));
|
|
1675
|
+
if (fileInputRef.current) {
|
|
1676
|
+
fileInputRef.current.files = dataTransfer.files;
|
|
1677
|
+
}
|
|
1678
|
+
if (fileUploadProps.onSelect) {
|
|
1679
|
+
fileUploadProps.onSelect(dataTransfer.files);
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
const handleFileSelect = (event) => {
|
|
1683
|
+
const files = event.target.files;
|
|
1684
|
+
if (files && files.length > 0) {
|
|
1685
|
+
const updatedFiles = processFiles(files, selectedFiles);
|
|
1686
|
+
if (updatedFiles.length > selectedFiles.length || !fileUploadProps.multiple) {
|
|
1687
|
+
setSelectedFiles(updatedFiles);
|
|
1688
|
+
updateFileInput(updatedFiles);
|
|
1689
|
+
}
|
|
1690
|
+
else {
|
|
1691
|
+
// Clear input if no new valid files were added
|
|
1692
|
+
if (fileInputRef.current) {
|
|
1693
|
+
fileInputRef.current.value = '';
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
const removeFile = (indexToRemove) => {
|
|
1699
|
+
const newFiles = selectedFiles.filter((_, index) => index !== indexToRemove);
|
|
1700
|
+
setSelectedFiles(newFiles);
|
|
1701
|
+
updateFileInput(newFiles);
|
|
1702
|
+
};
|
|
1703
|
+
const removeAllFiles = () => {
|
|
1704
|
+
setSelectedFiles([]);
|
|
1705
|
+
if (fileInputRef.current) {
|
|
1706
|
+
fileInputRef.current.value = '';
|
|
1707
|
+
}
|
|
1708
|
+
if (fileUploadProps.onSelect) {
|
|
1709
|
+
fileUploadProps.onSelect(null);
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
const handleButtonClick = () => {
|
|
1713
|
+
fileInputRef.current?.click();
|
|
1714
|
+
};
|
|
1715
|
+
const handleDragOver = (event) => {
|
|
1716
|
+
event.preventDefault();
|
|
1717
|
+
event.stopPropagation();
|
|
1718
|
+
};
|
|
1719
|
+
const handleDrop = (event) => {
|
|
1720
|
+
event.preventDefault();
|
|
1721
|
+
event.stopPropagation();
|
|
1722
|
+
const files = event.dataTransfer.files;
|
|
1723
|
+
if (files && files.length > 0) {
|
|
1724
|
+
const updatedFiles = processFiles(files, selectedFiles);
|
|
1725
|
+
if (updatedFiles.length > selectedFiles.length || !fileUploadProps.multiple) {
|
|
1726
|
+
setSelectedFiles(updatedFiles);
|
|
1727
|
+
updateFileInput(updatedFiles);
|
|
1728
|
+
}
|
|
1579
1729
|
}
|
|
1580
|
-
return globalThis.Buffer.from(bytes).toString("hex");
|
|
1581
1730
|
};
|
|
1582
|
-
return (jsxRuntime.jsxs("div", { children: [
|
|
1731
|
+
return (jsxRuntime.jsxs("div", { className: `${styles$8.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelect, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$8.hiddenInput }), selectedFiles.length === 0 ? (jsxRuntime.jsxs("div", { className: `${styles$8.uploadArea} ${fileUploadProps.disabled ? styles$8.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$8.uploadTitle}`, children: fileUploadProps.disabled ? 'Upload disabled' : 'Click to upload or drag and drop' }), jsxRuntime.jsxs("p", { className: `${styles$8.uploadSubtitle}`, children: [fileUploadProps.accept ? `Accepted files: ${fileUploadProps.accept}` : 'All file types accepted', !fileUploadProps.multiple && ' (Single file only)'] })] })) : (jsxRuntime.jsxs("div", { className: styles$8.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsxs("small", { className: styles$8.filesCount, children: [selectedFiles.length, " file", selectedFiles.length !== 1 ? 's' : '', " selected"] }), jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: "Clear all" })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$8.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$8.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$8.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$8.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$8.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$8.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$8.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: "Add More Files", icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: "Change File", icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
|
|
1583
1732
|
}
|
|
1584
1733
|
|
|
1585
1734
|
function CwInput(CwInputProps) {
|
|
@@ -7543,6 +7692,7 @@ exports.CwDropdownFilter = CwDropdownFilter;
|
|
|
7543
7692
|
exports.CwDropdownNavigation = CwDropdownNavigation;
|
|
7544
7693
|
exports.CwExpandable = CwExpandable;
|
|
7545
7694
|
exports.CwFileUpload = CwFileUpload;
|
|
7695
|
+
exports.CwFileUploadMultiple = CwFileUploadMultiple;
|
|
7546
7696
|
exports.CwFindAirport = CwFindAirport;
|
|
7547
7697
|
exports.CwFloatingButton = CwFloatingButton;
|
|
7548
7698
|
exports.CwGenericTooltip = CwGenericTooltip;
|